about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.mailmap4
-rw-r--r--Cargo.lock7
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/messages.ftl9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs126
-rw-r--r--compiler/rustc_borrowck/src/nll.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs33
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs41
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs19
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs2
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs195
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs32
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs5
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs41
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs52
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/locals.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs25
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/errors.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs276
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs58
-rw-r--r--compiler/rustc_data_structures/src/sync.rs179
-rw-r--r--compiler/rustc_data_structures/src/sync/freeze.rs61
-rw-r--r--compiler/rustc_data_structures/src/sync/lock.rs375
-rw-r--r--compiler/rustc_data_structures/src/sync/parallel.rs188
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs16
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0401.md6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0788.md16
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs64
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs61
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs11
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs26
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs14
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs69
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs15
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs1
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs75
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs20
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs3
-rw-r--r--compiler/rustc_interface/src/passes.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs8
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl11
-rw-r--r--compiler/rustc_lint/src/context.rs67
-rw-r--r--compiler/rustc_lint/src/errors.rs54
-rw-r--r--compiler/rustc_lint/src/late.rs25
-rw-r--r--compiler/rustc_lint/src/levels.rs95
-rw-r--r--compiler/rustc_lint/src/lints.rs68
-rw-r--r--compiler/rustc_lint/src/tests.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs11
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp11
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp16
-rw-r--r--compiler/rustc_metadata/messages.ftl3
-rw-r--r--compiler/rustc_metadata/src/creader.rs10
-rw-r--r--compiler/rustc_metadata/src/locator.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs205
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs43
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs55
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs50
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs21
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs211
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs10
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs63
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs72
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs94
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs249
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs44
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs5
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs7
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs10
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs18
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs11
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs27
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs158
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs321
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs6
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs2
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs11
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs3
-rw-r--r--compiler/rustc_passes/messages.ftl30
-rw-r--r--compiler/rustc_passes/src/abi_test.rs57
-rw-r--r--compiler/rustc_passes/src/check_attr.rs22
-rw-r--r--compiler/rustc_passes/src/errors.rs16
-rw-r--r--compiler/rustc_passes/src/layout_test.rs85
-rw-r--r--compiler/rustc_passes/src/reachable.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs3
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs12
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs8
-rw-r--r--compiler/rustc_query_system/src/query/job.rs4
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs6
-rw-r--r--compiler/rustc_resolve/messages.ftl33
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs55
-rw-r--r--compiler/rustc_resolve/src/errors.rs44
-rw-r--r--compiler/rustc_resolve/src/ident.rs15
-rw-r--r--compiler/rustc_resolve/src/imports.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_resolve/src/lib.rs23
-rw-r--r--compiler/rustc_resolve/src/macros.rs15
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs89
-rw-r--r--compiler/rustc_session/src/config.rs66
-rw-r--r--compiler/rustc_session/src/cstore.rs4
-rw-r--r--compiler/rustc_session/src/options.rs25
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs25
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs8
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs12
-rw-r--r--compiler/rustc_span/src/span_encoding.rs255
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs13
-rw-r--r--compiler/rustc_target/src/abi/mod.rs21
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_gnullvm.rs26
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs70
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs28
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs38
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect.rs212
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs13
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs23
-rw-r--r--compiler/rustc_transmute/src/lib.rs11
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs18
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs3
-rw-r--r--compiler/rustc_type_ir/src/fold.rs14
-rw-r--r--compiler/rustc_type_ir/src/visit.rs5
-rw-r--r--config.example.toml8
-rw-r--r--library/core/src/cmp.rs7
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/std/src/process.rs60
-rw-r--r--library/std/src/sys/unix/net.rs4
-rw-r--r--library/std/src/sys/unix/process/process_common.rs30
-rw-r--r--library/std/src/sys/unix/thread.rs4
-rw-r--r--library/std/src/sys/unsupported/process.rs20
-rw-r--r--library/std/src/sys/windows/process.rs35
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/format.rs4
-rw-r--r--src/bootstrap/test.rs126
-rwxr-xr-xsrc/ci/run.sh3
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/instrument-coverage.md4
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/pc-windows-gnullvm.md3
-rw-r--r--src/doc/rustdoc/src/write-documentation/re-exports.md2
-rw-r--r--src/doc/unstable-book/src/language-features/coverage-attribute.md (renamed from src/doc/unstable-book/src/language-features/no-coverage.md)8
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/clean/types.rs6
-rw-r--r--src/librustdoc/doctest.rs4
-rw-r--r--src/librustdoc/html/markdown.rs1
-rw-r--r--src/librustdoc/html/render/context.rs56
-rw-r--r--src/librustdoc/html/render/mod.rs48
-rw-r--r--src/librustdoc/html/render/sidebar.rs14
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css64
-rw-r--r--src/librustdoc/html/static/css/settings.css63
-rw-r--r--src/librustdoc/html/static/js/main.js36
-rw-r--r--src/librustdoc/html/static/js/settings.js8
-rw-r--r--src/librustdoc/html/static_files.rs1
-rw-r--r--src/librustdoc/html/templates/page.html1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs43
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs7
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs16
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs7
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs34
-rw-r--r--src/librustdoc/passes/lint/unescaped_backticks.rs13
-rw-r--r--src/librustdoc/passes/mod.rs91
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/driver.sh2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml33
-rw-r--r--src/tools/clippy/CHANGELOG.md5
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md3
-rw-r--r--src/tools/clippy/book/src/development/emitting_lints.md217
-rw-r--r--src/tools/clippy/book/src/development/trait_checking.md105
-rw-r--r--src/tools/clippy/book/src/development/writing_tests.md218
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md24
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs187
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs242
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs268
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs129
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs106
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs391
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs (renamed from src/tools/clippy/clippy_lints/src/incorrect_impls.rs)45
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs13
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/compile-test.rs47
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.stderr2
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr1
-rw-r--r--src/tools/clippy/tests/ui-internal/check_formulation.stderr1
-rw-r--r--src/tools/clippy/tests/ui-internal/if_chain_style.stderr1
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.stderr1
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr1
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs15
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs5
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr22
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs469
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs4
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs13
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs16
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.fixed7
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.rs7
-rw-r--r--src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr14
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.fixed2
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_size.32bit.stderr (renamed from src/tools/clippy/tests/ui/cast_size_32bit.stderr)56
-rw-r--r--src/tools/clippy/tests/ui/cast_size.64bit.stderr (renamed from src/tools/clippy/tests/ui/cast_size.stderr)34
-rw-r--r--src/tools/clippy/tests/ui/cast_size.rs31
-rw-r--r--src/tools/clippy/tests/ui/cast_size_32bit.rs56
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs51
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr70
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy_impl.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11337.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11422.fixed25
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11422.rs25
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11422.stderr16
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-360.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-360.stderr20
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.fixed13
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.rs13
-rw-r--r--src/tools/clippy/tests/ui/derive.rs6
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr20
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed10
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs10
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr13
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs2
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr21
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.rs16
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.stderr2
-rw-r--r--src/tools/clippy/tests/ui/empty_loop.rs3
-rw-r--r--src/tools/clippy/tests/ui/empty_loop.stderr4
-rw-r--r--src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs2
-rw-r--r--src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr17
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed30
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs28
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr12
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.fixed7
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.rs1
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.stderr65
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs13
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr12
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr (renamed from src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr)62
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr (renamed from src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr)44
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast.rs27
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs80
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs12
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed16
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs16
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr10
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed57
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.rs57
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr74
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.rs71
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.stderr119
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed6
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr18
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.fixed1
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.rs1
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.stderr14
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.fixed2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.rs2
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr280
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr (renamed from src/tools/clippy/tests/ui/large_enum_variant.stderr)44
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.fixed17
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.rs11
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.stderr66
-rw-r--r--src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed121
-rw-r--r--src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs121
-rw-r--r--src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr253
-rw-r--r--src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs49
-rw-r--r--src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr164
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed13
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs13
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.rs9
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.stderr42
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.fixed13
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.rs13
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.stderr48
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed19
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string_hashes.rs19
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr144
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs55
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr27
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed (renamed from src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.fixed)0
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_clone_impl.rs (renamed from src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.rs)0
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr (renamed from src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr)19
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed (renamed from src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed)0
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs (renamed from src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs)0
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr (renamed from src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr)11
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs (renamed from src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs)3
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr (renamed from src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr)14
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed8
-rw-r--r--src/tools/clippy/tests/ui/rename.rs8
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr132
-rw-r--r--src/tools/clippy/tests/ui/result_large_err.rs2
-rw-r--r--src/tools/clippy/tests/ui/result_large_err.stderr24
-rw-r--r--src/tools/clippy/tests/ui/similar_names.rs1
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr28
-rw-r--r--src/tools/clippy/tests/ui/single_call_fn.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_call_fn.stderr16
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs16
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr12
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed62
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs1
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr71
-rw-r--r--src/tools/clippy/tests/ui/transmute_32bit.stderr30
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs2
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed1
-rw-r--r--src/tools/clippy/tests/ui/vec.rs1
-rw-r--r--src/tools/clippy/tests/ui/vec.stderr10
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.stderr4
-rw-r--r--src/tools/compiletest/src/read2.rs63
-rw-r--r--src/tools/compiletest/src/read2/tests.rs50
-rw-r--r--src/tools/compiletest/src/runtest.rs40
-rw-r--r--src/tools/miri/.github/workflows/ci.yml2
-rwxr-xr-xsrc/tools/miri/miri2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs10
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs4
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs5
-rw-r--r--src/tools/miri/src/concurrency/thread.rs2
-rw-r--r--src/tools/miri/src/diagnostics.rs24
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/os_str.rs5
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs10
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs44
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs69
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs982
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr2
-rw-r--r--src/tools/miri/tests/pass/function_calls/abi_compat.rs65
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse.rs23
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse2.rs828
-rw-r--r--src/tools/miri/triagebot.toml3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs10
-rw-r--r--tests/codegen/debuginfo-inline-callsite-location.rs28
-rw-r--r--tests/codegen/issues/issue-115385-llvm-jump-threading.rs46
-rw-r--r--tests/coverage-map/status-quo/closure_macro.rs2
-rw-r--r--tests/coverage-map/status-quo/closure_macro_async.rs14
-rw-r--r--tests/coverage-map/status-quo/no_cov_crate.rs14
-rw-r--r--tests/debuginfo/pretty-std-collections.rs1
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir18
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff63
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff63
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff (renamed from tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff)0
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff82
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.32bit.diff (renamed from tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.diff)0
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.64bit.diff26
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.rs22
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff (renamed from tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff)0
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff63
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff126
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff126
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff129
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff129
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff51
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.rs11
-rw-r--r--tests/mir-opt/funky_arms.rs2
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir6
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir6
-rw-r--r--tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir6
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir (renamed from tests/mir-opt/issue_99325.main.built.after.mir)4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir276
-rw-r--r--tests/mir-opt/issue_99325.rs2
-rw-r--r--tests/pretty/tests-are-sorted.pp2
-rw-r--r--tests/run-coverage/closure_macro.coverage2
-rw-r--r--tests/run-coverage/closure_macro.rs2
-rw-r--r--tests/run-coverage/closure_macro_async.coverage14
-rw-r--r--tests/run-coverage/closure_macro_async.rs14
-rw-r--r--tests/run-coverage/no_cov_crate.coverage14
-rw-r--r--tests/run-coverage/no_cov_crate.rs14
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs3
-rw-r--r--tests/run-make/compressed-debuginfo/Makefile15
-rw-r--r--tests/run-make/compressed-debuginfo/foo.rs3
-rw-r--r--tests/run-make/emit-path-unhashed/Makefile8
-rw-r--r--tests/run-make/ls-metadata/Makefile4
-rw-r--r--tests/run-make/lto-linkage-used-attr/Makefile9
-rw-r--r--tests/run-make/lto-linkage-used-attr/lib.rs50
-rw-r--r--tests/run-make/lto-linkage-used-attr/main.rs10
-rw-r--r--tests/run-make/output-filename-overwrites-input/Makefile2
-rw-r--r--tests/rustdoc-gui/help-page.goml18
-rw-r--r--tests/rustdoc-gui/search-no-result.goml12
-rw-r--r--tests/rustdoc/issue-32077-type-alias-impls.rs7
-rw-r--r--tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr10
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs6
-rw-r--r--tests/ui/abi/compatibility.rs85
-rw-r--r--tests/ui/abi/debug.rs4
-rw-r--r--tests/ui/abi/debug.stderr222
-rw-r--r--tests/ui/associated-consts/associated-const-array-len.stderr6
-rw-r--r--tests/ui/associated-consts/issue-105330.stderr10
-rw-r--r--tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr6
-rw-r--r--tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr6
-rw-r--r--tests/ui/associated-types/defaults-suitability.stderr5
-rw-r--r--tests/ui/associated-types/issue-23595-2.stderr2
-rw-r--r--tests/ui/associated-types/issue-59324.stderr6
-rw-r--r--tests/ui/associated-types/issue-64855.stderr6
-rw-r--r--tests/ui/associated-types/issue-85103-layout-debug.rs9
-rw-r--r--tests/ui/associated-types/issue-85103-layout-debug.stderr16
-rw-r--r--tests/ui/associated-types/issue-85103.rs9
-rw-r--r--tests/ui/associated-types/issue-85103.stderr8
-rw-r--r--tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr15
-rw-r--r--tests/ui/async-await/async-is-unwindsafe.stderr2
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed20
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.rs20
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr16
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed36
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs36
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr16
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed30
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.rs30
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr29
-rw-r--r--tests/ui/cast/cast-as-bool.rs40
-rw-r--r--tests/ui/cast/cast-as-bool.stderr56
-rw-r--r--tests/ui/cast/cast-rfc0401-2.rs2
-rw-r--r--tests/ui/cast/cast-rfc0401-2.stderr2
-rw-r--r--tests/ui/codegen/subtyping-enforces-type-equality.rs48
-rw-r--r--tests/ui/codegen/subtyping-enforces-type-equality.stderr1
-rw-r--r--tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr5
-rw-r--r--tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr6
-rw-r--r--tests/ui/const-generics/early/const-param-from-outer-fn.rs2
-rw-r--r--tests/ui/const-generics/early/const-param-from-outer-fn.stderr8
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-85848.stderr6
-rw-r--r--tests/ui/const-generics/issues/issue-86530.stderr5
-rw-r--r--tests/ui/cross/cross-fn-cache-hole.stderr5
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout28
-rw-r--r--tests/ui/dst/dst-bad-coerce1.stderr10
-rw-r--r--tests/ui/dyn-star/error.stderr6
-rw-r--r--tests/ui/error-codes/E0054.stderr2
-rw-r--r--tests/ui/error-codes/E0220.stderr2
-rw-r--r--tests/ui/error-codes/E0277.stderr5
-rw-r--r--tests/ui/error-codes/E0401.stderr22
-rw-r--r--tests/ui/error-codes/E0602.rs2
-rw-r--r--tests/ui/error-codes/E0602.stderr11
-rw-r--r--tests/ui/error-festival.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.rs14
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-no_coverage.rs13
-rw-r--r--tests/ui/feature-gates/feature-gate-no_coverage.stderr12
-rw-r--r--tests/ui/generic-associated-types/issue-101020.stderr5
-rw-r--r--tests/ui/generics/issue-94432-garbage-ice.rs2
-rw-r--r--tests/ui/generics/issue-98432.rs2
-rw-r--r--tests/ui/generics/issue-98432.stderr8
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr15
-rw-r--r--tests/ui/impl-trait/async_scope_creep.rs15
-rw-r--r--tests/ui/impl-trait/async_scope_creep.tait.stderr9
-rw-r--r--tests/ui/imports/import-after-macro-expand-10.rs17
-rw-r--r--tests/ui/imports/import-after-macro-expand-11.rs21
-rw-r--r--tests/ui/imports/import-after-macro-expand-12.rs34
-rw-r--r--tests/ui/imports/import-after-macro-expand-13.rs22
-rw-r--r--tests/ui/imports/import-after-macro-expand-14.rs22
-rw-r--r--tests/ui/imports/import-after-macro-expand-2.rs4
-rw-r--r--tests/ui/imports/import-after-macro-expand-4.rs11
-rw-r--r--tests/ui/imports/import-after-macro-expand-4.stderr53
-rw-r--r--tests/ui/imports/import-after-macro-expand-6.rs4
-rw-r--r--tests/ui/imports/import-after-macro-expand-9.rs17
-rw-r--r--tests/ui/inner-static-type-parameter.rs2
-rw-r--r--tests/ui/inner-static-type-parameter.stderr6
-rw-r--r--tests/ui/issues/issue-18611.stderr6
-rw-r--r--tests/ui/issues/issue-25076.stderr5
-rw-r--r--tests/ui/issues/issue-3214.rs2
-rw-r--r--tests/ui/issues/issue-3214.stderr8
-rw-r--r--tests/ui/issues/issue-35570.stderr6
-rw-r--r--tests/ui/issues/issue-5997-enum.rs2
-rw-r--r--tests/ui/issues/issue-5997-enum.stderr8
-rw-r--r--tests/ui/issues/issue-5997-struct.rs2
-rw-r--r--tests/ui/issues/issue-5997-struct.stderr8
-rw-r--r--tests/ui/issues/issue-60218.stderr5
-rw-r--r--tests/ui/issues/issue-66353.stderr12
-rw-r--r--tests/ui/layout/debug.rs3
-rw-r--r--tests/ui/layout/debug.stderr16
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.rs44
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.stderr32
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.stderr6
-rw-r--r--tests/ui/lifetimes/issue-95023.stderr2
-rw-r--r--tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr6
-rw-r--r--tests/ui/limits/issue-55878.stderr4
-rw-r--r--tests/ui/limits/issue-56762.rs6
-rw-r--r--tests/ui/limits/issue-56762.stderr10
-rw-r--r--tests/ui/linkage-attr/common-linkage-non-zero-init.rs14
-rw-r--r--tests/ui/linkage-attr/common-linkage-non-zero-init.stderr3
-rw-r--r--tests/ui/lint/cli-unknown-force-warn.rs6
-rw-r--r--tests/ui/lint/cli-unknown-force-warn.stderr11
-rw-r--r--tests/ui/lint/lint-ctypes-94223.rs7
-rw-r--r--tests/ui/lint/lint-ctypes-94223.stderr27
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs8
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr16
-rw-r--r--tests/ui/lint/lint-removed-cmdline-deny.rs13
-rw-r--r--tests/ui/lint/lint-removed-cmdline-deny.stderr28
-rw-r--r--tests/ui/lint/lint-removed-cmdline.rs1
-rw-r--r--tests/ui/lint/lint-removed-cmdline.stderr5
-rw-r--r--tests/ui/lint/lint-renamed-cmdline-deny.rs10
-rw-r--r--tests/ui/lint/lint-renamed-cmdline-deny.stderr31
-rw-r--r--tests/ui/lint/lint-renamed-cmdline.rs1
-rw-r--r--tests/ui/lint/lint-renamed-cmdline.stderr8
-rw-r--r--tests/ui/lint/lint-unexported-no-mangle.stderr1
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-allow.rs4
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-deny.rs9
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr31
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline.rs2
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline.stderr20
-rw-r--r--tests/ui/lint/no-coverage.rs40
-rw-r--r--tests/ui/lint/no-coverage.stderr72
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.stderr4
-rw-r--r--tests/ui/namespace/namespace-mix.stderr220
-rw-r--r--tests/ui/nested-ty-params.rs2
-rw-r--r--tests/ui/nested-ty-params.stderr16
-rw-r--r--tests/ui/never_type/feature-gate-never_type_fallback.stderr5
-rw-r--r--tests/ui/never_type/impl_trait_fallback3.stderr6
-rw-r--r--tests/ui/never_type/impl_trait_fallback4.stderr6
-rw-r--r--tests/ui/on-unimplemented/on-trait.stderr10
-rw-r--r--tests/ui/on-unimplemented/parent-label.stderr20
-rw-r--r--tests/ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs21
-rw-r--r--tests/ui/pattern/issue-114896.rs7
-rw-r--r--tests/ui/pattern/issue-114896.stderr11
-rw-r--r--tests/ui/proc-macro/bad-projection.stderr6
-rw-r--r--tests/ui/resolve/bad-type-env-capture.stderr8
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr28
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr34
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs39
-rw-r--r--tests/ui/resolve/issue-12796.rs2
-rw-r--r--tests/ui/resolve/issue-12796.stderr4
-rw-r--r--tests/ui/resolve/issue-3021-c.rs4
-rw-r--r--tests/ui/resolve/issue-3021-c.stderr16
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.rs2
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr6
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.rs10
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.stderr30
-rw-r--r--tests/ui/resolve/resolve-type-param-in-item-in-trait.rs8
-rw-r--r--tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr32
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed16
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.rs15
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr14
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.rs6
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs9
-rw-r--r--tests/ui/sanitize/cfg.rs16
-rw-r--r--tests/ui/span/issue-29595.stderr6
-rw-r--r--tests/ui/specialization/issue-38091.stderr5
-rw-r--r--tests/ui/suggestions/issue-89333.stderr5
-rw-r--r--tests/ui/thir-print/thir-flat-const-variant.stdout96
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout20
-rw-r--r--tests/ui/trait-bounds/issue-82038.stderr6
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr10
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr5
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-locals.stderr10
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-static.stderr5
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums.stderr20
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.current.stderr5
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.next.stderr5
-rw-r--r--tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr5
-rw-r--r--tests/ui/traits/impl-bounds-checking.stderr5
-rw-r--r--tests/ui/traits/new-solver/projection-discr-kind.stderr5
-rw-r--r--tests/ui/traits/non_lifetime_binders/fail.stderr5
-rw-r--r--tests/ui/traits/object-does-not-impl-trait.stderr5
-rw-r--r--tests/ui/traits/vtable-res-trait-param.stderr5
-rw-r--r--tests/ui/trivial-bounds/trivial-bounds-leak.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs25
-rw-r--r--tests/ui/type/type-arg-out-of-scope.rs2
-rw-r--r--tests/ui/type/type-arg-out-of-scope.stderr16
-rw-r--r--tests/ui/union/projection-as-union-type-error-2.stderr5
-rw-r--r--tests/ui/union/projection-as-union-type-error.stderr6
-rw-r--r--tests/ui/unsized/issue-115809.rs13
-rw-r--r--tests/ui/unsized/issue-115809.stderr19
-rw-r--r--tests/ui/unsized/issue-75707.stderr5
-rw-r--r--tests/ui/wf/hir-wf-canonicalized.stderr12
-rw-r--r--tests/ui/wf/issue-95665.stderr5
-rw-r--r--tests/ui/wf/wf-complex-assoc-type.stderr5
-rw-r--r--tests/ui/wf/wf-foreign-fn-decl-ret.stderr11
-rw-r--r--tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr6
-rw-r--r--tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr5
-rw-r--r--tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr5
-rw-r--r--tests/ui/where-clauses/where-clause-method-substituion.stderr5
-rw-r--r--triagebot.toml2
694 files changed, 14983 insertions, 5352 deletions
diff --git a/.gitignore b/.gitignore
index 485968d9c56..4c8d1a03764 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@ build/
 \#*
 \#*\#
 .#*
+rustc-ice-*.txt
 
 ## Tags
 tags
diff --git a/.mailmap b/.mailmap
index c072f6282f1..eb82cf4de8d 100644
--- a/.mailmap
+++ b/.mailmap
@@ -205,6 +205,10 @@ Gareth Daniel Smith <garethdanielsmith@gmail.com> gareth <gareth@gareth-N56VM.(n
 Gareth Daniel Smith <garethdanielsmith@gmail.com> Gareth Smith <garethdanielsmith@gmail.com>
 Gauri Kholkar <f2013002@goa.bits-pilani.ac.in>
 Georges Dubus <georges.dubus@gmail.com> <georges.dubus@compiletoi.net>
+Ghost <ghost> <jonasschievink@gmail.com>
+Ghost <ghost> <jonas.schievink@ferrous-systems.com>
+Ghost <ghost> <jonas@schievink.net>
+Ghost <ghost> <Jonas.Schievink@sony.com>
 Giles Cope <gilescope@gmail.com>
 Glen De Cauwsemaecker <decauwsemaecker.glen@gmail.com>
 Graham Fawcett <graham.fawcett@gmail.com> Graham Fawcett <fawcett@uwindsor.ca>
diff --git a/Cargo.lock b/Cargo.lock
index 4cb2a584e6a..386b57e6a44 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -531,7 +531,7 @@ dependencies = [
  "tester",
  "tokio",
  "toml 0.7.5",
- "ui_test 0.18.1",
+ "ui_test 0.20.0",
  "walkdir",
 ]
 
@@ -558,7 +558,6 @@ dependencies = [
  "declare_clippy_lint",
  "if_chain",
  "itertools",
- "pulldown-cmark",
  "quine-mc_cluskey",
  "regex",
  "regex-syntax 0.7.2",
@@ -5597,9 +5596,9 @@ dependencies = [
 
 [[package]]
 name = "ui_test"
-version = "0.18.1"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "640159421816683e558867ffc0e60ed3a3ed97ec6ccb22c03adb41bf87c5cfa4"
+checksum = "bfd8fb9b15c8332cf51bfc2dc4830063b2446a9c9d732421b56f2478024a3971"
 dependencies = [
  "annotate-snippets",
  "anyhow",
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index f63a9bfcd70..8115c4b55b0 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -29,10 +29,6 @@ ast_lowering_bad_return_type_notation_inputs =
     argument types not allowed with return type notation
     .suggestion = remove the input types
 
-ast_lowering_bad_return_type_notation_needs_dots =
-    return type notation arguments must be elided with `..`
-    .suggestion = add `..`
-
 ast_lowering_bad_return_type_notation_output =
     return type not allowed with return type notation
     .suggestion = remove the return type
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 41db61d391a..32046b0febf 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -770,7 +770,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.tcx.sess.opts.incremental_relative_spans() {
+        if self.tcx.sess.opts.incremental.is_some() {
             span.with_parent(Some(self.current_hir_id_owner.def_id))
         } else {
             // Do not make spans relative when not using incremental compilation.
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index d8ca62565fa..2c7b97afa80 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -74,9 +74,6 @@ borrowck_higher_ranked_subtype_error =
 borrowck_lifetime_constraints_error =
     lifetime may not live long enough
 
-borrowck_move_borrowed =
-    cannot move out of `{$desc}` because it is borrowed
-
 borrowck_move_out_place_here =
     {$place} is moved here
 
@@ -250,12 +247,6 @@ borrowck_var_move_by_use_in_closure =
 borrowck_var_move_by_use_in_generator =
     move occurs due to use in generator
 
-borrowck_var_move_by_use_place_in_closure =
-    move occurs due to use of {$place} in closure
-
-borrowck_var_move_by_use_place_in_generator =
-    move occurs due to use of {$place} in generator
-
 borrowck_var_mutable_borrow_by_use_place_in_closure =
     mutable borrow occurs due to use of {$place} in closure
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 31e863b8a4e..a0edeec59d0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,9 +1,10 @@
+use hir::ExprKind;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
 use rustc_middle::{
     hir::place::PlaceBase,
     mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -370,12 +371,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     err.span_label(span, format!("cannot {act}"));
                 }
                 if suggest {
-                    err.span_suggestion_verbose(
-                        local_decl.source_info.span.shrink_to_lo(),
-                        "consider changing this to be mutable",
-                        "mut ",
-                        Applicability::MachineApplicable,
-                    );
+                    self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
                     let tcx = self.infcx.tcx;
                     if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
                         self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
@@ -491,6 +487,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             ),
                         );
 
+                        self.suggest_using_iter_mut(&mut err);
                         self.suggest_make_local_mut(&mut err, local, name);
                     }
                     _ => {
@@ -710,6 +707,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         )
     }
 
+    fn construct_mut_suggestion_for_local_binding_patterns(
+        &self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        local: Local,
+    ) {
+        let local_decl = &self.body.local_decls[local];
+        debug!("local_decl: {:?}", local_decl);
+        let pat_span = match *local_decl.local_info() {
+            LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+                opt_ty_info: _,
+                opt_match_place: _,
+                pat_span,
+            })) => pat_span,
+            _ => local_decl.source_info.span,
+        };
+
+        struct BindingFinder {
+            span: Span,
+            hir_id: Option<hir::HirId>,
+        }
+
+        impl<'tcx> Visitor<'tcx> for BindingFinder {
+            fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+                if let hir::StmtKind::Local(local) = s.kind {
+                    if local.pat.span == self.span {
+                        self.hir_id = Some(local.hir_id);
+                    }
+                }
+                hir::intravisit::walk_stmt(self, s);
+            }
+        }
+
+        let hir_map = self.infcx.tcx.hir();
+        let def_id = self.body.source.def_id();
+        let hir_id = if let Some(local_def_id) = def_id.as_local()
+            && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
+        {
+            let body = hir_map.body(body_id);
+            let mut v = BindingFinder {
+                span: pat_span,
+                hir_id: None,
+            };
+            v.visit_body(body);
+            v.hir_id
+        } else {
+            None
+        };
+
+        // With ref-binding patterns, the mutability suggestion has to apply to
+        // the binding, not the reference (which would be a type error):
+        //
+        // `let &b = a;` -> `let &(mut b) = a;`
+        if let Some(hir_id) = hir_id
+            && let Some(hir::Node::Local(hir::Local {
+                pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
+                ..
+            })) = hir_map.find(hir_id)
+            && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
+        {
+            err.span_suggestion(
+                pat_span,
+                "consider changing this to be mutable",
+                format!("&(mut {name})"),
+                Applicability::MachineApplicable,
+            );
+            return;
+        }
+
+        err.span_suggestion_verbose(
+            local_decl.source_info.span.shrink_to_lo(),
+            "consider changing this to be mutable",
+            "mut ",
+            Applicability::MachineApplicable,
+        );
+    }
+
     // point to span of upvar making closure call require mutable borrow
     fn show_mutating_upvar(
         &self,
@@ -953,6 +1027,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) {
+        let source = self.body.source;
+        let hir = self.infcx.tcx.hir();
+        if let InstanceDef::Item(def_id) = source.instance
+            && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
+            && let ExprKind::Closure(closure) = kind && closure.movability == None
+            && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
+                let mut cur_expr = expr;
+                while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
+                    if path_segment.ident.name == sym::iter {
+                        // check `_ty` has `iter_mut` method
+                        let res = self
+                            .infcx
+                            .tcx
+                            .typeck(path_segment.hir_id.owner.def_id)
+                            .type_dependent_def_id(cur_expr.hir_id)
+                            .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+                            .map(|def_id| self.infcx.tcx.associated_items(def_id))
+                            .map(|assoc_items| {
+                                assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
+                            });
+
+                        if let Some(mut res) = res && res.peek().is_some() {
+                            err.span_suggestion_verbose(
+                                path_segment.ident.span,
+                                "you may want to use `iter_mut` here",
+                                "iter_mut",
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                        break;
+                    } else {
+                        cur_expr = recv;
+                    }
+                }
+            }
+    }
+
     fn suggest_make_local_mut(
         &self,
         err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 679a19710a7..3f60f5aca71 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::{
     Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
     START_BLOCK,
 };
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_span::symbol::sym;
 use std::env;
@@ -441,7 +442,10 @@ fn for_each_region_constraint<'tcx>(
         let subject = match req.subject {
             ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"),
             ClosureOutlivesSubject::Ty(ty) => {
-                format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)))
+                with_no_trimmed_paths!(format!(
+                    "{}",
+                    ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))
+                ))
             }
         };
         with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?;
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4da7b602571..b7da15af6dc 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -328,19 +328,26 @@ fn check_opaque_type_well_formed<'tcx>(
 
     // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
     // the bounds that the function supplies.
-    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
-    ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
-        .map_err(|err| {
-            infcx
-                .err_ctxt()
-                .report_mismatched_types(
-                    &ObligationCause::misc(definition_span, def_id),
-                    opaque_ty,
-                    definition_ty,
-                    err,
-                )
-                .emit()
-        })?;
+    let mut obligations = vec![];
+    infcx
+        .insert_hidden_type(
+            OpaqueTypeKey { def_id, args: identity_args },
+            &ObligationCause::misc(definition_span, def_id),
+            param_env,
+            definition_ty,
+            true,
+            &mut obligations,
+        )
+        .unwrap();
+    infcx.add_item_bounds_for_hidden_type(
+        def_id.to_def_id(),
+        identity_args,
+        ObligationCause::misc(definition_span, def_id),
+        param_env,
+        definition_ty,
+        &mut obligations,
+    );
+    ocx.register_obligations(obligations);
 
     // Require the hidden type to be well-formed with only the generics of the opaque type.
     // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 56945f43fcd..3b5f1178db5 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -21,6 +21,7 @@ use rustc_hir::BodyOwnerKind;
 use rustc_index::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_span::symbol::{kw, sym};
@@ -332,10 +333,16 @@ impl<'tcx> UniversalRegions<'tcx> {
     pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
         match self.defining_ty {
             DefiningTy::Closure(def_id, args) => {
+                let v = with_no_trimmed_paths!(
+                    args[tcx.generics_of(def_id).parent_count..]
+                        .iter()
+                        .map(|arg| arg.to_string())
+                        .collect::<Vec<_>>()
+                );
                 err.note(format!(
-                    "defining type: {} with closure args {:#?}",
+                    "defining type: {} with closure args [\n    {},\n]",
                     tcx.def_path_str_with_args(def_id, args),
-                    &args[tcx.generics_of(def_id).parent_count..],
+                    v.join(",\n    "),
                 ));
 
                 // FIXME: It'd be nice to print the late-bound regions
@@ -348,10 +355,16 @@ impl<'tcx> UniversalRegions<'tcx> {
                 });
             }
             DefiningTy::Generator(def_id, args, _) => {
+                let v = with_no_trimmed_paths!(
+                    args[tcx.generics_of(def_id).parent_count..]
+                        .iter()
+                        .map(|arg| arg.to_string())
+                        .collect::<Vec<_>>()
+                );
                 err.note(format!(
-                    "defining type: {} with generator args {:#?}",
+                    "defining type: {} with generator args [\n    {},\n]",
                     tcx.def_path_str_with_args(def_id, args),
-                    &args[tcx.generics_of(def_id).parent_count..],
+                    v.join(",\n    "),
                 ));
 
                 // FIXME: As above, we'd like to print out the region
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index c78a0eb04a0..745358fde4b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -34,7 +34,7 @@ pub fn expand_deriving_eq(
             attributes: thin_vec![
                 cx.attr_word(sym::inline, span),
                 cx.attr_nested_word(sym::doc, sym::hidden, span),
-                cx.attr_word(sym::no_coverage, span)
+                cx.attr_nested_word(sym::coverage, sym::off, span)
             ],
             fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index d8846a9f0aa..53ff089d7b4 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -254,7 +254,7 @@ fn generate_test_harness(
     let expn_id = ext_cx.resolver.expansion_for_ast_pass(
         DUMMY_SP,
         AstPass::TestHarness,
-        &[sym::test, sym::rustc_attrs, sym::no_coverage],
+        &[sym::test, sym::rustc_attrs, sym::coverage_attribute],
         None,
     );
     let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
@@ -335,8 +335,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     // #[rustc_main]
     let main_attr = ecx.attr_word(sym::rustc_main, sp);
-    // #[no_coverage]
-    let no_coverage_attr = ecx.attr_word(sym::no_coverage, sp);
+    // #[coverage(off)]
+    let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp);
 
     // pub fn main() { ... }
     let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
@@ -366,7 +366,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let main = P(ast::Item {
         ident: main_id,
-        attrs: thin_vec![main_attr, no_coverage_attr],
+        attrs: thin_vec![main_attr, coverage_attr],
         id: ast::DUMMY_NODE_ID,
         kind: main,
         vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 9159bc36987..54f82dcc8ae 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -723,11 +723,8 @@ fn codegen_stmt<'tcx>(
                 }
                 Rvalue::Repeat(ref operand, times) => {
                     let operand = codegen_operand(fx, operand);
-                    let times = fx
-                        .monomorphize(times)
-                        .eval(fx.tcx, ParamEnv::reveal_all())
-                        .try_to_bits(fx.tcx.data_layout.pointer_size)
-                        .unwrap();
+                    let times =
+                        fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all());
                     if operand.layout().size.bytes() == 0 {
                         // Do nothing for ZST's
                     } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index a934b0767f1..b9d4bc9ff29 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -77,31 +77,9 @@ pub(crate) fn eval_mir_constant<'tcx>(
     fx: &FunctionCx<'_, '_, 'tcx>,
     constant: &Constant<'tcx>,
 ) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
-    let constant_kind = fx.monomorphize(constant.literal);
-    let uv = match constant_kind {
-        ConstantKind::Ty(const_) => match const_.kind() {
-            ty::ConstKind::Unevaluated(uv) => uv.expand(),
-            ty::ConstKind::Value(val) => {
-                return Some((fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty()));
-            }
-            err => span_bug!(
-                constant.span,
-                "encountered bad ConstKind after monomorphizing: {:?}",
-                err
-            ),
-        },
-        ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
-            if fx.tcx.is_static(def) =>
-        {
-            span_bug!(constant.span, "MIR constant refers to static");
-        }
-        ConstantKind::Unevaluated(uv, _) => uv,
-        ConstantKind::Val(val, _) => return Some((val, constant_kind.ty())),
-    };
-
-    let val = fx
-        .tcx
-        .const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None)
+    let cv = fx.monomorphize(constant.literal);
+    let val = cv
+        .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
         .map_err(|err| match err {
             ErrorHandled::Reported(_) => {
                 fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
@@ -111,7 +89,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
             }
         })
         .ok();
-    val.map(|val| (val, constant_kind.ty()))
+    val.map(|val| (val, cv.ty()))
 }
 
 pub(crate) fn codegen_constant_operand<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index d143bcc96ef..3e93830951c 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -269,7 +269,7 @@ fn module_codegen(
     ),
 ) -> OngoingModuleCodegen {
     let (cgu_name, mut cx, mut module, codegened_functions) =
-        tcx.prof.verbose_generic_activity_with_arg("codegen cgu", cgu_name.as_str()).run(|| {
+        tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()).run(|| {
             let cgu = tcx.codegen_unit(cgu_name);
             let mono_items = cgu.items_in_deterministic_order(tcx);
 
@@ -322,35 +322,24 @@ fn module_codegen(
         });
 
     OngoingModuleCodegen::Async(std::thread::spawn(move || {
-        cx.profiler.clone().verbose_generic_activity_with_arg("compile functions", &*cgu_name).run(
-            || {
-                cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
-                    cx.profiler.clone(),
-                )));
-
-                let mut cached_context = Context::new();
-                for codegened_func in codegened_functions {
-                    crate::base::compile_fn(
-                        &mut cx,
-                        &mut cached_context,
-                        &mut module,
-                        codegened_func,
-                    );
-                }
-            },
-        );
+        cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| {
+            cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
+                cx.profiler.clone(),
+            )));
+
+            let mut cached_context = Context::new();
+            for codegened_func in codegened_functions {
+                crate::base::compile_fn(&mut cx, &mut cached_context, &mut module, codegened_func);
+            }
+        });
 
-        let global_asm_object_file = cx
-            .profiler
-            .verbose_generic_activity_with_arg("compile assembly", &*cgu_name)
-            .run(|| {
+        let global_asm_object_file =
+            cx.profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
                 crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm)
             })?;
 
-        let codegen_result = cx
-            .profiler
-            .verbose_generic_activity_with_arg("write object file", &*cgu_name)
-            .run(|| {
+        let codegen_result =
+            cx.profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
                 emit_cgu(
                     &global_asm_config.output_filenames,
                     &cx.profiler,
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 7598c6eee03..41ea0b122de 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -48,19 +48,12 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
 ) -> (Pointer, Value) {
     let (ptr, vtable) = 'block: {
         if let Abi::Scalar(_) = arg.layout().abi {
-            'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
-                for i in 0..arg.layout().fields.count() {
-                    let field = arg.value_field(fx, FieldIdx::new(i));
-                    if !field.layout().is_1zst() {
-                        // we found the one non-1-ZST field that is allowed
-                        // now find *its* non-zero-sized field, or stop if it's a
-                        // pointer
-                        arg = field;
-                        continue 'descend_newtypes;
-                    }
-                }
-
-                bug!("receiver has no non-zero-sized fields {:?}", arg);
+            while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
+                let (idx, _) = arg
+                    .layout()
+                    .non_1zst_field(fx)
+                    .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type");
+                arg = arg.value_field(fx, FieldIdx::new(idx));
             }
         }
 
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index a81585d4128..d1bfd833cd8 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         _fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         _llfn: RValue<'gcc>,
         _mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
+    ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
         // TODO(antoyo)
         None
     }
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index aed4a8f3c85..ddaff36f24b 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix =
     unknown feature specified for `-Ctarget-feature`: `{$feature}`
     .note = features must begin with a `+` to enable or `-` to disable it
 
+codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
+
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
 
 codegen_llvm_write_ir = failed to write LLVM IR to {$path}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 5cf83b1accb..ba263296bb4 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -605,7 +605,7 @@ pub(crate) fn run_pass_manager(
     module: &mut ModuleCodegen<ModuleLlvm>,
     thin: bool,
 ) -> Result<(), FatalError> {
-    let _timer = cgcx.prof.verbose_generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
+    let _timer = cgcx.prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
     let config = cgcx.config(module.kind);
 
     // Now we have one massive module inside of llmod. Time to run the
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index de6541635cf..1f394a7335c 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -5,13 +5,17 @@ use crate::back::profiling::{
 use crate::base;
 use crate::common;
 use crate::errors::{
-    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
+    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
+    WithLlvmError, WriteBytecode,
 };
 use crate::llvm::{self, DiagnosticInfo, PassManager};
 use crate::llvm_util;
 use crate::type_::Type;
 use crate::LlvmCodegenBackend;
 use crate::ModuleLlvm;
+use llvm::{
+    LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
+};
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{
     BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
@@ -234,6 +238,22 @@ pub fn target_machine_factory(
         args_cstr_buff
     };
 
+    let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
+    match sess.opts.debuginfo_compression {
+        rustc_session::config::DebugInfoCompression::Zlib => {
+            if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
+                sess.emit_warning(UnknownCompression { algorithm: "zlib" });
+            }
+        }
+        rustc_session::config::DebugInfoCompression::Zstd => {
+            if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
+                sess.emit_warning(UnknownCompression { algorithm: "zstd" });
+            }
+        }
+        rustc_session::config::DebugInfoCompression::None => {}
+    };
+    let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
+
     Arc::new(move |config: TargetMachineFactoryConfig| {
         let split_dwarf_file =
             path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
@@ -259,6 +279,7 @@ pub fn target_machine_factory(
                 relax_elf_relocations,
                 use_init_array,
                 split_dwarf_file.as_ptr(),
+                debuginfo_compression.as_ptr(),
                 force_emulated_tls,
                 args_cstr_buff.as_ptr() as *const c_char,
                 args_cstr_buff.len(),
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 97a99e51056..8ba7a11abe5 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,13 +1,14 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::coverageinfo::ffi::{Counter, CounterExpression, CounterMappingRegion};
+use crate::coverageinfo::ffi::CounterMappingRegion;
+use crate::coverageinfo::map_data::FunctionCoverage;
 use crate::llvm;
 
 use rustc_codegen_ssa::traits::ConstMethods;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_llvm::RustString;
+use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
@@ -55,7 +56,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         return;
     }
 
-    let mut mapgen = CoverageMapGenerator::new(tcx);
+    let mut global_file_table = GlobalFileTable::new(tcx);
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
@@ -64,12 +65,9 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         let mangled_function_name = tcx.symbol_name(instance).name;
         let source_hash = function_coverage.source_hash();
         let is_used = function_coverage.is_used();
-        let (expressions, counter_regions) =
-            function_coverage.get_expressions_and_counter_regions();
 
-        let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
-            mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
-        });
+        let coverage_mapping_buffer =
+            encode_mappings_for_function(&mut global_file_table, &function_coverage);
 
         if coverage_mapping_buffer.is_empty() {
             if function_coverage.is_used() {
@@ -87,19 +85,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
     }
 
     // Encode all filenames referenced by counters/expressions in this module
-    let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
-        coverageinfo::write_filenames_section_to_buffer(
-            mapgen.filenames.iter().map(Symbol::as_str),
-            filenames_buffer,
-        );
-    });
+    let filenames_buffer = global_file_table.into_filenames_buffer();
 
     let filenames_size = filenames_buffer.len();
     let filenames_val = cx.const_bytes(&filenames_buffer);
     let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer);
 
     // Generate the LLVM IR representation of the coverage map and store it in a well-known global
-    let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val);
+    let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
 
     let covfun_section_name = coverageinfo::covfun_section_name(cx);
     for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
@@ -118,13 +111,13 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
     coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
 }
 
-struct CoverageMapGenerator {
-    filenames: FxIndexSet<Symbol>,
+struct GlobalFileTable {
+    global_file_table: FxIndexSet<Symbol>,
 }
 
-impl CoverageMapGenerator {
+impl GlobalFileTable {
     fn new(tcx: TyCtxt<'_>) -> Self {
-        let mut filenames = FxIndexSet::default();
+        let mut global_file_table = FxIndexSet::default();
         // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
         // requires setting the first filename to the compilation directory.
         // Since rustc generates coverage maps with relative paths, the
@@ -133,94 +126,114 @@ impl CoverageMapGenerator {
         let working_dir = Symbol::intern(
             &tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
         );
-        filenames.insert(working_dir);
-        Self { filenames }
+        global_file_table.insert(working_dir);
+        Self { global_file_table }
     }
 
-    /// Using the `expressions` and `counter_regions` collected for the current function, generate
-    /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
-    /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
-    /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
-    fn write_coverage_mapping<'a>(
-        &mut self,
-        expressions: Vec<CounterExpression>,
-        counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
-        coverage_mapping_buffer: &RustString,
-    ) {
-        let mut counter_regions = counter_regions.collect::<Vec<_>>();
-        if counter_regions.is_empty() {
-            return;
-        }
+    fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> u32 {
+        let (global_file_id, _) = self.global_file_table.insert_full(file_name);
+        global_file_id as u32
+    }
 
-        let mut virtual_file_mapping = Vec::new();
-        let mut mapping_regions = Vec::new();
-        let mut current_file_name = None;
-        let mut current_file_id = 0;
-
-        // Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
-        // by filename and position. Capture any new files to compute the `CounterMappingRegion`s
-        // `file_id` (indexing files referenced by the current function), and construct the
-        // function-specific `virtual_file_mapping` from `file_id` to its index in the module's
-        // `filenames` array.
-        counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
-        for (counter, region) in counter_regions {
-            let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
-            let same_file = current_file_name.is_some_and(|p| p == file_name);
-            if !same_file {
-                if current_file_name.is_some() {
-                    current_file_id += 1;
-                }
-                current_file_name = Some(file_name);
-                debug!("  file_id: {} = '{:?}'", current_file_id, file_name);
-                let (filenames_index, _) = self.filenames.insert_full(file_name);
-                virtual_file_mapping.push(filenames_index as u32);
-            }
-            debug!("Adding counter {:?} to map for {:?}", counter, region);
+    fn into_filenames_buffer(self) -> Vec<u8> {
+        // This method takes `self` so that the caller can't accidentally
+        // modify the original file table after encoding it into a buffer.
+
+        llvm::build_byte_buffer(|buffer| {
+            coverageinfo::write_filenames_section_to_buffer(
+                self.global_file_table.iter().map(Symbol::as_str),
+                buffer,
+            );
+        })
+    }
+}
+
+/// Using the expressions and counter regions collected for a single function,
+/// generate the variable-sized payload of its corresponding `__llvm_covfun`
+/// entry. The payload is returned as a vector of bytes.
+///
+/// Newly-encountered filenames will be added to the global file table.
+fn encode_mappings_for_function(
+    global_file_table: &mut GlobalFileTable,
+    function_coverage: &FunctionCoverage<'_>,
+) -> Vec<u8> {
+    let (expressions, counter_regions) = function_coverage.get_expressions_and_counter_regions();
+
+    let mut counter_regions = counter_regions.collect::<Vec<_>>();
+    if counter_regions.is_empty() {
+        return Vec::new();
+    }
+
+    let mut virtual_file_mapping = IndexVec::<u32, u32>::new();
+    let mut mapping_regions = Vec::with_capacity(counter_regions.len());
+
+    // Sort the list of (counter, region) mapping pairs by region, so that they
+    // can be grouped by filename. Prepare file IDs for each filename, and
+    // prepare the mapping data so that we can pass it through FFI to LLVM.
+    counter_regions.sort_by_key(|(_counter, region)| *region);
+    for counter_regions_for_file in
+        counter_regions.group_by(|(_, a), (_, b)| a.file_name == b.file_name)
+    {
+        // Look up (or allocate) the global file ID for this filename.
+        let file_name = counter_regions_for_file[0].1.file_name;
+        let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
+
+        // Associate that global file ID with a local file ID for this function.
+        let local_file_id: u32 = virtual_file_mapping.push(global_file_id);
+        debug!("  file id: local {local_file_id} => global {global_file_id} = '{file_name:?}'");
+
+        // For each counter/region pair in this function+file, convert it to a
+        // form suitable for FFI.
+        for &(counter, region) in counter_regions_for_file {
+            let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = *region;
+
+            debug!("Adding counter {counter:?} to map for {region:?}");
             mapping_regions.push(CounterMappingRegion::code_region(
                 counter,
-                current_file_id,
+                local_file_id,
                 start_line,
                 start_col,
                 end_line,
                 end_col,
             ));
         }
+    }
 
-        // Encode and append the current function's coverage mapping data
+    // Encode the function's coverage mappings into a buffer.
+    llvm::build_byte_buffer(|buffer| {
         coverageinfo::write_mapping_to_buffer(
-            virtual_file_mapping,
+            virtual_file_mapping.raw,
             expressions,
             mapping_regions,
-            coverage_mapping_buffer,
+            buffer,
         );
-    }
+    })
+}
 
-    /// Construct coverage map header and the array of function records, and combine them into the
-    /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
-    /// specific, well-known section and name.
-    fn generate_coverage_map<'ll>(
-        self,
-        cx: &CodegenCx<'ll, '_>,
-        version: u32,
-        filenames_size: usize,
-        filenames_val: &'ll llvm::Value,
-    ) -> &'ll llvm::Value {
-        debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
-
-        // Create the coverage data header (Note, fields 0 and 2 are now always zero,
-        // as of `llvm::coverage::CovMapVersion::Version4`.)
-        let zero_was_n_records_val = cx.const_u32(0);
-        let filenames_size_val = cx.const_u32(filenames_size as u32);
-        let zero_was_coverage_size_val = cx.const_u32(0);
-        let version_val = cx.const_u32(version);
-        let cov_data_header_val = cx.const_struct(
-            &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
-            /*packed=*/ false,
-        );
+/// Construct coverage map header and the array of function records, and combine them into the
+/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
+/// specific, well-known section and name.
+fn generate_coverage_map<'ll>(
+    cx: &CodegenCx<'ll, '_>,
+    version: u32,
+    filenames_size: usize,
+    filenames_val: &'ll llvm::Value,
+) -> &'ll llvm::Value {
+    debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
+
+    // Create the coverage data header (Note, fields 0 and 2 are now always zero,
+    // as of `llvm::coverage::CovMapVersion::Version4`.)
+    let zero_was_n_records_val = cx.const_u32(0);
+    let filenames_size_val = cx.const_u32(filenames_size as u32);
+    let zero_was_coverage_size_val = cx.const_u32(0);
+    let version_val = cx.const_u32(version);
+    let cov_data_header_val = cx.const_struct(
+        &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
+        /*packed=*/ false,
+    );
 
-        // Create the complete LLVM coverage data value to add to the LLVM IR
-        cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
-    }
+    // Create the complete LLVM coverage data value to add to the LLVM IR
+    cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
 }
 
 /// Construct a function record and combine it with the function's coverage mapping data.
@@ -317,10 +330,10 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
     {
         let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
 
-        // If a function is marked `#[no_coverage]`, then skip generating a
+        // If a function is marked `#[coverage(off)]`, then skip generating a
         // dead code stub for it.
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
-            debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id);
+            debug!("skipping unused fn marked #[coverage(off)]: {:?}", non_codegenned_def_id);
             continue;
         }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index ebf4ee4164f..5ca2942ac4e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
-    debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
+    debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
 ) {
     // Find all scopes with variables defined in them.
     let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
@@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>(
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
     variables: &Option<BitSet<SourceScope>>,
-    debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
+    debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
     instantiated: &mut BitSet<SourceScope>,
     scope: SourceScope,
 ) {
@@ -86,7 +86,7 @@ fn make_mir_scope<'ll, 'tcx>(
     let loc = cx.lookup_debug_loc(scope_data.span.lo());
     let file_metadata = file_metadata(cx, &loc.file);
 
-    let dbg_scope = match scope_data.inlined {
+    let parent_dbg_scope = match scope_data.inlined {
         Some((callee, _)) => {
             // FIXME(eddyb) this would be `self.monomorphize(&callee)`
             // if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
@@ -95,18 +95,22 @@ fn make_mir_scope<'ll, 'tcx>(
                 ty::ParamEnv::reveal_all(),
                 ty::EarlyBinder::bind(callee),
             );
-            let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
-            cx.dbg_scope_fn(callee, callee_fn_abi, None)
+            debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
+                let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
+                cx.dbg_scope_fn(callee, callee_fn_abi, None)
+            })
         }
-        None => unsafe {
-            llvm::LLVMRustDIBuilderCreateLexicalBlock(
-                DIB(cx),
-                parent_scope.dbg_scope,
-                file_metadata,
-                loc.line,
-                loc.col,
-            )
-        },
+        None => parent_scope.dbg_scope,
+    };
+
+    let dbg_scope = unsafe {
+        llvm::LLVMRustDIBuilderCreateLexicalBlock(
+            DIB(cx),
+            parent_dbg_scope,
+            file_metadata,
+            loc.line,
+            loc.col,
+        )
     };
 
     let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 487263709e1..52481a1090c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -292,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         llfn: &'ll Value,
         mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
+    ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
         if self.sess().opts.debuginfo == DebugInfo::None {
             return None;
         }
@@ -304,8 +304,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
         };
-        let mut fn_debug_context =
-            FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
+        let mut fn_debug_context = FunctionDebugContext {
+            scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
+            inlined_function_scopes: Default::default(),
+        };
 
         // Fill in all the scopes, with the information from the MIR body.
         compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index fced6d504d2..264c273ba30 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> {
 pub(crate) struct CopyBitcode {
     pub err: std::io::Error,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_debuginfo_compression)]
+pub struct UnknownCompression {
+    pub algorithm: &'static str,
+}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index d283299ac46..ac199624e34 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
+#![feature(slice_group_by)]
 #![feature(impl_trait_in_assoc_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 8e96410deaf..2ebfdae39e8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2131,6 +2131,7 @@ extern "C" {
         RelaxELFRelocations: bool,
         UseInitArray: bool,
         SplitDwarfFile: *const c_char,
+        DebugInfoCompression: *const c_char,
         ForceEmulatedTls: bool,
         ArgsCstrBuff: *const c_char,
         ArgsCstrBuffLen: usize,
@@ -2366,6 +2367,10 @@ extern "C" {
 
     pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
 
+    pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;
+
+    pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;
+
     pub fn LLVMRustGetSymbols(
         buf_ptr: *const u8,
         buf_len: usize,
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 3dc83f50b21..9ce13ff469c 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -23,6 +23,8 @@ codegen_ssa_erroneous_constant = erroneous constant encountered
 
 codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
 
+codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
+
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index f6936c80b77..59efe4cd3cc 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -16,7 +16,10 @@ use rustc_target::spec::{abi, SanitizerSet};
 
 use crate::errors;
 use crate::target_features::from_target_feature;
-use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
+use crate::{
+    errors::{ExpectedCoverageSymbol, ExpectedUsedSymbol},
+    target_features::check_target_feature_trait_unsafe,
+};
 
 fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
     use rustc_middle::mir::mono::Linkage::*;
@@ -128,7 +131,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         .emit();
                 }
             }
-            sym::no_coverage => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE,
+            sym::coverage => {
+                let inner = attr.meta_item_list();
+                match inner.as_deref() {
+                    Some([item]) if item.has_name(sym::off) => {
+                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+                    }
+                    Some([item]) if item.has_name(sym::on) => {
+                        // Allow #[coverage(on)] for being explicit, maybe also in future to enable
+                        // coverage on a smaller scope within an excluded larger scope.
+                    }
+                    Some(_) | None => {
+                        tcx.sess.emit_err(ExpectedCoverageSymbol { span: attr.span });
+                    }
+                }
+            }
             sym::rustc_std_internal_symbol => {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
             }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 067c824aba0..02f022b9454 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -670,10 +670,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                 // avoiding collisions and will make the emitted type names shorter.
                 let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
                     let mut hasher = StableHasher::new();
-                    let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
-                    hcx.while_hashing_spans(false, |hcx| {
-                        ct.to_valtree().hash_stable(hcx, &mut hasher)
-                    });
+                    let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), None).unwrap();
+                    hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
                     hasher.finish::<Hash64>()
                 });
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 41602321ded..fa49095c9e8 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -562,6 +562,13 @@ pub struct UnknownArchiveKind<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_coverage_symbol)]
+pub struct ExpectedCoverageSymbol {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_expected_used_symbol)]
 pub struct ExpectedUsedSymbol {
     #[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index d78a0c49107..d8f6b4ed836 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -928,21 +928,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // we get a value of a built-in pointer type.
                         //
                         // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
-                        'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
-                            && !op.layout.ty.is_ref()
-                        {
-                            for i in 0..op.layout.fields.count() {
-                                let field = op.extract_field(bx, i);
-                                if !field.layout.is_1zst() {
-                                    // we found the one non-1-ZST field that is allowed
-                                    // now find *its* non-zero-sized field, or stop if it's a
-                                    // pointer
-                                    op = field;
-                                    continue 'descend_newtypes;
-                                }
-                            }
-
-                            span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
+                        while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() {
+                            let (idx, _) = op.layout.non_1zst_field(bx).expect(
+                                "not exactly one non-1-ZST field in a `DispatchFromDyn` type",
+                            );
+                            op = op.extract_field(bx, idx);
                         }
 
                         // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
@@ -970,22 +960,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                     Immediate(_) => {
                         // See comment above explaining why we peel these newtypes
-                        'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
-                            && !op.layout.ty.is_ref()
-                        {
-                            for i in 0..op.layout.fields.count() {
-                                let field = op.extract_field(bx, i);
-                                if !field.layout.is_1zst() {
-                                    // We found the one non-1-ZST field that is allowed. (The rules
-                                    // for `DispatchFromDyn` ensure there's exactly one such field.)
-                                    // Now find *its* non-zero-sized field, or stop if it's a
-                                    // pointer.
-                                    op = field;
-                                    continue 'descend_newtypes;
-                                }
-                            }
-
-                            span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
+                        while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() {
+                            let (idx, _) = op.layout.non_1zst_field(bx).expect(
+                                "not exactly one non-1-ZST field in a `DispatchFromDyn` type",
+                            );
+                            op = op.extract_field(bx, idx);
                         }
 
                         // Make sure that we've actually unwrapped the rcvr down
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index babcf9bee24..4d7bd60ceca 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -24,43 +24,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         constant: &mir::Constant<'tcx>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
-        let ct = self.monomorphize(constant.literal);
-        let uv = match ct {
-            mir::ConstantKind::Ty(ct) => match ct.kind() {
-                ty::ConstKind::Unevaluated(uv) => uv.expand(),
-                ty::ConstKind::Value(val) => {
-                    return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val)));
+        self.monomorphize(constant.literal)
+            .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
+            .map_err(|err| {
+                match err {
+                    ErrorHandled::Reported(_) => {
+                        self.cx
+                            .tcx()
+                            .sess
+                            .emit_err(errors::ErroneousConstant { span: constant.span });
+                    }
+                    ErrorHandled::TooGeneric => {
+                        self.cx.tcx().sess.diagnostic().emit_bug(
+                            errors::PolymorphicConstantTooGeneric { span: constant.span },
+                        );
+                    }
                 }
-                err => span_bug!(
-                    constant.span,
-                    "encountered bad ConstKind after monomorphizing: {:?}",
-                    err
-                ),
-            },
-            mir::ConstantKind::Unevaluated(uv, _) => uv,
-            mir::ConstantKind::Val(val, _) => return Ok(val),
-        };
-
-        self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
-            match err {
-                ErrorHandled::Reported(_) => {
-                    self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
-                }
-                ErrorHandled::TooGeneric => {
-                    self.cx
-                        .tcx()
-                        .sess
-                        .diagnostic()
-                        .emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
-                }
-            }
-            err
-        })
+                err
+            })
     }
 
     /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
     /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
     /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
+    ///
+    /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
     pub fn eval_unevaluated_mir_constant_to_valtree(
         &self,
         constant: &mir::Constant<'tcx>,
@@ -80,7 +68,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but
             // the user pass through arbitrary expressions.
             // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real
-            // const generic.
+            // const generic, and get rid of this entire function.
             other => span_bug!(constant.span, "{other:#?}"),
         };
         let uv = self.monomorphize(uv);
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 7cd9efe3ee2..ac705a5f35c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -1,10 +1,12 @@
 use crate::traits::*;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::Instance;
 use rustc_middle::ty::Ty;
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
@@ -17,10 +19,13 @@ use super::{FunctionCx, LocalRef};
 
 use std::ops::Range;
 
-pub struct FunctionDebugContext<S, L> {
+pub struct FunctionDebugContext<'tcx, S, L> {
+    /// Maps from source code to the corresponding debug info scope.
     pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
-}
 
+    /// Maps from an inlined function to its debug info declaration.
+    pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
+}
 #[derive(Copy, Clone)]
 pub enum VariableKind {
     ArgumentVariable(usize /*index*/),
diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs
index da8bf5e7916..378c5401322 100644
--- a/compiler/rustc_codegen_ssa/src/mir/locals.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs
@@ -7,7 +7,6 @@ use rustc_index::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use std::ops::{Index, IndexMut};
-
 pub(super) struct Locals<'tcx, V> {
     values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
 }
@@ -36,17 +35,18 @@ impl<'tcx, V> Locals<'tcx, V> {
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
         assert!(self.locals.values.is_empty());
-
+        // FIXME(#115215): After #115025 get's merged this might not be necessary
         for (local, value) in values.into_iter().enumerate() {
             match value {
                 LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
                 LocalRef::Operand(op) => {
                     let local = mir::Local::from_usize(local);
                     let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
-                    assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type");
+                    if expected_ty != op.layout.ty {
+                        warn!("Unexpected initial operand type. See the issues/114858");
+                    }
                 }
             }
-
             self.locals.values.push(value);
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index bf937c2fc7c..c4408f2db4c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 
     mir: &'tcx mir::Body<'tcx>,
 
-    debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
+    debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>,
 
     llfn: Bx::Function,
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index 63fecaf34fd..4acc0ea076c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         llfn: Self::Function,
         mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
+    ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>;
 
     // FIXME(eddyb) find a common convention for all of the debuginfo-related
     // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index f146b93ff0c..2d20d553ef7 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -4,7 +4,6 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
-use rustc_span::source_map::Spanned;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 use super::InterpCx;
@@ -132,7 +131,8 @@ where
 {
     // Special handling for certain errors
     match error {
-        // Don't emit a new diagnostic for these errors
+        // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
+        // should remain silent.
         err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
             ErrorHandled::TooGeneric
         }
@@ -140,27 +140,8 @@ where
         err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
             ErrorHandled::Reported(guar.into())
         }
-        err_inval!(Layout(layout_error @ LayoutError::SizeOverflow(_))) => {
-            // We must *always* hard error on these, even if the caller wants just a lint.
-            // The `message` makes little sense here, this is a more serious error than the
-            // caller thinks anyway.
-            // See <https://github.com/rust-lang/rust/pull/63152>.
-            let (our_span, frames) = get_span_and_frames();
-            let span = span.unwrap_or(our_span);
-            let mut err =
-                tcx.sess.create_err(Spanned { span, node: layout_error.into_diagnostic() });
-            err.code(rustc_errors::error_code!(E0080));
-            let Some((mut err, handler)) = err.into_diagnostic() else {
-                panic!("did not emit diag");
-            };
-            for frame in frames {
-                err.eager_subdiagnostic(handler, frame);
-            }
-
-            ErrorHandled::Reported(handler.emit_diagnostic(&mut err).unwrap().into())
-        }
+        // Report remaining errors.
         _ => {
-            // Report as hard error.
             let (our_span, frames) = get_span_and_frames();
             let span = span.unwrap_or(our_span);
             let err = mk(span, frames);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 9df3e4030ff..369dc8821d6 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -372,7 +372,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
             };
             let alloc_id = mplace.ptr().provenance.unwrap();
 
-            // Validation failed, report an error. This is always a hard error.
+            // Validation failed, report an error.
             if let Err(error) = validation {
                 let (error, backtrace) = error.into_parts();
                 backtrace.print_backtrace();
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c74fed0e47f..c3c6cbe3991 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -482,6 +482,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
         use UndefinedBehaviorInfo::*;
         match self {
             Ub(msg) => msg.clone().into(),
+            Custom(x) => (x.msg)(),
+            ValidationError(e) => e.diagnostic_message(),
+
             Unreachable => const_eval_unreachable,
             BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
             DivisionByZero => const_eval_division_by_zero,
@@ -513,8 +516,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
             UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
             UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
-            ValidationError(e) => e.diagnostic_message(),
-            Custom(x) => (x.msg)(),
+            AbiMismatchArgument { .. } => const_eval_incompatible_types,
+            AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
         }
     }
 
@@ -525,8 +528,15 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
     ) {
         use UndefinedBehaviorInfo::*;
         match self {
-            Ub(_)
-            | Unreachable
+            Ub(_) => {}
+            Custom(custom) => {
+                (custom.add_args)(&mut |name, value| {
+                    builder.set_arg(name, value);
+                });
+            }
+            ValidationError(e) => e.add_args(handler, builder),
+
+            Unreachable
             | DivisionByZero
             | RemainderByZero
             | DivisionOverflow
@@ -593,11 +603,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                 builder.set_arg("target_size", info.target_size);
                 builder.set_arg("data_size", info.data_size);
             }
-            ValidationError(e) => e.add_args(handler, builder),
-            Custom(custom) => {
-                (custom.add_args)(&mut |name, value| {
-                    builder.set_arg(name, value);
-                });
+            AbiMismatchArgument { caller_ty, callee_ty }
+            | AbiMismatchReturn { caller_ty, callee_ty } => {
+                builder.set_arg("caller_ty", caller_ty.to_string());
+                builder.set_arg("callee_ty", callee_ty.to_string());
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 6c35fb01a93..440ee06e7fe 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -247,9 +247,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         layout: TyAndLayout<'tcx>,
         variant: VariantIdx,
-    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         let discr_layout = self.layout_of(layout.ty.discriminant_ty(*self.tcx))?;
-        Ok(match layout.ty.discriminant_for_variant(*self.tcx, variant) {
+        let discr_value = match layout.ty.discriminant_for_variant(*self.tcx, variant) {
             Some(discr) => {
                 // This type actually has discriminants.
                 assert_eq!(discr.ty, discr_layout.ty);
@@ -260,6 +260,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 assert_eq!(variant.as_u32(), 0);
                 Scalar::from_uint(variant.as_u32(), discr_layout.size)
             }
-        })
+        };
+        Ok(ImmTy::from_scalar(discr_value, discr_layout))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index db1eaf58621..966ce66c7ad 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -749,10 +749,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.stack_mut().push(frame);
 
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
-        for ct in &body.required_consts {
-            let span = ct.span;
-            let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
-            self.eval_mir_constant(&ct, Some(span), None)?;
+        if M::POST_MONO_CHECKS {
+            for ct in &body.required_consts {
+                let span = ct.span;
+                let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
+                self.eval_mir_constant(&ct, Some(span), None)?;
+            }
         }
 
         // done
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 7feed74ceae..3b58f66353b 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -222,7 +222,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let place = self.deref_pointer(&args[0])?;
                 let variant = self.read_discriminant(&place)?;
                 let discr = self.discriminant_for_variant(place.layout, variant)?;
-                self.write_scalar(discr, dest)?;
+                self.write_immediate(*discr, dest)?;
             }
             sym::exact_div => {
                 let l = self.read_immediate(&args[0])?;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 9fda6b037c8..1353b7daf08 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -130,6 +130,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     /// Should the machine panic on allocation failures?
     const PANIC_ON_ALLOC_FAIL: bool;
 
+    /// Should post-monomorphization checks be run when a stack frame is pushed?
+    const POST_MONO_CHECKS: bool = true;
+
     /// Whether memory accesses should be alignment-checked.
     fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
 
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 57f99bd8f61..cf1f7ff75e1 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -301,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let op = self.eval_place_to_op(place, None)?;
                 let variant = self.read_discriminant(&op)?;
                 let discr = self.discriminant_for_variant(op.layout, variant)?;
-                self.write_scalar(discr, &dest)?;
+                self.write_immediate(*discr, &dest)?;
             }
         }
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index eb4673c0edc..e15499bc68d 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -6,12 +6,16 @@ use rustc_middle::{
     mir,
     ty::{
         self,
-        layout::{FnAbiOf, LayoutOf, TyAndLayout},
-        Instance, Ty,
+        layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout},
+        AdtDef, Instance, Ty,
     },
 };
-use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_span::sym;
 use rustc_target::abi::{self, FieldIdx};
+use rustc_target::abi::{
+    call::{ArgAbi, FnAbi, PassMode},
+    Integer,
+};
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -255,93 +259,169 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Find the wrapped inner type of a transparent wrapper.
     /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
-    fn unfold_transparent(&self, layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx> {
+    ///
+    /// We work with `TyAndLayout` here since that makes it much easier to iterate over all fields.
+    fn unfold_transparent(
+        &self,
+        layout: TyAndLayout<'tcx>,
+        may_unfold: impl Fn(AdtDef<'tcx>) -> bool,
+    ) -> TyAndLayout<'tcx> {
         match layout.ty.kind() {
-            ty::Adt(adt_def, _) if adt_def.repr().transparent() => {
+            ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => {
                 assert!(!adt_def.is_enum());
-                // Find the non-1-ZST field.
-                let mut non_1zst_fields = (0..layout.fields.count()).filter_map(|idx| {
-                    let field = layout.field(self, idx);
-                    if field.is_1zst() { None } else { Some(field) }
-                });
-                let first = non_1zst_fields.next().expect("`unfold_transparent` called on 1-ZST");
-                assert!(
-                    non_1zst_fields.next().is_none(),
-                    "more than one non-1-ZST field in a transparent type"
-                );
-
-                // Found it!
-                self.unfold_transparent(first)
+                // Find the non-1-ZST field, and recurse.
+                let (_, field) = layout.non_1zst_field(self).unwrap();
+                self.unfold_transparent(field, may_unfold)
             }
             // Not a transparent type, no further unfolding.
             _ => layout,
         }
     }
 
+    /// Unwrap types that are guaranteed a null-pointer-optimization
+    fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
+        // Check if this is `Option` wrapping some type.
+        let inner = match layout.ty.kind() {
+            ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => {
+                args[0].as_type().unwrap()
+            }
+            _ => {
+                // Not an `Option`.
+                return Ok(layout);
+            }
+        };
+        let inner = self.layout_of(inner)?;
+        // Check if the inner type is one of the NPO-guaranteed ones.
+        // For that we first unpeel transparent *structs* (but not unions).
+        let is_npo = |def: AdtDef<'tcx>| {
+            self.tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
+        };
+        let inner = self.unfold_transparent(inner, /* may_unfold */ |def| {
+            // Stop at NPO tpyes so that we don't miss that attribute in the check below!
+            def.is_struct() && !is_npo(def)
+        });
+        Ok(match inner.ty.kind() {
+            ty::Ref(..) | ty::FnPtr(..) => {
+                // Option<&T> behaves like &T, and same for fn()
+                inner
+            }
+            ty::Adt(def, _) if is_npo(*def) => {
+                // Once we found a `nonnull_optimization_guaranteed` type, further strip off
+                // newtype structs from it to find the underlying ABI type.
+                self.unfold_transparent(inner, /* may_unfold */ |def| def.is_struct())
+            }
+            _ => {
+                // Everything else we do not unfold.
+                layout
+            }
+        })
+    }
+
     /// Check if these two layouts look like they are fn-ABI-compatible.
     /// (We also compare the `PassMode`, so this doesn't have to check everything. But it turns out
     /// that only checking the `PassMode` is insufficient.)
     fn layout_compat(
         &self,
-        caller_layout: TyAndLayout<'tcx>,
-        callee_layout: TyAndLayout<'tcx>,
-    ) -> bool {
-        if caller_layout.ty == callee_layout.ty {
-            // Fast path: equal types are definitely compatible.
-            return true;
+        caller: TyAndLayout<'tcx>,
+        callee: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, bool> {
+        // Fast path: equal types are definitely compatible.
+        if caller.ty == callee.ty {
+            return Ok(true);
         }
-
-        match caller_layout.abi {
-            // For Scalar/Vector/ScalarPair ABI, we directly compare them.
-            // NOTE: this is *not* a stable guarantee! It just reflects a property of our current
-            // ABIs. It's also fragile; the same pair of types might be considered ABI-compatible
-            // when used directly by-value but not considered compatible as a struct field or array
-            // element.
-            abi::Abi::Scalar(..) | abi::Abi::ScalarPair(..) | abi::Abi::Vector { .. } => {
-                caller_layout.abi.eq_up_to_validity(&callee_layout.abi)
-            }
-            _ => {
-                // Everything else is compatible only if they newtype-wrap the same type, or if they are both 1-ZST.
-                // (The latter part is needed to ensure e.g. that `struct Zst` is compatible with `struct Wrap((), Zst)`.)
-                // This is conservative, but also means that our check isn't quite so heavily dependent on the `PassMode`,
-                // which means having ABI-compatibility on one target is much more likely to imply compatibility for other targets.
-                if caller_layout.is_1zst() || callee_layout.is_1zst() {
-                    // If either is a 1-ZST, both must be.
-                    caller_layout.is_1zst() && callee_layout.is_1zst()
-                } else {
-                    // Neither is a 1-ZST, so we can check what they are wrapping.
-                    self.unfold_transparent(caller_layout).ty
-                        == self.unfold_transparent(callee_layout).ty
+        // 1-ZST are compatible with all 1-ZST (and with nothing else).
+        if caller.is_1zst() || callee.is_1zst() {
+            return Ok(caller.is_1zst() && callee.is_1zst());
+        }
+        // Unfold newtypes and NPO optimizations.
+        let unfold = |layout: TyAndLayout<'tcx>| {
+            self.unfold_npo(self.unfold_transparent(layout, /* may_unfold */ |_def| true))
+        };
+        let caller = unfold(caller)?;
+        let callee = unfold(callee)?;
+        // Now see if these inner types are compatible.
+
+        // Compatible pointer types. For thin pointers, we have to accept even non-`repr(transparent)`
+        // things as compatible due to `DispatchFromDyn`. For instance, `Rc<i32>` and `*mut i32`
+        // must be compatible. So we just accept everything with Pointer ABI as compatible,
+        // even if this will accept some code that is not stably guaranteed to work.
+        // This also handles function pointers.
+        let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.abi {
+            abi::Abi::Scalar(s) => match s.primitive() {
+                abi::Primitive::Pointer(addr_space) => Some(addr_space),
+                _ => None,
+            },
+            _ => None,
+        };
+        if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) {
+            return Ok(caller == callee);
+        }
+        // For wide pointers we have to get the pointee type.
+        let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option<Ty<'tcx>>> {
+            // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`.
+            Ok(Some(match ty.kind() {
+                ty::Ref(_, ty, _) => *ty,
+                ty::RawPtr(mt) => mt.ty,
+                // We should only accept `Box` with the default allocator.
+                // It's hard to test for that though so we accept every 1-ZST allocator.
+                ty::Adt(def, args)
+                    if def.is_box()
+                        && self.layout_of(args[1].expect_ty()).is_ok_and(|l| l.is_1zst()) =>
+                {
+                    args[0].expect_ty()
                 }
-            }
+                _ => return Ok(None),
+            }))
+        };
+        if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) {
+            // This is okay if they have the same metadata type.
+            let meta_ty = |ty: Ty<'tcx>| {
+                let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, |ty| ty);
+                assert!(
+                    !only_if_sized,
+                    "there should be no more 'maybe has that metadata' types during interpretation"
+                );
+                meta
+            };
+            return Ok(meta_ty(caller) == meta_ty(callee));
+        }
+
+        // Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
+        let int_ty = |ty: Ty<'tcx>| {
+            Some(match ty.kind() {
+                ty::Int(ity) => (Integer::from_int_ty(&self.tcx, *ity), /* signed */ true),
+                ty::Uint(uty) => (Integer::from_uint_ty(&self.tcx, *uty), /* signed */ false),
+                _ => return None,
+            })
+        };
+        if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) {
+            // This is okay if they are the same integer type.
+            return Ok(caller == callee);
         }
+
+        // Fall back to exact equality.
+        // FIXME: We are missing the rules for "repr(C) wrapping compatible types".
+        Ok(caller == callee)
     }
 
     fn check_argument_compat(
         &self,
         caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
         callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
-    ) -> bool {
-        // Ideally `PassMode` would capture everything there is about argument passing, but that is
-        // not the case: in `FnAbi::llvm_type`, also parts of the layout and type information are
-        // used. So we need to check that *both* sufficiently agree to ensures the arguments are
-        // compatible.
-        // For instance, `layout_compat` is needed to reject `i32` vs `f32`, which is not reflected
-        // in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`, which have the same
-        // `abi::Primitive` but different `arg_ext`.
-        if self.layout_compat(caller_abi.layout, callee_abi.layout)
-            && caller_abi.mode.eq_abi(&callee_abi.mode)
-        {
-            // Something went very wrong if our checks don't imply layout ABI compatibility.
-            assert!(caller_abi.layout.eq_abi(&callee_abi.layout));
-            return true;
+    ) -> InterpResult<'tcx, bool> {
+        // We do not want to accept things as ABI-compatible that just "happen to be" compatible on the current target,
+        // so we implement a type-based check that reflects the guaranteed rules for ABI compatibility.
+        if self.layout_compat(caller_abi.layout, callee_abi.layout)? {
+            // Ensure that our checks imply actual ABI compatibility for this concrete call.
+            assert!(caller_abi.eq_abi(&callee_abi));
+            return Ok(true);
         } else {
             trace!(
                 "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
                 caller_abi,
                 callee_abi
             );
-            return false;
+            return Ok(false);
         }
     }
 
@@ -360,6 +440,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         'tcx: 'x,
         'tcx: 'y,
     {
+        assert_eq!(callee_ty, callee_abi.layout.ty);
         if matches!(callee_abi.mode, PassMode::Ignore) {
             // This one is skipped. Still must be made live though!
             if !already_live {
@@ -371,15 +452,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let Some((caller_arg, caller_abi)) = caller_args.next() else {
             throw_ub_custom!(fluent::const_eval_not_enough_caller_args);
         };
+        assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout);
+        // Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are
+        // equal; in closures the types sometimes differ. We just hope that `caller_abi` is the
+        // right type to print to the user.
+
         // Check compatibility
-        if !self.check_argument_compat(caller_abi, callee_abi) {
-            let callee_ty = format!("{}", callee_ty);
-            let caller_ty = format!("{}", caller_arg.layout().ty);
-            throw_ub_custom!(
-                fluent::const_eval_incompatible_types,
-                callee_ty = callee_ty,
-                caller_ty = caller_ty,
-            )
+        if !self.check_argument_compat(caller_abi, callee_abi)? {
+            throw_ub!(AbiMismatchArgument {
+                caller_ty: caller_abi.layout.ty,
+                callee_ty: callee_abi.layout.ty
+            });
         }
         // We work with a copy of the argument for now; if this is in-place argument passing, we
         // will later protect the source it comes from. This means the callee cannot observe if we
@@ -583,7 +666,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // taking into account the `spread_arg`. If we could write
                     // this is a single iterator (that handles `spread_arg`), then
                     // `pass_argument` would be the loop body. It takes care to
-                    // not advance `caller_iter` for ZSTs.
+                    // not advance `caller_iter` for ignored arguments.
                     let mut callee_args_abis = callee_fn_abi.args.iter();
                     for local in body.args_iter() {
                         // Construct the destination place for this argument. At this point all
@@ -645,14 +728,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         throw_ub_custom!(fluent::const_eval_too_many_caller_args);
                     }
                     // Don't forget to check the return type!
-                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret) {
-                        let callee_ty = format!("{}", callee_fn_abi.ret.layout.ty);
-                        let caller_ty = format!("{}", caller_fn_abi.ret.layout.ty);
-                        throw_ub_custom!(
-                            fluent::const_eval_incompatible_return_types,
-                            callee_ty = callee_ty,
-                            caller_ty = caller_ty,
-                        )
+                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
+                        throw_ub!(AbiMismatchReturn {
+                            caller_ty: caller_fn_abi.ret.layout.ty,
+                            callee_ty: callee_fn_abi.ret.layout.ty
+                        });
                     }
                     // Ensure the return place is aligned and dereferenceable, and protect it for
                     // in-place return value passing.
@@ -674,7 +754,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Ok(()) => Ok(()),
                 }
             }
-            // cannot use the shim here, because that will only result in infinite recursion
+            // `InstanceDef::Virtual` does not have callable MIR. Calls to `Virtual` instances must be
+            // codegen'd / interpreted as virtual calls through the vtable.
             ty::InstanceDef::Virtual(def_id, idx) => {
                 let mut args = args.to_vec();
                 // We have to implement all "object safe receivers". So we have to go search for a
@@ -706,25 +787,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         _ => {
                             // Not there yet, search for the only non-ZST field.
                             // (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
-                            let mut non_zst_field = None;
-                            for i in 0..receiver.layout.fields.count() {
-                                let field = self.project_field(&receiver, i)?;
-                                let zst = field.layout.is_1zst();
-                                if !zst {
-                                    assert!(
-                                        non_zst_field.is_none(),
-                                        "multiple non-1-ZST fields in dyn receiver type {}",
-                                        receiver.layout.ty
-                                    );
-                                    non_zst_field = Some(field);
-                                }
-                            }
-                            receiver = non_zst_field.unwrap_or_else(|| {
-                                panic!(
-                                    "no non-1-ZST fields in dyn receiver type {}",
-                                    receiver.layout.ty
-                                )
-                            });
+                            let (idx, _) = receiver.layout.non_1zst_field(self).expect(
+                                "not exactly one non-1-ZST field in a `DispatchFromDyn` type",
+                            );
+                            receiver = self.project_field(&receiver, idx)?;
                         }
                     }
                 };
@@ -798,18 +864,26 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
 
                 // Adjust receiver argument. Layout can be any (thin) ptr.
+                let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
                 args[0] = FnArg::Copy(
                     ImmTy::from_immediate(
                         Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
-                        self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?,
+                        self.layout_of(receiver_ty)?,
                     )
                     .into(),
                 );
                 trace!("Patched receiver operand to {:#?}", args[0]);
+                // Need to also adjust the type in the ABI. Strangely, the layout there is actually
+                // already fine! Just the type is bogus. This is due to what `force_thin_self_ptr`
+                // does in `fn_abi_new_uncached`; supposedly, codegen relies on having the bogus
+                // type, so we just patch this up locally.
+                let mut caller_fn_abi = caller_fn_abi.clone();
+                caller_fn_abi.args[0].layout.ty = receiver_ty;
+
                 // recurse with concrete function
                 self.eval_fn_call(
                     FnVal::Instance(fn_inst),
-                    (caller_abi, caller_fn_abi),
+                    (caller_abi, &caller_fn_abi),
                     &args,
                     with_caller_location,
                     destination,
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 0f769c1f3bf..29516fffd6a 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,7 +1,7 @@
 use crate::fx::{FxHashMap, FxHasher};
 #[cfg(parallel_compiler)]
 use crate::sync::{is_dyn_thread_safe, CacheAligned};
-use crate::sync::{Lock, LockGuard};
+use crate::sync::{Lock, LockGuard, Mode};
 #[cfg(parallel_compiler)]
 use itertools::Either;
 use std::borrow::Borrow;
@@ -73,6 +73,56 @@ impl<T> Sharded<T> {
         }
     }
 
+    /// The shard is selected by hashing `val` with `FxHasher`.
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_value<K: Hash + ?Sized>(&self, _val: &K) -> LockGuard<'_, T> {
+        match self {
+            Self::Single(single) => {
+                // Syncronization is disabled so use the `lock_assume_no_sync` method optimized
+                // for that case.
+
+                // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
+                // `might_be_dyn_thread_safe` was also false.
+                unsafe { single.lock_assume(Mode::NoSync) }
+            }
+            #[cfg(parallel_compiler)]
+            Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)),
+        }
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_hash(&self, hash: u64) -> LockGuard<'_, T> {
+        self.lock_shard_by_index(get_shard_hash(hash))
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_index(&self, _i: usize) -> LockGuard<'_, T> {
+        match self {
+            Self::Single(single) => {
+                // Syncronization is disabled so use the `lock_assume_no_sync` method optimized
+                // for that case.
+
+                // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
+                // `might_be_dyn_thread_safe` was also false.
+                unsafe { single.lock_assume(Mode::NoSync) }
+            }
+            #[cfg(parallel_compiler)]
+            Self::Shards(shards) => {
+                // Syncronization is enabled so use the `lock_assume_sync` method optimized
+                // for that case.
+
+                // SAFETY (get_unchecked): The index gets ANDed with the shard mask, ensuring it is
+                // always inbounds.
+                // SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating
+                // the lock thus `might_be_dyn_thread_safe` was also true.
+                unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) }
+            }
+        }
+    }
+
     #[inline]
     pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> {
         match self {
@@ -124,7 +174,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
         Q: Hash + Eq,
     {
         let hash = make_hash(value);
-        let mut shard = self.get_shard_by_hash(hash).lock();
+        let mut shard = self.lock_shard_by_hash(hash);
         let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value);
 
         match entry {
@@ -144,7 +194,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
         Q: Hash + Eq,
     {
         let hash = make_hash(&value);
-        let mut shard = self.get_shard_by_hash(hash).lock();
+        let mut shard = self.lock_shard_by_hash(hash);
         let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value);
 
         match entry {
@@ -166,7 +216,7 @@ pub trait IntoPointer {
 impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
     pub fn contains_pointer_to<T: Hash + IntoPointer>(&self, value: &T) -> bool {
         let hash = make_hash(&value);
-        let shard = self.get_shard_by_hash(hash).lock();
+        let shard = self.lock_shard_by_hash(hash);
         let value = value.into_pointer();
         shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some()
     }
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 8eda9043e35..cca043ba0d1 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -41,19 +41,21 @@
 //! [^2] `MTLockRef` is a typedef.
 
 pub use crate::marker::*;
-use parking_lot::Mutex;
-use std::any::Any;
 use std::collections::HashMap;
 use std::hash::{BuildHasher, Hash};
 use std::ops::{Deref, DerefMut};
-use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
 
 mod lock;
-pub use lock::{Lock, LockGuard};
+pub use lock::{Lock, LockGuard, Mode};
 
 mod worker_local;
 pub use worker_local::{Registry, WorkerLocal};
 
+mod parallel;
+#[cfg(parallel_compiler)]
+pub use parallel::scope;
+pub use parallel::{join, par_for_each_in, par_map, parallel_guard};
+
 pub use std::sync::atomic::Ordering;
 pub use std::sync::atomic::Ordering::SeqCst;
 
@@ -86,7 +88,6 @@ mod mode {
 
     // Whether thread safety might be enabled.
     #[inline]
-    #[cfg(parallel_compiler)]
     pub fn might_be_dyn_thread_safe() -> bool {
         DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE
     }
@@ -108,37 +109,6 @@ mod mode {
 
 pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
 
-/// A guard used to hold panics that occur during a parallel section to later by unwound.
-/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
-/// hiding errors by ensuring that everything in the section has completed executing before
-/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
-/// output match the parallel compiler for testing purposes.
-pub struct ParallelGuard {
-    panic: Mutex<Option<Box<dyn Any + std::marker::Send + 'static>>>,
-}
-
-impl ParallelGuard {
-    pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
-        catch_unwind(AssertUnwindSafe(f))
-            .map_err(|err| {
-                *self.panic.lock() = Some(err);
-            })
-            .ok()
-    }
-}
-
-/// This gives access to a fresh parallel guard in the closure and will unwind any panics
-/// caught in it after the closure returns.
-#[inline]
-pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
-    let guard = ParallelGuard { panic: Mutex::new(None) };
-    let ret = f(&guard);
-    if let Some(panic) = guard.panic.into_inner() {
-        resume_unwind(panic);
-    }
-    ret
-}
-
 cfg_if! {
     if #[cfg(not(parallel_compiler))] {
         use std::ops::Add;
@@ -230,44 +200,6 @@ cfg_if! {
         pub type AtomicU32 = Atomic<u32>;
         pub type AtomicU64 = Atomic<u64>;
 
-        pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
-            where A: FnOnce() -> RA,
-                  B: FnOnce() -> RB
-        {
-            let (a, b) = parallel_guard(|guard| {
-                let a = guard.run(oper_a);
-                let b = guard.run(oper_b);
-                (a, b)
-            });
-            (a.unwrap(), b.unwrap())
-        }
-
-        #[macro_export]
-        macro_rules! parallel {
-            ($($blocks:block),*) => {{
-                $crate::sync::parallel_guard(|guard| {
-                    $(guard.run(|| $blocks);)*
-                });
-            }}
-        }
-
-        pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) {
-            parallel_guard(|guard| {
-                t.into_iter().for_each(|i| {
-                    guard.run(|| for_each(i));
-                });
-            })
-        }
-
-        pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
-            t: T,
-            mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
-        ) -> C {
-            parallel_guard(|guard| {
-                t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
-            })
-        }
-
         pub use std::rc::Rc as Lrc;
         pub use std::rc::Weak as Weak;
         pub use std::cell::Ref as ReadGuard;
@@ -373,105 +305,6 @@ cfg_if! {
 
         use std::thread;
 
-        #[inline]
-        pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
-        where
-            A: FnOnce() -> RA + DynSend,
-            B: FnOnce() -> RB + DynSend,
-        {
-            if mode::is_dyn_thread_safe() {
-                let oper_a = FromDyn::from(oper_a);
-                let oper_b = FromDyn::from(oper_b);
-                let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()()));
-                (a.into_inner(), b.into_inner())
-            } else {
-                let (a, b) = parallel_guard(|guard| {
-                    let a = guard.run(oper_a);
-                    let b = guard.run(oper_b);
-                    (a, b)
-                });
-                (a.unwrap(), b.unwrap())
-            }
-        }
-
-        // This function only works when `mode::is_dyn_thread_safe()`.
-        pub fn scope<'scope, OP, R>(op: OP) -> R
-        where
-            OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
-            R: DynSend,
-        {
-            let op = FromDyn::from(op);
-            rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
-        }
-
-        /// Runs a list of blocks in parallel. The first block is executed immediately on
-        /// the current thread. Use that for the longest running block.
-        #[macro_export]
-        macro_rules! parallel {
-            (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
-                parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
-            };
-            (impl $fblock:block [$($blocks:expr,)*] []) => {
-                ::rustc_data_structures::sync::scope(|s| {
-                    $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
-                    s.spawn(move |_| block.into_inner()());)*
-                    (|| $fblock)();
-                });
-            };
-            ($fblock:block, $($blocks:block),*) => {
-                if rustc_data_structures::sync::is_dyn_thread_safe() {
-                    // Reverse the order of the later blocks since Rayon executes them in reverse order
-                    // when using a single thread. This ensures the execution order matches that
-                    // of a single threaded rustc.
-                    parallel!(impl $fblock [] [$($blocks),*]);
-                } else {
-                    $crate::sync::parallel_guard(|guard| {
-                        guard.run(|| $fblock);
-                        $(guard.run(|| $blocks);)*
-                    });
-                }
-            };
-        }
-
-        use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
-
-        pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
-            t: T,
-            for_each: impl Fn(I) + DynSync + DynSend
-        ) {
-            parallel_guard(|guard| {
-                if mode::is_dyn_thread_safe() {
-                    let for_each = FromDyn::from(for_each);
-                    t.into_par_iter().for_each(|i| {
-                        guard.run(|| for_each(i));
-                    });
-                } else {
-                    t.into_iter().for_each(|i| {
-                        guard.run(|| for_each(i));
-                    });
-                }
-            });
-        }
-
-        pub fn par_map<
-            I,
-            T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
-            R: std::marker::Send,
-            C: FromIterator<R> + FromParallelIterator<R>
-        >(
-            t: T,
-            map: impl Fn(I) -> R + DynSync + DynSend
-        ) -> C {
-            parallel_guard(|guard| {
-                if mode::is_dyn_thread_safe() {
-                    let map = FromDyn::from(map);
-                    t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
-                } else {
-                    t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
-                }
-            })
-        }
-
         /// This makes locks panic if they are already held.
         /// It is only useful when you are running in a single thread
         const ERROR_CHECKING: bool = false;
diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs
index 58ab91237f4..466c44f59bb 100644
--- a/compiler/rustc_data_structures/src/sync/freeze.rs
+++ b/compiler/rustc_data_structures/src/sync/freeze.rs
@@ -6,6 +6,7 @@ use std::{
     intrinsics::likely,
     marker::PhantomData,
     ops::{Deref, DerefMut},
+    ptr::NonNull,
     sync::atomic::Ordering,
 };
 
@@ -79,7 +80,7 @@ impl<T> FreezeLock<T> {
             } else {
                 Some(self.lock.read())
             },
-            lock: self,
+            data: unsafe { NonNull::new_unchecked(self.data.get()) },
         }
     }
 
@@ -101,7 +102,12 @@ impl<T> FreezeLock<T> {
         if self.frozen.load(Ordering::Relaxed) {
             None
         } else {
-            Some(FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData })
+            Some(FreezeWriteGuard {
+                _lock_guard,
+                data: unsafe { NonNull::new_unchecked(self.data.get()) },
+                frozen: &self.frozen,
+                marker: PhantomData,
+            })
         }
     }
 
@@ -120,52 +126,75 @@ impl<T> FreezeLock<T> {
 
 /// A guard holding shared access to a `FreezeLock` which is in a locked state or frozen.
 #[must_use = "if unused the FreezeLock may immediately unlock"]
-pub struct FreezeReadGuard<'a, T> {
+pub struct FreezeReadGuard<'a, T: ?Sized> {
     _lock_guard: Option<ReadGuard<'a, ()>>,
-    lock: &'a FreezeLock<T>,
+    data: NonNull<T>,
 }
 
-impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> {
+impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> {
     type Target = T;
     #[inline]
     fn deref(&self) -> &T {
-        // SAFETY: If `lock` is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so
-        // this has shared access until the `FreezeReadGuard` is dropped. If `lock` is frozen,
+        // SAFETY: If the lock is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so
+        // this has shared access until the `FreezeReadGuard` is dropped. If the lock is frozen,
         // the data cannot be modified and shared access is sound.
-        unsafe { &*self.lock.data.get() }
+        unsafe { &*self.data.as_ptr() }
+    }
+}
+
+impl<'a, T: ?Sized> FreezeReadGuard<'a, T> {
+    #[inline]
+    pub fn map<U: ?Sized>(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> {
+        FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard }
     }
 }
 
 /// A guard holding mutable access to a `FreezeLock` which is in a locked state or frozen.
 #[must_use = "if unused the FreezeLock may immediately unlock"]
-pub struct FreezeWriteGuard<'a, T> {
+pub struct FreezeWriteGuard<'a, T: ?Sized> {
     _lock_guard: WriteGuard<'a, ()>,
-    lock: &'a FreezeLock<T>,
+    frozen: &'a AtomicBool,
+    data: NonNull<T>,
     marker: PhantomData<&'a mut T>,
 }
 
 impl<'a, T> FreezeWriteGuard<'a, T> {
     pub fn freeze(self) -> &'a T {
-        self.lock.frozen.store(true, Ordering::Release);
+        self.frozen.store(true, Ordering::Release);
 
         // SAFETY: This is frozen so the data cannot be modified and shared access is sound.
-        unsafe { &*self.lock.data.get() }
+        unsafe { &*self.data.as_ptr() }
+    }
+}
+
+impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> {
+    #[inline]
+    pub fn map<U: ?Sized>(
+        mut this: Self,
+        f: impl FnOnce(&mut T) -> &mut U,
+    ) -> FreezeWriteGuard<'a, U> {
+        FreezeWriteGuard {
+            data: NonNull::from(f(&mut *this)),
+            _lock_guard: this._lock_guard,
+            frozen: this.frozen,
+            marker: PhantomData,
+        }
     }
 }
 
-impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> {
+impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> {
     type Target = T;
     #[inline]
     fn deref(&self) -> &T {
         // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has shared access.
-        unsafe { &*self.lock.data.get() }
+        unsafe { &*self.data.as_ptr() }
     }
 }
 
-impl<'a, T: 'a> DerefMut for FreezeWriteGuard<'a, T> {
+impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> {
     #[inline]
     fn deref_mut(&mut self) -> &mut T {
         // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has mutable access.
-        unsafe { &mut *self.lock.data.get() }
+        unsafe { &mut *self.data.as_ptr() }
     }
 }
diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs
index 62cd1b993de..339aebbf81a 100644
--- a/compiler/rustc_data_structures/src/sync/lock.rs
+++ b/compiler/rustc_data_structures/src/sync/lock.rs
@@ -3,224 +3,229 @@
 //!
 //! When `cfg(parallel_compiler)` is not set, the lock is instead a wrapper around `RefCell`.
 
-#[cfg(not(parallel_compiler))]
-use std::cell::RefCell;
-#[cfg(parallel_compiler)]
-use {
-    crate::cold_path,
-    crate::sync::DynSend,
-    crate::sync::DynSync,
-    parking_lot::lock_api::RawMutex,
-    std::cell::Cell,
-    std::cell::UnsafeCell,
-    std::fmt,
-    std::intrinsics::{likely, unlikely},
-    std::marker::PhantomData,
-    std::mem::ManuallyDrop,
-    std::ops::{Deref, DerefMut},
-};
+#![allow(dead_code)]
 
-#[cfg(not(parallel_compiler))]
-pub use std::cell::RefMut as LockGuard;
+use std::fmt;
 
+#[cfg(parallel_compiler)]
+pub use maybe_sync::*;
 #[cfg(not(parallel_compiler))]
-#[derive(Debug)]
-pub struct Lock<T>(RefCell<T>);
+pub use no_sync::*;
 
-#[cfg(not(parallel_compiler))]
-impl<T> Lock<T> {
-    #[inline(always)]
-    pub fn new(inner: T) -> Self {
-        Lock(RefCell::new(inner))
-    }
+#[derive(Clone, Copy, PartialEq)]
+pub enum Mode {
+    NoSync,
+    Sync,
+}
 
-    #[inline(always)]
-    pub fn into_inner(self) -> T {
-        self.0.into_inner()
+mod maybe_sync {
+    use super::Mode;
+    use crate::sync::mode;
+    #[cfg(parallel_compiler)]
+    use crate::sync::{DynSend, DynSync};
+    use parking_lot::lock_api::RawMutex as _;
+    use parking_lot::RawMutex;
+    use std::cell::Cell;
+    use std::cell::UnsafeCell;
+    use std::intrinsics::unlikely;
+    use std::marker::PhantomData;
+    use std::mem::ManuallyDrop;
+    use std::ops::{Deref, DerefMut};
+
+    /// A guard holding mutable access to a `Lock` which is in a locked state.
+    #[must_use = "if unused the Lock will immediately unlock"]
+    pub struct LockGuard<'a, T> {
+        lock: &'a Lock<T>,
+        marker: PhantomData<&'a mut T>,
+
+        /// The syncronization mode of the lock. This is explicitly passed to let LLVM relate it
+        /// to the original lock operation.
+        mode: Mode,
     }
 
-    #[inline(always)]
-    pub fn get_mut(&mut self) -> &mut T {
-        self.0.get_mut()
+    impl<'a, T: 'a> Deref for LockGuard<'a, T> {
+        type Target = T;
+        #[inline]
+        fn deref(&self) -> &T {
+            // SAFETY: We have shared access to the mutable access owned by this type,
+            // so we can give out a shared reference.
+            unsafe { &*self.lock.data.get() }
+        }
     }
 
-    #[inline(always)]
-    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-        self.0.try_borrow_mut().ok()
+    impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
+        #[inline]
+        fn deref_mut(&mut self) -> &mut T {
+            // SAFETY: We have mutable access to the data so we can give out a mutable reference.
+            unsafe { &mut *self.lock.data.get() }
+        }
     }
 
-    #[inline(always)]
-    #[track_caller]
-    pub fn lock(&self) -> LockGuard<'_, T> {
-        self.0.borrow_mut()
+    impl<'a, T: 'a> Drop for LockGuard<'a, T> {
+        #[inline]
+        fn drop(&mut self) {
+            // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
+            // with the `lock.mode` state. This means we access the right union fields.
+            match self.mode {
+                Mode::NoSync => {
+                    let cell = unsafe { &self.lock.mode_union.no_sync };
+                    debug_assert_eq!(cell.get(), true);
+                    cell.set(false);
+                }
+                // SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
+                Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
+            }
+        }
     }
-}
 
-/// A guard holding mutable access to a `Lock` which is in a locked state.
-#[cfg(parallel_compiler)]
-#[must_use = "if unused the Lock will immediately unlock"]
-pub struct LockGuard<'a, T> {
-    lock: &'a Lock<T>,
-    marker: PhantomData<&'a mut T>,
-}
+    union ModeUnion {
+        /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
+        no_sync: ManuallyDrop<Cell<bool>>,
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> Deref for LockGuard<'a, T> {
-    type Target = T;
-    #[inline]
-    fn deref(&self) -> &T {
-        // SAFETY: We have shared access to the mutable access owned by this type,
-        // so we can give out a shared reference.
-        unsafe { &*self.lock.data.get() }
+        /// A lock implementation that's only used if `Lock.mode` is `Sync`.
+        sync: ManuallyDrop<RawMutex>,
     }
-}
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut T {
-        // SAFETY: We have mutable access to the data so we can give out a mutable reference.
-        unsafe { &mut *self.lock.data.get() }
-    }
-}
+    /// The value representing a locked state for the `Cell`.
+    const LOCKED: bool = true;
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> Drop for LockGuard<'a, T> {
-    #[inline]
-    fn drop(&mut self) {
-        // SAFETY: We know that the lock is in a locked
-        // state because it is a invariant of this type.
-        unsafe { self.lock.raw.unlock() };
-    }
-}
+    /// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
+    /// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
+    pub struct Lock<T> {
+        /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
+        /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
+        /// This is set on initialization and never changed.
+        mode: Mode,
 
-#[cfg(parallel_compiler)]
-union LockRawUnion {
-    /// Indicates if the cell is locked. Only used if `LockRaw.sync` is false.
-    cell: ManuallyDrop<Cell<bool>>,
+        mode_union: ModeUnion,
+        data: UnsafeCell<T>,
+    }
 
-    /// A lock implementation that's only used if `LockRaw.sync` is true.
-    lock: ManuallyDrop<parking_lot::RawMutex>,
-}
+    impl<T> Lock<T> {
+        #[inline(always)]
+        pub fn new(inner: T) -> Self {
+            let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
+                // Create the lock with synchronization enabled using the `RawMutex` type.
+                (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
+            } else {
+                // Create the lock with synchronization disabled.
+                (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
+            };
+            Lock { mode, mode_union, data: UnsafeCell::new(inner) }
+        }
 
-/// A raw lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
-/// It contains no associated data and is used in the implementation of `Lock` which does have such data.
-///
-/// A manual implementation of a tagged union is used with the `sync` field and the `LockRawUnion` instead
-/// of using enums as it results in better code generation.
-#[cfg(parallel_compiler)]
-struct LockRaw {
-    /// Indicates if synchronization is used via `opt.lock` if true,
-    /// or if a non-thread safe cell is used via `opt.cell`. This is set on initialization and never changed.
-    sync: bool,
-    opt: LockRawUnion,
-}
+        #[inline(always)]
+        pub fn into_inner(self) -> T {
+            self.data.into_inner()
+        }
 
-#[cfg(parallel_compiler)]
-impl LockRaw {
-    fn new() -> Self {
-        if unlikely(super::mode::might_be_dyn_thread_safe()) {
-            // Create the lock with synchronization enabled using the `RawMutex` type.
-            LockRaw {
-                sync: true,
-                opt: LockRawUnion { lock: ManuallyDrop::new(parking_lot::RawMutex::INIT) },
-            }
-        } else {
-            // Create the lock with synchronization disabled.
-            LockRaw { sync: false, opt: LockRawUnion { cell: ManuallyDrop::new(Cell::new(false)) } }
+        #[inline(always)]
+        pub fn get_mut(&mut self) -> &mut T {
+            self.data.get_mut()
         }
-    }
 
-    #[inline(always)]
-    fn try_lock(&self) -> bool {
-        // SAFETY: This is safe since the union fields are used in accordance with `self.sync`.
-        unsafe {
-            if likely(!self.sync) {
-                if self.opt.cell.get() {
-                    false
-                } else {
-                    self.opt.cell.set(true);
-                    true
+        #[inline(always)]
+        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
+            let mode = self.mode;
+            // SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
+            match mode {
+                Mode::NoSync => {
+                    let cell = unsafe { &self.mode_union.no_sync };
+                    let was_unlocked = cell.get() != LOCKED;
+                    if was_unlocked {
+                        cell.set(LOCKED);
+                    }
+                    was_unlocked
                 }
-            } else {
-                self.opt.lock.try_lock()
+                Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
             }
+            .then(|| LockGuard { lock: self, marker: PhantomData, mode })
         }
-    }
 
-    #[inline(always)]
-    fn lock(&self) {
-        if super::ERROR_CHECKING {
-            // We're in the debugging mode, so assert that the lock is not held so we
-            // get a panic instead of waiting for the lock.
-            assert_eq!(self.try_lock(), true, "lock must not be hold");
-        } else {
-            // SAFETY: This is safe since the union fields are used in accordance with `self.sync`.
+        /// This acquires the lock assuming syncronization is in a specific mode.
+        ///
+        /// Safety
+        /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
+        /// true on lock creation.
+        #[inline(always)]
+        #[track_caller]
+        pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
+            #[inline(never)]
+            #[track_caller]
+            #[cold]
+            fn lock_held() -> ! {
+                panic!("lock was already held")
+            }
+
+            // SAFETY: This is safe since the union fields are used in accordance with `mode`
+            // which also must match `self.mode` due to the safety precondition.
             unsafe {
-                if likely(!self.sync) {
-                    if unlikely(self.opt.cell.replace(true)) {
-                        cold_path(|| panic!("lock was already held"))
+                match mode {
+                    Mode::NoSync => {
+                        if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
+                            lock_held()
+                        }
                     }
-                } else {
-                    self.opt.lock.lock();
+                    Mode::Sync => self.mode_union.sync.lock(),
                 }
             }
+            LockGuard { lock: self, marker: PhantomData, mode }
         }
-    }
 
-    /// This unlocks the lock.
-    ///
-    /// Safety
-    /// This method may only be called if the lock is currently held.
-    #[inline(always)]
-    unsafe fn unlock(&self) {
-        // SAFETY: The union use is safe since the union fields are used in accordance with
-        // `self.sync` and the `unlock` method precondition is upheld by the caller.
-        unsafe {
-            if likely(!self.sync) {
-                debug_assert_eq!(self.opt.cell.get(), true);
-                self.opt.cell.set(false);
-            } else {
-                self.opt.lock.unlock();
-            }
+        #[inline(always)]
+        #[track_caller]
+        pub fn lock(&self) -> LockGuard<'_, T> {
+            unsafe { self.lock_assume(self.mode) }
         }
     }
-}
 
-/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
-/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
-#[cfg(parallel_compiler)]
-pub struct Lock<T> {
-    raw: LockRaw,
-    data: UnsafeCell<T>,
+    #[cfg(parallel_compiler)]
+    unsafe impl<T: DynSend> DynSend for Lock<T> {}
+    #[cfg(parallel_compiler)]
+    unsafe impl<T: DynSend> DynSync for Lock<T> {}
 }
 
-#[cfg(parallel_compiler)]
-impl<T> Lock<T> {
-    #[inline(always)]
-    pub fn new(inner: T) -> Self {
-        Lock { raw: LockRaw::new(), data: UnsafeCell::new(inner) }
-    }
+mod no_sync {
+    use super::Mode;
+    use std::cell::RefCell;
 
-    #[inline(always)]
-    pub fn into_inner(self) -> T {
-        self.data.into_inner()
-    }
+    pub use std::cell::RefMut as LockGuard;
 
-    #[inline(always)]
-    pub fn get_mut(&mut self) -> &mut T {
-        self.data.get_mut()
-    }
+    pub struct Lock<T>(RefCell<T>);
 
-    #[inline(always)]
-    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-        if self.raw.try_lock() { Some(LockGuard { lock: self, marker: PhantomData }) } else { None }
-    }
+    impl<T> Lock<T> {
+        #[inline(always)]
+        pub fn new(inner: T) -> Self {
+            Lock(RefCell::new(inner))
+        }
 
-    #[inline(always)]
-    pub fn lock(&self) -> LockGuard<'_, T> {
-        self.raw.lock();
-        LockGuard { lock: self, marker: PhantomData }
+        #[inline(always)]
+        pub fn into_inner(self) -> T {
+            self.0.into_inner()
+        }
+
+        #[inline(always)]
+        pub fn get_mut(&mut self) -> &mut T {
+            self.0.get_mut()
+        }
+
+        #[inline(always)]
+        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
+            self.0.try_borrow_mut().ok()
+        }
+
+        #[inline(always)]
+        #[track_caller]
+        // This is unsafe to match the API for the `parallel_compiler` case.
+        pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> {
+            self.0.borrow_mut()
+        }
+
+        #[inline(always)]
+        #[track_caller]
+        pub fn lock(&self) -> LockGuard<'_, T> {
+            self.0.borrow_mut()
+        }
     }
 }
 
@@ -244,12 +249,13 @@ impl<T> Lock<T> {
     }
 }
 
-#[cfg(parallel_compiler)]
-unsafe impl<T: DynSend> DynSend for Lock<T> {}
-#[cfg(parallel_compiler)]
-unsafe impl<T: DynSend> DynSync for Lock<T> {}
+impl<T: Default> Default for Lock<T> {
+    #[inline]
+    fn default() -> Self {
+        Lock::new(T::default())
+    }
+}
 
-#[cfg(parallel_compiler)]
 impl<T: fmt::Debug> fmt::Debug for Lock<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.try_lock() {
@@ -267,10 +273,3 @@ impl<T: fmt::Debug> fmt::Debug for Lock<T> {
         }
     }
 }
-
-impl<T: Default> Default for Lock<T> {
-    #[inline]
-    fn default() -> Self {
-        Lock::new(T::default())
-    }
-}
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
new file mode 100644
index 00000000000..1944ddfb710
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -0,0 +1,188 @@
+//! This module defines parallel operations that are implemented in
+//! one way for the serial compiler, and another way the parallel compiler.
+
+#![allow(dead_code)]
+
+use parking_lot::Mutex;
+use std::any::Any;
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+#[cfg(not(parallel_compiler))]
+pub use disabled::*;
+#[cfg(parallel_compiler)]
+pub use enabled::*;
+
+/// A guard used to hold panics that occur during a parallel section to later by unwound.
+/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
+/// hiding errors by ensuring that everything in the section has completed executing before
+/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
+/// output match the parallel compiler for testing purposes.
+pub struct ParallelGuard {
+    panic: Mutex<Option<Box<dyn Any + Send + 'static>>>,
+}
+
+impl ParallelGuard {
+    pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
+        catch_unwind(AssertUnwindSafe(f))
+            .map_err(|err| {
+                *self.panic.lock() = Some(err);
+            })
+            .ok()
+    }
+}
+
+/// This gives access to a fresh parallel guard in the closure and will unwind any panics
+/// caught in it after the closure returns.
+#[inline]
+pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
+    let guard = ParallelGuard { panic: Mutex::new(None) };
+    let ret = f(&guard);
+    if let Some(panic) = guard.panic.into_inner() {
+        resume_unwind(panic);
+    }
+    ret
+}
+
+mod disabled {
+    use crate::sync::parallel_guard;
+
+    #[macro_export]
+    #[cfg(not(parallel_compiler))]
+    macro_rules! parallel {
+        ($($blocks:block),*) => {{
+            $crate::sync::parallel_guard(|guard| {
+                $(guard.run(|| $blocks);)*
+            });
+        }}
+    }
+
+    pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+    where
+        A: FnOnce() -> RA,
+        B: FnOnce() -> RB,
+    {
+        let (a, b) = parallel_guard(|guard| {
+            let a = guard.run(oper_a);
+            let b = guard.run(oper_b);
+            (a, b)
+        });
+        (a.unwrap(), b.unwrap())
+    }
+
+    pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item)) {
+        parallel_guard(|guard| {
+            t.into_iter().for_each(|i| {
+                guard.run(|| for_each(i));
+            });
+        })
+    }
+
+    pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
+        t: T,
+        mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
+    ) -> C {
+        parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect())
+    }
+}
+
+#[cfg(parallel_compiler)]
+mod enabled {
+    use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn};
+
+    /// Runs a list of blocks in parallel. The first block is executed immediately on
+    /// the current thread. Use that for the longest running block.
+    #[macro_export]
+    macro_rules! parallel {
+        (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
+            parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
+        };
+        (impl $fblock:block [$($blocks:expr,)*] []) => {
+            ::rustc_data_structures::sync::scope(|s| {
+                $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
+                s.spawn(move |_| block.into_inner()());)*
+                (|| $fblock)();
+            });
+        };
+        ($fblock:block, $($blocks:block),*) => {
+            if rustc_data_structures::sync::is_dyn_thread_safe() {
+                // Reverse the order of the later blocks since Rayon executes them in reverse order
+                // when using a single thread. This ensures the execution order matches that
+                // of a single threaded rustc.
+                parallel!(impl $fblock [] [$($blocks),*]);
+            } else {
+                $crate::sync::parallel_guard(|guard| {
+                    guard.run(|| $fblock);
+                    $(guard.run(|| $blocks);)*
+                });
+            }
+        };
+    }
+
+    // This function only works when `mode::is_dyn_thread_safe()`.
+    pub fn scope<'scope, OP, R>(op: OP) -> R
+    where
+        OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
+        R: DynSend,
+    {
+        let op = FromDyn::from(op);
+        rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
+    }
+
+    #[inline]
+    pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
+    where
+        A: FnOnce() -> RA + DynSend,
+        B: FnOnce() -> RB + DynSend,
+    {
+        if mode::is_dyn_thread_safe() {
+            let oper_a = FromDyn::from(oper_a);
+            let oper_b = FromDyn::from(oper_b);
+            let (a, b) = rayon::join(
+                move || FromDyn::from(oper_a.into_inner()()),
+                move || FromDyn::from(oper_b.into_inner()()),
+            );
+            (a.into_inner(), b.into_inner())
+        } else {
+            super::disabled::join(oper_a, oper_b)
+        }
+    }
+
+    use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
+
+    pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
+        t: T,
+        for_each: impl Fn(I) + DynSync + DynSend,
+    ) {
+        parallel_guard(|guard| {
+            if mode::is_dyn_thread_safe() {
+                let for_each = FromDyn::from(for_each);
+                t.into_par_iter().for_each(|i| {
+                    guard.run(|| for_each(i));
+                });
+            } else {
+                t.into_iter().for_each(|i| {
+                    guard.run(|| for_each(i));
+                });
+            }
+        });
+    }
+
+    pub fn par_map<
+        I,
+        T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
+        R: std::marker::Send,
+        C: FromIterator<R> + FromParallelIterator<R>,
+    >(
+        t: T,
+        map: impl Fn(I) -> R + DynSync + DynSend,
+    ) -> C {
+        parallel_guard(|guard| {
+            if mode::is_dyn_thread_safe() {
+                let map = FromDyn::from(map);
+                t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
+            } else {
+                t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
+            }
+        })
+    }
+}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e56347ab38e..c02ae70166d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -162,9 +162,10 @@ pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T
 pub trait Callbacks {
     /// Called before creating the compiler instance
     fn config(&mut self, _config: &mut interface::Config) {}
-    /// Called after parsing. Return value instructs the compiler whether to
+    /// Called after parsing the crate root. Submodules are not yet parsed when
+    /// this callback is called. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_parsing<'tcx>(
+    fn after_crate_root_parsing<'tcx>(
         &mut self,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
@@ -184,7 +185,6 @@ pub trait Callbacks {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
@@ -407,7 +407,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
+            if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -445,7 +445,7 @@ fn run_compiler(
 
             queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
 
-            if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
+            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -700,12 +700,14 @@ pub fn list_metadata(
     sess: &Session,
     metadata_loader: &dyn MetadataLoader,
 ) -> Compilation {
-    if sess.opts.unstable_opts.ls {
+    let ls_kinds = &sess.opts.unstable_opts.ls;
+    if !ls_kinds.is_empty() {
         match sess.io.input {
             Input::File(ref ifile) => {
                 let path = &(*ifile);
                 let mut v = Vec::new();
-                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
+                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v, ls_kinds)
+                    .unwrap();
                 safe_println!("{}", String::from_utf8(v).unwrap());
             }
             Input::Str { .. } => {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0401.md b/compiler/rustc_error_codes/src/error_codes/E0401.md
index 4c93053d5f8..45d083681e5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0401.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0401.md
@@ -1,4 +1,4 @@
-Inner items do not inherit type or const parameters from the functions
+Inner items do not inherit the generic parameters from the items
 they are embedded in.
 
 Erroneous code example:
@@ -32,8 +32,8 @@ fn foo<T>(x: T) {
 }
 ```
 
-Items inside functions are basically just like top-level items, except
-that they can only be used from the function they are in.
+Items nested inside other items are basically just like top-level items, except
+that they can only be used from the item they are in.
 
 There are a couple of solutions for this.
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md
index d26f9b59455..d655e51fa66 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0788.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0788.md
@@ -1,4 +1,4 @@
-A `#[no_coverage]` attribute was applied to something which does not show up
+A `#[coverage]` attribute was applied to something which does not show up
 in code coverage, or is too granular to be excluded from the coverage report.
 
 For now, this attribute can only be applied to function, method, and closure
@@ -9,18 +9,18 @@ will just emit an `unused_attributes` lint instead of this error.
 Example of erroneous code:
 
 ```compile_fail,E0788
-#[no_coverage]
+#[coverage(off)]
 struct Foo;
 
-#[no_coverage]
+#[coverage(on)]
 const FOO: Foo = Foo;
 ```
 
-`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
-a piece of code when the `-C instrument-coverage` flag is passed. Things like
-structs and consts are not coverable code, and thus cannot do anything with this
-attribute.
+`#[coverage(off)]` tells the compiler to not generate coverage instrumentation
+for a piece of code when the `-C instrument-coverage` flag is passed. Things
+like structs and consts are not coverable code, and thus cannot do anything
+with this attribute.
 
 If you wish to apply this attribute to all methods in an impl or module,
 manually annotate each method; it is not possible to annotate the entire impl
-with a `#[no_coverage]` attribute.
+with a `#[coverage]` attribute.
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 34d16bf00cd..f87f4aba2b9 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -587,7 +587,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 .resolver
                 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
 
-            if self.cx.sess.opts.incremental_relative_spans() {
+            if self.cx.sess.opts.incremental.is_some() {
                 for (invoc, _) in invocations.iter_mut() {
                     let expn_id = invoc.expansion_data.id;
                     let parent_def = self.cx.resolver.invocation_parent(expn_id);
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 1941390dc4a..fcb112eadfe 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -398,6 +398,9 @@ declare_features! (
     (active, const_trait_impl, "1.42.0", Some(67792), None),
     /// Allows the `?` operator in const contexts.
     (active, const_try, "1.56.0", Some(74935), None),
+    /// Allows function attribute `#[coverage(on/off)]`, to control coverage
+    /// instrumentation of that function.
+    (active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
     /// Allows non-builtin attributes in inner attribute position.
     (active, custom_inner_attributes, "1.30.0", Some(54726), None),
     /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
@@ -509,9 +512,6 @@ declare_features! (
     (active, never_type_fallback, "1.41.0", Some(65992), None),
     /// Allows `#![no_core]`.
     (active, no_core, "1.3.0", Some(29639), None),
-    /// Allows function attribute `#[no_coverage]`, to bypass coverage
-    /// instrumentation of that function.
-    (active, no_coverage, "1.53.0", Some(84605), None),
     /// Allows the use of `no_sanitize` attribute.
     (active, no_sanitize, "1.42.0", Some(39699), None),
     /// Allows using the `non_exhaustive_omitted_patterns` lint.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e745ef1ec07..b4b794d4e09 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -395,7 +395,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
         experimental!(no_sanitize)
     ),
-    gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
+    gated!(coverage, Normal, template!(Word, List: "on|off"), WarnFollowing, coverage_attribute, experimental!(coverage)),
 
     ungated!(
         doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index ed5d76b861a..c70e8e3e6b1 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -136,6 +136,9 @@ declare_features! (
      Some("subsumed by `#![feature(allocator_internals)]`")),
     /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
     (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
+    /// Allows `#[no_coverage]` on functions.
+    /// The feature was renamed to `coverage` and the attribute to `#[coverage(on|off)]`
+    (removed, no_coverage, "CURRENT_RUSTC_VERSION", Some(84605), None, Some("renamed to `coverage`")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
     /// Allows using `#[on_unimplemented(..)]` on traits.
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 6082d446979..ed4dde419c4 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     {
         // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
         // valid span, so we point at the whole path segment instead.
-        let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
+        let is_dummy = assoc_name.span == DUMMY_SP;
+
         let mut err = struct_span_err!(
             self.tcx().sess,
-            span,
+            if is_dummy { span } else { assoc_name.span },
             E0220,
             "associated type `{}` not found for `{}`",
             assoc_name,
             ty_param_name
         );
 
+        if is_dummy {
+            err.span_label(span, format!("associated type `{assoc_name}` not found"));
+            return err.emit();
+        }
+
         let all_candidate_names: Vec<_> = all_candidates()
             .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
             .filter_map(|item| {
@@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             })
             .collect();
 
-        if let (Some(suggested_name), true) = (
-            find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
-            assoc_name.span != DUMMY_SP,
-        ) {
+        if let Some(suggested_name) =
+            find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
+        {
             err.span_suggestion(
                 assoc_name.span,
                 "there is an associated type with a similar name",
@@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             })
             .collect();
 
-        if let (Some(suggested_name), true) = (
-            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
-            assoc_name.span != DUMMY_SP,
-        ) {
+        if let Some(suggested_name) =
+            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
+        {
             if let [best_trait] = visible_traits
                 .iter()
                 .filter(|trait_def_id| {
@@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
-        err.span_label(span, format!("associated type `{assoc_name}` not found"));
+        // If we still couldn't find any associated type, and only one associated type exists,
+        // suggests using it.
+
+        if all_candidate_names.len() == 1 {
+            // this should still compile, except on `#![feature(associated_type_defaults)]`
+            // where it could suggests `type A = Self::A`, thus recursing infinitely
+            let applicability = if self.tcx().features().associated_type_defaults {
+                Applicability::Unspecified
+            } else {
+                Applicability::MaybeIncorrect
+            };
+
+            err.span_suggestion(
+                assoc_name.span,
+                format!("`{ty_param_name}` has the following associated type"),
+                all_candidate_names.first().unwrap().to_string(),
+                applicability,
+            );
+        } else {
+            err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
+        }
+
         err.emit()
     }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 90f64e18632..acfd8dcb112 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -523,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             Ty::new_misc_error(tcx).into()
                         }
                     }
-                    GenericParamDefKind::Const { has_default } => {
+                    GenericParamDefKind::Const { has_default, .. } => {
                         let ty = tcx
                             .at(self.span)
                             .type_of(param.def_id)
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f5beefc47f3..b97e0a80fe6 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1255,7 +1255,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
         GenericParamDefKind::Type { has_default, .. }
-        | GenericParamDefKind::Const { has_default } => {
+        | GenericParamDefKind::Const { has_default, .. } => {
             has_default && def.index >= generics.parent_count as u32
         }
         GenericParamDefKind::Lifetime => unreachable!(),
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 67aef0a7c43..94f3e8706fc 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -157,6 +157,14 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     let infcx = tcx.infer_ctxt().build();
     let cause = ObligationCause::misc(span, impl_did);
 
+    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
+    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
+    // that are effectively repr(transparent) newtypes around types that already hav a
+    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some
+    // of them support an allocator, but we ensure that for the cases where the type implements this
+    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
+    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
+    // even if they do not carry that attribute.
     use rustc_type_ir::sty::TyKind::*;
     match (source.kind(), target.kind()) {
         (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 4842008279a..3d60c57b9d5 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -328,7 +328,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 name: param.name.ident().name,
                 def_id: param.def_id.to_def_id(),
                 pure_wrt_drop: param.pure_wrt_drop,
-                kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+                kind: ty::GenericParamDefKind::Const {
+                    has_default: default.is_some(),
+                    is_host_effect: is_host_param,
+                },
             })
         }
     }));
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 31a03fabe4f..e8d4e6b447f 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -321,8 +321,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .emit();
             }
             CastError::CastToBool => {
-                let mut err =
-                    struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`");
+                let mut err = struct_span_err!(
+                    fcx.tcx.sess,
+                    self.span,
+                    E0054,
+                    "cannot cast `{}` as `bool`",
+                    self.expr_ty
+                );
 
                 if self.expr_ty.is_numeric() {
                     match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 5b5986a349f..97091c39c65 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::{
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::{self, Ty};
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
@@ -23,20 +24,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
             self.fulfillment_cx.borrow_mut().pending_obligations()
         );
 
-        // Check if we have any unsolved variables. If not, no need for fallback.
-        let unsolved_variables = self.unsolved_variables();
-        if unsolved_variables.is_empty() {
-            return;
-        }
+        let fallback_occured = self.fallback_types() || self.fallback_effects();
 
-        let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
-
-        // We do fallback in two passes, to try to generate
-        // better error messages.
-        // The first time, we do *not* replace opaque types.
-        for ty in unsolved_variables {
-            debug!("unsolved_variable = {:?}", ty);
-            self.fallback_if_possible(ty, &diverging_fallback);
+        if !fallback_occured {
+            return;
         }
 
         // We now see if we can make progress. This might cause us to
@@ -65,6 +56,53 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         self.select_obligations_where_possible(|_| {});
     }
 
+    fn fallback_types(&self) -> bool {
+        // Check if we have any unsolved variables. If not, no need for fallback.
+        let unsolved_variables = self.unsolved_variables();
+
+        if unsolved_variables.is_empty() {
+            return false;
+        }
+
+        let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
+        for ty in unsolved_variables {
+            debug!("unsolved_variable = {:?}", ty);
+            self.fallback_if_possible(ty, &diverging_fallback);
+        }
+
+        true
+    }
+
+    fn fallback_effects(&self) -> bool {
+        let unsolved_effects = self.unsolved_effects();
+
+        if unsolved_effects.is_empty() {
+            return false;
+        }
+
+        // not setting `fallback_has_occured` here because that field is only used for type fallback
+        // diagnostics.
+
+        for effect in unsolved_effects {
+            let expected = self.tcx.consts.true_;
+            let cause = self.misc(rustc_span::DUMMY_SP);
+            match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) {
+                Ok(InferOk { obligations, value: () }) => {
+                    self.register_predicates(obligations);
+                }
+                Err(e) => {
+                    bug!("cannot eq unsolved effect: {e:?}")
+                }
+            }
+        }
+
+        true
+    }
+
     // Tries to apply a fallback to `ty` if it is an unsolved variable.
     //
     // - Unconstrained ints are replaced with `i32`.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 28fe2e062e5..c94cfde0670 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1295,17 +1295,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
                         self.fcx.ty_infer(Some(param), inf.span).into()
                     }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                    (
+                        &GenericParamDefKind::Const { has_default, is_host_effect },
+                        GenericArg::Infer(inf),
+                    ) => {
                         let tcx = self.fcx.tcx();
-                        self.fcx
-                            .ct_infer(
-                                tcx.type_of(param.def_id)
-                                    .no_bound_vars()
-                                    .expect("const parameter types cannot be generic"),
-                                Some(param),
-                                inf.span,
-                            )
-                            .into()
+
+                        if has_default && is_host_effect {
+                            self.fcx.var_for_effect(param)
+                        } else {
+                            self.fcx
+                                .ct_infer(
+                                    tcx.type_of(param.def_id)
+                                        .no_bound_vars()
+                                        .expect("const parameter types cannot be generic"),
+                                    Some(param),
+                                    inf.span,
+                                )
+                                .into()
+                        }
                     }
                     _ => unreachable!(),
                 }
@@ -1324,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
-                            // If we have a default, then we it doesn't matter that we're not
+                            // If we have a default, then it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.
                             tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
@@ -1336,17 +1344,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.fcx.var_for_def(self.span, param)
                         }
                     }
-                    GenericParamDefKind::Const { has_default } => {
-                        if !infer_args
-                            && has_default
-                            && !tcx.has_attr(param.def_id, sym::rustc_host)
-                        {
-                            tcx.const_param_default(param.def_id)
-                                .instantiate(tcx, args.unwrap())
-                                .into()
-                        } else {
-                            self.fcx.var_for_def(self.span, param)
+                    GenericParamDefKind::Const { has_default, is_host_effect } => {
+                        if has_default {
+                            // N.B. this is a bit of a hack. `infer_args` is passed depending on
+                            // whether the user has provided generic args. E.g. for `Vec::new`
+                            // we would have to infer the generic types. However, for `Vec::<T>::new`
+                            // where the allocator param `A` has a default we will *not* infer. But
+                            // for effect params this is a different story: if the user has not written
+                            // anything explicit for the effect param, we always need to try to infer
+                            // it before falling back to default, such that a `const fn` such as
+                            // `needs_drop::<()>` can still be called in const contexts. (if we defaulted
+                            // instead of inferred, typeck would error)
+                            if is_host_effect {
+                                return self.fcx.var_for_effect(param);
+                            } else if !infer_args {
+                                return tcx
+                                    .const_param_default(param.def_id)
+                                    .instantiate(tcx, args.unwrap())
+                                    .into();
+                            }
                         }
+
+                        self.fcx.var_for_def(self.span, param)
                     }
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 7707cc6de54..4237b4488ca 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -266,7 +266,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         param: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> Const<'tcx> {
+        // FIXME ideally this shouldn't use unwrap
         match param {
+            Some(
+                param @ ty::GenericParamDef {
+                    kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
+                    ..
+                },
+            ) => self.var_for_effect(param).as_const().unwrap(),
             Some(param) => self.var_for_def(span, param).as_const().unwrap(),
             None => self.next_const_var(
                 ty,
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 6a817122491..566dc09cdd2 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -643,17 +643,14 @@ fn check_must_not_suspend_ty<'tcx>(
         }
         ty::Array(ty, len) => {
             let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
+            let target_usize =
+                len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize;
+            let plural_len = target_usize.saturating_add(1);
             check_must_not_suspend_ty(
                 fcx,
                 ty,
                 hir_id,
-                SuspendCheckData {
-                    descr_pre,
-                    plural_len: len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0)
-                        as usize
-                        + 1,
-                    ..data
-                },
+                SuspendCheckData { descr_pre, plural_len, ..data },
             )
         }
         // If drop tracking is enabled, we want to look through references, since the referent
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 0cfaf583774..7719482890e 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -48,18 +48,6 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
 
         join(
             move || {
-                sess.time("incr_comp_persist_result_cache", || {
-                    // Drop the memory map so that we can remove the file and write to it.
-                    if let Some(odc) = &tcx.query_system.on_disk_cache {
-                        odc.drop_serialized_data(tcx);
-                    }
-
-                    file_format::save_in(sess, query_cache_path, "query cache", |e| {
-                        encode_query_cache(tcx, e)
-                    });
-                });
-            },
-            move || {
                 sess.time("incr_comp_persist_dep_graph", || {
                     if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
                         sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
@@ -73,6 +61,20 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
                     }
                 });
             },
+            move || {
+                // We execute this after `incr_comp_persist_dep_graph` for the serial compiler
+                // to catch any potential query execution writing to the dep graph.
+                sess.time("incr_comp_persist_result_cache", || {
+                    // Drop the memory map so that we can remove the file and write to it.
+                    if let Some(odc) = &tcx.query_system.on_disk_cache {
+                        odc.drop_serialized_data(tcx);
+                    }
+
+                    file_format::save_in(sess, query_cache_path, "query cache", |e| {
+                        encode_query_cache(tcx, e)
+                    });
+                });
+            },
         );
     })
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9d7a9fefd08..99bd296d0d5 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -522,6 +522,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                     }
                 }
             }
+            ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
+                match self.infcx.probe_effect_var(vid) {
+                    Some(value) => return self.fold_const(value.as_const(self.infcx.tcx)),
+                    None => {
+                        return self.canonicalize_const_var(
+                            CanonicalVarInfo { kind: CanonicalVarKind::Effect },
+                            ct,
+                        );
+                    }
+                }
+            }
             ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                 bug!("encountered a fresh const during canonicalization")
             }
@@ -690,7 +701,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             .iter()
             .map(|v| CanonicalVarInfo {
                 kind: match v.kind {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
+                    | CanonicalVarKind::Effect => {
                         return *v;
                     }
                     CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 8ca2e403043..41787ee2942 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -151,7 +151,11 @@ impl<'tcx> InferCtxt<'tcx> {
                     universe_map(ui),
                 )
                 .into(),
-
+            CanonicalVarKind::Effect => {
+                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
+                    .into()
+            }
             CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index ddc8e7e50eb..ee13eb0271e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -30,7 +30,7 @@ use super::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::infer::generalize::{self, CombineDelegate, Generalization};
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::infer::canonical::OriginalQueryValues;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
@@ -91,7 +91,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .borrow_mut()
                     .float_unification_table()
                     .unify_var_var(a_id, b_id)
-                    .map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
+                    .map_err(|e| float_unification_error(a_is_expected, e))?;
                 Ok(a)
             }
             (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
@@ -210,10 +210,30 @@ impl<'tcx> InferCtxt<'tcx> {
                 return Ok(a);
             }
 
+            (
+                ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
+                ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
+            ) => {
+                self.inner
+                    .borrow_mut()
+                    .effect_unification_table()
+                    .unify_var_var(a_vid, b_vid)
+                    .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?;
+                return Ok(a);
+            }
+
             // All other cases of inference with other variables are errors.
-            (ty::ConstKind::Infer(InferConst::Var(_)), ty::ConstKind::Infer(_))
-            | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(InferConst::Var(_))) => {
-                bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)")
+            (
+                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
+                ty::ConstKind::Infer(_),
+            )
+            | (
+                ty::ConstKind::Infer(_),
+                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
+            ) => {
+                bug!(
+                    "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
+                )
             }
 
             (ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
@@ -223,6 +243,23 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
                 return self.unify_const_variable(vid, a, relation.param_env());
             }
+
+            (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
+                return self.unify_effect_variable(
+                    relation.a_is_expected(),
+                    vid,
+                    EffectVarValue::Const(b),
+                );
+            }
+
+            (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
+                return self.unify_effect_variable(
+                    !relation.a_is_expected(),
+                    vid,
+                    EffectVarValue::Const(a),
+                );
+            }
+
             (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
                 if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
             {
@@ -340,6 +377,20 @@ impl<'tcx> InferCtxt<'tcx> {
             .map_err(|e| float_unification_error(vid_is_expected, e))?;
         Ok(Ty::new_float(self.tcx, val))
     }
+
+    fn unify_effect_variable(
+        &self,
+        vid_is_expected: bool,
+        vid: ty::EffectVid<'tcx>,
+        val: EffectVarValue<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        self.inner
+            .borrow_mut()
+            .effect_unification_table()
+            .unify_var_value(vid, Some(val))
+            .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?;
+        Ok(val.as_const(self.tcx))
+    }
 }
 
 impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
@@ -493,3 +544,11 @@ fn float_unification_error<'tcx>(
     let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
     TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
 }
+
+fn effect_unification_error<'tcx>(
+    _tcx: TyCtxt<'tcx>,
+    _a_is_expected: bool,
+    (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>),
+) -> TypeError<'tcx> {
+    bug!("unexpected effect unification error")
+}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 689945d644c..0596ce373cf 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -156,6 +156,21 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
                     .known();
                 self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
+                let opt_ct = self
+                    .infcx
+                    .inner
+                    .borrow_mut()
+                    .effect_unification_table()
+                    .probe_value(v)
+                    .map(|effect| effect.as_const(self.infcx.tcx));
+                self.freshen_const(
+                    opt_ct,
+                    ty::InferConst::EffectVar(v),
+                    ty::InferConst::Fresh,
+                    ct.ty(),
+                )
+            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
                 if i >= self.const_freshen_count {
                     bug!(
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index cf674d5dda6..dd7f8d35441 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -403,6 +403,7 @@ where
                     }
                 }
             }
+            ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
             // FIXME: remove this branch once `structurally_relate_consts` is fully
             // structural.
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index dabebe0adc0..abb59a789da 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -21,7 +21,7 @@ use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
@@ -33,13 +33,14 @@ use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
-use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
+use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
+use std::marker::PhantomData;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -115,6 +116,9 @@ pub struct InferCtxtInner<'tcx> {
     /// Map from floating variable to the kind of float it represents.
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
+    /// Map from effect variable to the effect param it represents.
+    effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
+
     /// Tracks the set of region variables and the constraints between them.
     ///
     /// This is initially `Some(_)` but when
@@ -172,6 +176,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
             const_unification_storage: ut::UnificationTableStorage::new(),
             int_unification_storage: ut::UnificationTableStorage::new(),
             float_unification_storage: ut::UnificationTableStorage::new(),
+            effect_unification_storage: ut::UnificationTableStorage::new(),
             region_constraint_storage: Some(RegionConstraintStorage::new()),
             region_obligations: vec![],
             opaque_type_storage: Default::default(),
@@ -223,6 +228,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
         self.const_unification_storage.with_log(&mut self.undo_log)
     }
 
+    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
+        self.effect_unification_storage.with_log(&mut self.undo_log)
+    }
+
     #[inline]
     pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
         self.region_constraint_storage
@@ -356,6 +365,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
                 Err(universe) => Some(universe),
                 Ok(_) => None,
             },
+            EffectVar(_) => None,
             Fresh(_) => None,
         }
     }
@@ -777,6 +787,19 @@ impl<'tcx> InferCtxt<'tcx> {
         vars
     }
 
+    pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> {
+        let mut inner = self.inner.borrow_mut();
+        let mut table = inner.effect_unification_table();
+
+        (0..table.len())
+            .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
+            .filter(|&vid| table.probe_value(vid).is_none())
+            .map(|v| {
+                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
+            })
+            .collect()
+    }
+
     fn combine_fields<'a>(
         &'a self,
         trace: TypeTrace<'tcx>,
@@ -1158,7 +1181,10 @@ impl<'tcx> InferCtxt<'tcx> {
 
                 Ty::new_var(self.tcx, ty_var_id).into()
             }
-            GenericParamDefKind::Const { .. } => {
+            GenericParamDefKind::Const { is_host_effect, .. } => {
+                if is_host_effect {
+                    return self.var_for_effect(param);
+                }
                 let origin = ConstVariableOrigin {
                     kind: ConstVariableOriginKind::ConstParameterDefinition(
                         param.name,
@@ -1184,6 +1210,17 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 
+    pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
+        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+        let ty = self
+            .tcx
+            .type_of(param.def_id)
+            .no_bound_vars()
+            .expect("const parameter types cannot be generic");
+        debug_assert_eq!(self.tcx.types.bool, ty);
+        ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
+    }
+
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
     pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
@@ -1369,6 +1406,10 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 
+    pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
+        self.inner.borrow_mut().effect_unification_table().probe_value(vid)
+    }
+
     /// Attempts to resolve all type/region/const variables in
     /// `value`. Region inference must have been run already (e.g.,
     /// by calling `resolve_regions_and_report_errors`). If some
@@ -1649,6 +1690,14 @@ impl<'tcx> InferCtxt<'tcx> {
                     ConstVariableValue::Known { .. } => true,
                 }
             }
+
+            TyOrConstInferVar::Effect(v) => {
+                // If `probe_value` returns `Some`, it never equals
+                // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`.
+                //
+                // Not `inlined_probe_value(v)` because this call site is colder.
+                self.probe_effect_var(v).is_some()
+            }
         }
     }
 }
@@ -1720,6 +1769,8 @@ pub enum TyOrConstInferVar<'tcx> {
 
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
     Const(ConstVid<'tcx>),
+    /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
+    Effect(EffectVid<'tcx>),
 }
 
 impl<'tcx> TyOrConstInferVar<'tcx> {
@@ -1750,6 +1801,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
     fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
         match ct.kind() {
             ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
+            ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
             _ => None,
         }
     }
@@ -1793,17 +1845,24 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
-            self.infcx
+        match ct.kind() {
+            ty::ConstKind::Infer(InferConst::Var(vid)) => self
+                .infcx
                 .inner
                 .borrow_mut()
                 .const_unification_table()
                 .probe_value(vid)
                 .val
                 .known()
-                .unwrap_or(ct)
-        } else {
-            ct
+                .unwrap_or(ct),
+            ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .effect_unification_table()
+                .probe_value(vid)
+                .map_or(ct, |val| val.as_const(self.infcx.tcx)),
+            _ => ct,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 1c3a5c36076..09df93fcc2f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -145,7 +145,25 @@ impl<'tcx> InferCtxt<'tcx> {
                             return None;
                         }
                     }
-                    DefiningAnchor::Bubble => {}
+                    DefiningAnchor::Bubble => {
+                        if let ty::Alias(ty::Opaque, _) = b.kind() {
+                            // In bubble mode we don't know which of the two opaque types is supposed to have the other
+                            // as a hidden type (both, none or either one of them could be in its defining scope).
+                            let predicate = ty::PredicateKind::AliasRelate(
+                                a.into(),
+                                b.into(),
+                                ty::AliasRelationDirection::Equate,
+                            );
+                            let obligation = traits::Obligation::new(
+                                self.tcx,
+                                cause.clone(),
+                                param_env,
+                                predicate,
+                            );
+                            let obligations = vec![obligation];
+                            return Some(Ok(InferOk { value: (), obligations }));
+                        }
+                    }
                     DefiningAnchor::Error => return None,
                 };
                 if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 25d06b21ec8..79144b3e643 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -24,6 +24,7 @@ pub(crate) enum UndoLog<'tcx> {
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -55,6 +56,7 @@ impl_from! {
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
 
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
 
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
 
@@ -71,6 +73,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
             UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
             UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
             UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
+            UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo),
             UndoLog::RegionConstraintCollector(undo) => {
                 self.region_constraint_storage.as_mut().unwrap().reverse(undo)
             }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 9fcaf643179..e5ae6d5b5d6 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -584,7 +584,7 @@ fn resolver_for_lowering<'tcx>(
     let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
 
     // Make sure we don't mutate the cstore from here on.
-    tcx.untracked().cstore.leak();
+    tcx.untracked().cstore.freeze();
 
     let ty::ResolverOutputs {
         global_ctxt: untracked_resolutions,
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index e0d9998d919..449d7a29590 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -7,9 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{
-    AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, RwLock, WorkerLocal,
-};
+use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal};
 use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_incremental::DepGraphFuture;
@@ -116,6 +114,7 @@ impl<'tcx> Queries<'tcx> {
             .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
     }
 
+    #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."]
     pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
         self.pre_configure.compute(|| {
             let mut krate = self.parse()?.steal();
@@ -173,6 +172,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
         self.gcx.compute(|| {
             let sess = self.session();
+            #[allow(deprecated)]
             let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
 
             // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
@@ -195,7 +195,7 @@ impl<'tcx> Queries<'tcx> {
                 self.compiler.register_lints.as_deref(),
                 &pre_configured_attrs,
             ));
-            let cstore = RwLock::new(Box::new(CStore::new(
+            let cstore = FreezeLock::new(Box::new(CStore::new(
                 self.codegen_backend().metadata_loader(),
                 stable_crate_id,
             )) as _);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ccf8b5630d4..1746cc8b719 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -704,7 +704,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(keep_hygiene_data, true);
     untracked!(link_native_libraries, false);
     untracked!(llvm_time_trace, true);
-    untracked!(ls, true);
+    untracked!(ls, vec!["all".to_owned()]);
     untracked!(macro_backtrace, true);
     untracked!(meta_stats, true);
     untracked!(mir_include_spans, true);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7f7f36ca170..ba50c9e00e3 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -156,15 +156,6 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
-lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
-
-lint_check_name_removed = lint `{$lint_name}` has been removed: {$reason}
-
-lint_check_name_renamed = lint `{$lint_name}` has been renamed to `{$replace}`
-
-lint_check_name_unknown = unknown lint: `{$lint_name}`
-    .help = did you mean: `{$suggestion}`
-
 lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
 
 lint_command_line_source = `forbid` lint level was set on command line
@@ -187,6 +178,7 @@ lint_default_source = `forbid` lint level is the default for {$id}
 lint_deprecated_lint_name =
     lint name `{$name}` is deprecated and may not have an effect in the future.
     .suggestion = change it to
+    .help = change it to {$replace}
 
 lint_diag_out_of_impl =
     diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
@@ -528,6 +520,7 @@ lint_unknown_gated_lint =
 lint_unknown_lint =
     unknown lint: `{$name}`
     .suggestion = did you mean
+    .help = did you mean: `{$replace}`
 
 lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
     .help = add `#![register_tool({$tool_name})]` to the crate root
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 9dfde84b552..7a336a8f694 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,10 +16,6 @@
 
 use self::TargetLint::*;
 
-use crate::errors::{
-    CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown,
-    CheckNameUnknownTool, RequestedLevel, UnsupportedGroup,
-};
 use crate::levels::LintLevelsBuilder;
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
@@ -330,58 +326,6 @@ impl LintStore {
         }
     }
 
-    /// Checks the validity of lint names derived from the command line.
-    pub fn check_lint_name_cmdline(
-        &self,
-        sess: &Session,
-        lint_name: &str,
-        level: Level,
-        registered_tools: &RegisteredTools,
-    ) {
-        let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
-        if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) {
-            sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
-            return;
-        }
-        match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
-            CheckLintNameResult::Renamed(replace) => {
-                sess.emit_warning(CheckNameRenamed {
-                    lint_name,
-                    replace: &replace,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::Removed(reason) => {
-                sess.emit_warning(CheckNameRemoved {
-                    lint_name,
-                    reason: &reason,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::NoLint(suggestion) => {
-                sess.emit_err(CheckNameUnknown {
-                    lint_name,
-                    suggestion,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::Tool(Err((Some(_), new_name))) => {
-                sess.emit_warning(CheckNameDeprecated {
-                    lint_name,
-                    new_name: &new_name,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::NoTool => {
-                sess.emit_err(CheckNameUnknownTool {
-                    tool_name: tool_name.unwrap(),
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            _ => {}
-        };
-    }
-
     /// True if this symbol represents a lint group name.
     pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
         debug!(
@@ -1402,14 +1346,3 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
         err
     }
 }
-
-pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
-    match lint_name.split_once("::") {
-        Some((tool_name, lint_name)) => {
-            let tool_name = Symbol::intern(tool_name);
-
-            (Some(tool_name), lint_name)
-        }
-        None => (None, lint_name),
-    }
-}
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 607875b3faa..eccea35c702 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,7 +1,5 @@
 use crate::fluent_generated as fluent;
-use rustc_errors::{
-    AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage,
-};
+use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
@@ -102,29 +100,6 @@ pub struct UnsupportedGroup {
     pub lint_group: String,
 }
 
-pub struct CheckNameUnknown<'a> {
-    pub lint_name: &'a str,
-    pub suggestion: Option<Symbol>,
-    pub sub: RequestedLevel<'a>,
-}
-
-impl IntoDiagnostic<'_> for CheckNameUnknown<'_> {
-    fn into_diagnostic(
-        self,
-        handler: &Handler,
-    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
-        diag.code(rustc_errors::error_code!(E0602));
-        if let Some(suggestion) = self.suggestion {
-            diag.help(fluent::lint_help);
-            diag.set_arg("suggestion", suggestion);
-        }
-        diag.set_arg("lint_name", self.lint_name);
-        diag.subdiagnostic(self.sub);
-        diag
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag(lint_check_name_unknown_tool, code = "E0602")]
 pub struct CheckNameUnknownTool<'a> {
@@ -132,30 +107,3 @@ pub struct CheckNameUnknownTool<'a> {
     #[subdiagnostic]
     pub sub: RequestedLevel<'a>,
 }
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_renamed)]
-pub struct CheckNameRenamed<'a> {
-    pub lint_name: &'a str,
-    pub replace: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_removed)]
-pub struct CheckNameRemoved<'a> {
-    pub lint_name: &'a str,
-    pub reason: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_deprecated)]
-pub struct CheckNameDeprecated<'a> {
-    pub lint_name: &'a str,
-    pub new_name: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 43f668ca122..6c8b60c8d74 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -21,7 +21,6 @@ use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit as hir_visit;
-use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
@@ -61,6 +60,9 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
         self.context.last_node_with_lint_attrs = id;
         debug!("late context: enter_attrs({:?})", attrs);
         lint_callback!(self, enter_lint_attrs, attrs);
+        for attr in attrs {
+            lint_callback!(self, check_attribute, attr);
+        }
         f(self);
         debug!("late context: exit_attrs({:?})", attrs);
         lint_callback!(self, exit_lint_attrs, attrs);
@@ -381,20 +383,18 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
 
     let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
 
-    // There is no module lint that will have the crate itself as an item, so check it here.
-    if hir_id == hir::CRATE_HIR_ID {
-        lint_callback!(cx, check_crate,);
-    }
+    cx.with_lint_attrs(hir_id, |cx| {
+        // There is no module lint that will have the crate itself as an item, so check it here.
+        if hir_id == hir::CRATE_HIR_ID {
+            lint_callback!(cx, check_crate,);
+        }
 
-    cx.process_mod(module, hir_id);
+        cx.process_mod(module, hir_id);
 
-    // Visit the crate attributes
-    if hir_id == hir::CRATE_HIR_ID {
-        for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
-            cx.visit_attribute(attr)
+        if hir_id == hir::CRATE_HIR_ID {
+            lint_callback!(cx, check_crate_post,);
         }
-        lint_callback!(cx, check_crate_post,);
-    }
+    });
 }
 
 fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
@@ -435,7 +435,6 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
         // item), warn for it here.
         lint_callback!(cx, check_crate,);
         tcx.hir().walk_toplevel_module(cx);
-        tcx.hir().walk_attributes(cx);
         lint_callback!(cx, check_crate_post,);
     })
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index ed5627931be..ba521b969ce 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,3 +1,8 @@
+use crate::errors::{CheckNameUnknownTool, RequestedLevel, UnsupportedGroup};
+use crate::lints::{
+    DeprecatedLintNameFromCommandLine, RemovedLintFromCommandLine, RenamedLintFromCommandLine,
+    UnknownLintFromCommandLine,
+};
 use crate::{
     builtin::MISSING_DOCS,
     context::{CheckLintNameResult, LintStore},
@@ -557,12 +562,55 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
     fn add_command_line(&mut self) {
         for &(ref lint_name, level) in &self.sess.opts.lint_opts {
-            self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools);
+            // Checks the validity of lint names derived from the command line.
+            let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
+            if lint_name_only == crate::WARNINGS.name_lower()
+                && matches!(level, Level::ForceWarn(_))
+            {
+                self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
+            }
+            match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
+                CheckLintNameResult::Renamed(ref replace) => {
+                    let name = lint_name.as_str();
+                    let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = RenamedLintFromCommandLine { name, suggestion, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::Removed(ref reason) => {
+                    let name = lint_name.as_str();
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = RemovedLintFromCommandLine { name, reason, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::NoLint(suggestion) => {
+                    let name = lint_name.clone();
+                    let suggestion =
+                        suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace });
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
+                    self.emit_lint(UNKNOWN_LINTS, lint);
+                }
+                CheckLintNameResult::Tool(Err((Some(_), ref replace))) => {
+                    let name = lint_name.clone();
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::NoTool => {
+                    self.sess.emit_err(CheckNameUnknownTool {
+                        tool_name: tool_name.unwrap(),
+                        sub: RequestedLevel { level, lint_name },
+                    });
+                }
+                _ => {}
+            };
+
             let orig_level = level;
             let lint_flag_val = Symbol::intern(lint_name);
 
             let Ok(ids) = self.store.find_lints(&lint_name) else {
-                // errors handled in check_lint_name_cmdline above
+                // errors already handled above
                 continue;
             };
             for id in ids {
@@ -920,24 +968,18 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
                     _ if !self.warn_about_weird_lints => {}
 
-                    CheckLintNameResult::Renamed(new_name) => {
+                    CheckLintNameResult::Renamed(ref replace) => {
                         let suggestion =
-                            RenamedLintSuggestion { suggestion: sp, replace: new_name.as_str() };
+                            RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
                         let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
-                        self.emit_spanned_lint(
-                            RENAMED_AND_REMOVED_LINTS,
-                            sp.into(),
-                            RenamedLint { name: name.as_str(), suggestion },
-                        );
+                        let lint = RenamedLint { name: name.as_str(), suggestion };
+                        self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
                     }
 
-                    CheckLintNameResult::Removed(reason) => {
+                    CheckLintNameResult::Removed(ref reason) => {
                         let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
-                        self.emit_spanned_lint(
-                            RENAMED_AND_REMOVED_LINTS,
-                            sp.into(),
-                            RemovedLint { name: name.as_str(), reason: reason.as_str() },
-                        );
+                        let lint = RemovedLint { name: name.as_str(), reason };
+                        self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
                     }
 
                     CheckLintNameResult::NoLint(suggestion) => {
@@ -946,13 +988,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                         } else {
                             name.to_string()
                         };
-                        let suggestion = suggestion
-                            .map(|replace| UnknownLintSuggestion { suggestion: sp, replace });
-                        self.emit_spanned_lint(
-                            UNKNOWN_LINTS,
-                            sp.into(),
-                            UnknownLint { name, suggestion },
-                        );
+                        let suggestion = suggestion.map(|replace| {
+                            UnknownLintSuggestion::WithSpan { suggestion: sp, replace }
+                        });
+                        let lint = UnknownLint { name, suggestion };
+                        self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint);
                     }
                 }
                 // If this lint was renamed, apply the new lint instead of ignoring the attribute.
@@ -1097,3 +1137,14 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers };
 }
+
+pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
+    match lint_name.split_once("::") {
+        Some((tool_name, lint_name)) => {
+            let tool_name = Symbol::intern(tool_name);
+
+            (Some(tool_name), lint_name)
+        }
+        None => (None, lint_name),
+    }
+}
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0e942d774a7..3e26d6dc32d 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2,6 +2,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 use std::num::NonZeroU32;
 
+use crate::errors::RequestedLevel;
 use crate::fluent_generated as fluent;
 use rustc_errors::{
     AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString,
@@ -1013,6 +1014,16 @@ pub struct DeprecatedLintName<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_deprecated_lint_name)]
+#[help]
+pub struct DeprecatedLintNameFromCommandLine<'a> {
+    pub name: String,
+    pub replace: &'a str,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_renamed_lint)]
 pub struct RenamedLint<'a> {
     pub name: &'a str,
@@ -1021,11 +1032,25 @@ pub struct RenamedLint<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
-pub struct RenamedLintSuggestion<'a> {
-    #[primary_span]
-    pub suggestion: Span,
-    pub replace: &'a str,
+pub enum RenamedLintSuggestion<'a> {
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
+    WithSpan {
+        #[primary_span]
+        suggestion: Span,
+        replace: &'a str,
+    },
+    #[help(lint_help)]
+    WithoutSpan { replace: &'a str },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_renamed_lint)]
+pub struct RenamedLintFromCommandLine<'a> {
+    pub name: &'a str,
+    #[subdiagnostic]
+    pub suggestion: RenamedLintSuggestion<'a>,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
 }
 
 #[derive(LintDiagnostic)]
@@ -1036,6 +1061,15 @@ pub struct RemovedLint<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_removed_lint)]
+pub struct RemovedLintFromCommandLine<'a> {
+    pub name: &'a str,
+    pub reason: &'a str,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unknown_lint)]
 pub struct UnknownLint {
     pub name: String,
@@ -1044,11 +1078,25 @@ pub struct UnknownLint {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
-pub struct UnknownLintSuggestion {
-    #[primary_span]
-    pub suggestion: Span,
-    pub replace: Symbol,
+pub enum UnknownLintSuggestion {
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    WithSpan {
+        #[primary_span]
+        suggestion: Span,
+        replace: Symbol,
+    },
+    #[help(lint_help)]
+    WithoutSpan { replace: Symbol },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_lint, code = "E0602")]
+pub struct UnknownLintFromCommandLine<'a> {
+    pub name: String,
+    #[subdiagnostic]
+    pub suggestion: Option<UnknownLintSuggestion>,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
 }
 
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs
index fc9d6f636b2..4fd054cb717 100644
--- a/compiler/rustc_lint/src/tests.rs
+++ b/compiler/rustc_lint/src/tests.rs
@@ -1,4 +1,4 @@
-use crate::context::parse_lint_and_tool_name;
+use crate::levels::parse_lint_and_tool_name;
 use rustc_span::{create_default_session_globals_then, Symbol};
 
 #[test]
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fc4c29eb36d..57c2e289f20 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -917,13 +917,18 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
         // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
         // If the computed size for the field and the enum are different, the nonnull optimization isn't
         // being applied (and we've got a problem somewhere).
-        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap();
-        if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
+        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).ok();
+        if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) {
             bug!("improper_ctypes: Option nonnull optimization not applied?");
         }
 
         // Return the nullable type this Option-like enum can be safely represented with.
-        let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
+        let field_ty_layout = tcx.layout_of(param_env.and(field_ty));
+        if field_ty_layout.is_err() && !field_ty.has_non_region_param() {
+            bug!("should be able to compute the layout of non-polymorphic type");
+        }
+
+        let field_ty_abi = &field_ty_layout.ok()?.abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
             match field_ty_scalar.valid_range(&tcx) {
                 WrappingRange { start: 0, end }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 09627e1cfed..fefb1e0fbe0 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -410,6 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool RelaxELFRelocations,
     bool UseInitArray,
     const char *SplitDwarfFile,
+    const char *DebugInfoCompression,
     bool ForceEmulatedTls,
     const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
 
@@ -441,6 +442,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   if (SplitDwarfFile) {
       Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
   }
+#if LLVM_VERSION_GE(16, 0)
+  if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
+    Options.CompressDebugSections = DebugCompressionType::Zlib;
+  } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
+    Options.CompressDebugSections = DebugCompressionType::Zstd;
+  } else if (!strcmp("none", DebugInfoCompression)) {
+    Options.CompressDebugSections = DebugCompressionType::None;
+  }
+#endif
+
   Options.RelaxELFRelocations = RelaxELFRelocations;
   Options.UseInitArray = UseInitArray;
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 70cdf3d6d23..4390486b0de 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
   }
   return false;
 }
+
+extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
+#if LLVM_VERSION_GE(16, 0)
+  return llvm::compression::zlib::isAvailable();
+#else
+  return false;
+#endif
+}
+
+extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
+#if LLVM_VERSION_GE(16, 0)
+  return llvm::compression::zstd::isAvailable();
+#else
+  return false;
+#endif
+}
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index cc58d51befd..633004fdddf 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -259,9 +259,6 @@ metadata_std_required =
 metadata_symbol_conflicts_current =
     the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
 
-metadata_symbol_conflicts_others =
-    found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
-
 metadata_target_no_std_support =
     the `{$locator_triple}` target may not support the standard library
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index fce80ab37dd..69221475356 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -8,7 +8,7 @@ use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, All
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
+use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
@@ -134,14 +134,14 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
 }
 
 impl CStore {
-    pub fn from_tcx(tcx: TyCtxt<'_>) -> MappedReadGuard<'_, CStore> {
-        ReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
+    pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
+        FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
             cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
         })
     }
 
-    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> MappedWriteGuard<'_, CStore> {
-        WriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
+    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {
+        FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
             cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
         })
     }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index bf6004ba864..3062939d8da 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -903,10 +903,11 @@ pub fn list_file_metadata(
     path: &Path,
     metadata_loader: &dyn MetadataLoader,
     out: &mut dyn Write,
+    ls_kinds: &[String],
 ) -> IoResult<()> {
     let flavor = get_flavor_from_path(path);
     match get_metadata_section(target, flavor, path, metadata_loader) {
-        Ok(metadata) => metadata.list_crate_metadata(out),
+        Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
         Err(msg) => write!(out, "{msg}\n"),
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 7fd3c0f494a..a57bff3730d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -725,25 +725,196 @@ impl MetadataBlob {
         LazyValue::<CrateRoot>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
     }
 
-    pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> {
+    pub(crate) fn list_crate_metadata(
+        &self,
+        out: &mut dyn io::Write,
+        ls_kinds: &[String],
+    ) -> io::Result<()> {
         let root = self.get_root();
-        writeln!(out, "Crate info:")?;
-        writeln!(out, "name {}{}", root.name(), root.extra_filename)?;
-        writeln!(out, "hash {} stable_crate_id {:?}", root.hash(), root.stable_crate_id)?;
-        writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?;
-        writeln!(out, "=External Dependencies=")?;
-
-        for (i, dep) in root.crate_deps.decode(self).enumerate() {
-            let CrateDep { name, extra_filename, hash, host_hash, kind, is_private } = dep;
-            let number = i + 1;
-
-            writeln!(
-                out,
-                "{number} {name}{extra_filename} hash {hash} host_hash {host_hash:?} kind {kind:?} {privacy}",
-                privacy = if is_private { "private" } else { "public" }
-            )?;
+
+        let all_ls_kinds = vec![
+            "root".to_owned(),
+            "lang_items".to_owned(),
+            "features".to_owned(),
+            "items".to_owned(),
+        ];
+        let ls_kinds = if ls_kinds.contains(&"all".to_owned()) { &all_ls_kinds } else { ls_kinds };
+
+        for kind in ls_kinds {
+            match &**kind {
+                "root" => {
+                    writeln!(out, "Crate info:")?;
+                    writeln!(out, "name {}{}", root.name(), root.extra_filename)?;
+                    writeln!(
+                        out,
+                        "hash {} stable_crate_id {:?}",
+                        root.hash(),
+                        root.stable_crate_id
+                    )?;
+                    writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?;
+                    writeln!(out, "triple {}", root.header.triple.triple())?;
+                    writeln!(out, "edition {}", root.edition)?;
+                    writeln!(out, "symbol_mangling_version {:?}", root.symbol_mangling_version)?;
+                    writeln!(
+                        out,
+                        "required_panic_strategy {:?} panic_in_drop_strategy {:?}",
+                        root.required_panic_strategy, root.panic_in_drop_strategy
+                    )?;
+                    writeln!(
+                        out,
+                        "has_global_allocator {} has_alloc_error_handler {} has_panic_handler {} has_default_lib_allocator {}",
+                        root.has_global_allocator,
+                        root.has_alloc_error_handler,
+                        root.has_panic_handler,
+                        root.has_default_lib_allocator
+                    )?;
+                    writeln!(
+                        out,
+                        "compiler_builtins {} needs_allocator {} needs_panic_runtime {} no_builtins {} panic_runtime {} profiler_runtime {}",
+                        root.compiler_builtins,
+                        root.needs_allocator,
+                        root.needs_panic_runtime,
+                        root.no_builtins,
+                        root.panic_runtime,
+                        root.profiler_runtime
+                    )?;
+
+                    writeln!(out, "=External Dependencies=")?;
+                    let dylib_dependency_formats =
+                        root.dylib_dependency_formats.decode(self).collect::<Vec<_>>();
+                    for (i, dep) in root.crate_deps.decode(self).enumerate() {
+                        let CrateDep { name, extra_filename, hash, host_hash, kind, is_private } =
+                            dep;
+                        let number = i + 1;
+
+                        writeln!(
+                            out,
+                            "{number} {name}{extra_filename} hash {hash} host_hash {host_hash:?} kind {kind:?} {privacy}{linkage}",
+                            privacy = if is_private { "private" } else { "public" },
+                            linkage = if dylib_dependency_formats.is_empty() {
+                                String::new()
+                            } else {
+                                format!(" linkage {:?}", dylib_dependency_formats[i])
+                            }
+                        )?;
+                    }
+                    write!(out, "\n")?;
+                }
+
+                "lang_items" => {
+                    writeln!(out, "=Lang items=")?;
+                    for (id, lang_item) in root.lang_items.decode(self) {
+                        writeln!(
+                            out,
+                            "{} = crate{}",
+                            lang_item.name(),
+                            DefPath::make(LOCAL_CRATE, id, |parent| root
+                                .tables
+                                .def_keys
+                                .get(self, parent)
+                                .unwrap()
+                                .decode(self))
+                            .to_string_no_crate_verbose()
+                        )?;
+                    }
+                    for lang_item in root.lang_items_missing.decode(self) {
+                        writeln!(out, "{} = <missing>", lang_item.name())?;
+                    }
+                    write!(out, "\n")?;
+                }
+
+                "features" => {
+                    writeln!(out, "=Lib features=")?;
+                    for (feature, since) in root.lib_features.decode(self) {
+                        writeln!(
+                            out,
+                            "{}{}",
+                            feature,
+                            if let Some(since) = since {
+                                format!(" since {since}")
+                            } else {
+                                String::new()
+                            }
+                        )?;
+                    }
+                    write!(out, "\n")?;
+                }
+
+                "items" => {
+                    writeln!(out, "=Items=")?;
+
+                    fn print_item(
+                        blob: &MetadataBlob,
+                        out: &mut dyn io::Write,
+                        item: DefIndex,
+                        indent: usize,
+                    ) -> io::Result<()> {
+                        let root = blob.get_root();
+
+                        let def_kind = root.tables.opt_def_kind.get(blob, item).unwrap();
+                        let def_key = root.tables.def_keys.get(blob, item).unwrap().decode(blob);
+                        let def_name = if item == CRATE_DEF_INDEX {
+                            rustc_span::symbol::kw::Crate
+                        } else {
+                            def_key
+                                .disambiguated_data
+                                .data
+                                .get_opt_name()
+                                .unwrap_or_else(|| Symbol::intern("???"))
+                        };
+                        let visibility =
+                            root.tables.visibility.get(blob, item).unwrap().decode(blob).map_id(
+                                |index| {
+                                    format!(
+                                        "crate{}",
+                                        DefPath::make(LOCAL_CRATE, index, |parent| root
+                                            .tables
+                                            .def_keys
+                                            .get(blob, parent)
+                                            .unwrap()
+                                            .decode(blob))
+                                        .to_string_no_crate_verbose()
+                                    )
+                                },
+                            );
+                        write!(
+                            out,
+                            "{nil: <indent$}{:?} {:?} {} {{",
+                            visibility,
+                            def_kind,
+                            def_name,
+                            nil = "",
+                        )?;
+
+                        if let Some(children) =
+                            root.tables.module_children_non_reexports.get(blob, item)
+                        {
+                            write!(out, "\n")?;
+                            for child in children.decode(blob) {
+                                print_item(blob, out, child, indent + 4)?;
+                            }
+                            writeln!(out, "{nil: <indent$}}}", nil = "")?;
+                        } else {
+                            writeln!(out, "}}")?;
+                        }
+
+                        Ok(())
+                    }
+
+                    print_item(self, out, CRATE_DEF_INDEX, 0)?;
+
+                    write!(out, "\n")?;
+                }
+
+                _ => {
+                    writeln!(
+                        out,
+                        "unknown -Zls kind. allowed values are: all, root, lang_items, features, items"
+                    )?;
+                }
+            }
         }
-        write!(out, "\n")?;
+
         Ok(())
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index aeda8af6d2c..f964a8c76c0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -131,7 +131,7 @@ macro_rules! provide_one {
                 $tcx.ensure().crate_hash($def_id.krate);
             }
 
-            let cdata = rustc_data_structures::sync::MappedReadGuard::map(CStore::from_tcx($tcx), |c| {
+            let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {
                 c.get_crate_data($def_id.krate).cdata
             });
             let $cdata = crate::creader::CrateMetadataRef {
@@ -510,7 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
         crates: |tcx, ()| {
             // The list of loaded crates is now frozen in query cache,
             // so make sure cstore is not mutably accessed from here on.
-            tcx.untracked().cstore.leak();
+            tcx.untracked().cstore.freeze();
             tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
         },
         ..*providers
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index bace48cec44..cc7ae932e11 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -14,7 +14,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{
-    CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
+    CrateNum, DefId, DefIndex, LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX,
+    LOCAL_CRATE,
 };
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::lang_items::LangItem;
@@ -50,7 +51,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::FileEncoder,
     tcx: TyCtxt<'tcx>,
     feat: &'tcx rustc_feature::Features,
-
     tables: TableBuilders,
 
     lazy_state: LazyState,
@@ -1002,15 +1002,31 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
     }
 }
 
-/// Whether we should encode MIR.
+/// Whether we should encode MIR. Return a pair, resp. for CTFE and for LLVM.
 ///
 /// Computing, optimizing and encoding the MIR is a relatively expensive operation.
 /// We want to avoid this work when not required. Therefore:
 /// - we only compute `mir_for_ctfe` on items with const-eval semantics;
 /// - we skip `optimized_mir` for check runs.
+/// - we only encode `optimized_mir` that could be generated in other crates, that is, a code that
+///   is either generic or has inline hint, and is reachable from the other crates (contained
+///   in reachable set).
+///
+/// Note: Reachable set describes definitions that might be generated or referenced from other
+/// crates and it can be used to limit optimized MIR that needs to be encoded. On the other hand,
+/// the reachable set doesn't have much to say about which definitions might be evaluated at compile
+/// time in other crates, so it cannot be used to omit CTFE MIR. For example, `f` below is
+/// unreachable and yet it can be evaluated in other crates:
 ///
-/// Return a pair, resp. for CTFE and for LLVM.
-fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
+/// ```
+/// const fn f() -> usize { 0 }
+/// pub struct S { pub a: [usize; f()] }
+/// ```
+fn should_encode_mir(
+    tcx: TyCtxt<'_>,
+    reachable_set: &LocalDefIdSet,
+    def_id: LocalDefId,
+) -> (bool, bool) {
     match tcx.def_kind(def_id) {
         // Constructors
         DefKind::Ctor(_, _) => {
@@ -1027,14 +1043,15 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
         // Full-fledged functions + closures
         DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
             let generics = tcx.generics_of(def_id);
-            let needs_inline = (generics.requires_monomorphization(tcx)
-                || tcx.codegen_fn_attrs(def_id).requests_inline())
-                && tcx.sess.opts.output_types.should_codegen();
+            let opt = tcx.sess.opts.unstable_opts.always_encode_mir
+                || (tcx.sess.opts.output_types.should_codegen()
+                    && reachable_set.contains(&def_id)
+                    && (generics.requires_monomorphization(tcx)
+                        || tcx.codegen_fn_attrs(def_id).requests_inline()));
             // The function has a `const` modifier or is in a `#[const_trait]`.
             let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
                 || tcx.is_const_default_method(def_id.to_def_id());
-            let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
-            (is_const_fn, needs_inline || always_encode_mir)
+            (is_const_fn, opt)
         }
         // Generators require optimized MIR to compute layout.
         DefKind::Generator => (false, true),
@@ -1580,9 +1597,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
 
         let tcx = self.tcx;
+        let reachable_set = tcx.reachable_set(());
 
         let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| {
-            let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+            let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
             if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None }
         });
         for (def_id, encode_const, encode_opt) in keys_and_jobs {
@@ -2067,8 +2085,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
         return;
     }
 
+    let reachable_set = tcx.reachable_set(());
     par_for_each_in(tcx.mir_keys(()), |&def_id| {
-        let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+        let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
 
         if encode_const {
             tcx.ensure_with_value().mir_for_ctfe(def_id);
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e20a202561f..f67f8015c04 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1206,7 +1206,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
         upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
         source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
         debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
-        if tcx.sess.opts.incremental_relative_spans() {
+        if tcx.sess.opts.incremental.is_some() {
             let definitions = tcx.untracked().definitions.freeze();
             let mut owner_spans: Vec<_> = krate
                 .owners
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 81823118ab8..b17f1512886 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -27,6 +27,7 @@ use crate::ty::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
+use std::fmt::Display;
 use std::ops::Index;
 
 /// A "canonicalized" type `V` is one where all free inference
@@ -40,6 +41,16 @@ pub struct Canonical<'tcx, V> {
     pub variables: CanonicalVarInfos<'tcx>,
 }
 
+impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
+            self.value, self.max_universe, self.variables
+        )
+    }
+}
+
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
 impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
@@ -173,6 +184,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::PlaceholderRegion(..) => false,
             CanonicalVarKind::Const(..) => true,
             CanonicalVarKind::PlaceholderConst(_, _) => false,
+            CanonicalVarKind::Effect => true,
         }
     }
 
@@ -182,7 +194,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::Ty(_)
             | CanonicalVarKind::PlaceholderTy(_)
             | CanonicalVarKind::Const(_, _)
-            | CanonicalVarKind::PlaceholderConst(_, _) => false,
+            | CanonicalVarKind::PlaceholderConst(_, _)
+            | CanonicalVarKind::Effect => false,
         }
     }
 
@@ -190,7 +203,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
         match self.kind {
             CanonicalVarKind::Ty(_)
             | CanonicalVarKind::Region(_)
-            | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"),
+            | CanonicalVarKind::Const(_, _)
+            | CanonicalVarKind::Effect => bug!("expected placeholder: {self:?}"),
 
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
@@ -222,6 +236,9 @@ pub enum CanonicalVarKind<'tcx> {
     /// Some kind of const inference variable.
     Const(ty::UniverseIndex, Ty<'tcx>),
 
+    /// Effect variable `'?E`.
+    Effect,
+
     /// A "placeholder" that represents "any const".
     PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
 }
@@ -229,11 +246,11 @@ pub enum CanonicalVarKind<'tcx> {
 impl<'tcx> CanonicalVarKind<'tcx> {
     pub fn universe(self) -> ty::UniverseIndex {
         match self {
-            CanonicalVarKind::Ty(kind) => match kind {
-                CanonicalTyVarKind::General(ui) => ui,
-                CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
-            },
-
+            CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
+            CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
+                ty::UniverseIndex::ROOT
+            }
+            CanonicalVarKind::Effect => ty::UniverseIndex::ROOT,
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
@@ -248,15 +265,14 @@ impl<'tcx> CanonicalVarKind<'tcx> {
     /// the updated universe is not the root.
     pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
         match self {
-            CanonicalVarKind::Ty(kind) => match kind {
-                CanonicalTyVarKind::General(_) => {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
-                }
-                CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
-                    assert_eq!(ui, ty::UniverseIndex::ROOT);
-                    CanonicalVarKind::Ty(kind)
-                }
-            },
+            CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
+                CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
+            }
+            CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
+            | CanonicalVarKind::Effect => {
+                assert_eq!(ui, ty::UniverseIndex::ROOT);
+                self
+            }
             CanonicalVarKind::PlaceholderTy(placeholder) => {
                 CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
             }
@@ -443,6 +459,13 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                             };
                             ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
                         }
+                        CanonicalVarKind::Effect => ty::Const::new_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            tcx.types.bool,
+                        )
+                        .into(),
                         CanonicalVarKind::Const(_, ty)
                         | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
                             tcx,
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 85fb9214d9d..7ca9647590a 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -188,3 +188,53 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
         })
     }
 }
+
+/// values for the effect inference variable
+#[derive(Clone, Copy, Debug)]
+pub enum EffectVarValue<'tcx> {
+    /// The host effect is on, enabling access to syscalls, filesystem access, etc.
+    Host,
+    /// The host effect is off. Execution is restricted to const operations only.
+    NoHost,
+    Const(ty::Const<'tcx>),
+}
+
+impl<'tcx> EffectVarValue<'tcx> {
+    pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
+        match self {
+            EffectVarValue::Host => tcx.consts.true_,
+            EffectVarValue::NoHost => tcx.consts.false_,
+            EffectVarValue::Const(c) => c,
+        }
+    }
+}
+
+impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
+    type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
+    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+        match (value1, value2) {
+            (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
+            (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
+            (EffectVarValue::NoHost | EffectVarValue::Host, _)
+            | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
+            (EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
+                bug!("equating two const variables, both of which have known values")
+            }
+        }
+    }
+}
+
+impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
+    type Value = Option<EffectVarValue<'tcx>>;
+    #[inline]
+    fn index(&self) -> u32 {
+        self.index
+    }
+    #[inline]
+    fn from_index(i: u32) -> Self {
+        ty::EffectVid { index: i, phantom: PhantomData }
+    }
+    fn tag() -> &'static str {
+        "EffectVid"
+    }
+}
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 02fd6ed7ba6..4e5725876c4 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -87,7 +87,7 @@ bitflags! {
         /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
         /// function as an entry function from Non-Secure code.
         const CMSE_NONSECURE_ENTRY      = 1 << 14;
-        /// `#[no_coverage]`: indicates that the function should be ignored by
+        /// `#[coverage(off)]`: indicates that the function should be ignored by
         /// the MIR `InstrumentCoverage` pass and not added to the coverage map
         /// during codegen.
         const NO_COVERAGE               = 1 << 15;
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 577cd20b74c..7e3be0b5d5f 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -71,6 +71,8 @@ TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
+/// This is needed in `thir::pattern::lower_inline_const`.
 pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
 pub fn struct_error<'tcx>(
@@ -255,9 +257,16 @@ impl_into_diagnostic_arg_through_debug! {
 
 /// Error information for when the program caused Undefined Behavior.
 #[derive(Debug)]
-pub enum UndefinedBehaviorInfo<'a> {
+pub enum UndefinedBehaviorInfo<'tcx> {
     /// Free-form case. Only for errors that are never caught! Used by miri
     Ub(String),
+    // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
+    // dispatched
+    /// A custom (free-form) fluent-translated error, created by `err_ub_custom!`.
+    Custom(crate::error::CustomSubdiagnostic<'tcx>),
+    /// Validation error.
+    ValidationError(ValidationErrorInfo<'tcx>),
+
     /// Unreachable code was executed.
     Unreachable,
     /// A slice/array index projection went out-of-bounds.
@@ -319,12 +328,10 @@ pub enum UndefinedBehaviorInfo<'a> {
     UninhabitedEnumVariantWritten(VariantIdx),
     /// An uninhabited enum variant is projected.
     UninhabitedEnumVariantRead(VariantIdx),
-    /// Validation error.
-    ValidationError(ValidationErrorInfo<'a>),
-    // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
-    // dispatched
-    /// A custom (free-form) error, created by `err_ub_custom!`.
-    Custom(crate::error::CustomSubdiagnostic<'a>),
+    /// ABI-incompatible argument types.
+    AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+    /// ABI-incompatible return types.
+    AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
 }
 
 #[derive(Debug, Clone, Copy)]
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index c78b1e0e2f4..3b22ecfbe50 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -8,6 +8,7 @@ use crate::mir::interpret::{
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::print::with_no_trimmed_paths;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{self, List, Ty, TyCtxt};
@@ -25,6 +26,7 @@ use rustc_target::abi::{FieldIdx, Size, VariantIdx};
 
 use polonius_engine::Atom;
 pub use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -35,6 +37,8 @@ use rustc_span::{Span, DUMMY_SP};
 use either::Either;
 
 use std::borrow::Cow;
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
 use std::fmt::{self, Debug, Display, Formatter, Write};
 use std::ops::{Index, IndexMut};
 use std::{iter, mem};
@@ -97,6 +101,36 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
     }
 }
 
+thread_local! {
+    static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
+        RefCell::new(FxHashMap::default())
+    };
+}
+
+/// Converts a MIR pass name into a snake case form to match the profiling naming style.
+fn to_profiler_name(type_name: &'static str) -> &'static str {
+    PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
+        Entry::Occupied(e) => *e.get(),
+        Entry::Vacant(e) => {
+            let snake_case: String = type_name
+                .chars()
+                .flat_map(|c| {
+                    if c.is_ascii_uppercase() {
+                        vec!['_', c.to_ascii_lowercase()]
+                    } else if c == '-' {
+                        vec!['_']
+                    } else {
+                        vec![c]
+                    }
+                })
+                .collect();
+            let result = &*String::leak(format!("mir_pass{}", snake_case));
+            e.insert(result);
+            result
+        }
+    })
+}
+
 /// A streamlined trait that you can implement to create a pass; the
 /// pass will be named after the type, and it will consist of a main
 /// loop that goes over each available MIR and applies `run_pass`.
@@ -106,6 +140,10 @@ pub trait MirPass<'tcx> {
         if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
     }
 
+    fn profiler_name(&self) -> &'static str {
+        to_profiler_name(self.name())
+    }
+
     /// Returns `true` if this pass is enabled with the current combination of compiler flags.
     fn is_enabled(&self, _sess: &Session) -> bool {
         true
@@ -1794,7 +1832,7 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
                 write!(fmt, ")")?;
             }
             ProjectionElem::Field(field, ty) => {
-                write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
+                with_no_trimmed_paths!(write!(fmt, ".{:?}: {})", field.index(), ty)?);
             }
             ProjectionElem::Index(ref index) => {
                 write!(fmt, "[{index:?}]")?;
@@ -2077,7 +2115,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
             Len(ref a) => write!(fmt, "Len({a:?})"),
             Cast(ref kind, ref place, ref ty) => {
-                write!(fmt, "{place:?} as {ty:?} ({kind:?})")
+                with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
             }
             BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
             CheckedBinaryOp(ref op, box (ref a, ref b)) => {
@@ -2085,11 +2123,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
             UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
             Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
-            NullaryOp(ref op, ref t) => match op {
-                NullOp::SizeOf => write!(fmt, "SizeOf({t:?})"),
-                NullOp::AlignOf => write!(fmt, "AlignOf({t:?})"),
-                NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t:?}, {fields:?})"),
-            },
+            NullaryOp(ref op, ref t) => {
+                let t = with_no_trimmed_paths!(format!("{}", t));
+                match op {
+                    NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
+                    NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
+                    NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
+                }
+            }
             ThreadLocalRef(did) => ty::tls::with(|tcx| {
                 let muta = tcx.static_mutability(did).unwrap().prefix_str();
                 write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
@@ -2225,7 +2266,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
 
             ShallowInitBox(ref place, ref ty) => {
-                write!(fmt, "ShallowInitBox({place:?}, {ty:?})")
+                with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
             }
         }
     }
@@ -2296,18 +2337,6 @@ impl<'tcx> ConstantKind<'tcx> {
     }
 
     #[inline]
-    pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
-        match self {
-            ConstantKind::Ty(c) => match c.kind() {
-                ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
-                _ => None,
-            },
-            ConstantKind::Val(val, _) => Some(val),
-            ConstantKind::Unevaluated(..) => None,
-        }
-    }
-
-    #[inline]
     pub fn try_to_scalar(self) -> Option<Scalar> {
         match self {
             ConstantKind::Ty(c) => match c.kind() {
@@ -2338,37 +2367,59 @@ impl<'tcx> ConstantKind<'tcx> {
     }
 
     #[inline]
-    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        match self {
-            Self::Ty(c) => {
-                if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
-                    match val {
-                        Ok(val) => Self::Val(val, c.ty()),
-                        Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
-                    }
+    pub fn eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        span: Option<Span>,
+    ) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
+        let (uneval, param_env) = match self {
+            ConstantKind::Ty(c) => {
+                if let ty::ConstKind::Unevaluated(uneval) = c.kind() {
+                    // Avoid the round-trip via valtree, evaluate directly to ConstValue.
+                    let (param_env, uneval) = uneval.prepare_for_eval(tcx, param_env);
+                    (uneval.expand(), param_env)
                 } else {
-                    self
+                    // It's already a valtree, or an error.
+                    let val = c.eval(tcx, param_env, span)?;
+                    return Ok(tcx.valtree_to_const_val((self.ty(), val)));
                 }
             }
-            Self::Val(_, _) => self,
-            Self::Unevaluated(uneval, ty) => {
-                // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
-                match tcx.const_eval_resolve(param_env, uneval, None) {
-                    Ok(val) => Self::Val(val, ty),
-                    Err(ErrorHandled::TooGeneric) => self,
-                    Err(ErrorHandled::Reported(guar)) => {
-                        Self::Ty(ty::Const::new_error(tcx, guar.into(), ty))
-                    }
-                }
+            ConstantKind::Unevaluated(uneval, _) => (uneval, param_env),
+            ConstantKind::Val(val, _) => return Ok(val),
+        };
+        // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
+        tcx.const_eval_resolve(param_env, uneval, span)
+    }
+
+    /// Normalizes the constant to a value or an error if possible.
+    #[inline]
+    pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        match self.eval(tcx, param_env, None) {
+            Ok(val) => Self::Val(val, self.ty()),
+            Err(ErrorHandled::Reported(guar)) => {
+                Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
             }
+            Err(ErrorHandled::TooGeneric) => self,
         }
     }
 
-    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     #[inline]
-    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env, ty)
-            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    pub fn try_eval_scalar(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<Scalar> {
+        self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+    }
+
+    #[inline]
+    pub fn try_eval_scalar_int(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<ScalarInt> {
+        self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
     }
 
     #[inline]
@@ -2378,59 +2429,38 @@ impl<'tcx> ConstantKind<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
-        match self {
-            Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty),
-            Self::Val(val, t) => {
-                assert_eq!(*t, ty);
-                let size =
-                    tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
-                val.try_to_bits(size)
-            }
-            Self::Unevaluated(uneval, ty) => {
-                match tcx.const_eval_resolve(param_env, *uneval, None) {
-                    Ok(val) => {
-                        let size = tcx
-                            .layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty))
-                            .ok()?
-                            .size;
-                        val.try_to_bits(size)
-                    }
-                    Err(_) => None,
-                }
-            }
-        }
+        let int = self.try_eval_scalar_int(tcx, param_env)?;
+        assert_eq!(self.ty(), ty);
+        let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+        int.to_bits(size).ok()
     }
 
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     #[inline]
-    pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
-        match self {
-            Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
-            Self::Val(val, _) => val.try_to_bool(),
-            Self::Unevaluated(uneval, _) => {
-                match tcx.const_eval_resolve(param_env, *uneval, None) {
-                    Ok(val) => val.try_to_bool(),
-                    Err(_) => None,
-                }
-            }
-        }
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env, ty)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
     }
 
     #[inline]
     pub fn try_eval_target_usize(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Option<u64> {
-        match self {
-            Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
-            Self::Val(val, _) => val.try_to_target_usize(tcx),
-            Self::Unevaluated(uneval, _) => {
-                match tcx.const_eval_resolve(param_env, *uneval, None) {
-                    Ok(val) => val.try_to_target_usize(tcx),
-                    Err(_) => None,
-                }
-            }
-        }
+        self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
+    }
+
+    #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
+    pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 {
+        self.try_eval_target_usize(tcx, param_env)
+            .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
+    }
+
+    #[inline]
+    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
+        self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
     }
 
     #[inline]
@@ -2572,7 +2602,7 @@ impl<'tcx> ConstantKind<'tcx> {
         }
     }
 
-    pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+    pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
         match c.kind() {
             ty::ConstKind::Value(valtree) => {
                 let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
@@ -2606,6 +2636,11 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
         UnevaluatedConst { def, args, promoted: Default::default() }
     }
+
+    #[inline]
+    pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
+        UnevaluatedConst::new(instance.def_id(), instance.args)
+    }
 }
 
 /// A collection of projections into user types.
@@ -2880,7 +2915,7 @@ fn pretty_print_const_value<'tcx>(
                 }
             }
             (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
-                let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
+                let n = n.try_to_target_usize(tcx).unwrap();
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
                 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
                 let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 488526edb43..6b23a7f5bff 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -583,8 +583,10 @@ fn write_scope_tree(
 
         let mut_str = local_decl.mutability.prefix_str();
 
-        let mut indented_decl =
-            format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
+        let mut indented_decl = ty::print::with_no_trimmed_paths!(format!(
+            "{0:1$}let {2}{3:?}: {4}",
+            INDENT, indent, mut_str, local, local_decl.ty
+        ));
         if let Some(user_ty) = &local_decl.user_ty {
             for user_ty in user_ty.projections() {
                 write!(indented_decl, " as {user_ty:?}").unwrap();
@@ -1058,11 +1060,11 @@ fn write_user_type_annotations(
     for (index, annotation) in body.user_type_annotations.iter_enumerated() {
         writeln!(
             w,
-            "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
+            "| {:?}: user_ty: {}, span: {}, inferred_ty: {}",
             index.index(),
             annotation.user_ty,
             tcx.sess.source_map().span_to_embeddable_string(annotation.span),
-            annotation.inferred_ty,
+            with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)),
         )?;
     }
     if !body.user_type_annotations.is_empty() {
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 154c930dc0f..280f5d0a84c 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -896,7 +896,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
         }
 
         if let Some(parent) = span_data.parent {
-            let enclosing = s.tcx.source_span(parent).data_untracked();
+            let enclosing = s.tcx.source_span_untracked(parent).data_untracked();
             if enclosing.contains(span_data) {
                 TAG_RELATIVE_SPAN.encode(s);
                 (span_data.lo - enclosing.lo).to_u32().encode(s);
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 9d63d291854..27a1e64a78b 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -9,6 +9,9 @@ use crate::ty::{
     self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
     TypeVisitor,
 };
+use rustc_span::def_id::DefId;
+
+use super::BuiltinImplSource;
 
 mod cache;
 pub mod inspect;
@@ -235,3 +238,63 @@ pub enum IsNormalizesToHack {
     Yes,
     No,
 }
+
+/// Possible ways the given goal can be proven.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CandidateSource {
+    /// A user written impl.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x: Vec<u32> = Vec::new();
+    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
+    ///     let y = x.clone();
+    /// }
+    /// ```
+    Impl(DefId),
+    /// A builtin impl generated by the compiler. When adding a new special
+    /// trait, try to use actual impls whenever possible. Builtin impls should
+    /// only be used in cases where the impl cannot be manually be written.
+    ///
+    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
+    /// For a list of all traits with builtin impls, check out the
+    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
+    BuiltinImpl(BuiltinImplSource),
+    /// An assumption from the environment.
+    ///
+    /// More precisely we've used the `n-th` assumption in the `param_env`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
+    ///     // This uses the assumption `T: Clone` from the `where`-bounds
+    ///     // to prove `T: Clone`.
+    ///     (x.clone(), x)
+    /// }
+    /// ```
+    ParamEnv(usize),
+    /// If the self type is an alias type, e.g. an opaque type or a projection,
+    /// we know the bounds on that alias to hold even without knowing its concrete
+    /// underlying type.
+    ///
+    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
+    /// the self type.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     type Assoc: Clone;
+    /// }
+    ///
+    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
+    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
+    ///     // in the trait definition.
+    ///     let _y = x.clone();
+    /// }
+    /// ```
+    AliasBound,
+}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 4e2af3816ac..d8b3a061b77 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -1,5 +1,6 @@
 use super::{
-    CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult,
+    CandidateSource, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput,
+    QueryResult,
 };
 use crate::ty;
 use format::ProofTreeFormatter;
@@ -7,26 +8,30 @@ use std::fmt::{Debug, Write};
 
 mod format;
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+#[derive(Debug, Eq, PartialEq)]
 pub enum CacheHit {
     Provisional,
     Global,
 }
 
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
 pub struct GoalEvaluation<'tcx> {
     pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub canonicalized_goal: CanonicalInput<'tcx>,
-
-    pub kind: GoalEvaluationKind<'tcx>,
     pub is_normalizes_to_hack: IsNormalizesToHack,
+    pub evaluation: CanonicalGoalEvaluation<'tcx>,
     pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+}
 
+#[derive(Eq, PartialEq)]
+pub struct CanonicalGoalEvaluation<'tcx> {
+    pub goal: CanonicalInput<'tcx>,
+    pub kind: GoalEvaluationKind<'tcx>,
     pub result: QueryResult<'tcx>,
 }
 
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
 pub enum GoalEvaluationKind<'tcx> {
+    Overflow,
     CacheHit(CacheHit),
     Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
 }
@@ -36,55 +41,50 @@ impl Debug for GoalEvaluation<'_> {
     }
 }
 
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
 pub struct AddedGoalsEvaluation<'tcx> {
     pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
     pub result: Result<Certainty, NoSolution>,
 }
-impl Debug for AddedGoalsEvaluation<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_nested_goal_evaluation(self)
-    }
-}
 
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
 pub struct GoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
-    pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<GoalCandidate<'tcx>>,
-
-    pub result: QueryResult<'tcx>,
-}
-impl Debug for GoalEvaluationStep<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_evaluation_step(self)
-    }
+    /// The actual evaluation of the goal, always `ProbeKind::Root`.
+    pub evaluation: GoalCandidate<'tcx>,
 }
 
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
 pub struct GoalCandidate<'tcx> {
-    pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
+    pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
     pub candidates: Vec<GoalCandidate<'tcx>>,
-    pub kind: CandidateKind<'tcx>,
+    pub kind: ProbeKind<'tcx>,
+}
+
+impl Debug for GoalCandidate<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ProofTreeFormatter::new(f).format_candidate(self)
+    }
 }
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
-pub enum CandidateKind<'tcx> {
+#[derive(Debug, PartialEq, Eq)]
+pub enum ProbeKind<'tcx> {
+    /// The root inference context while proving a goal.
+    Root { result: QueryResult<'tcx> },
     /// Probe entered when normalizing the self ty during candidate assembly
     NormalizedSelfTyAssembly,
-    /// A normal candidate for proving a goal
-    Candidate { name: String, result: QueryResult<'tcx> },
+    /// Some candidate to prove the current goal.
+    ///
+    /// FIXME: Remove this in favor of always using more strongly typed variants.
+    MiscCandidate { name: &'static str, result: QueryResult<'tcx> },
+    /// A candidate for proving a trait or alias-relate goal.
+    TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
     /// Used in the probe that wraps normalizing the non-self type for the unsize
     /// trait, which is also structurally matched on.
     UnsizeAssembly,
     /// During upcasting from some source object to target object type, used to
     /// do a probe to find out what projection type(s) may be used to prove that
     /// the source type upholds all of the target type's object bounds.
-    UpcastProbe,
-}
-impl Debug for GoalCandidate<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_candidate(self)
-    }
+    UpcastProjectionCompatibility,
 }
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 8759fecb05a..d916e80a625 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -39,44 +39,52 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         func(&mut ProofTreeFormatter { f: &mut Indentor { f: self.f, on_newline: true } })
     }
 
-    pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result {
-        let goal_text = match goal.is_normalizes_to_hack {
+    pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
+        let goal_text = match eval.is_normalizes_to_hack {
             IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
             IsNormalizesToHack::No => "GOAL",
         };
+        writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
+        self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
+        if eval.returned_goals.len() > 0 {
+            writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
+            self.nested(|this| {
+                for goal in eval.returned_goals.iter() {
+                    writeln!(this.f, "ADDED GOAL: {goal:?},")?;
+                }
+                Ok(())
+            })?;
+
+            writeln!(self.f, "]")
+        } else {
+            Ok(())
+        }
+    }
 
-        writeln!(self.f, "{}: {:?}", goal_text, goal.uncanonicalized_goal)?;
-        writeln!(self.f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;
+    pub(super) fn format_canonical_goal_evaluation(
+        &mut self,
+        eval: &CanonicalGoalEvaluation<'_>,
+    ) -> std::fmt::Result {
+        writeln!(self.f, "GOAL: {:?}", eval.goal)?;
 
-        match &goal.kind {
+        match &eval.kind {
+            GoalEvaluationKind::Overflow => {
+                writeln!(self.f, "OVERFLOW: {:?}", eval.result)
+            }
             GoalEvaluationKind::CacheHit(CacheHit::Global) => {
-                writeln!(self.f, "GLOBAL CACHE HIT: {:?}", goal.result)
+                writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
             }
             GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
-                writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", goal.result)
+                writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
             }
             GoalEvaluationKind::Uncached { revisions } => {
                 for (n, step) in revisions.iter().enumerate() {
-                    writeln!(self.f, "REVISION {n}: {:?}", step.result)?;
+                    writeln!(self.f, "REVISION {n}")?;
                     self.nested(|this| this.format_evaluation_step(step))?;
                 }
-                writeln!(self.f, "RESULT: {:?}", goal.result)
+                writeln!(self.f, "RESULT: {:?}", eval.result)
             }
-        }?;
-
-        if goal.returned_goals.len() > 0 {
-            writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
-            self.nested(|this| {
-                for goal in goal.returned_goals.iter() {
-                    writeln!(this.f, "ADDED GOAL: {goal:?},")?;
-                }
-                Ok(())
-            })?;
-
-            writeln!(self.f, "]")?;
         }
-
-        Ok(())
     }
 
     pub(super) fn format_evaluation_step(
@@ -84,54 +92,52 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         evaluation_step: &GoalEvaluationStep<'_>,
     ) -> std::fmt::Result {
         writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
-
-        for candidate in &evaluation_step.candidates {
-            self.nested(|this| this.format_candidate(candidate))?;
-        }
-        for nested in &evaluation_step.nested_goal_evaluations {
-            self.nested(|this| this.format_nested_goal_evaluation(nested))?;
-        }
-
-        Ok(())
+        self.format_candidate(&evaluation_step.evaluation)
     }
 
     pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
         match &candidate.kind {
-            CandidateKind::NormalizedSelfTyAssembly => {
+            ProbeKind::Root { result } => {
+                writeln!(self.f, "ROOT RESULT: {result:?}")
+            }
+            ProbeKind::NormalizedSelfTyAssembly => {
                 writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
             }
-            CandidateKind::UnsizeAssembly => {
+            ProbeKind::UnsizeAssembly => {
                 writeln!(self.f, "ASSEMBLING CANDIDATES FOR UNSIZING:")
             }
-            CandidateKind::UpcastProbe => {
+            ProbeKind::UpcastProjectionCompatibility => {
                 writeln!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
             }
-            CandidateKind::Candidate { name, result } => {
+            ProbeKind::MiscCandidate { name, result } => {
                 writeln!(self.f, "CANDIDATE {name}: {result:?}")
             }
+            ProbeKind::TraitCandidate { source, result } => {
+                writeln!(self.f, "CANDIDATE {source:?}: {result:?}")
+            }
         }?;
 
         self.nested(|this| {
             for candidate in &candidate.candidates {
                 this.format_candidate(candidate)?;
             }
-            for nested in &candidate.nested_goal_evaluations {
-                this.format_nested_goal_evaluation(nested)?;
+            for nested in &candidate.added_goals_evaluations {
+                this.format_added_goals_evaluation(nested)?;
             }
             Ok(())
         })
     }
 
-    pub(super) fn format_nested_goal_evaluation(
+    pub(super) fn format_added_goals_evaluation(
         &mut self,
-        nested_goal_evaluation: &AddedGoalsEvaluation<'_>,
+        added_goals_evaluation: &AddedGoalsEvaluation<'_>,
     ) -> std::fmt::Result {
-        writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?;
+        writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?;
 
-        for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() {
-            writeln!(self.f, "REVISION {n}")?;
+        for (n, iterations) in added_goals_evaluation.evaluations.iter().enumerate() {
+            writeln!(self.f, "ITERATION {n}")?;
             self.nested(|this| {
-                for goal_evaluation in revision {
+                for goal_evaluation in iterations {
                     this.format_goal_evaluation(goal_evaluation)?;
                 }
                 Ok(())
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index cce10417e1b..629f9f8cd7d 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,5 +1,5 @@
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
+use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
@@ -14,9 +14,8 @@ mod valtree;
 
 pub use int::*;
 pub use kind::*;
-use rustc_span::ErrorGuaranteed;
+use rustc_span::Span;
 use rustc_span::DUMMY_SP;
-use rustc_target::abi::Size;
 pub use valtree::*;
 
 use super::sty::ConstKind;
@@ -36,16 +35,6 @@ pub struct ConstData<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(ConstData<'_>, 40);
 
-enum EvalMode {
-    Typeck,
-    Mir,
-}
-
-enum EvalResult<'tcx> {
-    ValTree(ty::ValTree<'tcx>),
-    ConstVal(ConstValue<'tcx>),
-}
-
 impl<'tcx> Const<'tcx> {
     #[inline]
     pub fn ty(self) -> Ty<'tcx> {
@@ -165,7 +154,7 @@ impl<'tcx> Const<'tcx> {
 
         let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
 
-        match Self::try_eval_lit_or_param(tcx, ty, expr) {
+        match Self::try_from_lit_or_param(tcx, ty, expr) {
             Some(v) => v,
             None => ty::Const::new_unevaluated(
                 tcx,
@@ -179,7 +168,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[instrument(skip(tcx), level = "debug")]
-    fn try_eval_lit_or_param(
+    fn try_from_lit_or_param(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
@@ -254,14 +243,6 @@ impl<'tcx> Const<'tcx> {
         }
     }
 
-    /// Panics if self.kind != ty::ConstKind::Value
-    pub fn to_valtree(self) -> ty::ValTree<'tcx> {
-        match self.kind() {
-            ty::ConstKind::Value(valtree) => valtree,
-            _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
-        }
-    }
-
     #[inline]
     /// Creates a constant with the given integer value and interns it.
     pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
@@ -294,14 +275,66 @@ impl<'tcx> Const<'tcx> {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
-    /// Attempts to convert to a `ValTree`
-    pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
+    /// Returns the evaluated constant
+    #[inline]
+    pub fn eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        span: Option<Span>,
+    ) -> Result<ValTree<'tcx>, ErrorHandled> {
+        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
         match self.kind() {
-            ty::ConstKind::Value(valtree) => Some(valtree),
-            _ => None,
+            ConstKind::Unevaluated(unevaluated) => {
+                // FIXME(eddyb) maybe the `const_eval_*` methods should take
+                // `ty::ParamEnvAnd` instead of having them separate.
+                let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
+                // try to resolve e.g. associated constants to their definition on an impl, and then
+                // evaluate the const.
+                let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
+                Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type"))
+            }
+            ConstKind::Value(val) => Ok(val),
+            ConstKind::Error(g) => Err(g.into()),
+            ConstKind::Param(_)
+            | ConstKind::Infer(_)
+            | ConstKind::Bound(_, _)
+            | ConstKind::Placeholder(_)
+            | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
         }
     }
 
+    /// Normalizes the constant to a value or an error if possible.
+    #[inline]
+    pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
+        match self.eval(tcx, param_env, None) {
+            Ok(val) => Self::new_value(tcx, val, self.ty()),
+            Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
+            Err(ErrorHandled::TooGeneric) => self,
+        }
+    }
+
+    #[inline]
+    pub fn try_eval_scalar(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<Scalar> {
+        self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+    }
+
+    #[inline]
+    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+    /// contains const generic parameters or pointers).
+    pub fn try_eval_scalar_int(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<ScalarInt> {
+        self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
+    }
+
     #[inline]
     /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
     /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
@@ -312,15 +345,18 @@ impl<'tcx> Const<'tcx> {
         param_env: ParamEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
+        let int = self.try_eval_scalar_int(tcx, param_env)?;
         assert_eq!(self.ty(), ty);
         let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
-        self.eval(tcx, param_env).try_to_bits(size)
+        int.to_bits(size).ok()
     }
 
     #[inline]
-    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.eval(tcx, param_env).try_to_bool()
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env, ty)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
     }
 
     #[inline]
@@ -329,29 +365,12 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Option<u64> {
-        self.eval(tcx, param_env).try_to_target_usize(tcx)
-    }
-
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
-    /// unevaluated constant.
-    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
-        if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
-            match val {
-                Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
-                Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
-            }
-        } else {
-            // Either the constant isn't evaluatable or ValTree creation failed.
-            self
-        }
+        self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
     }
 
     #[inline]
-    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
-    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env, ty)
-            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+        self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
     }
 
     #[inline]
@@ -361,136 +380,30 @@ impl<'tcx> Const<'tcx> {
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
 
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
-    /// return `None`.
-    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
-    pub fn try_eval_for_mir(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
-        match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
-            Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
-            Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
-            Some(Err(e)) => Some(Err(e)),
-            None => None,
-        }
-    }
-
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
-    /// return `None`.
-    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
-    pub fn try_eval_for_typeck(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
-        match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
-            Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
-            Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
-            Some(Err(e)) => Some(Err(e)),
-            None => None,
+    /// Panics if self.kind != ty::ConstKind::Value
+    pub fn to_valtree(self) -> ty::ValTree<'tcx> {
+        match self.kind() {
+            ty::ConstKind::Value(valtree) => valtree,
+            _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
         }
     }
 
-    #[inline]
-    fn try_eval_inner(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        eval_mode: EvalMode,
-    ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
-        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
-        if let ConstKind::Unevaluated(unevaluated) = self.kind() {
-            use crate::mir::interpret::ErrorHandled;
-
-            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
-            // also does later, but we want to do it before checking for
-            // inference variables.
-            // Note that we erase regions *before* calling `with_reveal_all_normalized`,
-            // so that we don't try to invoke this query with
-            // any region variables.
-
-            // HACK(eddyb) when the query key would contain inference variables,
-            // attempt using identity args and `ParamEnv` instead, that will succeed
-            // when the expression doesn't depend on any parameters.
-            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
-            // we can call `infcx.const_eval_resolve` which handles inference variables.
-            let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
-                tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
-                    def: unevaluated.def,
-                    args: GenericArgs::identity_for_item(tcx, unevaluated.def),
-                })
-            } else {
-                tcx.erase_regions(param_env)
-                    .with_reveal_all_normalized(tcx)
-                    .and(tcx.erase_regions(unevaluated))
-            };
-
-            // FIXME(eddyb) maybe the `const_eval_*` methods should take
-            // `ty::ParamEnvAnd` instead of having them separate.
-            let (param_env, unevaluated) = param_env_and.into_parts();
-            // try to resolve e.g. associated constants to their definition on an impl, and then
-            // evaluate the const.
-            match eval_mode {
-                EvalMode::Typeck => {
-                    match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
-                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                        // and we use the original type, so nothing from `args`
-                        // (which may be identity args, see above),
-                        // can leak through `val` into the const we return.
-                        Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
-                        Err(ErrorHandled::TooGeneric) => None,
-                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
-                    }
-                }
-                EvalMode::Mir => {
-                    match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
-                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                        // and we use the original type, so nothing from `args`
-                        // (which may be identity args, see above),
-                        // can leak through `val` into the const we return.
-                        Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
-                        Err(ErrorHandled::TooGeneric) => None,
-                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
-                    }
-                }
-            }
-        } else {
-            None
+    /// Attempts to convert to a `ValTree`
+    pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
+        match self.kind() {
+            ty::ConstKind::Value(valtree) => Some(valtree),
+            _ => None,
         }
     }
 
     #[inline]
-    pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
-        if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
-    }
-
-    #[inline]
     pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
-        self.try_to_value()?.try_to_scalar()
-    }
-
-    #[inline]
-    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
-        self.try_to_value()?.try_to_scalar_int()
-    }
-
-    #[inline]
-    pub fn try_to_bits(self, size: Size) -> Option<u128> {
-        self.try_to_scalar_int()?.to_bits(size).ok()
-    }
-
-    #[inline]
-    pub fn try_to_bool(self) -> Option<bool> {
-        self.try_to_scalar_int()?.try_into().ok()
+        self.try_to_valtree()?.try_to_scalar()
     }
 
     #[inline]
     pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
-        self.try_to_value()?.try_to_target_usize(tcx)
+        self.try_to_valtree()?.try_to_target_usize(tcx)
     }
 
     pub fn is_ct_infer(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index db4a15fbee5..a0a7331a37e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -2,7 +2,7 @@ use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
 use crate::ty::GenericArgsRef;
-use crate::ty::{self, List, Ty};
+use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -26,6 +26,39 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
         mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
     }
+
+    /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
+    /// hurts performance.
+    #[inline]
+    pub(crate) fn prepare_for_eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> (ty::ParamEnv<'tcx>, Self) {
+        // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
+        // also does later, but we want to do it before checking for
+        // inference variables.
+        // Note that we erase regions *before* calling `with_reveal_all_normalized`,
+        // so that we don't try to invoke this query with
+        // any region variables.
+
+        // HACK(eddyb) when the query key would contain inference variables,
+        // attempt using identity args and `ParamEnv` instead, that will succeed
+        // when the expression doesn't depend on any parameters.
+        // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+        // we can call `infcx.const_eval_resolve` which handles inference variables.
+        if (param_env, self).has_non_region_infer() {
+            (
+                tcx.param_env(self.def),
+                ty::UnevaluatedConst {
+                    def: self.def,
+                    args: ty::GenericArgs::identity_for_item(tcx, self.def),
+                },
+            )
+        } else {
+            (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
+        }
+    }
 }
 
 impl<'tcx> UnevaluatedConst<'tcx> {
@@ -55,6 +88,11 @@ static_assert_size!(super::ConstKind<'_>, 32);
 pub enum InferConst<'tcx> {
     /// Infer the value of the const.
     Var(ty::ConstVid<'tcx>),
+    /// Infer the value of the effect.
+    ///
+    /// For why this is separate from the `Var` variant above, see the
+    /// documentation on `EffectVid`.
+    EffectVar(ty::EffectVid<'tcx>),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
 }
@@ -62,7 +100,9 @@ pub enum InferConst<'tcx> {
 impl<CTX> HashStable<CTX> for InferConst<'_> {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         match self {
-            InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+            InferConst::Var(_) | InferConst::EffectVar(_) => {
+                panic!("const variables should not be hashed: {self:?}")
+            }
             InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 90d847804f0..eeb87d5561d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -39,9 +39,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{
-    self, FreezeReadGuard, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal,
-};
+use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{
     DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
@@ -995,8 +993,8 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     #[inline]
-    pub fn cstore_untracked(self) -> MappedReadGuard<'tcx, CrateStoreDyn> {
-        ReadGuard::map(self.untracked.cstore.read(), |c| &**c)
+    pub fn cstore_untracked(self) -> FreezeReadGuard<'tcx, CrateStoreDyn> {
+        FreezeReadGuard::map(self.untracked.cstore.read(), |c| &**c)
     }
 
     /// Give out access to the untracked data without any sanity checks.
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index bbd4a623330..3cafd9a8da9 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -324,7 +324,9 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
                     InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
-                    InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
+                    InferConst::Var(_) | InferConst::EffectVar(_) => {
+                        self.add_flags(TypeFlags::HAS_CT_INFER)
+                    }
                 }
             }
             ty::ConstKind::Bound(debruijn, _) => {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 53a3d5fc6be..153b24acba1 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -450,6 +450,11 @@ impl<'tcx> GenericArgs<'tcx> {
     pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> {
         self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
     }
+
+    pub fn print_as_list(&self) -> String {
+        let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>();
+        format!("[{}]", v.join(", "))
+    }
 }
 
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 70a35f137d8..ceac21cf6ea 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -12,7 +12,7 @@ use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamT
 pub enum GenericParamDefKind {
     Lifetime,
     Type { has_default: bool, synthetic: bool },
-    Const { has_default: bool },
+    Const { has_default: bool, is_host_effect: bool },
 }
 
 impl GenericParamDefKind {
@@ -87,7 +87,7 @@ impl GenericParamDef {
             GenericParamDefKind::Type { has_default, .. } if has_default => {
                 Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
             }
-            GenericParamDefKind::Const { has_default } if has_default => {
+            GenericParamDefKind::Const { has_default, .. } if has_default => {
                 Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
@@ -187,7 +187,7 @@ impl<'tcx> Generics {
                 GenericParamDefKind::Type { has_default, .. } => {
                     own_defaults.types += has_default as usize;
                 }
-                GenericParamDefKind::Const { has_default } => {
+                GenericParamDefKind::Const { has_default, .. } => {
                     own_defaults.consts += has_default as usize;
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1fdc4f7500f..99b697d0ea5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -98,9 +98,9 @@ pub use self::sty::BoundRegionKind::*;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
     BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
-    EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
-    FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs, InlineConstArgsParts,
-    ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
+    EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
+    FnSig, FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs,
+    InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
     PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
     TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
 };
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 12254ed1a4d..f24ac79323f 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -760,9 +760,12 @@ pub trait PrettyPrinter<'tcx>:
                 // only affect certain debug messages (e.g. messages printed
                 // from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
                 // and should have no effect on any compiler output.
+                // [Unless `-Zverbose` is used, e.g. in the output of
+                // `tests/ui/nll/ty-outlives/impl-trait-captures.rs`, for
+                // example.]
                 if self.should_print_verbose() {
                     // FIXME(eddyb) print this with `print_def_path`.
-                    p!(write("Opaque({:?}, {:?})", def_id, args));
+                    p!(write("Opaque({:?}, {})", def_id, args.print_as_list()));
                     return Ok(self);
                 }
 
@@ -894,7 +897,7 @@ pub trait PrettyPrinter<'tcx>:
                     p!(print_def_path(did, args));
                     if !args.as_closure().is_valid() {
                         p!(" closure_args=(unavailable)");
-                        p!(write(" args={:?}", args));
+                        p!(write(" args={}", args.print_as_list()));
                     } else {
                         p!(" closure_kind_ty=", print(args.as_closure().kind_ty()));
                         p!(
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f979ddd00fa..99a19f01b2b 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -138,6 +138,12 @@ impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
     }
 }
 
+impl fmt::Debug for ty::EffectVid<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "?{}e", self.index)
+    }
+}
+
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@@ -154,7 +160,7 @@ impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
 }
 impl<'tcx> fmt::Debug for Ty<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        with_no_trimmed_paths!(fmt::Display::fmt(self, f))
+        with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
     }
 }
 
@@ -253,6 +259,7 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             InferConst::Var(var) => write!(f, "{var:?}"),
+            InferConst::EffectVar(var) => write!(f, "{var:?}"),
             InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
         }
     }
@@ -267,6 +274,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
                 Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
+                EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
                 Fresh(_) => {
                     unreachable!()
                 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index fbbdfe5f14f..2502e303f7a 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1577,6 +1577,20 @@ pub struct ConstVid<'tcx> {
     pub phantom: PhantomData<&'tcx ()>,
 }
 
+/// An **effect** **v**ariable **ID**.
+///
+/// Handling effect infer variables happens separately from const infer variables
+/// because we do not want to reuse any of the const infer machinery. If we try to
+/// relate an effect variable with a normal one, we would ICE, which can catch bugs
+/// where we are not correctly using the effect var for an effect param. Fallback
+/// is also implemented on top of having separate effect and normal const variables.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable)]
+pub struct EffectVid<'tcx> {
+    pub index: u32,
+    pub phantom: PhantomData<&'tcx ()>,
+}
+
 rustc_index::newtype_index! {
     /// A **region** (lifetime) **v**ariable **ID**.
     #[derive(HashStable)]
@@ -2735,6 +2749,8 @@ impl<'tcx> Ty<'tcx> {
             | ty::Error(_)
             // Extern types have metadata = ().
             | ty::Foreign(..)
+            // `dyn*` has no metadata
+            | ty::Dynamic(_, _, DynKind::DynStar)
             // If returned by `struct_tail_without_normalization` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
@@ -2743,7 +2759,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Tuple(..) => (tcx.types.unit, false),
 
             ty::Str | ty::Slice(_) => (tcx.types.usize, false),
-            ty::Dynamic(..) => {
+            ty::Dynamic(_, _, DynKind::Dyn) => {
                 let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
                 (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
             },
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6e55e7915c9..bf9b244936f 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -90,6 +90,10 @@ pub struct TraitImpls {
 }
 
 impl TraitImpls {
+    pub fn is_empty(&self) -> bool {
+        self.blanket_impls.is_empty() && self.non_blanket_impls.is_empty()
+    }
+
     pub fn blanket_impls(&self) -> &[DefId] {
         self.blanket_impls.as_slice()
     }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 327cd0a5d7b..7ecc7e6014d 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -722,3 +722,14 @@ pub enum UserType<'tcx> {
     /// given substitutions applied.
     TypeOf(DefId, UserArgs<'tcx>),
 }
+
+impl<'tcx> std::fmt::Display for UserType<'tcx> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Ty(arg0) => {
+                ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0))
+            }
+            Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1),
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 156eda477ad..fb760654ea7 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -33,14 +33,6 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
     }
 
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        // N.B. Even though this uses a visitor, the visitor does not actually
-        //      recurse through the whole `TypeVisitable` implementor type.
-        //
-        //      Instead it stops on the first "level", visiting types, regions,
-        //      consts and predicates just fetches their type flags.
-        //
-        //      Thus this is a lot faster than it might seem and should be
-        //      optimized to a simple field access.
         let res =
             self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
         trace!(?self, ?flags, ?res, "has_type_flags");
@@ -485,11 +477,16 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
     }
 }
 
+// Note: this visitor traverses values down to the level of
+// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
+// type flags at the outer layer are enough. So it's faster than it first
+// looks, particular for `Ty`/`Predicate` where it's just a field access.
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
 
     #[inline]
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
         let flags = t.flags();
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
@@ -500,6 +497,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
 
     #[inline]
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call, as usual for `Region`.
         let flags = r.type_flags();
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
@@ -510,6 +508,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
 
     #[inline]
     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
         let flags = FlagComputation::for_const(c);
         trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
@@ -521,6 +520,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
 
     #[inline]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
         if predicate.flags().intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7736183027f..0ea61ec8d40 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -198,11 +198,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             (Some(PatKind::Constant { value: lo }), None) => {
                 let hi = ty.numeric_max_val(self.tcx)?;
-                Some((*lo, mir::ConstantKind::from_const(hi, self.tcx)))
+                Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx)))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
                 let lo = ty.numeric_min_val(self.tcx)?;
-                Some((mir::ConstantKind::from_const(lo, self.tcx), *hi))
+                Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi))
             }
             _ => None,
         }
@@ -626,6 +626,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
         // First try using a valtree in order to destructure the constant into a pattern.
+        // FIXME: replace "try to do a thing, then fall back to another thing"
+        // but something more principled, like a trait query checking whether this can be turned into a valtree.
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 299bf692307..514146b5030 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -532,7 +532,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     /// places that are non-overlapping or identical.
     ///
     /// The target place must have been flooded before calling this method.
-    fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
+    pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
         let StateData::Reachable(values) = &mut self.0 else { return };
 
         // If both places are tracked, we copy the value to the target.
@@ -928,6 +928,31 @@ impl Map {
             f(v)
         }
     }
+
+    /// Invoke a function on each value in the given place and all descendants.
+    pub fn for_each_projection_value<O>(
+        &self,
+        root: PlaceIndex,
+        value: O,
+        project: &mut impl FnMut(TrackElem, &O) -> Option<O>,
+        f: &mut impl FnMut(PlaceIndex, &O),
+    ) {
+        // Fast path is there is nothing to do.
+        if self.inner_values[root].is_empty() {
+            return;
+        }
+
+        if self.places[root].value_index.is_some() {
+            f(root, &value)
+        }
+
+        for child in self.children(root) {
+            let elem = self.places[child].proj_elem.unwrap();
+            if let Some(value) = project(elem, &value) {
+                self.for_each_projection_value(child, value, project, f);
+            }
+        }
+    }
 }
 
 /// This is the information tracked for every [`PlaceIndex`] and is stored by [`Map`].
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 5f135e96980..0c44bccbb4f 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -15,10 +15,11 @@ use rustc_middle::mir::visit::{
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::{def_id::DefId, Span, DUMMY_SP};
+use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi as CallAbi;
 
+use crate::dataflow_const_prop::Patch;
 use crate::MirPass;
 use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, ConstValue, FnArg, Frame, ImmTy,
@@ -32,32 +33,30 @@ const MAX_ALLOC_LIMIT: u64 = 1024;
 
 /// Macro for machine-specific `InterpError` without allocation.
 /// (These will never be shown to the user, but they help diagnose ICEs.)
-macro_rules! throw_machine_stop_str {
-    ($($tt:tt)*) => {{
-        // We make a new local type for it. The type itself does not carry any information,
-        // but its vtable (for the `MachineStopType` trait) does.
-        #[derive(Debug)]
-        struct Zst;
-        // Printing this type shows the desired string.
-        impl std::fmt::Display for Zst {
-            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                write!(f, $($tt)*)
-            }
+pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
+    // We make a new local type for it. The type itself does not carry any information,
+    // but its vtable (for the `MachineStopType` trait) does.
+    #[derive(Debug)]
+    struct Zst;
+    // Printing this type shows the desired string.
+    impl std::fmt::Display for Zst {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, $($tt)*)
         }
+    }
 
-        impl rustc_middle::mir::interpret::MachineStopType for Zst {
-            fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
-                self.to_string().into()
-            }
-
-            fn add_args(
-                self: Box<Self>,
-                _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>),
-            ) {}
+    impl rustc_middle::mir::interpret::MachineStopType for Zst {
+        fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
+            self.to_string().into()
         }
-        throw_machine_stop!(Zst)
-    }};
-}
+
+        fn add_args(
+            self: Box<Self>,
+            _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>),
+        ) {}
+    }
+    throw_machine_stop!(Zst)
+}}
 
 pub struct ConstProp;
 
@@ -85,9 +84,9 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
             return;
         }
 
-        let is_generator = tcx.type_of(def_id.to_def_id()).instantiate_identity().is_generator();
         // FIXME(welseywiser) const prop doesn't work on generators because of query cycles
         // computing their layout.
+        let is_generator = def_kind == DefKind::Generator;
         if is_generator {
             trace!("ConstProp skipped for generator {:?}", def_id);
             return;
@@ -95,33 +94,22 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
 
         trace!("ConstProp starting for {:?}", def_id);
 
-        let dummy_body = &Body::new(
-            body.source,
-            (*body.basic_blocks).to_owned(),
-            body.source_scopes.clone(),
-            body.local_decls.clone(),
-            Default::default(),
-            body.arg_count,
-            Default::default(),
-            body.span,
-            body.generator_kind(),
-            body.tainted_by_errors,
-        );
-
         // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
         // constants, instead of just checking for const-folding succeeding.
         // That would require a uniform one-def no-mutation analysis
         // and RPO (or recursing when needing the value of a local).
-        let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
+        let mut optimization_finder = ConstPropagator::new(body, tcx);
 
         // Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
         // assigned before being read.
-        let rpo = body.basic_blocks.reverse_postorder().to_vec();
-        for bb in rpo {
-            let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
+        for &bb in body.basic_blocks.reverse_postorder() {
+            let data = &body.basic_blocks[bb];
             optimization_finder.visit_basic_block_data(bb, data);
         }
 
+        let mut patch = optimization_finder.patch;
+        patch.visit_body_preserves_cfg(body);
+
         trace!("ConstProp done for {:?}", def_id);
     }
 }
@@ -145,8 +133,11 @@ impl ConstPropMachine<'_, '_> {
 
 impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
     compile_time_machine!(<'mir, 'tcx>);
+
     const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
 
+    const POST_MONO_CHECKS: bool = false; // this MIR is still generic!
+
     type MemoryKind = !;
 
     #[inline(always)]
@@ -301,6 +292,7 @@ struct ConstPropagator<'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     local_decls: &'mir IndexSlice<Local, LocalDecl<'tcx>>,
+    patch: Patch<'tcx>,
 }
 
 impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
@@ -334,11 +326,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
 }
 
 impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
-    fn new(
-        body: &Body<'tcx>,
-        dummy_body: &'mir Body<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ConstPropagator<'mir, 'tcx> {
+    fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
         let def_id = body.source.def_id();
         let args = &GenericArgs::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
@@ -369,7 +357,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
         ecx.push_stack_frame(
             Instance::new(def_id, args),
-            dummy_body,
+            body,
             &ret,
             StackPopCleanup::Root { cleanup: false },
         )
@@ -384,7 +372,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             ecx.frame_mut().locals[local].make_live_uninit();
         }
 
-        ConstPropagator { ecx, tcx, param_env, local_decls: &dummy_body.local_decls }
+        let patch = Patch::new(tcx);
+        ConstPropagator { ecx, tcx, param_env, local_decls: &body.local_decls, patch }
     }
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
@@ -421,12 +410,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         ecx.machine.written_only_inside_own_block_locals.remove(&local);
     }
 
-    fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
-        if let Some(place) = operand.place() && let Some(op) = self.replace_with_const(place) {
-            *operand = op;
-        }
-    }
-
     fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
         // Perform any special handling for specific Rvalue types.
         // Generally, checks here fall into one of two categories:
@@ -542,16 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    /// Creates a new `Operand::Constant` from a `Scalar` value
-    fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> Operand<'tcx> {
-        Operand::Constant(Box::new(Constant {
-            span: DUMMY_SP,
-            user_ty: None,
-            literal: ConstantKind::from_scalar(self.tcx, scalar, ty),
-        }))
-    }
-
-    fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Operand<'tcx>> {
+    fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<ConstantKind<'tcx>> {
         // This will return None if the above `const_prop` invocation only "wrote" a
         // type whose creation requires no write. E.g. a generator whose initial state
         // consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -567,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         let Right(imm) = imm else { return None };
         match *imm {
             Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
-                Some(self.operand_from_scalar(scalar, value.layout.ty))
+                Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty))
             }
             Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
                 let alloc = self
@@ -577,15 +551,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     })
                     .ok()?;
 
-                let literal = ConstantKind::Val(
+                Some(ConstantKind::Val(
                     ConstValue::ByRef { alloc, offset: Size::ZERO },
                     value.layout.ty,
-                );
-                Some(Operand::Constant(Box::new(Constant {
-                    span: DUMMY_SP,
-                    user_ty: None,
-                    literal,
-                })))
+                ))
             }
             // Scalars or scalar pairs that contain undef values are assumed to not have
             // successfully evaluated and are thus not propagated.
@@ -727,40 +696,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
+impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
+    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         self.super_operand(operand, location);
-        self.propagate_operand(operand)
+        if let Some(place) = operand.place() && let Some(value) = self.replace_with_const(place) {
+            self.patch.before_effect.insert((location, place), value);
+        }
     }
 
-    fn process_projection_elem(
+    fn visit_projection_elem(
         &mut self,
+        _: PlaceRef<'tcx>,
         elem: PlaceElem<'tcx>,
-        _: Location,
-    ) -> Option<PlaceElem<'tcx>> {
+        _: PlaceContext,
+        location: Location,
+    ) {
         if let PlaceElem::Index(local) = elem
-            && let Some(value) = self.get_const(local.into())
-            && let Some(imm) = value.as_mplace_or_imm().right()
-            && let Immediate::Scalar(scalar) = *imm
-            && let Ok(offset) = scalar.to_target_usize(&self.tcx)
-            && let Some(min_length) = offset.checked_add(1)
+            && let Some(value) = self.replace_with_const(local.into())
         {
-            Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
-        } else {
-            None
+            self.patch.before_effect.insert((location, local.into()), value);
         }
     }
 
-    fn visit_assign(
-        &mut self,
-        place: &mut Place<'tcx>,
-        rvalue: &mut Rvalue<'tcx>,
-        location: Location,
-    ) {
+    fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         self.super_assign(place, rvalue, location);
 
         let Some(()) = self.check_rvalue(rvalue) else { return };
@@ -777,7 +735,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
                     {
                         trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
                     } else if let Some(operand) = self.replace_with_const(*place) {
-                        *rvalue = Rvalue::Use(operand);
+                        self.patch.assignments.insert(location, operand);
                     }
                 } else {
                     // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -801,7 +759,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
         }
     }
 
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         trace!("visit_statement: {:?}", statement);
 
         // We want to evaluate operands before any change to the assigned-to value,
@@ -845,7 +803,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
         }
     }
 
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
+    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
         self.super_basic_block_data(block, data);
 
         // We remove all Locals which are restricted in propagation to their containing blocks and
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 333a14be996..c7c5f17dfec 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -3,17 +3,19 @@
 //! Currently, this pass only propagates scalar values.
 
 use rustc_const_eval::const_eval::CheckAlignment;
-use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
+use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
-use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ConstValue, InterpResult, Scalar};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
-    Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
+    Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
 };
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
+use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Align, FieldIdx, VariantIdx};
 
@@ -58,13 +60,10 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
             .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
 
         // Collect results and patch the body afterwards.
-        let mut visitor = CollectAndPatch::new(tcx, &body.local_decls);
+        let mut visitor = Collector::new(tcx, &body.local_decls);
         debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
-        debug_span!("patch").in_scope(|| {
-            for (block, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
-                visitor.visit_basic_block_data(block, bbdata);
-            }
-        })
+        let mut patch = visitor.patch;
+        debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
     }
 }
 
@@ -77,7 +76,7 @@ struct ConstAnalysis<'a, 'tcx> {
 }
 
 impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
-    type Value = FlatSet<ScalarInt>;
+    type Value = FlatSet<Scalar>;
 
     const NAME: &'static str = "ConstAnalysis";
 
@@ -111,6 +110,18 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         state: &mut State<Self::Value>,
     ) {
         match rvalue {
+            Rvalue::Use(operand) => {
+                state.flood(target.as_ref(), self.map());
+                if let Some(target) = self.map.find(target.as_ref()) {
+                    self.assign_operand(state, target, operand);
+                }
+            }
+            Rvalue::CopyForDeref(rhs) => {
+                state.flood(target.as_ref(), self.map());
+                if let Some(target) = self.map.find(target.as_ref()) {
+                    self.assign_operand(state, target, &Operand::Copy(*rhs));
+                }
+            }
             Rvalue::Aggregate(kind, operands) => {
                 // If we assign `target = Enum::Variant#0(operand)`,
                 // we must make sure that all `target as Variant#i` are `Top`.
@@ -138,8 +149,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                             variant_target_idx,
                             TrackElem::Field(FieldIdx::from_usize(field_index)),
                         ) {
-                            let result = self.handle_operand(operand, state);
-                            state.insert_idx(field, result, self.map());
+                            self.assign_operand(state, field, operand);
                         }
                     }
                 }
@@ -176,7 +186,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     if let Some(overflow_target) = overflow_target {
                         let overflow = match overflow {
                             FlatSet::Top => FlatSet::Top,
-                            FlatSet::Elem(overflow) => FlatSet::Elem(overflow.into()),
+                            FlatSet::Elem(overflow) => FlatSet::Elem(Scalar::from_bool(overflow)),
                             FlatSet::Bottom => FlatSet::Bottom,
                         };
                         // We have flooded `target` earlier.
@@ -196,9 +206,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     && let operand_ty = operand.ty(self.local_decls, self.tcx)
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
                     && let ty::Array(_, len) = operand_ty.ty.kind()
-                    && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int()
+                    && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
                 {
-                    state.insert_value_idx(target_len, FlatSet::Elem(len), self.map());
+                    state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
                 }
             }
             _ => self.super_assign(target, rvalue, state),
@@ -215,8 +225,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 let place_ty = place.ty(self.local_decls, self.tcx);
                 if let ty::Array(_, len) = place_ty.ty.kind() {
                     ConstantKind::Ty(*len)
-                        .eval(self.tcx, self.param_env)
-                        .try_to_scalar_int()
+                        .try_eval_scalar(self.tcx, self.param_env)
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
                     state.get_len(place.local.into(), self.map())
@@ -257,9 +266,10 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 val
             }
             Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
-                FlatSet::Elem(value) => {
-                    self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val))
-                }
+                FlatSet::Elem(value) => self
+                    .ecx
+                    .unary_op(*op, &value)
+                    .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
                 FlatSet::Bottom => FlatSet::Bottom,
                 FlatSet::Top => FlatSet::Top,
             },
@@ -275,7 +285,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                         .bytes(),
                     _ => return ValueOrPlace::Value(FlatSet::Top),
                 };
-                ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
+                FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx))
             }
             Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
             _ => return self.super_rvalue(rvalue, state),
@@ -290,8 +300,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
     ) -> Self::Value {
         constant
             .literal
-            .eval(self.tcx, self.param_env)
-            .try_to_scalar_int()
+            .try_eval_scalar(self.tcx, self.param_env)
             .map_or(FlatSet::Top, FlatSet::Elem)
     }
 
@@ -330,13 +339,98 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         }
     }
 
+    /// The caller must have flooded `place`.
+    fn assign_operand(
+        &self,
+        state: &mut State<FlatSet<Scalar>>,
+        place: PlaceIndex,
+        operand: &Operand<'tcx>,
+    ) {
+        match operand {
+            Operand::Copy(rhs) | Operand::Move(rhs) => {
+                if let Some(rhs) = self.map.find(rhs.as_ref()) {
+                    state.insert_place_idx(place, rhs, &self.map);
+                } else if rhs.projection.first() == Some(&PlaceElem::Deref)
+                    && let FlatSet::Elem(pointer) = state.get(rhs.local.into(), &self.map)
+                    && let rhs_ty = self.local_decls[rhs.local].ty
+                    && let Ok(rhs_layout) = self.tcx.layout_of(self.param_env.and(rhs_ty))
+                {
+                    let op = ImmTy::from_scalar(pointer, rhs_layout).into();
+                    self.assign_constant(state, place, op, &rhs.projection);
+                }
+            }
+            Operand::Constant(box constant) => {
+                if let Ok(constant) = self.ecx.eval_mir_constant(&constant.literal, None, None) {
+                    self.assign_constant(state, place, constant, &[]);
+                }
+            }
+        }
+    }
+
+    /// The caller must have flooded `place`.
+    ///
+    /// Perform: `place = operand.projection`.
+    #[instrument(level = "trace", skip(self, state))]
+    fn assign_constant(
+        &self,
+        state: &mut State<FlatSet<Scalar>>,
+        place: PlaceIndex,
+        mut operand: OpTy<'tcx>,
+        projection: &[PlaceElem<'tcx>],
+    ) -> Option<!> {
+        for &(mut proj_elem) in projection {
+            if let PlaceElem::Index(index) = proj_elem {
+                if let FlatSet::Elem(index) = state.get(index.into(), &self.map)
+                    && let Ok(offset) = index.to_target_usize(&self.tcx)
+                    && let Some(min_length) = offset.checked_add(1)
+                {
+                    proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false };
+                } else {
+                    return None;
+                }
+            }
+            operand = self.ecx.project(&operand, proj_elem).ok()?;
+        }
+
+        self.map.for_each_projection_value(
+            place,
+            operand,
+            &mut |elem, op| match elem {
+                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
+                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
+                TrackElem::Discriminant => {
+                    let variant = self.ecx.read_discriminant(op).ok()?;
+                    let discr_value = self.ecx.discriminant_for_variant(op.layout, variant).ok()?;
+                    Some(discr_value.into())
+                }
+                TrackElem::DerefLen => {
+                    let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into();
+                    let len_usize = op.len(&self.ecx).ok()?;
+                    let layout =
+                        self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap();
+                    Some(ImmTy::from_uint(len_usize, layout).into())
+                }
+            },
+            &mut |place, op| {
+                if let Ok(imm) = self.ecx.read_immediate_raw(op)
+                    && let Some(imm) = imm.right()
+                {
+                    let elem = self.wrap_immediate(*imm);
+                    state.insert_value_idx(place, elem, &self.map);
+                }
+            },
+        );
+
+        None
+    }
+
     fn binary_op(
         &self,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
         op: BinOp,
         left: &Operand<'tcx>,
         right: &Operand<'tcx>,
-    ) -> (FlatSet<ScalarInt>, FlatSet<bool>) {
+    ) -> (FlatSet<Scalar>, FlatSet<bool>) {
         let left = self.eval_operand(left, state);
         let right = self.eval_operand(right, state);
 
@@ -345,9 +439,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             // Both sides are known, do the actual computation.
             (FlatSet::Elem(left), FlatSet::Elem(right)) => {
                 match self.ecx.overflowing_binary_op(op, &left, &right) {
-                    Ok((Scalar::Int(val), overflow, _)) => {
-                        (FlatSet::Elem(val), FlatSet::Elem(overflow))
-                    }
+                    Ok((val, overflow, _)) => (FlatSet::Elem(val), FlatSet::Elem(overflow)),
                     _ => (FlatSet::Top, FlatSet::Top),
                 }
             }
@@ -359,9 +451,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
 
                 let arg_scalar = const_arg.to_scalar();
-                let Ok(arg_scalar) = arg_scalar.try_to_int() else {
-                    return (FlatSet::Top, FlatSet::Top);
-                };
                 let Ok(arg_value) = arg_scalar.to_bits(layout.size) else {
                     return (FlatSet::Top, FlatSet::Top);
                 };
@@ -387,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     fn eval_operand(
         &self,
         op: &Operand<'tcx>,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
     ) -> FlatSet<ImmTy<'tcx>> {
         let value = match self.handle_operand(op, state) {
             ValueOrPlace::Value(value) => value,
@@ -397,74 +486,83 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             FlatSet::Top => FlatSet::Top,
             FlatSet::Elem(scalar) => {
                 let ty = op.ty(self.local_decls, self.tcx);
-                self.tcx
-                    .layout_of(self.param_env.and(ty))
-                    .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout)))
-                    .unwrap_or(FlatSet::Top)
+                self.tcx.layout_of(self.param_env.and(ty)).map_or(FlatSet::Top, |layout| {
+                    FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout))
+                })
             }
             FlatSet::Bottom => FlatSet::Bottom,
         }
     }
 
-    fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<ScalarInt> {
+    fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<Scalar> {
         if !enum_ty.is_enum() {
             return None;
         }
-        let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
-        let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
-        let discr_value = ScalarInt::try_from_uint(discr.val, discr_layout.size)?;
-        Some(discr_value)
+        let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?;
+        let discr_value = self.ecx.discriminant_for_variant(enum_ty_layout, variant_index).ok()?;
+        Some(discr_value.to_scalar())
     }
 
-    fn wrap_immediate(&self, imm: Immediate) -> FlatSet<ScalarInt> {
+    fn wrap_immediate(&self, imm: Immediate) -> FlatSet<Scalar> {
         match imm {
-            Immediate::Scalar(Scalar::Int(scalar)) => FlatSet::Elem(scalar),
+            Immediate::Scalar(scalar) => FlatSet::Elem(scalar),
+            Immediate::Uninit => FlatSet::Bottom,
             _ => FlatSet::Top,
         }
     }
-
-    fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarInt> {
-        self.wrap_immediate(*val)
-    }
 }
 
-struct CollectAndPatch<'tcx, 'locals> {
+pub(crate) struct Patch<'tcx> {
     tcx: TyCtxt<'tcx>,
-    local_decls: &'locals LocalDecls<'tcx>,
 
     /// For a given MIR location, this stores the values of the operands used by that location. In
     /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
     /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
-    before_effect: FxHashMap<(Location, Place<'tcx>), ScalarInt>,
+    pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>,
 
     /// Stores the assigned values for assignments where the Rvalue is constant.
-    assignments: FxHashMap<Location, ScalarInt>,
+    pub(crate) assignments: FxHashMap<Location, ConstantKind<'tcx>>,
 }
 
-impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> {
-    fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
-        Self {
-            tcx,
-            local_decls,
-            before_effect: FxHashMap::default(),
-            assignments: FxHashMap::default(),
-        }
+impl<'tcx> Patch<'tcx> {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
+    }
+
+    fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
+        Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal }))
+    }
+}
+
+struct Collector<'tcx, 'locals> {
+    patch: Patch<'tcx>,
+    local_decls: &'locals LocalDecls<'tcx>,
+}
+
+impl<'tcx, 'locals> Collector<'tcx, 'locals> {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
+        Self { patch: Patch::new(tcx), local_decls }
     }
 
-    fn make_operand(&self, scalar: ScalarInt, ty: Ty<'tcx>) -> Operand<'tcx> {
-        Operand::Constant(Box::new(Constant {
-            span: DUMMY_SP,
-            user_ty: None,
-            literal: ConstantKind::Val(ConstValue::Scalar(scalar.into()), ty),
-        }))
+    fn try_make_constant(
+        &self,
+        place: Place<'tcx>,
+        state: &State<FlatSet<Scalar>>,
+        map: &Map,
+    ) -> Option<ConstantKind<'tcx>> {
+        let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
+            return None;
+        };
+        let ty = place.ty(self.local_decls, self.patch.tcx).ty;
+        Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty))
     }
 }
 
 impl<'mir, 'tcx>
     ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
-    for CollectAndPatch<'tcx, '_>
+    for Collector<'tcx, '_>
 {
-    type FlowState = State<FlatSet<ScalarInt>>;
+    type FlowState = State<FlatSet<Scalar>>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
@@ -494,14 +592,8 @@ impl<'mir, 'tcx>
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
             StatementKind::Assign(box (place, _)) => {
-                match state.get(place.as_ref(), &results.analysis.0.map) {
-                    FlatSet::Top => (),
-                    FlatSet::Elem(value) => {
-                        self.assignments.insert(location, value);
-                    }
-                    FlatSet::Bottom => {
-                        // This assignment is either unreachable, or an uninitialized value is assigned.
-                    }
+                if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) {
+                    self.patch.assignments.insert(location, value);
                 }
             }
             _ => (),
@@ -520,7 +612,7 @@ impl<'mir, 'tcx>
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
+impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -529,8 +621,7 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
         if let Some(value) = self.assignments.get(&location) {
             match &mut statement.kind {
                 StatementKind::Assign(box (_, rvalue)) => {
-                    let ty = rvalue.ty(self.local_decls, self.tcx);
-                    *rvalue = Rvalue::Use(self.make_operand(*value, ty));
+                    *rvalue = Rvalue::Use(self.make_operand(*value));
                 }
                 _ => bug!("found assignment info for non-assign statement"),
             }
@@ -543,8 +634,7 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
         match operand {
             Operand::Copy(place) | Operand::Move(place) => {
                 if let Some(value) = self.before_effect.get(&(location, *place)) {
-                    let ty = place.ty(self.local_decls, self.tcx).ty;
-                    *operand = self.make_operand(*value, ty);
+                    *operand = self.make_operand(*value);
                 } else if !place.projection.is_empty() {
                     self.super_operand(operand, location)
                 }
@@ -558,11 +648,11 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
         elem: PlaceElem<'tcx>,
         location: Location,
     ) -> Option<PlaceElem<'tcx>> {
-        if let PlaceElem::Index(local) = elem
-            && let Some(value) = self.before_effect.get(&(location, local.into()))
-            && let Ok(offset) = value.try_to_target_usize(self.tcx)
-            && let Some(min_length) = offset.checked_add(1)
-        {
+        if let PlaceElem::Index(local) = elem {
+            let offset = self.before_effect.get(&(location, local.into()))?;
+            let offset = offset.try_to_scalar()?;
+            let offset = offset.to_target_usize(&self.tcx).ok()?;
+            let min_length = offset.checked_add(1)?;
             Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
         } else {
             None
@@ -571,30 +661,36 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
 }
 
 struct OperandCollector<'tcx, 'map, 'locals, 'a> {
-    state: &'a State<FlatSet<ScalarInt>>,
-    visitor: &'a mut CollectAndPatch<'tcx, 'locals>,
+    state: &'a State<FlatSet<Scalar>>,
+    visitor: &'a mut Collector<'tcx, 'locals>,
     map: &'map Map,
 }
 
 impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
+    fn visit_projection_elem(
+        &mut self,
+        _: PlaceRef<'tcx>,
+        elem: PlaceElem<'tcx>,
+        _: PlaceContext,
+        location: Location,
+    ) {
+        if let PlaceElem::Index(local) = elem
+            && let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
+        {
+            self.visitor.patch.before_effect.insert((location, local.into()), value);
+        }
+    }
+
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         if let Some(place) = operand.place() {
-            if let FlatSet::Elem(value) = self.state.get(place.as_ref(), self.map) {
-                self.visitor.before_effect.insert((location, place), value);
+            if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) {
+                self.visitor.patch.before_effect.insert((location, place), value);
             } else if !place.projection.is_empty() {
                 // Try to propagate into `Index` projections.
                 self.super_operand(operand, location)
             }
         }
     }
-
-    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) {
-        if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt
-            && let FlatSet::Elem(value) = self.state.get(local.into(), self.map)
-        {
-            self.visitor.before_effect.insert((location, local.into()), value);
-        }
-    }
 }
 
 struct DummyMachine;
@@ -604,8 +700,11 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
     type MemoryKind = !;
     const PANIC_ON_ALLOC_FAIL: bool = true;
 
+    #[inline(always)]
     fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
-        unimplemented!()
+        // We do not check for alignment to avoid having to carry an `Align`
+        // in `ConstValue::ByRef`.
+        CheckAlignment::No
     }
 
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
@@ -620,6 +719,27 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         unimplemented!()
     }
 
+    fn before_access_global(
+        _tcx: TyCtxt<'tcx>,
+        _machine: &Self,
+        _alloc_id: AllocId,
+        alloc: ConstAllocation<'tcx>,
+        _static_def_id: Option<DefId>,
+        is_write: bool,
+    ) -> InterpResult<'tcx> {
+        if is_write {
+            crate::const_prop::throw_machine_stop_str!("can't write to global");
+        }
+
+        // If the static allocation is mutable, then we can't const prop it as its content
+        // might be different at runtime.
+        if alloc.inner().mutability.is_mut() {
+            crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp");
+        }
+
+        Ok(())
+    }
+
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
@@ -688,7 +808,8 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         _ecx: &'a InterpCx<'mir, 'tcx, Self>,
     ) -> &'a [rustc_const_eval::interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>]
     {
-        unimplemented!()
+        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
+        &[]
     }
 
     fn stack_mut<'a>(
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 8b0a0903d18..6e191b285be 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -136,7 +136,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
                     return;
                 }
 
-                let literal = ConstantKind::from_const(len, self.tcx);
+                let literal = ConstantKind::from_ty_const(len, self.tcx);
                 let constant = Constant { span: source_info.span, literal, user_ty: None };
                 *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
             }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index bf798adee19..70d4ea74d1a 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -2,6 +2,7 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(box_patterns)]
+#![feature(decl_macro)]
 #![feature(is_sorted)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
@@ -605,6 +606,11 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
     let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
     let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
     debug!("body: {:#?}", body);
+
+    if body.tainted_by_errors.is_some() {
+        return body;
+    }
+
     run_optimization_passes(tcx, &mut body);
 
     body
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 6c3b7c58fab..1b846987d38 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -93,7 +93,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
             *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
                 span: rustc_span::DUMMY_SP,
                 user_ty: None,
-                literal: ConstantKind::from_const(len, self.tcx),
+                literal: ConstantKind::from_ty_const(len, self.tcx),
             })));
         }
         self.super_rvalue(rvalue, loc);
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 057f5fe8293..5abb2f3d041 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -94,6 +94,8 @@ fn run_passes_inner<'tcx>(
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
+    let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));
+
     if !body.should_skip() {
         for pass in passes {
             let name = pass.name();
@@ -121,7 +123,14 @@ fn run_passes_inner<'tcx>(
                 validate_body(tcx, body, format!("before pass {name}"));
             }
 
-            tcx.sess.time(name, || pass.run_pass(tcx, body));
+            if let Some(prof_arg) = &prof_arg {
+                tcx.sess
+                    .prof
+                    .generic_activity_with_arg(pass.profiler_name(), &**prof_arg)
+                    .run(|| pass.run_pass(tcx, body));
+            } else {
+                pass.run_pass(tcx, body);
+            }
 
             if dump_enabled {
                 dump_mir_for_pass(tcx, body, &name, true);
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 4aadb7d7ca5..3e4e9278910 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -830,7 +830,8 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
 
-        if !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
+        if self.may_recover()
+            && !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
             && self.check_noexpect(&token::Lt)
             && self.look_ahead(1, |t| t.can_begin_type())
         {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 9f3cd656bd1..56f4b387df8 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -104,15 +104,24 @@ passes_collapse_debuginfo =
 passes_confusables = attribute should be applied to an inherent method
     .label = not an inherent method
 
-passes_const_impl_const_trait =
-    const `impl`s must be for traits marked with `#[const_trait]`
-    .note = this trait must be annotated with `#[const_trait]`
-
 passes_continue_labeled_block =
     `continue` pointing to a labeled block
     .label = labeled blocks cannot be `continue`'d
     .block_label = labeled block the `continue` points to
 
+passes_coverage_fn_defn =
+    `#[coverage]` may only be applied to function definitions
+
+passes_coverage_ignored_function_prototype =
+    `#[coverage]` is ignored on function prototypes
+
+passes_coverage_not_coverable =
+    `#[coverage]` must be applied to coverable code
+    .label = not coverable code
+
+passes_coverage_propagate =
+    `#[coverage]` does not propagate into items and must be applied to the contained functions directly
+
 passes_dead_codes =
     { $multiple ->
       *[true] multiple {$descr}s are
@@ -503,19 +512,6 @@ passes_naked_functions_operands =
 passes_naked_tracked_caller =
     cannot use `#[track_caller]` with `#[naked]`
 
-passes_no_coverage_fn_defn =
-    `#[no_coverage]` may only be applied to function definitions
-
-passes_no_coverage_ignored_function_prototype =
-    `#[no_coverage]` is ignored on function prototypes
-
-passes_no_coverage_not_coverable =
-    `#[no_coverage]` must be applied to coverable code
-    .label = not coverable code
-
-passes_no_coverage_propagate =
-    `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
-
 passes_no_link =
     attribute should be applied to an `extern crate` item
     .label = not an `extern crate` item
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index 7e781bdd6f4..9e4d960af14 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -1,12 +1,13 @@
 use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::layout::{FnAbiError, LayoutError};
 use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_target::abi::call::FnAbi;
 
+use super::layout_test::ensure_wf;
 use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField};
 
 pub fn test_abi(tcx: TyCtxt<'_>) {
@@ -14,32 +15,17 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
         // if the `rustc_attrs` feature is not enabled, don't bother testing ABI
         return;
     }
-    for id in tcx.hir().items() {
-        for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
-            match tcx.def_kind(id.owner_id) {
-                DefKind::Fn => {
-                    dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr);
+    for id in tcx.hir_crate_items(()).definitions() {
+        for attr in tcx.get_attrs(id, sym::rustc_abi) {
+            match tcx.def_kind(id) {
+                DefKind::Fn | DefKind::AssocFn => {
+                    dump_abi_of_fn_item(tcx, id, attr);
                 }
                 DefKind::TyAlias { .. } => {
-                    dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr);
+                    dump_abi_of_fn_type(tcx, id, attr);
                 }
                 _ => {
-                    tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id.owner_id) });
-                }
-            }
-        }
-        if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
-            // To find associated functions we need to go into the child items here.
-            for &id in tcx.associated_item_def_ids(id.owner_id) {
-                for attr in tcx.get_attrs(id, sym::rustc_abi) {
-                    match tcx.def_kind(id) {
-                        DefKind::AssocFn => {
-                            dump_abi_of_fn_item(tcx, id, attr);
-                        }
-                        _ => {
-                            tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
-                        }
-                    }
+                    tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
                 }
             }
         }
@@ -49,7 +35,7 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
 fn unwrap_fn_abi<'tcx>(
     abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>,
     tcx: TyCtxt<'tcx>,
-    item_def_id: DefId,
+    item_def_id: LocalDefId,
 ) -> &'tcx FnAbi<'tcx, Ty<'tcx>> {
     match abi {
         Ok(abi) => abi,
@@ -71,10 +57,10 @@ fn unwrap_fn_abi<'tcx>(
     }
 }
 
-fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
+fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let args = GenericArgs::identity_for_item(tcx, item_def_id);
-    let instance = match Instance::resolve(tcx, param_env, item_def_id, args) {
+    let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) {
         Ok(Some(instance)) => instance,
         Ok(None) => {
             // Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
@@ -99,10 +85,11 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
     for meta_item in meta_items {
         match meta_item.name_or_empty() {
             sym::debug => {
-                let fn_name = tcx.item_name(item_def_id);
+                let fn_name = tcx.item_name(item_def_id.into());
                 tcx.sess.emit_err(AbiOf {
                     span: tcx.def_span(item_def_id),
                     fn_name,
+                    // FIXME: using the `Debug` impl here isn't ideal.
                     fn_abi: format!("{:#?}", abi),
                 });
             }
@@ -128,9 +115,13 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx,
         && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2))
 }
 
-fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
+fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
+    let span = tcx.def_span(item_def_id);
+    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+        return;
+    }
     let meta_items = attr.meta_item_list().unwrap_or_default();
     for meta_item in meta_items {
         match meta_item.name_or_empty() {
@@ -147,12 +138,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
                     item_def_id,
                 );
 
-                let fn_name = tcx.item_name(item_def_id);
-                tcx.sess.emit_err(AbiOf {
-                    span: tcx.def_span(item_def_id),
-                    fn_name,
-                    fn_abi: format!("{:#?}", abi),
-                });
+                let fn_name = tcx.item_name(item_def_id.into());
+                tcx.sess.emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
             }
             sym::assert_eq => {
                 let ty::Tuple(fields) = ty.kind() else {
@@ -196,7 +183,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
 
                 if !test_abi_eq(abi1, abi2) {
                     tcx.sess.emit_err(AbiNe {
-                        span: tcx.def_span(item_def_id),
+                        span,
                         left: format!("{:#?}", abi1),
                         right: format!("{:#?}", abi2),
                     });
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 50a087c7847..879d1dd680c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -107,7 +107,7 @@ impl CheckAttrVisitor<'_> {
             match attr.name_or_empty() {
                 sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
                 sym::inline => self.check_inline(hir_id, attr, span, target),
-                sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
+                sym::coverage => self.check_coverage(hir_id, attr, span, target),
                 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
                 sym::marker => self.check_marker(hir_id, attr, span, target),
                 sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
@@ -327,16 +327,10 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
-    /// Checks if a `#[no_coverage]` is applied directly to a function
-    fn check_no_coverage(
-        &self,
-        hir_id: HirId,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    /// Checks if a `#[coverage]` is applied directly to a function
+    fn check_coverage(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
         match target {
-            // no_coverage on function is fine
+            // #[coverage] on function is fine
             Target::Fn
             | Target::Closure
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
@@ -347,7 +341,7 @@ impl CheckAttrVisitor<'_> {
                     UNUSED_ATTRIBUTES,
                     hir_id,
                     attr.span,
-                    errors::IgnoredNoCoverageFnProto,
+                    errors::IgnoredCoverageFnProto,
                 );
                 true
             }
@@ -357,7 +351,7 @@ impl CheckAttrVisitor<'_> {
                     UNUSED_ATTRIBUTES,
                     hir_id,
                     attr.span,
-                    errors::IgnoredNoCoveragePropagate,
+                    errors::IgnoredCoveragePropagate,
                 );
                 true
             }
@@ -367,13 +361,13 @@ impl CheckAttrVisitor<'_> {
                     UNUSED_ATTRIBUTES,
                     hir_id,
                     attr.span,
-                    errors::IgnoredNoCoverageFnDefn,
+                    errors::IgnoredCoverageFnDefn,
                 );
                 true
             }
 
             _ => {
-                self.tcx.sess.emit_err(errors::IgnoredNoCoverageNotCoverable {
+                self.tcx.sess.emit_err(errors::IgnoredCoverageNotCoverable {
                     attr_span: attr.span,
                     defn_span: span,
                 });
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index d7319ef91e0..8b65e301b74 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -64,20 +64,20 @@ pub struct InlineNotFnOrClosure {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes_no_coverage_ignored_function_prototype)]
-pub struct IgnoredNoCoverageFnProto;
+#[diag(passes_coverage_ignored_function_prototype)]
+pub struct IgnoredCoverageFnProto;
 
 #[derive(LintDiagnostic)]
-#[diag(passes_no_coverage_propagate)]
-pub struct IgnoredNoCoveragePropagate;
+#[diag(passes_coverage_propagate)]
+pub struct IgnoredCoveragePropagate;
 
 #[derive(LintDiagnostic)]
-#[diag(passes_no_coverage_fn_defn)]
-pub struct IgnoredNoCoverageFnDefn;
+#[diag(passes_coverage_fn_defn)]
+pub struct IgnoredCoverageFnDefn;
 
 #[derive(Diagnostic)]
-#[diag(passes_no_coverage_not_coverable, code = "E0788")]
-pub struct IgnoredNoCoverageNotCoverable {
+#[diag(passes_coverage_not_coverable, code = "E0788")]
+pub struct IgnoredCoverageNotCoverable {
     #[primary_span]
     pub attr_span: Span,
     #[label]
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index f3c12e0746d..e3a63f2e004 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -2,11 +2,13 @@ use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::{infer::TyCtxtInferExt, traits};
 
 use crate::errors::{
     LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
@@ -18,21 +20,13 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         return;
     }
-    for id in tcx.hir().items() {
-        for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
-            match tcx.def_kind(id.owner_id) {
+    for id in tcx.hir_crate_items(()).definitions() {
+        for attr in tcx.get_attrs(id, sym::rustc_layout) {
+            match tcx.def_kind(id) {
                 DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union => {
-                    dump_layout_of(tcx, id.owner_id.def_id, attr);
+                    dump_layout_of(tcx, id, attr);
                 }
                 _ => {
-                    tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id.owner_id) });
-                }
-            }
-        }
-        if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
-            // To find associated functions we need to go into the child items here.
-            for &id in tcx.associated_item_def_ids(id.owner_id) {
-                for _attr in tcx.get_attrs(id, sym::rustc_layout) {
                     tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) });
                 }
             }
@@ -40,9 +34,44 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
     }
 }
 
+pub fn ensure_wf<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    def_id: LocalDefId,
+    span: Span,
+) -> bool {
+    let pred = ty::ClauseKind::WellFormed(ty.into());
+    let obligation = traits::Obligation::new(
+        tcx,
+        traits::ObligationCause::new(
+            span,
+            def_id,
+            traits::ObligationCauseCode::WellFormed(Some(traits::WellFormedLoc::Ty(def_id))),
+        ),
+        param_env,
+        pred,
+    );
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = traits::ObligationCtxt::new(&infcx);
+    ocx.register_obligation(obligation);
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors);
+        false
+    } else {
+        // looks WF!
+        true
+    }
+}
+
 fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
+    let span = tcx.def_span(item_def_id.to_def_id());
+    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+        return;
+    }
     match tcx.layout_of(param_env.and(ty)) {
         Ok(ty_layout) => {
             // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
@@ -51,29 +80,24 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
             for meta_item in meta_items {
                 match meta_item.name_or_empty() {
                     sym::abi => {
-                        tcx.sess.emit_err(LayoutAbi {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            abi: format!("{:?}", ty_layout.abi),
-                        });
+                        tcx.sess.emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) });
                     }
 
                     sym::align => {
                         tcx.sess.emit_err(LayoutAlign {
-                            span: tcx.def_span(item_def_id.to_def_id()),
+                            span,
                             align: format!("{:?}", ty_layout.align),
                         });
                     }
 
                     sym::size => {
-                        tcx.sess.emit_err(LayoutSize {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            size: format!("{:?}", ty_layout.size),
-                        });
+                        tcx.sess
+                            .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
                     }
 
                     sym::homogeneous_aggregate => {
                         tcx.sess.emit_err(LayoutHomogeneousAggregate {
-                            span: tcx.def_span(item_def_id.to_def_id()),
+                            span,
                             homogeneous_aggregate: format!(
                                 "{:?}",
                                 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
@@ -83,18 +107,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
 
                     sym::debug => {
                         let normalized_ty = format!(
-                            "{:?}",
+                            "{}",
                             tcx.normalize_erasing_regions(
                                 param_env.with_reveal_all_normalized(tcx),
                                 ty,
                             )
                         );
+                        // FIXME: using the `Debug` impl here isn't ideal.
                         let ty_layout = format!("{:#?}", *ty_layout);
-                        tcx.sess.emit_err(LayoutOf {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            normalized_ty,
-                            ty_layout,
-                        });
+                        tcx.sess.emit_err(LayoutOf { span, normalized_ty, ty_layout });
                     }
 
                     name => {
@@ -105,11 +126,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
         }
 
         Err(layout_error) => {
-            tcx.sess.emit_fatal(Spanned {
-                node: layout_error.into_diagnostic(),
-
-                span: tcx.def_span(item_def_id.to_def_id()),
-            });
+            tcx.sess.emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index e62833b358b..1239d6d91ac 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -90,6 +90,10 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
                 .typeck_results()
                 .type_dependent_def(expr.hir_id)
                 .map(|(kind, def_id)| Res::Def(kind, def_id)),
+            hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
+                self.reachable_symbols.insert(def_id);
+                None
+            }
             _ => None,
         };
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index aedc7b22725..1c2303ae9e0 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -836,7 +836,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
                         self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
                     }
                 }
-                GenericParamDefKind::Const { has_default } => {
+                GenericParamDefKind::Const { has_default, .. } => {
                     self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
                     if has_default {
                         self.visit(
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index a30ea7c1ddc..f2fdf066d15 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -348,8 +348,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
     Q: super::QueryConfigRestored<'tcx>,
     Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
 {
-    let _timer =
-        qcx.profiler().verbose_generic_activity_with_arg("encode_query_results_for", query.name());
+    let _timer = qcx.profiler().generic_activity_with_arg("encode_query_results_for", query.name());
 
     assert!(query.query_state(qcx).all_inactive());
     let cache = query.query_cache(qcx);
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 7b7981e1425..fa54e1a2e6a 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -629,12 +629,7 @@ impl<K: DepKind> DepGraphData<K> {
         if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
             self.current.prev_index_to_index.lock()[prev_index]
         } else {
-            self.current
-                .new_node_to_index
-                .get_shard_by_value(dep_node)
-                .lock()
-                .get(dep_node)
-                .copied()
+            self.current.new_node_to_index.lock_shard_by_value(dep_node).get(dep_node).copied()
         }
     }
 
@@ -1201,8 +1196,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
         edges: EdgesVec,
         current_fingerprint: Fingerprint,
     ) -> DepNodeIndex {
-        let dep_node_index = match self.new_node_to_index.get_shard_by_value(&key).lock().entry(key)
-        {
+        let dep_node_index = match self.new_node_to_index.lock_shard_by_value(&key).entry(key) {
             Entry::Occupied(entry) => *entry.get(),
             Entry::Vacant(entry) => {
                 let dep_node_index =
@@ -1328,7 +1322,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     ) {
         let node = &prev_graph.index_to_node(prev_index);
         debug_assert!(
-            !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node),
+            !self.new_node_to_index.lock_shard_by_value(node).contains_key(node),
             "node from previous graph present in new node collection"
         );
     }
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index d8aa377af42..0240f012da0 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -55,7 +55,7 @@ where
     #[inline(always)]
     fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
         let key_hash = sharded::make_hash(key);
-        let lock = self.cache.get_shard_by_hash(key_hash).lock();
+        let lock = self.cache.lock_shard_by_hash(key_hash);
         let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
 
         if let Some((_, value)) = result { Some(*value) } else { None }
@@ -63,7 +63,7 @@ where
 
     #[inline]
     fn complete(&self, key: K, value: V, index: DepNodeIndex) {
-        let mut lock = self.cache.get_shard_by_value(&key).lock();
+        let mut lock = self.cache.lock_shard_by_value(&key);
         // We may be overwriting another value. This is all right, since the dep-graph
         // will check that the fingerprint matches.
         lock.insert(key, (value, index));
@@ -148,13 +148,13 @@ where
 
     #[inline(always)]
     fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
-        let lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
+        let lock = self.cache.lock_shard_by_hash(key.index() as u64);
         if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None }
     }
 
     #[inline]
     fn complete(&self, key: K, value: V, index: DepNodeIndex) {
-        let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
+        let mut lock = self.cache.lock_shard_by_hash(key.index() as u64);
         lock.insert(key, (value, index));
     }
 
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 9cba549a3b5..6c01dc3c00d 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -552,7 +552,9 @@ pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Regis
     // which in turn will wait on X causing a deadlock. We have a false dependency from
     // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
     // only considers the true dependency and won't detect a cycle.
-    assert!(found_cycle);
+    if !found_cycle {
+        panic!("deadlock detected");
+    }
 
     // FIXME: Ensure this won't cause a deadlock before we return
     for waiter in wakelist.into_iter() {
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 4fa168965a7..07db15e6d8b 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -158,7 +158,7 @@ where
         cache.complete(key, result, dep_node_index);
 
         let job = {
-            let mut lock = state.active.get_shard_by_value(&key).lock();
+            let mut lock = state.active.lock_shard_by_value(&key);
             match lock.remove(&key).unwrap() {
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
@@ -180,7 +180,7 @@ where
         // Poison the query so jobs waiting on it panic.
         let state = self.state;
         let job = {
-            let mut shard = state.active.get_shard_by_value(&self.key).lock();
+            let mut shard = state.active.lock_shard_by_value(&self.key);
             let job = match shard.remove(&self.key).unwrap() {
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
@@ -303,7 +303,7 @@ where
     Qcx: QueryContext,
 {
     let state = query.query_state(qcx);
-    let mut state_lock = state.active.get_shard_by_value(&key).lock();
+    let mut state_lock = state.active.lock_shard_by_value(&key);
 
     // For the parallel compiler we need to check both the query cache and query state structures
     // while holding the state lock to ensure that 1) the query has not yet completed and 2) the
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index f98918cba88..9a970f5db39 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -58,15 +58,16 @@ resolve_cannot_determine_import_resolution =
     cannot determine resolution for the import
     .note = import resolution is stuck, try simplifying other imports
 
+resolve_cannot_determine_macro_resolution =
+    cannot determine resolution for the {$kind} `{$path}`
+    .note = import resolution is stuck, try simplifying macro imports
+
 resolve_cannot_find_ident_in_this_scope =
     cannot find {$expected} `{$ident}` in this scope
 
 resolve_cannot_glob_import_possible_crates =
     cannot glob-import all possible crates
 
-resolve_cannot_use_self_type_here =
-    can't use `Self` here
-
 resolve_change_import_binding =
     you can use `as` to change the binding name of the import
 
@@ -86,9 +87,6 @@ resolve_const_not_member_of_trait =
     const `{$const_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
 
-resolve_const_param_from_outer_fn =
-    const parameter from outer function
-
 resolve_const_param_in_enum_discriminant =
     const parameters may not be used in enum discriminant values
 
@@ -115,10 +113,19 @@ resolve_forward_declared_generic_param =
     generic parameters with a default cannot use forward declared identifiers
     .label = defaulted generic parameters cannot be forward declared
 
-resolve_generic_params_from_outer_function =
-    can't use generic parameters from outer function
-    .label = use of generic parameter from outer function
-    .suggestion = try using a local generic parameter instead
+resolve_generic_params_from_outer_item =
+    can't use generic parameters from outer item
+    .label = use of generic parameter from outer item
+    .refer_to_type_directly = refer to the type directly here instead
+    .suggestion = try introducing a local generic parameter here
+
+resolve_generic_params_from_outer_item_const_param = const parameter from outer item
+
+resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`
+
+resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
+
+resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
 
 resolve_glob_import_doesnt_reexport =
     glob import doesn't reexport anything because no candidate is public enough
@@ -273,9 +280,6 @@ resolve_type_not_member_of_trait =
     type `{$type_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
 
-resolve_type_param_from_outer_fn =
-    type parameter from outer function
-
 resolve_type_param_in_enum_discriminant =
     type parameters may not be used in enum discriminant values
 
@@ -311,9 +315,6 @@ resolve_unreachable_label_suggestion_use_similarly_named =
 resolve_unreachable_label_with_similar_name_exists =
     a label with a similar name exists but is unreachable
 
-resolve_use_a_type_here_instead =
-    use a type here instead
-
 resolve_variable_bound_with_different_mode =
     variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
     .label = bound in different ways
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 30db450870b..2c36c83ae72 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1239,7 +1239,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     use_span_with_attributes: span,
                     use_span: span,
                     root_span: span,
-                    span: span,
+                    span,
                     module_path: Vec::new(),
                     vis: Cell::new(Some(vis)),
                     used: Cell::new(true),
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d99fc07a7cd..9b7fd76d103 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -553,43 +553,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         resolution_error: ResolutionError<'a>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
+            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
+                use errs::GenericParamsFromOuterItemLabel as Label;
+                let mut err = errs::GenericParamsFromOuterItem {
                     span,
-                    E0401,
-                    "can't use generic parameters from outer function",
-                );
-                err.span_label(span, "use of generic parameter from outer function");
+                    label: None,
+                    refer_to_type_directly: None,
+                    sugg: None,
+                };
 
                 let sm = self.tcx.sess.source_map();
                 let def_id = match outer_res {
                     Res::SelfTyParam { .. } => {
-                        err.span_label(span, "can't use `Self` here");
-                        return err;
+                        err.label = Some(Label::SelfTyParam(span));
+                        return self.tcx.sess.create_err(err);
                     }
                     Res::SelfTyAlias { alias_to: def_id, .. } => {
-                        err.span_label(
-                            reduce_impl_span_to_impl_keyword(sm, self.def_span(def_id)),
-                            "`Self` type implicitly declared here, by this `impl`",
-                        );
-                        err.span_label(span, "use a type here instead");
-                        return err;
+                        err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
+                            sm,
+                            self.def_span(def_id),
+                        )));
+                        err.refer_to_type_directly = Some(span);
+                        return self.tcx.sess.create_err(err);
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
-                        err.span_label(self.def_span(def_id), "type parameter from outer function");
+                        err.label = Some(Label::TyParam(self.def_span(def_id)));
                         def_id
                     }
                     Res::Def(DefKind::ConstParam, def_id) => {
-                        err.span_label(
-                            self.def_span(def_id),
-                            "const parameter from outer function",
-                        );
+                        err.label = Some(Label::ConstParam(self.def_span(def_id)));
                         def_id
                     }
                     _ => {
                         bug!(
-                            "GenericParamsFromOuterFunction should only be used with \
+                            "GenericParamsFromOuterItem should only be used with \
                             Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
                             DefKind::ConstParam"
                         );
@@ -597,9 +594,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 };
 
                 if let HasGenericParams::Yes(span) = has_generic_params {
-                    // Try to retrieve the span of the function signature and generate a new
-                    // message with a local type or const parameter.
-                    let sugg_msg = "try using a local generic parameter instead";
                     let name = self.tcx.item_name(def_id);
                     let (span, snippet) = if span.is_empty() {
                         let snippet = format!("<{name}>");
@@ -609,11 +603,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         let snippet = format!("{name}, ");
                         (span, snippet)
                     };
-                    // Suggest the modification to the user
-                    err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
+                    err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
                 }
 
-                err
+                self.tcx.sess.create_err(err)
             }
             ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
                 .tcx
@@ -2753,7 +2746,13 @@ fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
     for item in items {
         if let ItemKind::Use(..) = item.kind {
             if is_span_suitable_for_use_injection(item.span) {
-                return Some(item.span.shrink_to_lo());
+                let mut lo = item.span.lo();
+                for attr in &item.attrs {
+                    if attr.span.eq_ctxt(item.span) {
+                        lo = std::cmp::min(lo, attr.span.lo());
+                    }
+                }
+                return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index e4b89c65853..72ff959bbd6 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -33,6 +33,40 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate)
 pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span);
 
 #[derive(Diagnostic)]
+#[diag(resolve_generic_params_from_outer_item, code = "E0401")]
+pub(crate) struct GenericParamsFromOuterItem {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) label: Option<GenericParamsFromOuterItemLabel>,
+    #[label(resolve_refer_to_type_directly)]
+    pub(crate) refer_to_type_directly: Option<Span>,
+    #[subdiagnostic]
+    pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum GenericParamsFromOuterItemLabel {
+    #[label(resolve_generic_params_from_outer_item_self_ty_param)]
+    SelfTyParam(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_self_ty_alias)]
+    SelfTyAlias(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_ty_param)]
+    TyParam(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_const_param)]
+    ConstParam(#[primary_span] Span),
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(resolve_suggestion, code = "{snippet}", applicability = "maybe-incorrect")]
+pub(crate) struct GenericParamsFromOuterItemSugg {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) snippet: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")]
 pub(crate) struct NameAlreadyUsedInParameterList {
     #[primary_span]
@@ -655,6 +689,16 @@ pub(crate) struct CannotDetermineImportResolution {
 }
 
 #[derive(Diagnostic)]
+#[diag(resolve_cannot_determine_macro_resolution)]
+#[note]
+pub(crate) struct CannotDetermineMacroResolution {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) kind: &'static str,
+    pub(crate) path: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(resolve_cannot_be_reexported_private, code = "E0364")]
 pub(crate) struct CannotBeReexportedPrivate {
     #[primary_span]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 61e05b65f90..54388f80f15 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -972,9 +972,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // progress, we have to ignore those potential unresolved invocations from other modules
         // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
         // shadowing is enabled, see `macro_expanded_macro_export_errors`).
-        let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
         if let Some(binding) = binding {
-            if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
+            if binding.determined() || ns == MacroNS || restricted_shadowing {
                 return check_usable(self, binding);
             } else {
                 return Err((Undetermined, Weak::No));
@@ -991,7 +990,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         // Check if one of unexpanded macros can still define the name,
         // if it can then our "no resolution" result is not determined and can be invalidated.
-        if unexpanded_macros {
+        if !module.unexpanded_invocations.borrow().is_empty() {
             return Err((Undetermined, Weak::Yes));
         }
 
@@ -1229,10 +1228,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
+                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
                         );
                     }
                     return Res::Err;
@@ -1296,10 +1292,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
+                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
                         );
                     }
                     return Res::Err;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index a175d9f6c7f..820ac9ef61b 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -319,10 +319,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             // We should replace the `old_binding` with `binding` regardless
                             // of whether they has same resolution or not when they are
                             // imported from the same glob-import statement.
-                            // However we currently using `Some(old_binding)` for back compact
-                            // purposes.
-                            // This case can be removed after once `Undetermined` is prepared
-                            // for glob-imports.
+                            resolution.binding = Some(binding);
                         } else if res != old_binding.res() {
                             let binding = if warn_ambiguity {
                                 this.warn_ambiguity(
@@ -805,13 +802,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     // For better failure detection, pretend that the import will
                     // not define any names while resolving its module path.
                     let orig_vis = import.vis.take();
-                    let binding = this.resolve_ident_in_module(
+                    let binding = this.maybe_resolve_ident_in_module(
                         module,
                         source,
                         ns,
                         &import.parent_scope,
-                        None,
-                        None,
                     );
                     import.vis.set(orig_vis);
                     source_bindings[ns].set(binding);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 486d60eab21..d40b1b2e3a9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2450,7 +2450,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(if self.r.tcx.features().generic_const_items {
+                        HasGenericParams::Yes(generics.span)
+                    } else {
+                        HasGenericParams::No
+                    }),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::ConstItem,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b757f42eaa0..949c6ab5ac0 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -34,7 +34,7 @@ use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArg
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{Lrc, MappedReadGuard};
+use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
 use rustc_errors::{
     Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
 };
@@ -186,8 +186,8 @@ struct BindingError {
 
 #[derive(Debug)]
 enum ResolutionError<'a> {
-    /// Error E0401: can't use type or const parameters from outer function.
-    GenericParamsFromOuterFunction(Res, HasGenericParams),
+    /// Error E0401: can't use type or const parameters from outer item.
+    GenericParamsFromOuterItem(Res, HasGenericParams),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
@@ -881,6 +881,19 @@ impl<'a> NameBindingData<'a> {
             invoc_parent_expansion.is_descendant_of(self_parent_expansion);
         !(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
     }
+
+    // Its purpose is to postpone the determination of a single binding because
+    // we can't predict whether it will be overwritten by recently expanded macros.
+    // FIXME: How can we integrate it with the `update_resolution`?
+    fn determined(&self) -> bool {
+        match &self.kind {
+            NameBindingKind::Import { binding, import, .. } if import.is_glob() => {
+                import.parent_scope.module.unexpanded_invocations.borrow().is_empty()
+                    && binding.determined()
+            }
+            _ => true,
+        }
+    }
 }
 
 #[derive(Default, Clone)]
@@ -1544,7 +1557,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         ))
     }
 
-    fn cstore(&self) -> MappedReadGuard<'_, CStore> {
+    fn cstore(&self) -> FreezeReadGuard<'_, CStore> {
         CStore::from_tcx(self.tcx)
     }
 
@@ -1599,7 +1612,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         });
 
         // Make sure we don't mutate the cstore from here on.
-        self.tcx.untracked().cstore.leak();
+        self.tcx.untracked().cstore.freeze();
     }
 
     fn traits_in_scope(
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 1199290a4d1..82060716575 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -2,7 +2,8 @@
 //! interface provided by `Resolver` to macro expander.
 
 use crate::errors::{
-    self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive,
+    self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
+    MacroExpectedFound, RemoveSurroundingDerive,
 };
 use crate::Namespace::*;
 use crate::{BuiltinMacroState, Determinacy};
@@ -719,13 +720,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 // even if speculative `resolve_path` returned nothing previously, so we skip this
                 // less informative error if the privacy error is reported elsewhere.
                 if this.privacy_errors.is_empty() {
-                    let msg = format!(
-                        "cannot determine resolution for the {} `{}`",
-                        kind.descr(),
-                        Segment::names_to_string(path)
-                    );
-                    let msg_note = "import resolution is stuck, try simplifying macro imports";
-                    this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit();
+                    this.tcx.sess.emit_err(CannotDetermineMacroResolution {
+                        span,
+                        kind: kind.descr(),
+                        path: Segment::names_to_string(path),
+                    });
                 }
             }
         };
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index ba7417b6dda..7c41c32d022 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -2,9 +2,11 @@ use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
 use rustc_ast as ast;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::{InnerSpan, Span, DUMMY_SP};
+use std::ops::Range;
 use std::{cmp, mem};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -462,3 +464,88 @@ fn collect_link_data<'input, 'callback>(
 
     display_text.map(String::into_boxed_str)
 }
+
+/// Returns a span encompassing all the document fragments.
+pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
+    if fragments.is_empty() {
+        return None;
+    }
+    let start = fragments[0].span;
+    if start == DUMMY_SP {
+        return None;
+    }
+    let end = fragments.last().expect("no doc strings provided").span;
+    Some(start.to(end))
+}
+
+/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
+///
+/// This method will return `None` if we cannot construct a span from the source map or if the
+/// fragments are not all sugared doc comments. It's difficult to calculate the correct span in
+/// that case due to escaping and other source features.
+pub fn source_span_for_markdown_range(
+    tcx: TyCtxt<'_>,
+    markdown: &str,
+    md_range: &Range<usize>,
+    fragments: &[DocFragment],
+) -> Option<Span> {
+    let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
+
+    if !is_all_sugared_doc {
+        return None;
+    }
+
+    let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?;
+
+    let starting_line = markdown[..md_range.start].matches('\n').count();
+    let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
+
+    // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
+    // CRLF and LF line endings the same way.
+    let mut src_lines = snippet.split_terminator('\n');
+    let md_lines = markdown.split_terminator('\n');
+
+    // The number of bytes from the source span to the markdown span that are not part
+    // of the markdown, like comment markers.
+    let mut start_bytes = 0;
+    let mut end_bytes = 0;
+
+    'outer: for (line_no, md_line) in md_lines.enumerate() {
+        loop {
+            let source_line = src_lines.next()?;
+            match source_line.find(md_line) {
+                Some(offset) => {
+                    if line_no == starting_line {
+                        start_bytes += offset;
+
+                        if starting_line == ending_line {
+                            break 'outer;
+                        }
+                    } else if line_no == ending_line {
+                        end_bytes += offset;
+                        break 'outer;
+                    } else if line_no < starting_line {
+                        start_bytes += source_line.len() - md_line.len();
+                    } else {
+                        end_bytes += source_line.len() - md_line.len();
+                    }
+                    break;
+                }
+                None => {
+                    // Since this is a source line that doesn't include a markdown line,
+                    // we have to count the newline that we split from earlier.
+                    if line_no <= starting_line {
+                        start_bytes += source_line.len() + 1;
+                    } else {
+                        end_bytes += source_line.len() + 1;
+                    }
+                }
+            }
+        }
+    }
+
+    Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
+        md_range.start + start_bytes,
+        md_range.end + start_bytes + end_bytes,
+    )))
+}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 302e4e55d59..ba82ee95caa 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -381,6 +381,24 @@ pub enum DebugInfo {
     Full,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum DebugInfoCompression {
+    None,
+    Zlib,
+    Zstd,
+}
+
+impl ToString for DebugInfoCompression {
+    fn to_string(&self) -> String {
+        match self {
+            DebugInfoCompression::None => "none",
+            DebugInfoCompression::Zlib => "zlib",
+            DebugInfoCompression::Zstd => "zstd",
+        }
+        .to_owned()
+    }
+}
+
 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
 /// uses DWARF for debug-information.
@@ -1015,6 +1033,7 @@ impl Default for Options {
             crate_types: Vec::new(),
             optimize: OptLevel::No,
             debuginfo: DebugInfo::None,
+            debuginfo_compression: DebugInfoCompression::None,
             lint_opts: Vec::new(),
             lint_cap: None,
             describe_lints: false,
@@ -1067,7 +1086,7 @@ impl Options {
     /// Returns `true` if there will be an output file generated.
     pub fn will_create_output_file(&self) -> bool {
         !self.unstable_opts.parse_only && // The file is just being parsed
-            !self.unstable_opts.ls // The file is just being queried
+            self.unstable_opts.ls.is_empty() // The file is just being queried
     }
 
     #[inline]
@@ -1084,12 +1103,6 @@ impl Options {
     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
     }
-
-    #[allow(rustc::bad_opt_access)]
-    pub fn incremental_relative_spans(&self) -> bool {
-        self.unstable_opts.incremental_relative_spans
-            || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
-    }
 }
 
 impl UnstableOptions {
@@ -2277,6 +2290,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
     if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
 }
 
+fn select_debuginfo_compression(
+    _handler: &EarlyErrorHandler,
+    unstable_opts: &UnstableOptions,
+) -> DebugInfoCompression {
+    unstable_opts.debuginfo_compression
+}
+
 pub(crate) fn parse_assert_incr_state(
     handler: &EarlyErrorHandler,
     opt_assertion: &Option<String>,
@@ -2752,6 +2772,8 @@ pub fn build_session_options(
     // for more details.
     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
     let debuginfo = select_debuginfo(matches, &cg);
+    let debuginfo_compression: DebugInfoCompression =
+        select_debuginfo_compression(handler, &unstable_opts);
 
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
@@ -2828,6 +2850,7 @@ pub fn build_session_options(
         crate_types,
         optimize: opt_level,
         debuginfo,
+        debuginfo_compression,
         lint_opts,
         lint_cap,
         describe_lints,
@@ -2953,6 +2976,7 @@ pub mod nightly_options {
     ) {
         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
         let really_allows_unstable_options = match_is_nightly_build(matches);
+        let mut nightly_options_on_stable = 0;
 
         for opt in flags.iter() {
             if opt.stability == OptionStability::Stable {
@@ -2973,20 +2997,27 @@ pub mod nightly_options {
             }
             match opt.stability {
                 OptionStability::Unstable => {
+                    nightly_options_on_stable += 1;
                     let msg = format!(
                         "the option `{}` is only accepted on the nightly compiler",
                         opt.name
                     );
                     let _ = handler.early_error_no_abort(msg);
-                    handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
-                    handler.early_help(
-                        "consider switching to a nightly toolchain: `rustup default nightly`",
-                    );
-                    handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
                 }
                 OptionStability::Stable => {}
             }
         }
+        if nightly_options_on_stable > 0 {
+            handler
+                .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
+            handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
+            handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
+            handler.early_error(format!(
+                "{} nightly option{} were parsed",
+                nightly_options_on_stable,
+                if nightly_options_on_stable > 1 { "s" } else { "" }
+            ));
+        }
     }
 }
 
@@ -3113,11 +3144,11 @@ impl PpMode {
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
     use super::{
-        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
-        InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
-        OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
-        SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
-        TraitSolver, TrimmedDefPaths,
+        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
+        ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
+        LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
+        Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
+        SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -3195,6 +3226,7 @@ pub(crate) mod dep_tracking {
         OptLevel,
         LtoCli,
         DebugInfo,
+        DebugInfoCompression,
         UnstableFeatures,
         NativeLib,
         NativeLibKind,
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 90f57be9324..d816842b02b 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -7,7 +7,7 @@ use crate::utils::NativeLibKind;
 use crate::Session;
 use rustc_ast as ast;
 use rustc_data_structures::owned_slice::OwnedSlice;
-use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock, RwLock};
+use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -258,7 +258,7 @@ pub trait CrateStore: std::fmt::Debug {
 pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend;
 
 pub struct Untracked {
-    pub cstore: RwLock<Box<CrateStoreDyn>>,
+    pub cstore: FreezeLock<Box<CrateStoreDyn>>,
     /// Reference span for definitions.
     pub source_span: AppendOnlyIndexVec<LocalDefId, Span>,
     pub definitions: FreezeLock<Definitions>,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 40099de707b..73fd7965895 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -139,6 +139,7 @@ top_level_options!(
         /// can influence whether overflow checks are done or not.
         debug_assertions: bool [TRACKED],
         debuginfo: DebugInfo [TRACKED],
+        debuginfo_compression: DebugInfoCompression [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH],
         lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH],
         describe_lints: bool [UNTRACKED],
@@ -376,6 +377,7 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
+    pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -782,6 +784,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_debuginfo_compression(
+        slot: &mut DebugInfoCompression,
+        v: Option<&str>,
+    ) -> bool {
+        match v {
+            Some("none") => *slot = DebugInfoCompression::None,
+            Some("zlib") => *slot = DebugInfoCompression::Zlib,
+            Some("zstd") => *slot = DebugInfoCompression::Zstd,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
         match v.and_then(LinkerFlavorCli::from_str) {
             Some(lf) => *slot = Some(lf),
@@ -1424,6 +1439,8 @@ options! {
         "emit discriminators and other data necessary for AutoFDO"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
         "emit line numbers debug info inside macros (default: no)"),
+    debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
+        "compress debug info sections (none, zlib, zstd, default: none)"),
     deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
         "deduplicate identical diagnostics (default: yes)"),
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
@@ -1524,9 +1541,6 @@ options! {
     incremental_info: bool = (false, parse_bool, [UNTRACKED],
         "print high-level information about incremental reuse (or the lack thereof) \
         (default: no)"),
-    #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
-    incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
-        "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
         "verify incr. comp. hashes of green query instances (default: no)"),
     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1580,8 +1594,9 @@ options! {
         "what location details should be tracked when using caller_location, either \
         `none`, or a comma separated list of location details, for which \
         valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
-    ls: bool = (false, parse_bool, [UNTRACKED],
-        "list the symbols defined by a library crate (default: no)"),
+    ls: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
+        "decode and print various parts of the crate metadata for a library crate \
+        (space separated)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
         "show macro backtraces (default: no)"),
     maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 73b8e060dd8..4203990ab05 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -16,7 +16,6 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_interface::{interface, Queries};
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::EarlyErrorHandler;
 pub use rustc_span::def_id::{CrateNum, DefId};
 
 fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
@@ -233,7 +232,6 @@ where
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index a7640736481..141a3efe964 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -42,6 +42,10 @@ impl<'tcx> Context for Tables<'tcx> {
         self.tcx.def_path_str(self[def_id])
     }
 
+    fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Span {
+        self.tcx.def_span(self[def_id]).stable(self)
+    }
+
     fn all_local_items(&mut self) -> stable_mir::CrateItems {
         self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
     }
@@ -80,7 +84,7 @@ impl<'tcx> Context for Tables<'tcx> {
 
     fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
         let def_id = self[item];
-        let mir = self.tcx.optimized_mir(def_id);
+        let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id));
         stable_mir::mir::Body {
             blocks: mir
                 .basic_blocks
@@ -131,6 +135,23 @@ impl<'tcx> Context for Tables<'tcx> {
                 .collect(),
         }
     }
+
+    fn explicit_predicates_of(
+        &mut self,
+        def_id: stable_mir::DefId,
+    ) -> stable_mir::ty::GenericPredicates {
+        let def_id = self[def_id];
+        let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id);
+        stable_mir::ty::GenericPredicates {
+            parent: parent.map(|did| self.trait_def(did)),
+            predicates: predicates
+                .iter()
+                .map(|(clause, span)| {
+                    (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
+                })
+                .collect(),
+        }
+    }
 }
 
 #[derive(Clone)]
@@ -1293,7 +1314,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
             ty::GenericParamDefKind::Type { has_default, synthetic } => {
                 GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
             }
-            ty::GenericParamDefKind::Const { has_default } => {
+            ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => {
                 GenericParamDefKind::Const { has_default: *has_default }
             }
         }
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index 9cab7230b97..ef5901482d8 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -89,6 +89,10 @@ impl CrateItem {
     pub fn body(&self) -> mir::Body {
         with(|cx| cx.mir_body(self.0))
     }
+
+    pub fn span(&self) -> ty::Span {
+        with(|cx| cx.span_of_an_item(self.0))
+    }
 }
 
 /// Return the function where execution starts if the current
@@ -145,6 +149,7 @@ pub trait Context {
     fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait;
     fn generics_of(&mut self, def_id: DefId) -> Generics;
     fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
+    fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
     /// Get information about the local crate.
     fn local_crate(&self) -> Crate;
     /// Retrieve a list of all external crates.
@@ -156,6 +161,9 @@ pub trait Context {
     /// Prints the name of given `DefId`
     fn name_of_def_id(&self, def_id: DefId) -> String;
 
+    /// `Span` of an item
+    fn span_of_an_item(&mut self, def_id: DefId) -> Span;
+
     /// Obtain the representation of a type.
     fn ty_kind(&mut self, ty: Ty) -> TyKind;
 
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 54cba1263b7..76e7beac571 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -395,6 +395,10 @@ impl TraitDecl {
     pub fn predicates_of(&self) -> GenericPredicates {
         with(|cx| cx.predicates_of(self.def_id.0))
     }
+
+    pub fn explicit_predicates_of(&self) -> GenericPredicates {
+        with(|cx| cx.explicit_predicates_of(self.def_id.0))
+    }
 }
 
 pub type ImplTrait = EarlyBinder<TraitRef>;
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 3a869a2410a..68724c48037 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -510,10 +510,6 @@ impl SpanData {
     pub fn is_dummy(self) -> bool {
         self.lo.0 == 0 && self.hi.0 == 0
     }
-    #[inline]
-    pub fn is_visible(self, sm: &SourceMap) -> bool {
-        !self.is_dummy() && sm.is_span_accessible(self.span())
-    }
     /// Returns `true` if `self` fully encloses `other`.
     pub fn contains(self, other: Self) -> bool {
         self.lo <= other.lo && other.hi <= self.hi
@@ -573,15 +569,9 @@ impl Span {
         self.data().with_parent(ctxt)
     }
 
-    /// Returns `true` if this is a dummy span with any hygienic context.
-    #[inline]
-    pub fn is_dummy(self) -> bool {
-        self.data_untracked().is_dummy()
-    }
-
     #[inline]
     pub fn is_visible(self, sm: &SourceMap) -> bool {
-        self.data_untracked().is_visible(sm)
+        !self.is_dummy() && sm.is_span_accessible(self)
     }
 
     /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index 1eea0f63ca0..93ab154601f 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -1,9 +1,3 @@
-// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
-// One format is used for keeping span data inline,
-// another contains index into an out-of-line span interner.
-// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
-// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
-
 use crate::def_id::{DefIndex, LocalDefId};
 use crate::hygiene::SyntaxContext;
 use crate::SPAN_TRACK;
@@ -13,59 +7,69 @@ use rustc_data_structures::fx::FxIndexSet;
 
 /// A compressed span.
 ///
-/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length, parent and
-/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
-/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
+/// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only
+/// takes up 8 bytes, with less space for the length, parent and context. The
+/// vast majority (99.9%+) of `SpanData` instances can be made to fit within
+/// those 8 bytes. Any `SpanData` whose fields don't fit into a `Span` are
 /// stored in a separate interner table, and the `Span` will index into that
 /// table. Interning is rare enough that the cost is low, but common enough
 /// that the code is exercised regularly.
 ///
 /// An earlier version of this code used only 4 bytes for `Span`, but that was
 /// slower because only 80--90% of spans could be stored inline (even less in
-/// very large crates) and so the interner was used a lot more.
+/// very large crates) and so the interner was used a lot more. That version of
+/// the code also predated the storage of parents.
+///
+/// There are four different span forms.
 ///
-/// Inline (compressed) format with no parent:
-/// - `span.base_or_index == span_data.lo`
-/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
-/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
+/// Inline-context format (requires non-huge length, non-huge context, and no parent):
+/// - `span.lo_or_index == span_data.lo`
+/// - `span.len_with_tag_or_marker == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
-/// Interned format with inline `SyntaxContext`:
-/// - `span.base_or_index == index` (indexes into the interner table)
-/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
-/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
+/// Inline-parent format (requires non-huge length, root context, and non-huge parent):
+/// - `span.lo_or_index == span_data.lo`
+/// - `span.len_with_tag_or_marker & !PARENT_TAG == len == span_data.hi - span_data.lo`
+///   (must be `<= MAX_LEN`)
+/// - `span.len_with_tag_or_marker` has top bit (`PARENT_TAG`) set
+/// - `span.ctxt_or_parent_or_marker == span_data.parent` (must be `<= MAX_CTXT`)
 ///
-/// Inline (compressed) format with root context:
-/// - `span.base_or_index == span_data.lo`
-/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
-/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
-/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+/// Partially-interned format (requires non-huge context):
+/// - `span.lo_or_index == index` (indexes into the interner table)
+/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER`
+/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
-/// Interned format:
-/// - `span.base_or_index == index` (indexes into the interner table)
-/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
-/// - `span.ctxt_or_tag == CTXT_TAG`
+/// Fully-interned format (all cases not covered above):
+/// - `span.lo_or_index == index` (indexes into the interner table)
+/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER`
+/// - `span.ctxt_or_parent_or_marker == CTXT_INTERNED_MARKER`
 ///
-/// The inline form uses 0 for the tag value (rather than 1) so that we don't
-/// need to mask out the tag bit when getting the length, and so that the
-/// dummy span can be all zeroes.
+/// The partially-interned form requires looking in the interning table for
+/// lo and length, but the context is stored inline as well as interned.
+/// This is useful because context lookups are often done in isolation, and
+/// inline lookups are quicker.
 ///
 /// Notes about the choice of field sizes:
-/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base`
-///   values never cause interning. The number of bits needed for `base`
+/// - `lo` is 32 bits in both `Span` and `SpanData`, which means that `lo`
+///   values never cause interning. The number of bits needed for `lo`
 ///   depends on the crate size. 32 bits allows up to 4 GiB of code in a crate.
-/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits
-///   in `SpanData`, which means that large `len` values will cause interning.
-///   The number of bits needed for `len` does not depend on the crate size.
-///   The most common numbers of bits for `len` are from 0 to 7, with a peak usually
-///   at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
-///   for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
-///   dozens of times in a typical crate.
-/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
-///   large `ctxt` values will cause interning. The number of bits needed for
-///   `ctxt` values depend partly on the crate size and partly on the form of
-///   the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`,
-///   but larger crates might need more than 16 bits.
+///   Having no compression on this field means there is no performance cliff
+///   if a crate exceeds a particular size.
+/// - `len` is ~15 bits in `Span` (a u16, minus 1 bit for PARENT_TAG) and 32
+///   bits in `SpanData`, which means that large `len` values will cause
+///   interning. The number of bits needed for `len` does not depend on the
+///   crate size. The most common numbers of bits for `len` are from 0 to 7,
+///   with a peak usually at 3 or 4, and then it drops off quickly from 8
+///   onwards. 15 bits is enough for 99.99%+ of cases, but larger values
+///   (sometimes 20+ bits) might occur dozens of times in a typical crate.
+/// - `ctxt_or_parent_or_marker` is 16 bits in `Span` and two 32 bit fields in
+///   `SpanData`, which means intering will happen if `ctxt` is large, if
+///   `parent` is large, or if both values are non-zero. The number of bits
+///   needed for `ctxt` values depend partly on the crate size and partly on
+///   the form of the code. No crates in `rustc-perf` need more than 15 bits
+///   for `ctxt_or_parent_or_marker`, but larger crates might need more than 16
+///   bits. The number of bits needed for `parent` hasn't been measured,
+///   because `parent` isn't currently used by default.
 ///
 /// In order to reliably use parented spans in incremental compilation,
 /// the dependency to the parent definition's span. This is performed
@@ -74,19 +78,22 @@ use rustc_data_structures::fx::FxIndexSet;
 #[derive(Clone, Copy, Eq, PartialEq, Hash)]
 #[rustc_pass_by_value]
 pub struct Span {
-    base_or_index: u32,
-    len_or_tag: u16,
-    ctxt_or_tag: u16,
+    lo_or_index: u32,
+    len_with_tag_or_marker: u16,
+    ctxt_or_parent_or_marker: u16,
 }
 
-const LEN_TAG: u16 = 0b1111_1111_1111_1111;
-const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
-const MAX_LEN: u32 = 0b0111_1111_1111_1111;
-const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
-const MAX_CTXT: u32 = CTXT_TAG - 1;
+// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
+// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
+const MAX_LEN: u32 = 0b0111_1111_1111_1110;
+const MAX_CTXT: u32 = 0b0111_1111_1111_1110;
+const PARENT_TAG: u16 = 0b1000_0000_0000_0000;
+const BASE_LEN_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111;
+const CTXT_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111;
 
-/// Dummy span, both position and length are zero, syntax context is zero as well.
-pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 };
+/// The dummy span has zero position, length, and context, and no parent.
+pub const DUMMY_SP: Span =
+    Span { lo_or_index: 0, len_with_tag_or_marker: 0, ctxt_or_parent_or_marker: 0 };
 
 impl Span {
     #[inline]
@@ -100,39 +107,43 @@ impl Span {
             std::mem::swap(&mut lo, &mut hi);
         }
 
-        let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
-
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
-            let len_or_tag = len as u16;
-            debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+        let (lo2, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-            if let Some(parent) = parent {
-                // Inline format with parent.
-                let len_or_tag = len_or_tag | PARENT_MASK;
-                let parent2 = parent.local_def_index.as_u32();
-                if ctxt2 == SyntaxContext::root().as_u32()
-                    && parent2 <= MAX_CTXT
-                    && len_or_tag < LEN_TAG
-                {
-                    debug_assert_ne!(len_or_tag, LEN_TAG);
-                    return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
-                }
-            } else {
-                // Inline format with ctxt.
-                debug_assert_ne!(len_or_tag, LEN_TAG);
+        if len <= MAX_LEN {
+            if ctxt2 <= MAX_CTXT && parent.is_none() {
+                // Inline-context format.
                 return Span {
-                    base_or_index: base,
-                    len_or_tag: len as u16,
-                    ctxt_or_tag: ctxt2 as u16,
+                    lo_or_index: lo2,
+                    len_with_tag_or_marker: len as u16,
+                    ctxt_or_parent_or_marker: ctxt2 as u16,
+                };
+            } else if ctxt2 == SyntaxContext::root().as_u32()
+                && let Some(parent) = parent
+                && let parent2 = parent.local_def_index.as_u32()
+                && parent2 <= MAX_CTXT
+            {
+                // Inline-parent format.
+                return Span {
+                    lo_or_index: lo2,
+                    len_with_tag_or_marker: PARENT_TAG | len as u16,
+                    ctxt_or_parent_or_marker: parent2 as u16
                 };
             }
         }
 
-        // Interned format.
+        // Partially-interned or fully-interned format.
         let index =
             with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
-        let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
-        Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+        let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT {
+            ctxt2 as u16 // partially-interned
+        } else {
+            CTXT_INTERNED_MARKER // fully-interned
+        };
+        Span {
+            lo_or_index: index,
+            len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER,
+            ctxt_or_parent_or_marker,
+        }
     }
 
     #[inline]
@@ -148,56 +159,80 @@ impl Span {
     /// This function must not be used outside the incremental engine.
     #[inline]
     pub fn data_untracked(self) -> SpanData {
-        if self.len_or_tag != LEN_TAG {
-            // Inline format.
-            if self.len_or_tag & PARENT_MASK == 0 {
-                debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            if self.len_with_tag_or_marker & PARENT_TAG == 0 {
+                // Inline-context format.
+                let len = self.len_with_tag_or_marker as u32;
+                debug_assert!(len <= MAX_LEN);
                 SpanData {
-                    lo: BytePos(self.base_or_index),
-                    hi: BytePos(self.base_or_index + self.len_or_tag as u32),
-                    ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+                    lo: BytePos(self.lo_or_index),
+                    hi: BytePos(self.lo_or_index + len),
+                    ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),
                     parent: None,
                 }
             } else {
-                let len = self.len_or_tag & !PARENT_MASK;
-                debug_assert!(len as u32 <= MAX_LEN);
-                let parent =
-                    LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+                // Inline-parent format.
+                let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
+                debug_assert!(len <= MAX_LEN);
+                let parent = LocalDefId {
+                    local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32),
+                };
                 SpanData {
-                    lo: BytePos(self.base_or_index),
-                    hi: BytePos(self.base_or_index + len as u32),
+                    lo: BytePos(self.lo_or_index),
+                    hi: BytePos(self.lo_or_index + len),
                     ctxt: SyntaxContext::root(),
                     parent: Some(parent),
                 }
             }
         } else {
-            // Interned format.
-            let index = self.base_or_index;
+            // Fully-interned or partially-interned format. In either case,
+            // the interned value contains all the data, so we don't need to
+            // distinguish them.
+            let index = self.lo_or_index;
             with_span_interner(|interner| interner.spans[index as usize])
         }
     }
 
+    /// Returns `true` if this is a dummy span with any hygienic context.
+    #[inline]
+    pub fn is_dummy(self) -> bool {
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            // Inline-context or inline-parent format.
+            let lo = self.lo_or_index;
+            let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
+            debug_assert!(len <= MAX_LEN);
+            lo == 0 && len == 0
+        } else {
+            // Fully-interned or partially-interned format.
+            let index = self.lo_or_index;
+            let data = with_span_interner(|interner| interner.spans[index as usize]);
+            data.lo == BytePos(0) && data.hi == BytePos(0)
+        }
+    }
+
     /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
+    /// It's a cut-down version of `data_untracked`.
     #[inline]
     pub fn ctxt(self) -> SyntaxContext {
-        let ctxt_or_tag = self.ctxt_or_tag as u32;
-        // Check for interned format.
-        if self.len_or_tag == LEN_TAG {
-            if ctxt_or_tag == CTXT_TAG {
-                // Fully interned format.
-                let index = self.base_or_index;
-                with_span_interner(|interner| interner.spans[index as usize].ctxt)
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            if self.len_with_tag_or_marker & PARENT_TAG == 0 {
+                // Inline-context format.
+                SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
             } else {
-                // Interned format with inline ctxt.
-                SyntaxContext::from_u32(ctxt_or_tag)
+                // Inline-parent format. We know that the SyntaxContext is root.
+                SyntaxContext::root()
             }
-        } else if self.len_or_tag & PARENT_MASK == 0 {
-            // Inline format with inline ctxt.
-            SyntaxContext::from_u32(ctxt_or_tag)
         } else {
-            // Inline format with inline parent.
-            // We know that the SyntaxContext is root.
-            SyntaxContext::root()
+            if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
+                // Partially-interned format. This path avoids looking up the
+                // interned value, and is the whole point of the
+                // partially-interned format.
+                SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
+            } else {
+                // Fully-interned format.
+                let index = self.lo_or_index;
+                with_span_interner(|interner| interner.spans[index as usize].ctxt)
+            }
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3247d5e46ef..448314cd9e1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -574,6 +574,8 @@ symbols! {
         cosf32,
         cosf64,
         count,
+        coverage,
+        coverage_attribute,
         cr,
         crate_id,
         crate_in_paths,
@@ -1069,6 +1071,7 @@ symbols! {
         note,
         object_safe_for_dispatch,
         of,
+        off,
         offset,
         offset_of,
         omit_gdb_pretty_printer_section,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 3a33568084c..2fc102bda13 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
                 self.write_str("[")?;
                 self = self.print_type(ty)?;
                 self.write_str("; ")?;
-                if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) {
+                if let Some(size) = size.try_to_target_usize(self.tcx()) {
                     write!(self, "{size}")?
                 } else if let ty::ConstKind::Param(param) = size.kind() {
                     self = param.print(self)?
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index da19a3ba4fd..2550570af65 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -562,7 +562,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
 
     fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // We only mangle a typed value if the const can be evaluated.
-        let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
+        let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all());
         match ct.kind() {
             ty::ConstKind::Value(_) => {}
 
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 5d75974279e..1a4a46ceb40 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -382,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
     /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
     /// special-cased in ABIs.
     ///
-    /// Note: We generally ignore fields of zero-sized type when computing
-    /// this value (see #56877).
+    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
     ///
     /// This is public so that it can be used in unit tests, but
     /// should generally only be relevant to the ABI details of
@@ -441,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
                         let mut total = start;
 
                         for i in 0..layout.fields.count() {
+                            let field = layout.field(cx, i);
+                            if field.is_1zst() {
+                                // No data here and no impact on layout, can be ignored.
+                                // (We might be able to also ignore all aligned ZST but that's less clear.)
+                                continue;
+                            }
+
                             if !is_union && total != layout.fields.offset(i) {
+                                // This field isn't just after the previous one we considered, abort.
                                 return Err(Heterogeneous);
                             }
 
-                            let field = layout.field(cx, i);
-
                             result = result.merge(field.homogeneous_aggregate(cx)?)?;
 
                             // Keep track of the offset (without padding).
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index dd435dbb0a3..a335585dbf3 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -144,4 +144,25 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
 
         offset
     }
+
+    /// Finds the one field that is not a 1-ZST.
+    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
+    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
+    where
+        Ty: TyAbiInterface<'a, C> + Copy,
+    {
+        let mut found = None;
+        for field_idx in 0..self.fields.count() {
+            let field = self.field(cx, field_idx);
+            if field.is_1zst() {
+                continue;
+            }
+            if found.is_some() {
+                // More than one non-1-ZST field.
+                return None;
+            }
+            found = Some((field_idx, field));
+        }
+        found
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnullvm.rs
new file mode 100644
index 00000000000..3154b512a52
--- /dev/null
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnullvm.rs
@@ -0,0 +1,26 @@
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target};
+
+pub fn target() -> Target {
+    let mut base = super::windows_gnullvm_base::opts();
+    base.cpu = "pentium4".into();
+    base.max_atomic_width = Some(64);
+    base.frame_pointer = FramePointer::Always; // Required for backtraces
+    base.linker = Some("i686-w64-mingw32-clang".into());
+
+    // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
+    // space available to x86 Windows binaries on x86_64.
+    base.add_pre_link_args(
+        LinkerFlavor::Gnu(Cc::No, Lld::No),
+        &["-m", "i386pe", "--large-address-aware"],
+    );
+
+    Target {
+        llvm_target: "i686-pc-windows-gnu".into(),
+        pointer_width: 32,
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .into(),
+        arch: "x86".into(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index fca99381c0c..8aa72797a0d 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1420,6 +1420,7 @@ supported_targets! {
     ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),
 
     ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm),
+    ("i686-pc-windows-gnullvm", i686_pc_windows_gnullvm),
     ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm),
 
     ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 2a09a7dcd89..2db24c43734 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -40,5 +40,7 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
     .label = expected value here
     .note = eg `#[rustc_on_unimplemented(message="foo")]`
 
+trait_selection_trait_has_no_impls = this trait has no implementations, consider adding one
+
 trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead
 trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 6b839d64b87..f7031c5f493 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -125,7 +125,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         direction: ty::AliasRelationDirection,
         invert: Invert,
     ) -> QueryResult<'tcx> {
-        self.probe_candidate("normalizes-to").enter(|ecx| {
+        self.probe_misc_candidate("normalizes-to").enter(|ecx| {
             ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
@@ -175,7 +175,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         alias_rhs: ty::AliasTy<'tcx>,
         direction: ty::AliasRelationDirection,
     ) -> QueryResult<'tcx> {
-        self.probe_candidate("args relate").enter(|ecx| {
+        self.probe_misc_candidate("args relate").enter(|ecx| {
             match direction {
                 ty::AliasRelationDirection::Equate => {
                     ecx.eq(param_env, alias_lhs, alias_rhs)?;
@@ -196,7 +196,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         rhs: ty::Term<'tcx>,
         direction: ty::AliasRelationDirection,
     ) -> QueryResult<'tcx> {
-        self.probe_candidate("bidir normalizes-to").enter(|ecx| {
+        self.probe_misc_candidate("bidir normalizes-to").enter(|ecx| {
             ecx.normalizes_to_inner(
                 param_env,
                 lhs.to_alias_ty(ecx.tcx()).unwrap(),
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 36194f973b5..128b9ad7e47 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -5,8 +5,10 @@ use crate::traits::coherence;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::Reveal;
-use rustc_middle::traits::solve::inspect::CandidateKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::inspect::ProbeKind;
+use rustc_middle::traits::solve::{
+    CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
+};
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -27,66 +29,6 @@ pub(super) struct Candidate<'tcx> {
     pub(super) result: CanonicalResponse<'tcx>,
 }
 
-/// Possible ways the given goal can be proven.
-#[derive(Debug, Clone, Copy)]
-pub(super) enum CandidateSource {
-    /// A user written impl.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn main() {
-    ///     let x: Vec<u32> = Vec::new();
-    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
-    ///     let y = x.clone();
-    /// }
-    /// ```
-    Impl(DefId),
-    /// A builtin impl generated by the compiler. When adding a new special
-    /// trait, try to use actual impls whenever possible. Builtin impls should
-    /// only be used in cases where the impl cannot be manually be written.
-    ///
-    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
-    /// For a list of all traits with builtin impls, check out the
-    /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
-    BuiltinImpl(BuiltinImplSource),
-    /// An assumption from the environment.
-    ///
-    /// More precisely we've used the `n-th` assumption in the `param_env`.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
-    ///     // This uses the assumption `T: Clone` from the `where`-bounds
-    ///     // to prove `T: Clone`.
-    ///     (x.clone(), x)
-    /// }
-    /// ```
-    ParamEnv(usize),
-    /// If the self type is an alias type, e.g. an opaque type or a projection,
-    /// we know the bounds on that alias to hold even without knowing its concrete
-    /// underlying type.
-    ///
-    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
-    /// the self type.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// trait Trait {
-    ///     type Assoc: Clone;
-    /// }
-    ///
-    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
-    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
-    ///     // in the trait definition.
-    ///     let _y = x.clone();
-    /// }
-    /// ```
-    AliasBound,
-}
-
 /// Methods used to assemble candidates for either trait or projection goals.
 pub(super) trait GoalKind<'tcx>:
     TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
@@ -399,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         let tcx = self.tcx();
         let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return };
 
-        candidates.extend(self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| {
+        candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
             if num_steps < ecx.local_overflow_limit() {
                 let normalized_ty = ecx.next_ty_infer();
                 let normalizes_to_goal = goal.with(
@@ -910,7 +852,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             SolverMode::Coherence => {}
         };
 
-        let result = self.probe_candidate("coherence unknowable").enter(|ecx| {
+        let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
             let trait_ref = goal.predicate.trait_ref(tcx);
 
             #[derive(Debug)]
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index a9d182abfb7..77c0f9f090c 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -365,6 +365,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
                 // FIXME: we should fold this ty eventually
                 CanonicalVarKind::Const(ui, c.ty())
             }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
+                bug!("effect var has no universe")
+            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
                 bug!("fresh var during canonicalization: {c:?}")
             }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 63ae83c8ef4..307c0516f70 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -237,7 +237,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<'tcx>,
         canonical_input: CanonicalInput<'tcx>,
-        goal_evaluation: &mut ProofTreeBuilder<'tcx>,
+        canonical_goal_evaluation: &mut ProofTreeBuilder<'tcx>,
         f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
     ) -> R {
         let intercrate = match search_graph.solver_mode() {
@@ -260,7 +260,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             search_graph,
             nested_goals: NestedGoals::new(),
             tainted: Ok(()),
-            inspect: goal_evaluation.new_goal_evaluation_step(input),
+            inspect: canonical_goal_evaluation.new_goal_evaluation_step(input),
         };
 
         for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
@@ -274,7 +274,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
 
         let result = f(&mut ecx, input.goal);
 
-        goal_evaluation.goal_evaluation_step(ecx.inspect);
+        canonical_goal_evaluation.goal_evaluation_step(ecx.inspect);
 
         // When creating a query response we clone the opaque type constraints
         // instead of taking them. This would cause an ICE here, since we have
@@ -302,24 +302,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<'tcx>,
         canonical_input: CanonicalInput<'tcx>,
-        mut goal_evaluation: &mut ProofTreeBuilder<'tcx>,
+        goal_evaluation: &mut ProofTreeBuilder<'tcx>,
     ) -> QueryResult<'tcx> {
-        goal_evaluation.canonicalized_goal(canonical_input);
+        let mut canonical_goal_evaluation =
+            goal_evaluation.new_canonical_goal_evaluation(canonical_input);
 
         // Deal with overflow, caching, and coinduction.
         //
         // The actual solver logic happens in `ecx.compute_goal`.
-        ensure_sufficient_stack(|| {
+        let result = ensure_sufficient_stack(|| {
             search_graph.with_new_goal(
                 tcx,
                 canonical_input,
-                goal_evaluation,
-                |search_graph, goal_evaluation| {
+                &mut canonical_goal_evaluation,
+                |search_graph, canonical_goal_evaluation| {
                     EvalCtxt::enter_canonical(
                         tcx,
                         search_graph,
                         canonical_input,
-                        goal_evaluation,
+                        canonical_goal_evaluation,
                         |ecx, goal| {
                             let result = ecx.compute_goal(goal);
                             ecx.inspect.query_result(result);
@@ -328,7 +329,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                     )
                 },
             )
-        })
+        });
+
+        canonical_goal_evaluation.query_result(result);
+        goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
+        result
     }
 
     /// Recursively evaluates `goal`, returning whether any inference vars have
@@ -347,7 +352,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             canonical_goal,
             &mut goal_evaluation,
         );
-        goal_evaluation.query_result(canonical_response);
         let canonical_response = match canonical_response {
             Err(e) => {
                 self.inspect.goal_evaluation(goal_evaluation);
@@ -916,7 +920,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             if candidate_key.def_id != key.def_id {
                 continue;
             }
-            values.extend(self.probe_candidate("opaque type storage").enter(|ecx| {
+            values.extend(self.probe_misc_candidate("opaque type storage").enter(|ecx| {
                 for (a, b) in std::iter::zip(candidate_key.args, key.args) {
                     ecx.eq(param_env, a, b)?;
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 317c43baf8f..f88cfbac3f3 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,5 +1,5 @@
 use super::EvalCtxt;
-use rustc_middle::traits::solve::{inspect, QueryResult};
+use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -10,7 +10,7 @@ pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
 
 impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T>
 where
-    F: FnOnce(&T) -> inspect::CandidateKind<'tcx>,
+    F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
 {
     pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
         let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
@@ -28,8 +28,8 @@ where
         };
         let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx));
         if !outer_ecx.inspect.is_noop() {
-            let cand_kind = probe_kind(&r);
-            nested_ecx.inspect.candidate_kind(cand_kind);
+            let probe_kind = probe_kind(&r);
+            nested_ecx.inspect.probe_kind(probe_kind);
             outer_ecx.inspect.goal_candidate(nested_ecx.inspect);
         }
         r
@@ -41,25 +41,45 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     /// as expensive as necessary to output the desired information.
     pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T>
     where
-        F: FnOnce(&T) -> inspect::CandidateKind<'tcx>,
+        F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
     {
         ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
     }
 
-    pub(in crate::solve) fn probe_candidate(
+    pub(in crate::solve) fn probe_misc_candidate(
         &mut self,
         name: &'static str,
     ) -> ProbeCtxt<
         '_,
         'a,
         'tcx,
-        impl FnOnce(&QueryResult<'tcx>) -> inspect::CandidateKind<'tcx>,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
         QueryResult<'tcx>,
     > {
         ProbeCtxt {
             ecx: self,
-            probe_kind: move |result: &QueryResult<'tcx>| inspect::CandidateKind::Candidate {
-                name: name.to_string(),
+            probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::MiscCandidate {
+                name,
+                result: *result,
+            },
+            _result: PhantomData,
+        }
+    }
+
+    pub(in crate::solve) fn probe_trait_candidate(
+        &mut self,
+        source: CandidateSource,
+    ) -> ProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
+        QueryResult<'tcx>,
+    > {
+        ProbeCtxt {
+            ecx: self,
+            probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
+                source,
                 result: *result,
             },
             _result: PhantomData,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 42d7a587cac..315df06be41 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -4,14 +4,14 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt};
 use rustc_infer::traits::{
     Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
 };
-use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
+use rustc_middle::traits::solve::{CandidateSource, CanonicalInput, Certainty, Goal};
 use rustc_middle::traits::{
     BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 
-use crate::solve::assembly::{Candidate, CandidateSource};
+use crate::solve::assembly::Candidate;
 use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
 use crate::solve::inspect::ProofTreeBuilder;
 use crate::traits::StructurallyNormalizeExt;
diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs
index cda68396321..46025da7683 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect.rs
@@ -1,5 +1,5 @@
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::inspect::{self, CacheHit, CandidateKind};
+use rustc_middle::traits::solve::inspect::{self, CacheHit, ProbeKind};
 use rustc_middle::traits::solve::{
     CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
 };
@@ -9,43 +9,60 @@ use rustc_session::config::DumpSolverProofTree;
 use super::eval_ctxt::UseGlobalCache;
 use super::GenerateProofTree;
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+#[derive(Eq, PartialEq, Debug)]
 pub struct WipGoalEvaluation<'tcx> {
     pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub canonicalized_goal: Option<CanonicalInput<'tcx>>,
-
-    pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>,
-
-    pub cache_hit: Option<CacheHit>,
+    pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>,
     pub is_normalizes_to_hack: IsNormalizesToHack,
     pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
-
-    pub result: Option<QueryResult<'tcx>>,
 }
 
 impl<'tcx> WipGoalEvaluation<'tcx> {
     pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> {
         inspect::GoalEvaluation {
             uncanonicalized_goal: self.uncanonicalized_goal,
-            canonicalized_goal: self.canonicalized_goal.unwrap(),
-            kind: match self.cache_hit {
-                Some(hit) => inspect::GoalEvaluationKind::CacheHit(hit),
-                None => inspect::GoalEvaluationKind::Uncached {
-                    revisions: self
-                        .evaluation_steps
-                        .into_iter()
-                        .map(WipGoalEvaluationStep::finalize)
-                        .collect(),
-                },
-            },
+            evaluation: self.evaluation.unwrap().finalize(),
             is_normalizes_to_hack: self.is_normalizes_to_hack,
             returned_goals: self.returned_goals,
-            result: self.result.unwrap(),
         }
     }
 }
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+#[derive(Eq, PartialEq, Debug)]
+pub enum WipGoalEvaluationKind {
+    Overflow,
+    CacheHit(CacheHit),
+}
+
+#[derive(Eq, PartialEq, Debug)]
+pub struct WipCanonicalGoalEvaluation<'tcx> {
+    pub goal: CanonicalInput<'tcx>,
+    pub kind: Option<WipGoalEvaluationKind>,
+    pub revisions: Vec<WipGoalEvaluationStep<'tcx>>,
+    pub result: Option<QueryResult<'tcx>>,
+}
+
+impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
+    pub fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
+        let kind = match self.kind {
+            Some(WipGoalEvaluationKind::Overflow) => inspect::GoalEvaluationKind::Overflow,
+            Some(WipGoalEvaluationKind::CacheHit(hit)) => {
+                inspect::GoalEvaluationKind::CacheHit(hit)
+            }
+            None => inspect::GoalEvaluationKind::Uncached {
+                revisions: self
+                    .revisions
+                    .into_iter()
+                    .map(WipGoalEvaluationStep::finalize)
+                    .collect(),
+            },
+        };
+
+        inspect::CanonicalGoalEvaluation { goal: self.goal, kind, result: self.result.unwrap() }
+    }
+}
+
+#[derive(Eq, PartialEq, Debug)]
 pub struct WipAddedGoalsEvaluation<'tcx> {
     pub evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>,
     pub result: Option<Result<Certainty, NoSolution>>,
@@ -66,43 +83,36 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+#[derive(Eq, PartialEq, Debug)]
 pub struct WipGoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
-    pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<WipGoalCandidate<'tcx>>,
-
-    pub result: Option<QueryResult<'tcx>>,
+    pub evaluation: WipGoalCandidate<'tcx>,
 }
 
 impl<'tcx> WipGoalEvaluationStep<'tcx> {
     pub fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> {
-        inspect::GoalEvaluationStep {
-            instantiated_goal: self.instantiated_goal,
-            nested_goal_evaluations: self
-                .nested_goal_evaluations
-                .into_iter()
-                .map(WipAddedGoalsEvaluation::finalize)
-                .collect(),
-            candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(),
-            result: self.result.unwrap(),
+        let evaluation = self.evaluation.finalize();
+        match evaluation.kind {
+            ProbeKind::Root { .. } => (),
+            _ => unreachable!("unexpected root evaluation: {evaluation:?}"),
         }
+        inspect::GoalEvaluationStep { instantiated_goal: self.instantiated_goal, evaluation }
     }
 }
 
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+#[derive(Eq, PartialEq, Debug)]
 pub struct WipGoalCandidate<'tcx> {
-    pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>,
+    pub added_goals_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>,
     pub candidates: Vec<WipGoalCandidate<'tcx>>,
-    pub kind: Option<CandidateKind<'tcx>>,
+    pub kind: Option<ProbeKind<'tcx>>,
 }
 
 impl<'tcx> WipGoalCandidate<'tcx> {
     pub fn finalize(self) -> inspect::GoalCandidate<'tcx> {
         inspect::GoalCandidate {
-            nested_goal_evaluations: self
-                .nested_goal_evaluations
+            added_goals_evaluations: self
+                .added_goals_evaluations
                 .into_iter()
                 .map(WipAddedGoalsEvaluation::finalize)
                 .collect(),
@@ -116,6 +126,7 @@ impl<'tcx> WipGoalCandidate<'tcx> {
 pub enum DebugSolver<'tcx> {
     Root,
     GoalEvaluation(WipGoalEvaluation<'tcx>),
+    CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>),
     AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>),
     GoalEvaluationStep(WipGoalEvaluationStep<'tcx>),
     GoalCandidate(WipGoalCandidate<'tcx>),
@@ -127,6 +138,12 @@ impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
     }
 }
 
+impl<'tcx> From<WipCanonicalGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
+    fn from(g: WipCanonicalGoalEvaluation<'tcx>) -> DebugSolver<'tcx> {
+        DebugSolver::CanonicalGoalEvaluation(g)
+    }
+}
+
 impl<'tcx> From<WipAddedGoalsEvaluation<'tcx>> for DebugSolver<'tcx> {
     fn from(g: WipAddedGoalsEvaluation<'tcx>) -> DebugSolver<'tcx> {
         DebugSolver::AddedGoalsEvaluation(g)
@@ -164,11 +181,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    fn nested(&self, state: impl Into<DebugSolver<'tcx>>) -> Self {
+    fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self {
         match &self.state {
             Some(prev_state) => Self {
                 state: Some(Box::new(BuilderData {
-                    tree: state.into(),
+                    tree: state().into(),
                     use_global_cache: prev_state.use_global_cache,
                 })),
             },
@@ -237,37 +254,43 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
         is_normalizes_to_hack: IsNormalizesToHack,
     ) -> ProofTreeBuilder<'tcx> {
-        if self.state.is_none() {
-            return ProofTreeBuilder { state: None };
-        }
-
-        self.nested(WipGoalEvaluation {
+        self.nested(|| WipGoalEvaluation {
             uncanonicalized_goal: goal,
-            canonicalized_goal: None,
-            evaluation_steps: vec![],
+            evaluation: None,
             is_normalizes_to_hack,
-            cache_hit: None,
             returned_goals: vec![],
+        })
+    }
+
+    pub fn new_canonical_goal_evaluation(
+        &mut self,
+        goal: CanonicalInput<'tcx>,
+    ) -> ProofTreeBuilder<'tcx> {
+        self.nested(|| WipCanonicalGoalEvaluation {
+            goal,
+            kind: None,
+            revisions: vec![],
             result: None,
         })
     }
 
-    pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) {
+    pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) {
         if let Some(this) = self.as_mut() {
-            match this {
-                DebugSolver::GoalEvaluation(goal_evaluation) => {
-                    assert_eq!(goal_evaluation.canonicalized_goal.replace(canonical_goal), None);
-                }
+            match (this, canonical_goal_evaluation.state.unwrap().tree) {
+                (
+                    DebugSolver::GoalEvaluation(goal_evaluation),
+                    DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation),
+                ) => goal_evaluation.evaluation = Some(canonical_goal_evaluation),
                 _ => unreachable!(),
             }
         }
     }
 
-    pub fn cache_hit(&mut self, cache_hit: CacheHit) {
+    pub fn goal_evaluation_kind(&mut self, kind: WipGoalEvaluationKind) {
         if let Some(this) = self.as_mut() {
             match this {
-                DebugSolver::GoalEvaluation(goal_evaluation) => {
-                    assert_eq!(goal_evaluation.cache_hit.replace(cache_hit), None);
+                DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
+                    assert_eq!(canonical_goal_evaluation.kind.replace(kind), None);
                 }
                 _ => unreachable!(),
             };
@@ -304,22 +327,23 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         &mut self,
         instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
     ) -> ProofTreeBuilder<'tcx> {
-        if self.state.is_none() {
-            return ProofTreeBuilder { state: None };
-        }
-
-        self.nested(WipGoalEvaluationStep {
+        self.nested(|| WipGoalEvaluationStep {
             instantiated_goal,
-            nested_goal_evaluations: vec![],
-            candidates: vec![],
-            result: None,
+            evaluation: WipGoalCandidate {
+                added_goals_evaluations: vec![],
+                candidates: vec![],
+                kind: None,
+            },
         })
     }
-    pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) {
+    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
         if let Some(this) = self.as_mut() {
-            match (this, goal_eval_step.state.unwrap().tree) {
-                (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => {
-                    goal_eval.evaluation_steps.push(step);
+            match (this, goal_evaluation_step.state.unwrap().tree) {
+                (
+                    DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations),
+                    DebugSolver::GoalEvaluationStep(goal_evaluation_step),
+                ) => {
+                    canonical_goal_evaluations.revisions.push(goal_evaluation_step);
                 }
                 _ => unreachable!(),
             }
@@ -327,22 +351,18 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     }
 
     pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> {
-        if self.state.is_none() {
-            return ProofTreeBuilder { state: None };
-        }
-
-        self.nested(WipGoalCandidate {
-            nested_goal_evaluations: vec![],
+        self.nested(|| WipGoalCandidate {
+            added_goals_evaluations: vec![],
             candidates: vec![],
             kind: None,
         })
     }
 
-    pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) {
+    pub fn probe_kind(&mut self, probe_kind: ProbeKind<'tcx>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::GoalCandidate(this) => {
-                    assert_eq!(this.kind.replace(candidate_kind), None)
+                    assert_eq!(this.kind.replace(probe_kind), None)
                 }
                 _ => unreachable!(),
             }
@@ -354,7 +374,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
             match (this, candidate.state.unwrap().tree) {
                 (
                     DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. })
-                    | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }),
+                    | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
+                        evaluation: WipGoalCandidate { candidates, .. },
+                        ..
+                    }),
                     DebugSolver::GoalCandidate(candidate),
                 ) => candidates.push(candidate),
                 _ => unreachable!(),
@@ -363,11 +386,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     }
 
     pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
-        if self.state.is_none() {
-            return ProofTreeBuilder { state: None };
-        }
-
-        self.nested(WipAddedGoalsEvaluation { evaluations: vec![], result: None })
+        self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None })
     }
 
     pub fn evaluate_added_goals_loop_start(&mut self) {
@@ -392,19 +411,19 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) {
+    pub fn added_goals_evaluation(&mut self, added_goals_evaluation: ProofTreeBuilder<'tcx>) {
         if let Some(this) = self.as_mut() {
-            match (this, goals_evaluation.state.unwrap().tree) {
+            match (this, added_goals_evaluation.state.unwrap().tree) {
                 (
                     DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
-                        nested_goal_evaluations,
+                        evaluation: WipGoalCandidate { added_goals_evaluations, .. },
                         ..
                     })
                     | DebugSolver::GoalCandidate(WipGoalCandidate {
-                        nested_goal_evaluations, ..
+                        added_goals_evaluations, ..
                     }),
                     DebugSolver::AddedGoalsEvaluation(added_goals_evaluation),
-                ) => nested_goal_evaluations.push(added_goals_evaluation),
+                ) => added_goals_evaluations.push(added_goals_evaluation),
                 _ => unreachable!(),
             }
         }
@@ -413,15 +432,16 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     pub fn query_result(&mut self, result: QueryResult<'tcx>) {
         if let Some(this) = self.as_mut() {
             match this {
-                DebugSolver::GoalEvaluation(goal_evaluation) => {
-                    assert_eq!(goal_evaluation.result.replace(result), None);
+                DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
+                    assert_eq!(canonical_goal_evaluation.result.replace(result), None);
                 }
                 DebugSolver::GoalEvaluationStep(evaluation_step) => {
-                    assert_eq!(evaluation_step.result.replace(result), None);
+                    assert_eq!(
+                        evaluation_step.evaluation.kind.replace(ProbeKind::Root { result }),
+                        None
+                    );
                 }
-                DebugSolver::Root
-                | DebugSolver::AddedGoalsEvaluation(_)
-                | DebugSolver::GoalCandidate(_) => unreachable!(),
+                _ => unreachable!(),
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 75a99f799a2..c492408bc76 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -233,9 +233,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
     #[instrument(level = "debug", skip(self, goals))]
     fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
-        let current_len = self.nested_goals.goals.len();
-        self.nested_goals.goals.extend(goals);
-        debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]);
+        for goal in goals {
+            self.add_goal(goal);
+        }
     }
 
     /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index df094af4f1f..3fe914e50be 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -8,8 +8,9 @@ use rustc_hir::LangItem;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
-use rustc_middle::traits::solve::inspect::CandidateKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{
+    CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
+};
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::ProjectionPredicate;
@@ -113,7 +114,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
                 let tcx = ecx.tcx();
-                ecx.probe_candidate("assumption").enter(|ecx| {
+                ecx.probe_misc_candidate("assumption").enter(|ecx| {
                     let assumption_projection_pred =
                         ecx.instantiate_binder_with_infer(projection_pred);
                     ecx.eq(
@@ -155,7 +156,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| {
+        ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
             let impl_args = ecx.fresh_args_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
 
@@ -369,7 +370,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        ecx.probe_candidate("builtin pointee").enter(|ecx| {
+        ecx.probe_misc_candidate("builtin pointee").enter(|ecx| {
             let metadata_ty = match goal.predicate.self_ty().kind() {
                 ty::Bool
                 | ty::Char
@@ -578,7 +579,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             ),
         };
 
-        ecx.probe_candidate("builtin discriminant kind").enter(|ecx| {
+        ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| {
             ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())
                 .expect("expected goal term to be fully unconstrained");
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 52a11abd545..c816b51f67a 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -1,6 +1,7 @@
 mod cache;
 
 use self::cache::ProvisionalEntry;
+use super::inspect;
 use super::inspect::ProofTreeBuilder;
 use super::SolverMode;
 use cache::ProvisionalCache;
@@ -185,6 +186,8 @@ impl<'tcx> SearchGraph<'tcx> {
             if let Some(last) = self.stack.raw.last_mut() {
                 last.encountered_overflow = true;
             }
+
+            inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::Overflow);
             return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
         };
 
@@ -200,6 +203,9 @@ impl<'tcx> SearchGraph<'tcx> {
                     available_depth,
                 )
             {
+                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                    CacheHit::Global,
+                ));
                 self.on_cache_hit(reached_depth, encountered_overflow);
                 return result;
             }
@@ -234,7 +240,9 @@ impl<'tcx> SearchGraph<'tcx> {
             // Finally we can return either the provisional response for that goal if we have a
             // coinductive cycle or an ambiguous result if the cycle is inductive.
             Entry::Occupied(entry_index) => {
-                inspect.cache_hit(CacheHit::Provisional);
+                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                    CacheHit::Provisional,
+                ));
 
                 let entry_index = *entry_index.get();
                 let stack_depth = cache.depth(entry_index);
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 8685f3100a8..f18eed94a68 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -5,7 +5,7 @@ use super::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::traits::solve::inspect::CandidateKind;
+use rustc_middle::traits::solve::inspect::ProbeKind;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
 use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
@@ -61,7 +61,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             },
         };
 
-        ecx.probe_candidate("impl").enter(|ecx| {
+        ecx.probe_misc_candidate("impl").enter(|ecx| {
             let impl_args = ecx.fresh_args_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
 
@@ -96,7 +96,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 && trait_clause.polarity() == goal.predicate.polarity
             {
                 // FIXME: Constness
-                ecx.probe_candidate("assumption").enter(|ecx| {
+                ecx.probe_misc_candidate("assumption").enter(|ecx| {
                     let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
                     ecx.eq(
                         goal.param_env,
@@ -167,7 +167,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
         let tcx = ecx.tcx();
 
-        ecx.probe_candidate("trait alias").enter(|ecx| {
+        ecx.probe_misc_candidate("trait alias").enter(|ecx| {
             let nested_obligations = tcx
                 .predicates_of(goal.predicate.def_id())
                 .instantiate(tcx, goal.predicate.trait_ref.args);
@@ -427,7 +427,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.probe(|_| CandidateKind::UnsizeAssembly).enter(|ecx| {
+        ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
             let a_ty = goal.predicate.self_ty();
             // We need to normalize the b_ty since it's destructured as a `dyn Trait`.
             let Some(b_ty) =
@@ -491,7 +491,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             Err(NoSolution) => vec![],
         };
 
-        ecx.probe(|_| CandidateKind::UnsizeAssembly).enter(|ecx| {
+        ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
             let a_ty = goal.predicate.self_ty();
             // We need to normalize the b_ty since it's matched structurally
             // in the other functions below.
@@ -597,7 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             self.walk_vtable(
                 a_principal.with_self_ty(tcx, a_ty),
                 |ecx, new_a_principal, _, vtable_vptr_slot| {
-                    if let Ok(resp) = ecx.probe_candidate("dyn upcast").enter(|ecx| {
+                    if let Ok(resp) = ecx.probe_misc_candidate("dyn upcast").enter(|ecx| {
                         ecx.consider_builtin_upcast_to_principal(
                             goal,
                             a_data,
@@ -640,7 +640,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
              target_projection: ty::PolyExistentialProjection<'tcx>| {
                 source_projection.item_def_id() == target_projection.item_def_id()
                     && ecx
-                        .probe(|_| CandidateKind::UpcastProbe)
+                        .probe(|_| ProbeKind::UpcastProjectionCompatibility)
                         .enter(|ecx| -> Result<(), NoSolution> {
                             ecx.eq(param_env, source_projection, target_projection)?;
                             let _ = ecx.try_evaluate_added_goals()?;
@@ -918,7 +918,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
     ) -> QueryResult<'tcx> {
-        self.probe_candidate("constituent tys").enter(|ecx| {
+        self.probe_misc_candidate("constituent tys").enter(|ecx| {
             ecx.add_goals(
                 constituent_tys(ecx, goal.predicate.self_ty())?
                     .into_iter()
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 746a38f956a..135410691f1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2054,7 +2054,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     tcx: self.tcx,
                     ty_op: |ty| ty,
                     lt_op: |lt| lt,
-                    ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()),
+                    ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
                 });
                 cand
             })
@@ -3009,10 +3009,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // Try to report a help message
         if is_fn_trait
             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
-            obligation.param_env,
-            trait_ref.self_ty(),
-            trait_predicate.skip_binder().polarity,
-        )
+                obligation.param_env,
+                trait_ref.self_ty(),
+                trait_predicate.skip_binder().polarity,
+            )
         {
             self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
         } else if !trait_ref.has_non_region_infer()
@@ -3031,6 +3031,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 None,
                 obligation.cause.body_id,
             );
+        } else if trait_ref.def_id().is_local()
+            && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
+            && !self.tcx.trait_is_auto(trait_ref.def_id())
+            && !self.tcx.trait_is_alias(trait_ref.def_id())
+        {
+            err.span_help(
+                self.tcx.def_span(trait_ref.def_id()),
+                crate::fluent_generated::trait_selection_trait_has_no_impls,
+            );
         } else if !suggested && !unsatisfied_const {
             // Can't show anything else useful, try to find similar impls.
             let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
@@ -3041,7 +3050,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 err,
                 true,
             ) {
-                self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+                self.report_similar_impl_candidates_for_root_obligation(
+                    &obligation,
+                    *trait_predicate,
+                    body_def_id,
+                    err,
+                );
             }
 
             self.suggest_convert_to_slice(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 0e73bad1918..fe71a9f07df 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -257,7 +257,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_string())));
-                let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
+                let len = len.try_to_valtree().and_then(|v| v.try_to_target_usize(self.tcx));
                 flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
                 if let Some(n) = len {
                     flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
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 32fb10ce4a6..d6ac7208715 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1805,7 +1805,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         );
                     } else {
                         err.note(format!(
-                            "`{}` is implemented for `{:?}`, but not for `{:?}`",
+                            "`{}` is implemented for `{}`, but not for `{}`",
                             trait_pred.print_modifiers_and_trait_path(),
                             suggested_ty,
                             trait_pred.skip_binder().self_ty(),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 3ebf1246a41..f1779451bc5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,6 +6,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::GenericArgsRef;
@@ -623,9 +624,27 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     }
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
-                ty::PredicateKind::AliasRelate(..) => {
-                    bug!("AliasRelate is only used for new solver")
+                ty::PredicateKind::AliasRelate(..)
+                    if matches!(self.selcx.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
+                {
+                    ProcessResult::Unchanged
                 }
+                ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
+                    ty::AliasRelationDirection::Equate => match self
+                        .selcx
+                        .infcx
+                        .at(&obligation.cause, obligation.param_env)
+                        .eq(DefineOpaqueTypes::Yes, a, b)
+                    {
+                        Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
+                        Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
+                            SelectionError::Unimplemented,
+                        )),
+                    },
+                    ty::AliasRelationDirection::Subtype => {
+                        bug!("AliasRelate with subtyping is only used for new solver")
+                    }
+                },
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
                         DefineOpaqueTypes::No,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d2210c6d5d9..956f8e047d7 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -288,7 +288,7 @@ pub fn normalize_param_env_or_error<'tcx>(
                     // should actually be okay since without `feature(generic_const_exprs)` the only
                     // const arguments that have a non-empty param env are array repeat counts. These
                     // do not appear in the type system though.
-                    c.eval(self.0, ty::ParamEnv::empty())
+                    c.normalize(self.0, ty::ParamEnv::empty())
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b31c0e655fb..6444c01a67b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -761,7 +761,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 self.selcx.infcx,
                 &mut self.universes,
                 constant,
-                |constant| constant.eval(tcx, self.param_env),
+                |constant| constant.normalize(tcx, self.param_env),
             )
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 87beaddc6c2..f785211c548 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -358,7 +358,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
             self.infcx,
             &mut self.universes,
             constant,
-            |constant| constant.eval(self.infcx.tcx, self.param_env),
+            |constant| constant.normalize(self.infcx.tcx, self.param_env),
         ))
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7e4d926dc8d..0d84fee8309 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -37,6 +37,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::relate::TypeRelation;
@@ -1000,9 +1001,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
                     }
                 }
-                ty::PredicateKind::AliasRelate(..) => {
-                    bug!("AliasRelate is only used for new solver")
+                ty::PredicateKind::AliasRelate(..)
+                    if matches!(self.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
+                {
+                    Ok(EvaluatedToAmbig)
                 }
+                ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
+                    ty::AliasRelationDirection::Equate => match self
+                        .infcx
+                        .at(&obligation.cause, obligation.param_env)
+                        .eq(DefineOpaqueTypes::Yes, a, b)
+                    {
+                        Ok(inf_ok) => self.evaluate_predicates_recursively(
+                            previous_stack,
+                            inf_ok.into_obligations(),
+                        ),
+                        Err(_) => Ok(EvaluatedToErr),
+                    },
+                    ty::AliasRelationDirection::Subtype => {
+                        bug!("AliasRelate subtyping is only used for new solver")
+                    }
+                },
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.infcx.at(&obligation.cause, obligation.param_env).eq(
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index af2ad547480..6c49e94dc31 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -129,19 +129,16 @@ mod rustc {
             c: Const<'tcx>,
         ) -> Option<Self> {
             use rustc_middle::ty::ScalarInt;
-            use rustc_middle::ty::TypeVisitableExt;
             use rustc_span::symbol::sym;
 
-            let c = c.eval(tcx, param_env);
-
-            if let Err(err) = c.error_reported() {
+            let Ok(cv) = c.eval(tcx, param_env, None) else {
                 return Some(Self {
                     alignment: true,
                     lifetimes: true,
                     safety: true,
                     validity: true,
                 });
-            }
+            };
 
             let adt_def = c.ty().ty_adt_def()?;
 
@@ -153,8 +150,8 @@ mod rustc {
             );
 
             let variant = adt_def.non_enum_variant();
-            let fields = match c.try_to_valtree() {
-                Some(ValTree::Branch(branch)) => branch,
+            let fields = match cv {
+                ValTree::Branch(branch) => branch,
                 _ => {
                     return Some(Self {
                         alignment: true,
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 3ffe670d87a..16183403d67 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -588,19 +588,11 @@ fn make_thin_self_ptr<'tcx>(
         // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
         // get a built-in pointer type
         let mut fat_pointer_layout = layout;
-        'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
-            && !fat_pointer_layout.ty.is_ref()
-        {
-            for i in 0..fat_pointer_layout.fields.count() {
-                let field_layout = fat_pointer_layout.field(cx, i);
-
-                if !field_layout.is_1zst() {
-                    fat_pointer_layout = field_layout;
-                    continue 'descend_newtypes;
-                }
-            }
-
-            bug!("receiver has no non-1-ZST fields {:?}", fat_pointer_layout);
+        while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() {
+            fat_pointer_layout = fat_pointer_layout
+                .non_1zst_field(cx)
+                .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
+                .1
         }
 
         fat_pointer_layout.ty
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index ed7b3496894..904f1b38740 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -7,6 +7,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
     self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt,
 };
@@ -937,7 +938,7 @@ fn record_layout_for_printing_outlined<'tcx>(
 
     // (delay format until we actually need it)
     let record = |kind, packed, opt_discr_size, variants| {
-        let type_desc = format!("{:?}", layout.ty);
+        let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty));
         cx.tcx.sess.code_stats.record_type_size(
             kind,
             type_desc,
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 371c6119122..e7a6831f5ee 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -11,7 +11,7 @@
 //! modification. These are the ones containing the most important type-related
 //! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
 //!
-//! There are three groups of traits involved in each traversal.
+//! There are three traits involved in each traversal.
 //! - `TypeFoldable`. This is implemented once for many types, including:
 //!   - Types of interest, for which the methods delegate to the folder.
 //!   - All other types, including generic containers like `Vec` and `Option`.
@@ -51,6 +51,12 @@ use crate::{visit::TypeVisitable, Interner};
 ///
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
+///
+/// This trait is a sub-trait of `TypeVisitable`. This is because many
+/// `TypeFolder` instances use the methods in `TypeVisitableExt` while folding,
+/// which means in practice almost every foldable type needs to also be
+/// visitable. (However, there are some types that are visitable without being
+/// foldable.)
 pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
     /// The entry point for folding. To fold a value `t` with a folder `f`
     /// call: `t.try_fold_with(f)`.
@@ -58,7 +64,7 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
     /// For most types, this just traverses the value, calling `try_fold_with`
     /// on each field/element.
     ///
-    /// For types of interest (such as `Ty`), the implementation of method
+    /// For types of interest (such as `Ty`), the implementation of this method
     /// calls a folder method specifically for that type (such as
     /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
     /// to `TypeFolder`.
@@ -121,7 +127,7 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> {
     }
 
     // The default region folder is a no-op because `Region` is non-recursive
-    // and has no `super_visit_with` method to call. That also explains the
+    // and has no `super_fold_with` method to call. That also explains the
     // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         r
@@ -170,7 +176,7 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
     }
 
     // The default region folder is a no-op because `Region` is non-recursive
-    // and has no `super_visit_with` method to call. That also explains the
+    // and has no `super_fold_with` method to call. That also explains the
     // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
     fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
         Ok(r)
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 878c7aec6c1..891a4dda22f 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -8,7 +8,7 @@
 //! visitation. These are the ones containing the most important type-related
 //! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
 //!
-//! There are three groups of traits involved in each traversal.
+//! There are three traits involved in each traversal.
 //! - `TypeVisitable`. This is implemented once for many types, including:
 //!   - Types of interest, for which the methods delegate to the visitor.
 //!   - All other types, including generic containers like `Vec` and `Option`.
@@ -17,7 +17,6 @@
 //!   interest, and defines the visiting "skeleton" for these types. (This
 //!   excludes `Region` because it is non-recursive, i.e. it never contains
 //!   other types of interest.)
-//!
 //! - `TypeVisitor`. This is implemented for each visitor. This defines how
 //!   types of interest are visited.
 //!
@@ -60,7 +59,7 @@ pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone {
     ///
     /// For types of interest (such as `Ty`), the implementation of this method
     /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+    /// `V::visit_ty`). This is where control transfers from `TypeVisitable` to
     /// `TypeVisitor`.
     fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
 }
diff --git a/config.example.toml b/config.example.toml
index 5c4bee87553..2e0558c3f1b 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -294,9 +294,11 @@ changelog-seen = 2
 
 # Enable a build of the extended Rust tool set which is not only the compiler
 # but also tools such as Cargo. This will also produce "combined installers"
-# which are used to install Rust and Cargo together. This is disabled by
-# default. The `tools` option (immediately below) specifies which tools should
-# be built if `extended = true`.
+# which are used to install Rust and Cargo together.
+# The `tools` (check `config.example.toml` to see its default value) option specifies
+# which tools should be built if `extended = true`.
+#
+# This is disabled by default.
 #extended = false
 
 # Set of tools to be included in the installation.
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 3c127efb390..6d5133646b5 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -289,7 +289,8 @@ pub trait Eq: PartialEq<Self> {
     //
     // This should never be implemented by hand.
     #[doc(hidden)]
-    #[no_coverage] // rust-lang/rust#84605
+    #[cfg_attr(bootstrap, no_coverage)] // rust-lang/rust#84605
+    #[cfg_attr(not(bootstrap), coverage(off))] //
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn assert_receiver_is_total_eq(&self) {}
@@ -298,7 +299,9 @@ pub trait Eq: PartialEq<Self> {
 /// Derive macro generating an impl of the trait [`Eq`].
 #[rustc_builtin_macro]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)]
+#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)]
+#[cfg_attr(bootstrap, allow_internal_unstable(no_coverage))]
+#[cfg_attr(not(bootstrap), allow_internal_unstable(coverage_attribute))]
 pub macro Eq($item:item) {
     /* compiler built-in */
 }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index c3edd3a9d7d..7c08d1703cc 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -110,6 +110,8 @@
 //
 // Library features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(no_coverage))] // rust-lang/rust#84605
+#![cfg_attr(not(bootstrap), feature(coverage_attribute))] // rust-lang/rust#84605
 #![feature(char_indices_offset)]
 #![feature(const_align_of_val)]
 #![feature(const_align_of_val_raw)]
@@ -235,7 +237,6 @@
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(no_core)]
-#![feature(no_coverage)] // rust-lang/rust#84605
 #![feature(platform_intrinsics)]
 #![feature(prelude_import)]
 #![feature(repr_simd)]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 7380b45b00f..762a1e9b408 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1501,6 +1501,66 @@ impl From<fs::File> for Stdio {
     }
 }
 
+#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")]
+impl From<io::Stdout> for Stdio {
+    /// Redirect command stdout/stderr to our stdout
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(exit_status_error)]
+    /// use std::io;
+    /// use std::process::Command;
+    ///
+    /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+    /// let output = Command::new("whoami")
+    // "whoami" is a command which exists on both Unix and Windows,
+    // and which succeeds, producing some stdout output but no stderr.
+    ///     .stdout(io::stdout())
+    ///     .output()?;
+    /// output.status.exit_ok()?;
+    /// assert!(output.stdout.is_empty());
+    /// # Ok(())
+    /// # }
+    /// #
+    /// # if cfg!(unix) {
+    /// #     test().unwrap();
+    /// # }
+    /// ```
+    fn from(inherit: io::Stdout) -> Stdio {
+        Stdio::from_inner(inherit.into())
+    }
+}
+
+#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")]
+impl From<io::Stderr> for Stdio {
+    /// Redirect command stdout/stderr to our stderr
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(exit_status_error)]
+    /// use std::io;
+    /// use std::process::Command;
+    ///
+    /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+    /// let output = Command::new("whoami")
+    ///     .stdout(io::stderr())
+    ///     .output()?;
+    /// output.status.exit_ok()?;
+    /// assert!(output.stdout.is_empty());
+    /// # Ok(())
+    /// # }
+    /// #
+    /// # if cfg!(unix) {
+    /// #     test().unwrap();
+    /// # }
+    /// ```
+    fn from(inherit: io::Stderr) -> Stdio {
+        Stdio::from_inner(inherit.into())
+    }
+}
+
 /// Describes the result of a process after it has terminated.
 ///
 /// This `struct` is used to represent the exit status or other termination of a child process.
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index ade8c75a657..48f163b6db0 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -102,7 +102,7 @@ impl Socket {
         }
     }
 
-    #[cfg(not(target_os = "vxworks"))]
+    #[cfg(not(any(target_os = "vxworks", target_os = "vita")))]
     pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
         unsafe {
             let mut fds = [0, 0];
@@ -133,7 +133,7 @@ impl Socket {
         }
     }
 
-    #[cfg(target_os = "vxworks")]
+    #[cfg(any(target_os = "vxworks", target_os = "vita"))]
     pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
         unimplemented!()
     }
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index e7d1533f122..f729da44774 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -13,7 +13,7 @@ use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::IntoInner;
+use crate::sys_common::{FromInner, IntoInner};
 
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
@@ -150,6 +150,7 @@ pub enum Stdio {
     Null,
     MakePipe,
     Fd(FileDesc),
+    StaticFd(BorrowedFd<'static>),
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -463,6 +464,11 @@ impl Stdio {
                 }
             }
 
+            Stdio::StaticFd(fd) => {
+                let fd = FileDesc::from_inner(fd.try_clone_to_owned()?);
+                Ok((ChildStdio::Owned(fd), None))
+            }
+
             Stdio::MakePipe => {
                 let (reader, writer) = pipe::anon_pipe()?;
                 let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
@@ -497,6 +503,28 @@ impl From<File> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        // This ought really to be is Stdio::StaticFd(input_argument.as_fd()).
+        // But AsFd::as_fd takes its argument by reference, and yields
+        // a bounded lifetime, so it's no use here. There is no AsStaticFd.
+        //
+        // Additionally AsFd is only implemented for the *locked* versions.
+        // We don't want to lock them here.  (The implications of not locking
+        // are the same as those for process::Stdio::inherit().)
+        //
+        // Arguably the hypothetical AsStaticFd and AsFd<'static>
+        // should be implemented for io::Stdout, not just for StdoutLocked.
+        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) })
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) })
+    }
+}
+
 impl ChildStdio {
     pub fn fd(&self) -> Option<c_int> {
         match *self {
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 4f2d9cf3655..7c242d4d334 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -182,6 +182,9 @@ impl Thread {
         }
 
         if let Some(f) = pthread_setname_np.get() {
+            #[cfg(target_os = "nto")]
+            let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name);
+
             let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
             debug_assert_eq!(res, 0);
         }
@@ -290,6 +293,7 @@ impl Drop for Thread {
     target_os = "ios",
     target_os = "tvos",
     target_os = "watchos",
+    target_os = "nto",
 ))]
 fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
     let mut result = [0; MAX_WITH_NUL];
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 77b675aaa4e..a639afcc674 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -27,6 +27,8 @@ pub struct StdioPipes {
     pub stderr: Option<AnonPipe>,
 }
 
+// FIXME: This should be a unit struct, so we can always construct it
+// The value here should be never used, since we cannot spawn processes.
 pub enum Stdio {
     Inherit,
     Null,
@@ -87,8 +89,26 @@ impl From<AnonPipe> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
 impl From<File> for Stdio {
     fn from(_file: File) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
         panic!("unsupported")
     }
 }
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 84a75d21305..cd5bf7f1538 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -172,6 +172,7 @@ pub struct Command {
 
 pub enum Stdio {
     Inherit,
+    InheritSpecific { from_stdio_id: c::DWORD },
     Null,
     MakePipe,
     Pipe(AnonPipe),
@@ -555,17 +556,19 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> {
 
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
-        match *self {
-            Stdio::Inherit => match stdio::get_handle(stdio_id) {
-                Ok(io) => unsafe {
-                    let io = Handle::from_raw_handle(io);
-                    let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
-                    io.into_raw_handle();
-                    ret
-                },
-                // If no stdio handle is available, then propagate the null value.
-                Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+        let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) {
+            Ok(io) => unsafe {
+                let io = Handle::from_raw_handle(io);
+                let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
+                io.into_raw_handle();
+                ret
             },
+            // If no stdio handle is available, then propagate the null value.
+            Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+        };
+        match *self {
+            Stdio::Inherit => use_stdio_id(stdio_id),
+            Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id),
 
             Stdio::MakePipe => {
                 let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
@@ -613,6 +616,18 @@ impl From<File> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE }
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Processes
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index c62548875bf..91fa5ec6633 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -737,6 +737,7 @@ impl<'a> Builder<'a> {
                 test::Incremental,
                 test::Debuginfo,
                 test::UiFullDeps,
+                test::CodegenCranelift,
                 test::Rustdoc,
                 test::RunCoverageRustdoc,
                 test::Pretty,
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index d658be0b8eb..11f2762f766 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -127,8 +127,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         Err(_) => false,
     };
 
-    let mut paths = paths.to_vec();
-
     if git_available {
         let in_working_tree = match build
             .config
@@ -201,8 +199,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                             "WARN: Something went wrong when running git commands:\n{err}\n\
                             Falling back to formatting all files."
                         );
-                        // Something went wrong when getting the version. Just format all the files.
-                        paths.push(".".into());
                     }
                 }
             }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index d78e0deda69..35e2e98e08e 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -2967,3 +2967,129 @@ impl Step for TestHelpers {
             .compile("rust_test_helpers");
     }
 }
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CodegenCranelift {
+    compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl Step for CodegenCranelift {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.paths(&["compiler/rustc_codegen_cranelift"])
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        let builder = run.builder;
+        let host = run.build_triple();
+        let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
+
+        if builder.doc_tests == DocTests::Only {
+            return;
+        }
+
+        let triple = run.target.triple;
+        let target_supported = if triple.contains("linux") {
+            triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x")
+        } else if triple.contains("darwin") || triple.contains("windows") {
+            triple.contains("x86_64")
+        } else {
+            false
+        };
+        if !target_supported {
+            builder.info("target not supported by rustc_codegen_cranelift. skipping");
+            return;
+        }
+
+        if builder.remote_tested(run.target) {
+            builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
+            return;
+        }
+
+        if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) {
+            builder.info("cranelift not in rust.codegen-backends. skipping");
+            return;
+        }
+
+        builder.ensure(CodegenCranelift { compiler, target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let compiler = self.compiler;
+        let target = self.target;
+
+        builder.ensure(compile::Std::new(compiler, target));
+
+        // If we're not doing a full bootstrap but we're testing a stage2
+        // version of libstd, then what we're actually testing is the libstd
+        // produced in stage1. Reflect that here by updating the compiler that
+        // we're working with automatically.
+        let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
+
+        let build_cargo = || {
+            let mut cargo = builder.cargo(
+                compiler,
+                Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
+                SourceType::InTree,
+                target,
+                "run",
+            );
+            cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
+            cargo
+                .arg("--manifest-path")
+                .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
+            compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
+
+            // Avoid incremental cache issues when changing rustc
+            cargo.env("CARGO_BUILD_INCREMENTAL", "false");
+
+            cargo
+        };
+
+        builder.info(&format!(
+            "{} cranelift stage{} ({} -> {})",
+            Kind::Test.description(),
+            compiler.stage,
+            &compiler.host,
+            target
+        ));
+        let _time = util::timeit(&builder);
+
+        // FIXME handle vendoring for source tarballs before removing the --skip-test below
+        let download_dir = builder.out.join("cg_clif_download");
+
+        /*
+        let mut prepare_cargo = build_cargo();
+        prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir);
+        #[allow(deprecated)]
+        builder.config.try_run(&mut prepare_cargo.into()).unwrap();
+        */
+
+        let mut cargo = build_cargo();
+        cargo
+            .arg("--")
+            .arg("test")
+            .arg("--download-dir")
+            .arg(&download_dir)
+            .arg("--out-dir")
+            .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif"))
+            .arg("--no-unstable-features")
+            .arg("--use-backend")
+            .arg("cranelift")
+            // Avoid having to vendor the standard library dependencies
+            .arg("--sysroot")
+            .arg("llvm")
+            // These tests depend on crates that are not yet vendored
+            // FIXME remove once vendoring is handled
+            .arg("--skip-test")
+            .arg("testsuite.extended_sysroot");
+        cargo.args(builder.config.test_args());
+
+        #[allow(deprecated)]
+        builder.config.try_run(&mut cargo.into()).unwrap();
+    }
+}
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b8cb758bf40..98f2cdac5dc 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -123,6 +123,9 @@ else
 
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
 
+  # Test the Cranelift backend in on CI, but don't ship it.
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift"
+
   # We enable this for non-dist builders, since those aren't trying to produce
   # fresh binaries. We currently don't entirely support distributing a fresh
   # copy of the compiler (including llvm tools, etc.) if we haven't actually
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 2751bdcef125468ea2ee006c11992cd1405aebe
+Subproject 34fca48ed284525b2f124bf93c51af36d668549
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 388750b081c0893c275044d37203f97709e058b
+Subproject e3f3af69dce71cd37a785bccb7e58449197d940
diff --git a/src/doc/reference b/src/doc/reference
-Subproject d43038932adeb16ada80e206d4c073d85129810
+Subproject ee7c676fd6e287459cb407337652412c990686c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 07e0df2f006e59d171c6bf3cafa9d61dbeb520d
+Subproject c954202c1e1720cba5628f99543cc01188c7d6f
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject b123ab4754127d822ffb38349ce0fbf561f1b2f
+Subproject 08bb147d51e815b96e8db7ba4cf870f201c11ff
diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md
index 2535cd4f12c..5b766318331 100644
--- a/src/doc/rustc/src/instrument-coverage.md
+++ b/src/doc/rustc/src/instrument-coverage.md
@@ -173,9 +173,9 @@ Some of the more notable options in this example include:
 [`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
 [`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
 
-> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`).
+> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`coverage(off)` attribute] (which requires the feature flag `#![feature(coverage)]`).
 
-[`no_coverage` attribute]: ../unstable-book/language-features/no-coverage.html
+[`coverage` attribute]: ../unstable-book/language-features/coverage.html
 
 ## Interpreting reports
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 269fe928754..70b35526ee5 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -267,6 +267,7 @@ target | std | host | notes
 [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS |
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | * |  | 32-bit Windows XP support
+[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
index fb0cea05d44..a6246fa3bd8 100644
--- a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
+++ b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
@@ -6,6 +6,7 @@ Windows targets similar to `*-pc-windows-gnu` but using UCRT as the runtime and
 
 Target triples available so far:
 - `aarch64-pc-windows-gnullvm`
+- `i686-pc-windows-gnullvm`
 - `x86_64-pc-windows-gnullvm`
 
 ## Target maintainers
@@ -42,7 +43,7 @@ Once these targets bootstrap themselves on native hardware they should pass Rust
 
 ## Cross-compilation toolchains and C code
 
-Compatible C code can be built with Clang's `aarch64-pc-windows-gnu` and `x86_64-pc-windows-gnu` targets as long as LLVM based C toolchains are used.
+Compatible C code can be built with Clang's `aarch64-pc-windows-gnu`, `i686-pc-windows-gnullvm` and `x86_64-pc-windows-gnu` targets as long as LLVM based C toolchains are used.
 Those include:
 - [llvm-mingw](https://github.com/mstorsjo/llvm-mingw)
 - [MSYS2 with CLANG* environment](https://www.msys2.org/docs/environments)
diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md
index 593428b8a70..8ce059cc29c 100644
--- a/src/doc/rustdoc/src/write-documentation/re-exports.md
+++ b/src/doc/rustdoc/src/write-documentation/re-exports.md
@@ -86,7 +86,7 @@ pub use self::Hidden as InlinedHidden;
 ```
 
 The same applies on re-exports themselves: if you have multiple re-exports and some of them have
-`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation:
+`#[doc(hidden)]`, then these ones (and only these) won't appear in the documentation:
 
 ```rust,ignore (inline)
 mod private_mod {
diff --git a/src/doc/unstable-book/src/language-features/no-coverage.md b/src/doc/unstable-book/src/language-features/coverage-attribute.md
index 327cdb39791..0a9bd07de07 100644
--- a/src/doc/unstable-book/src/language-features/no-coverage.md
+++ b/src/doc/unstable-book/src/language-features/coverage-attribute.md
@@ -1,4 +1,4 @@
-# `no_coverage`
+# `coverage_attribute`
 
 The tracking issue for this feature is: [#84605]
 
@@ -6,7 +6,7 @@ The tracking issue for this feature is: [#84605]
 
 ---
 
-The `no_coverage` attribute can be used to selectively disable coverage
+The `coverage` attribute can be used to selectively disable coverage
 instrumentation in an annotated function. This might be useful to:
 
 -   Avoid instrumentation overhead in a performance critical function
@@ -16,14 +16,14 @@ instrumentation in an annotated function. This might be useful to:
 ## Example
 
 ```rust
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 
 // `foo()` will get coverage instrumentation (by default)
 fn foo() {
   // ...
 }
 
-#[no_coverage]
+#[coverage(off)]
 fn bar() {
   // ...
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1f6e832c7cb..190b1b038b6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -542,7 +542,7 @@ fn clean_generic_param_def<'tcx>(
                 },
             )
         }
-        ty::GenericParamDefKind::Const { has_default } => (
+        ty::GenericParamDefKind::Const { has_default, .. } => (
             def.name,
             GenericParamDefKind::Const {
                 ty: Box::new(clean_middle_ty(
@@ -1863,7 +1863,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                     // does nothing for `ConstKind::Param`.
                     let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
                     let param_env = cx.tcx.param_env(anon_const.def_id);
-                    print_const(cx, ct.eval(cx.tcx, param_env))
+                    print_const(cx, ct.normalize(cx.tcx, param_env))
                 }
             };
 
@@ -2082,7 +2082,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Str => Primitive(PrimitiveType::Str),
         ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
         ty::Array(ty, mut n) => {
-            n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
+            n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
             Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index ff158fa8b4c..b276745f317 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -25,7 +25,9 @@ use rustc_index::IndexVec;
 use rustc_metadata::rendered_const;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt, Visibility};
-use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment};
+use rustc_resolve::rustdoc::{
+    add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments, DocFragment,
+};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -397,7 +399,7 @@ impl Item {
     }
 
     pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
-        crate::passes::span_of_attrs(&self.attrs)
+        span_of_fragments(&self.attrs.doc_strings)
             .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner()))
     }
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index bb7d26c541b..ea87268877f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -10,6 +10,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::attr::InnerAttrPolicy;
+use rustc_resolve::rustdoc::span_of_fragments;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::parse::ParseSess;
 use rustc_session::{lint, EarlyErrorHandler, Session};
@@ -33,7 +34,6 @@ use crate::clean::{types::AttributesExt, Attributes};
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
 use crate::lint::init_lints;
-use crate::passes::span_of_attrs;
 
 /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
 #[derive(Clone, Default)]
@@ -1241,7 +1241,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
                 Some(&crate::html::markdown::ExtraInfo::new(
                     self.tcx,
                     def_id.to_def_id(),
-                    span_of_attrs(&attrs).unwrap_or(sp),
+                    span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
                 )),
             );
         }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a8d85fb6fb4..b28019e3f91 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1609,6 +1609,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("blanket-implementations-list".into(), 1);
     map.insert("deref-methods".into(), 1);
     map.insert("layout".into(), 1);
+    map.insert("aliased-type".into(), 1);
     map
 }
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index bb1c186668c..736b6d7ebfa 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -7,8 +7,10 @@ use std::sync::mpsc::{channel, Receiver};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use rustc_span::{sym, Symbol};
@@ -22,13 +24,13 @@ use super::{
     sidebar::{sidebar_module_like, Sidebar},
     AllTypes, LinkFromSrc, StylePath,
 };
-use crate::clean::{self, types::ExternalLocation, ExternalCrate};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem};
 use crate::config::{ModuleSorting, RenderOptions};
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::formats::FormatRenderer;
+use crate::formats::{self, FormatRenderer};
 use crate::html::escape::Escape;
 use crate::html::format::{join_with_double_colon, Buffer};
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
@@ -147,6 +149,53 @@ impl SharedContext<'_> {
     pub(crate) fn edition(&self) -> Edition {
         self.tcx.sess.edition()
     }
+
+    /// Returns a list of impls on the given type, and, if it's a type alias,
+    /// other types that it aliases.
+    pub(crate) fn all_impls_for_item<'a>(
+        &'a self,
+        it: &clean::Item,
+        did: DefId,
+    ) -> Vec<&'a formats::Impl> {
+        let tcx = self.tcx;
+        let cache = &self.cache;
+        let mut saw_impls = FxHashSet::default();
+        let mut v: Vec<&formats::Impl> = cache
+            .impls
+            .get(&did)
+            .map(Vec::as_slice)
+            .unwrap_or(&[])
+            .iter()
+            .filter(|i| saw_impls.insert(i.def_id()))
+            .collect();
+        if let TypeAliasItem(ait) = &*it.kind &&
+            let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) &&
+            let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) &&
+            let Some(av) = cache.impls.get(&aliased_type_defid) &&
+            let Some(alias_def_id) = it.item_id.as_def_id()
+        {
+            // This branch of the compiler compares types structually, but does
+            // not check trait bounds. That's probably fine, since type aliases
+            // don't normally constrain on them anyway.
+            // https://github.com/rust-lang/rust/issues/21903
+            //
+            // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification.
+            // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress.
+            let aliased_ty = tcx.type_of(alias_def_id).skip_binder();
+            let reject_cx = DeepRejectCtxt {
+                treat_obligation_params: TreatParams::AsCandidateKey,
+            };
+            v.extend(av.iter().filter(|impl_| {
+                if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() {
+                    reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder())
+                        && saw_impls.insert(impl_def_id)
+                } else {
+                    false
+                }
+            }));
+        }
+        v
+    }
 }
 
 impl<'tcx> Context<'tcx> {
@@ -665,8 +714,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                             You need to enable JavaScript be able to update your settings.\
                         </section>\
                      </noscript>\
-                     <link rel=\"stylesheet\" \
-                         href=\"{static_root_path}{settings_css}\">\
                      <script defer src=\"{static_root_path}{settings_js}\"></script>\
                      <link rel=\"preload\" href=\"{static_root_path}{theme_light_css}\" \
                          as=\"style\">\
@@ -675,7 +722,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                      <link rel=\"preload\" href=\"{static_root_path}{theme_ayu_css}\" \
                          as=\"style\">",
                     static_root_path = page.get_static_root_path(),
-                    settings_css = static_files::STATIC_FILES.settings_css,
                     settings_js = static_files::STATIC_FILES.settings_js,
                     theme_light_css = static_files::STATIC_FILES.theme_light_css,
                     theme_dark_css = static_files::STATIC_FILES.theme_dark_css,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a85e8356c2f..5adbecd6d04 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -54,7 +54,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{
     symbol::{sym, Symbol},
@@ -63,7 +62,6 @@ use rustc_span::{
 use serde::ser::{SerializeMap, SerializeSeq};
 use serde::{Serialize, Serializer};
 
-use crate::clean::types::TypeAliasItem;
 use crate::clean::{self, ItemId, RenderedLink, SelfTy};
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -1119,13 +1117,13 @@ pub(crate) fn render_all_impls(
 fn render_assoc_items<'a, 'cx: 'a>(
     cx: &'a mut Context<'cx>,
     containing_item: &'a clean::Item,
-    it: DefId,
+    did: DefId,
     what: AssocItemRender<'a>,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     let mut derefs = DefIdSet::default();
-    derefs.insert(it);
+    derefs.insert(did);
     display_fn(move |f| {
-        render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
+        render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs);
         Ok(())
     })
 }
@@ -1134,46 +1132,16 @@ fn render_assoc_items_inner(
     mut w: &mut dyn fmt::Write,
     cx: &mut Context<'_>,
     containing_item: &clean::Item,
-    it: DefId,
+    did: DefId,
     what: AssocItemRender<'_>,
     derefs: &mut DefIdSet,
 ) {
     info!("Documenting associated items of {:?}", containing_item.name);
     let shared = Rc::clone(&cx.shared);
-    let cache = &shared.cache;
-    let tcx = cx.tcx();
-    let av = if let TypeAliasItem(ait) = &*containing_item.kind &&
-        let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) &&
-        let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) &&
-        let Some(mut av) = cache.impls.get(&aliased_type_defid).cloned() &&
-        let Some(alias_def_id) = containing_item.item_id.as_def_id()
-    {
-        // This branch of the compiler compares types structually, but does
-        // not check trait bounds. That's probably fine, since type aliases
-        // don't normally constrain on them anyway.
-        // https://github.com/rust-lang/rust/issues/21903
-        //
-        // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification.
-        // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress.
-        let aliased_ty = tcx.type_of(alias_def_id).skip_binder();
-        let reject_cx = DeepRejectCtxt {
-            treat_obligation_params: TreatParams::AsCandidateKey,
-        };
-        av.retain(|impl_| {
-            if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() {
-                reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder())
-            } else {
-                false
-            }
-        });
-        av
-    } else {
-        Vec::new()
-    };
-    let blank = Vec::new();
-    let v = cache.impls.get(&it).unwrap_or(&blank);
-    let (non_trait, traits): (Vec<_>, _) =
-        v.iter().chain(&av[..]).partition(|i| i.inner_impl().trait_.is_none());
+    let v = shared.all_impls_for_item(containing_item, did);
+    let v = v.as_slice();
+    let (non_trait, traits): (Vec<&Impl>, _) =
+        v.iter().partition(|i| i.inner_impl().trait_.is_none());
     let mut saw_impls = FxHashSet::default();
     if !non_trait.is_empty() {
         let mut tmp_buf = Buffer::html();
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index fce31a8423d..76f63c6f63e 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -237,6 +237,7 @@ fn sidebar_type_alias<'a>(
 ) -> Vec<LinkBlock<'a>> {
     let mut items = vec![];
     if let Some(inner_type) = &t.inner_type {
+        items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type")));
         match inner_type {
             clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => {
                 let mut variants = variants
@@ -278,11 +279,12 @@ fn sidebar_assoc_items<'a>(
     links: &mut Vec<LinkBlock<'a>>,
 ) {
     let did = it.item_id.expect_def_id();
-    let cache = cx.cache();
+    let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id());
+    let v = v.as_slice();
 
     let mut assoc_consts = Vec::new();
     let mut methods = Vec::new();
-    if let Some(v) = cache.impls.get(&did) {
+    if !v.is_empty() {
         let mut used_links = FxHashSet::default();
         let mut id_map = IdMap::new();
 
@@ -318,7 +320,7 @@ fn sidebar_assoc_items<'a>(
                     cx,
                     &mut deref_methods,
                     impl_,
-                    v,
+                    v.iter().copied(),
                     &mut derefs,
                     &mut used_links,
                 );
@@ -348,7 +350,7 @@ fn sidebar_deref_methods<'a>(
     cx: &'a Context<'_>,
     out: &mut Vec<LinkBlock<'a>>,
     impl_: &Impl,
-    v: &[Impl],
+    v: impl Iterator<Item = &'a Impl>,
     derefs: &mut DefIdSet,
     used_links: &mut FxHashSet<String>,
 ) {
@@ -373,7 +375,7 @@ fn sidebar_deref_methods<'a>(
             // Avoid infinite cycles
             return;
         }
-        let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
+        let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
         let inner_impl = target
             .def_id(c)
             .or_else(|| {
@@ -424,7 +426,7 @@ fn sidebar_deref_methods<'a>(
                 cx,
                 out,
                 target_deref_impl,
-                target_impls,
+                target_impls.iter(),
                 derefs,
                 used_links,
             );
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index da4da50106a..84123f4e9d3 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -925,6 +925,70 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	top: -5px;
 }
 
+.setting-line {
+	margin: 1.2em 0.6em;
+}
+
+.setting-radio input, .setting-check input {
+	margin-right: 0.3em;
+	height: 1.2rem;
+	width: 1.2rem;
+	border: 2px solid var(--settings-input-border-color);
+	outline: none;
+	-webkit-appearance: none;
+	cursor: pointer;
+}
+.setting-radio input {
+	border-radius: 50%;
+}
+
+.setting-radio span, .setting-check span {
+	padding-bottom: 1px;
+}
+
+.setting-radio {
+	margin-top: 0.1em;
+	margin-bottom: 0.1em;
+	min-width: 3.8em;
+	padding: 0.3em;
+	display: inline-flex;
+	align-items: center;
+	cursor: pointer;
+}
+.setting-radio + .setting-radio {
+	margin-left: 0.5em;
+}
+
+.setting-check {
+	margin-right: 20px;
+	display: flex;
+	align-items: center;
+	cursor: pointer;
+}
+
+.setting-radio input:checked {
+	box-shadow: inset 0 0 0 3px var(--main-background-color);
+	background-color: var(--settings-input-color);
+}
+.setting-check input:checked {
+	background-color: var(--settings-input-color);
+	border-width: 1px;
+	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
+		<path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
+		<path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
+}
+.setting-radio input:focus, .setting-check input:focus {
+	box-shadow: 0 0 1px 1px var(--settings-input-color);
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-radio input:checked:focus {
+	box-shadow: inset 0 0 0 3px var(--main-background-color),
+		0 0 2px 2px var(--settings-input-color);
+}
+.setting-radio input:hover, .setting-check input:hover {
+	border-color: var(--settings-input-color) !important;
+}
+
 /* use larger max-width for help popover, but not for help.html */
 #help.popover {
 	max-width: 600px;
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
deleted file mode 100644
index c1324c0760e..00000000000
--- a/src/librustdoc/html/static/css/settings.css
+++ /dev/null
@@ -1,63 +0,0 @@
-.setting-line {
-	margin: 1.2em 0.6em;
-}
-
-.setting-radio input, .setting-check input {
-	margin-right: 0.3em;
-	height: 1.2rem;
-	width: 1.2rem;
-	border: 2px solid var(--settings-input-border-color);
-	outline: none;
-	-webkit-appearance: none;
-	cursor: pointer;
-}
-.setting-radio input {
-	border-radius: 50%;
-}
-
-.setting-radio span, .setting-check span {
-	padding-bottom: 1px;
-}
-
-.setting-radio {
-	margin-top: 0.1em;
-	margin-bottom: 0.1em;
-	min-width: 3.8em;
-	padding: 0.3em;
-	display: inline-flex;
-	align-items: center;
-	cursor: pointer;
-}
-.setting-radio + .setting-radio {
-	margin-left: 0.5em;
-}
-
-.setting-check {
-	margin-right: 20px;
-	display: flex;
-	align-items: center;
-	cursor: pointer;
-}
-
-.setting-radio input:checked {
-	box-shadow: inset 0 0 0 3px var(--main-background-color);
-	background-color: var(--settings-input-color);
-}
-.setting-check input:checked {
-	background-color: var(--settings-input-color);
-	border-width: 1px;
-	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
-		<path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
-		<path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
-}
-.setting-radio input:focus, .setting-check input:focus {
-	box-shadow: 0 0 1px 1px var(--settings-input-color);
-}
-/* In here we combine both `:focus` and `:checked` properties. */
-.setting-radio input:checked:focus {
-	box-shadow: inset 0 0 0 3px var(--main-background-color),
-		0 0 2px 2px var(--settings-input-color);
-}
-.setting-radio input:hover, .setting-check input:hover {
-	border-color: var(--settings-input-color) !important;
-}
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index cb653d6b8df..822d22946b4 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -176,13 +176,6 @@ function browserSupportsHistoryApi() {
     return window.history && typeof window.history.pushState === "function";
 }
 
-function loadCss(cssUrl) {
-    const link = document.createElement("link");
-    link.href = cssUrl;
-    link.rel = "stylesheet";
-    document.getElementsByTagName("head")[0].appendChild(link);
-}
-
 function preLoadCss(cssUrl) {
     // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
     const link = document.createElement("link");
@@ -210,7 +203,6 @@ function preLoadCss(cssUrl) {
         event.preventDefault();
         // Sending request for the CSS and the JS files at the same time so it will
         // hopefully be loaded when the JS will generate the settings content.
-        loadCss(getVar("static-root-path") + getVar("settings-css"));
         loadScript(getVar("static-root-path") + getVar("settings-js"));
         preLoadCss(getVar("static-root-path") + getVar("theme-light-css"));
         preLoadCss(getVar("static-root-path") + getVar("theme-dark-css"));
@@ -852,14 +844,14 @@ function preLoadCss(cssUrl) {
         window.CURRENT_TOOLTIP_ELEMENT = wrapper;
         window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
         clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
-        wrapper.onpointerenter = function(ev) {
+        wrapper.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
             clearTooltipHoverTimeout(e);
         };
-        wrapper.onpointerleave = function(ev) {
+        wrapper.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
@@ -963,38 +955,38 @@ function preLoadCss(cssUrl) {
     }
 
     onEachLazy(document.getElementsByClassName("tooltip"), e => {
-        e.onclick = function() {
-            this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
-            if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
+        e.onclick = () => {
+            e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;
+            if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {
                 hideTooltip(true);
             } else {
-                showTooltip(this);
+                showTooltip(e);
                 window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
                 window.CURRENT_TOOLTIP_ELEMENT.focus();
                 window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
             }
             return false;
         };
-        e.onpointerenter = function(ev) {
+        e.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            setTooltipHoverTimeout(this, true);
+            setTooltipHoverTimeout(e, true);
         };
-        e.onpointermove = function(ev) {
+        e.onpointermove = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            setTooltipHoverTimeout(this, true);
+            setTooltipHoverTimeout(e, true);
         };
-        e.onpointerleave = function(ev) {
+        e.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            if (!this.TOOLTIP_FORCE_VISIBLE &&
+            if (!e.TOOLTIP_FORCE_VISIBLE &&
                 !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
                 // Tooltip pointer leave gesture:
                 //
@@ -1139,7 +1131,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
      *
      * Pass "true" to reset focus for tooltip popovers.
      */
-    window.hideAllModals = function(switchFocus) {
+    window.hideAllModals = switchFocus => {
         hideSidebar();
         window.hidePopoverMenus();
         hideTooltip(switchFocus);
@@ -1148,7 +1140,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
     /**
      * Hide all the popover menus.
      */
-    window.hidePopoverMenus = function() {
+    window.hidePopoverMenus = () => {
         onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
             elem.style.display = "none";
         });
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2cba32c1b50..63947789c54 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -59,8 +59,8 @@
             if (settingValue !== null) {
                 toggle.checked = settingValue === "true";
             }
-            toggle.onchange = function() {
-                changeSetting(this.id, this.checked);
+            toggle.onchange = () => {
+                changeSetting(toggle.id, toggle.checked);
             };
         });
         onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
@@ -224,14 +224,14 @@
 
     if (isSettingsPage) {
         // We replace the existing "onclick" callback to do nothing if clicked.
-        getSettingsButton().onclick = function(event) {
+        getSettingsButton().onclick = event => {
             event.preventDefault();
         };
     } else {
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
         const settingsMenu = document.getElementById("settings");
-        settingsButton.onclick = function(event) {
+        settingsButton.onclick = event => {
             if (elemIsInParent(event.target, settingsMenu)) {
                 return;
             }
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index a27aa2b58d2..7742646f81a 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -91,7 +91,6 @@ macro_rules! static_files {
 
 static_files! {
     rustdoc_css => "static/css/rustdoc.css",
-    settings_css => "static/css/settings.css",
     noscript_css => "static/css/noscript.css",
     normalize_css => "static/css/normalize.css",
     main_js => "static/js/main.js",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 8cb43634377..ad63571c6d0 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -33,7 +33,6 @@
          data-channel="{{rust_channel}}" {#+ #}
          data-search-js="{{files.search_js}}" {#+ #}
          data-settings-js="{{files.settings_js}}" {#+ #}
-         data-settings-css="{{files.settings_css}}" {#+ #}
          data-theme-light-css="{{files.theme_light_css}}" {#+ #}
          data-theme-dark-css="{{files.theme_dark_css}}" {#+ #}
          data-theme-ayu-css="{{files.theme_ayu_css}}" {#+ #}
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7b0a7a90d31..0db846bfc7e 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -16,7 +16,9 @@ use rustc_hir::Mutability;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
-use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
+use rustc_resolve::rustdoc::{
+    source_span_for_markdown_range, strip_generics_from_path, MalformedGenerics,
+};
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -1211,11 +1213,11 @@ impl LinkCollector<'_, '_> {
         ori_link: &MarkdownLinkRange,
         item: &Item,
     ) {
-        let span = super::source_span_for_markdown_range(
+        let span = source_span_for_markdown_range(
             self.cx.tcx,
             dox,
             ori_link.inner_range(),
-            &item.attrs,
+            &item.attrs.doc_strings,
         )
         .unwrap_or_else(|| item.attr_span(self.cx.tcx));
         rustc_session::parse::feature_err(
@@ -1702,26 +1704,27 @@ fn report_diagnostic(
         let (span, link_range) = match link_range {
             MarkdownLinkRange::Destination(md_range) => {
                 let mut md_range = md_range.clone();
-                let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs)
-                    .map(|mut sp| {
-                        while dox.as_bytes().get(md_range.start) == Some(&b' ')
-                            || dox.as_bytes().get(md_range.start) == Some(&b'`')
-                        {
-                            md_range.start += 1;
-                            sp = sp.with_lo(sp.lo() + BytePos(1));
-                        }
-                        while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
-                            || dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
-                        {
-                            md_range.end -= 1;
-                            sp = sp.with_hi(sp.hi() - BytePos(1));
-                        }
-                        sp
-                    });
+                let sp =
+                    source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings)
+                        .map(|mut sp| {
+                            while dox.as_bytes().get(md_range.start) == Some(&b' ')
+                                || dox.as_bytes().get(md_range.start) == Some(&b'`')
+                            {
+                                md_range.start += 1;
+                                sp = sp.with_lo(sp.lo() + BytePos(1));
+                            }
+                            while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
+                                || dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
+                            {
+                                md_range.end -= 1;
+                                sp = sp.with_hi(sp.hi() - BytePos(1));
+                            }
+                            sp
+                        });
                 (sp, MarkdownLinkRange::Destination(md_range))
             }
             MarkdownLinkRange::WholeLink(md_range) => (
-                super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs),
+                source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings),
                 link_range.clone(),
             ),
         };
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index 97078a5cb16..0c5cfffe1be 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -4,11 +4,11 @@
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 use core::ops::Range;
 use pulldown_cmark::{Event, Parser, Tag};
 use regex::Regex;
 use rustc_errors::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use std::mem;
 use std::sync::LazyLock;
 
@@ -21,8 +21,9 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     if !dox.is_empty() {
         let report_diag =
             |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| {
-                let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
-                    .unwrap_or_else(|| item.attr_span(cx.tcx));
+                let sp =
+                    source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
+                        .unwrap_or_else(|| item.attr_span(cx.tcx));
                 cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
                     lint.note("bare URLs are not automatically turned into clickable links")
                         .span_suggestion(
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 37e28e1fbca..316b1a41c7d 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -6,6 +6,7 @@ use rustc_errors::{
     Applicability, Diagnostic, Handler, LazyFallbackBundle,
 };
 use rustc_parse::parse_stream_from_source_str;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use rustc_session::parse::ParseSess;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::{FilePathMapping, SourceMap};
@@ -14,7 +15,6 @@ use rustc_span::{FileName, InnerSpan, DUMMY_SP};
 use crate::clean;
 use crate::core::DocContext;
 use crate::html::markdown::{self, RustCodeBlock};
-use crate::passes::source_span_for_markdown_range;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.opt_doc_value() {
@@ -77,11 +77,15 @@ fn check_rust_syntax(
     let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
 
     // The span and whether it is precise or not.
-    let (sp, precise_span) =
-        match source_span_for_markdown_range(cx.tcx, dox, &code_block.range, &item.attrs) {
-            Some(sp) => (sp, true),
-            None => (item.attr_span(cx.tcx), false),
-        };
+    let (sp, precise_span) = match source_span_for_markdown_range(
+        cx.tcx,
+        dox,
+        &code_block.range,
+        &item.attrs.doc_strings,
+    ) {
+        Some(sp) => (sp, true),
+        None => (item.attr_span(cx.tcx), false),
+    };
 
     let msg = if buffer.has_errors {
         "could not parse code block as Rust code"
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index c135c584cec..79fc599e176 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -2,9 +2,9 @@
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 
 use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 
 use std::iter::Peekable;
 use std::ops::Range;
@@ -20,7 +20,8 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let dox = item.doc_value();
     if !dox.is_empty() {
         let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| {
-            let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) {
+            let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs.doc_strings)
+            {
                 Some(sp) => sp,
                 None => item.attr_span(tcx),
             };
@@ -60,7 +61,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
                             tcx,
                             &dox,
                             &(generics_start..generics_end),
-                            &item.attrs,
+                            &item.attrs.doc_strings,
                         ) {
                             Some(sp) => sp,
                             None => item.attr_span(tcx),
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 67cd2cc9732..0c15bf5f764 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -6,6 +6,7 @@ use rustc_errors::SuggestionStyle;
 use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res};
 use rustc_hir::HirId;
 use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use rustc_span::Symbol;
 
 use crate::clean::utils::find_nearest_parent_module;
@@ -13,7 +14,6 @@ use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::Item;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 
 #[derive(Debug)]
 struct LinkData {
@@ -160,16 +160,21 @@ fn check_inline_or_reference_unknown_redundancy(
         (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
 
     if dest_res == display_res {
-        let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
-            .unwrap_or(item.attr_span(cx.tcx));
+        let link_span =
+            source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings)
+                .unwrap_or(item.attr_span(cx.tcx));
         let explicit_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_explicit_range(doc, link_range, open, close),
-            &item.attrs,
+            &item.attrs.doc_strings,
+        )?;
+        let display_span = source_span_for_markdown_range(
+            cx.tcx,
+            &doc,
+            &resolvable_link_range,
+            &item.attrs.doc_strings,
         )?;
-        let display_span =
-            source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
 
         cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
             lint.span_label(explicit_span, "explicit target is redundant")
@@ -201,21 +206,26 @@ fn check_reference_redundancy(
         (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
 
     if dest_res == display_res {
-        let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
-            .unwrap_or(item.attr_span(cx.tcx));
+        let link_span =
+            source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings)
+                .unwrap_or(item.attr_span(cx.tcx));
         let explicit_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_explicit_range(doc, link_range.clone(), b'[', b']'),
-            &item.attrs,
+            &item.attrs.doc_strings,
+        )?;
+        let display_span = source_span_for_markdown_range(
+            cx.tcx,
+            &doc,
+            &resolvable_link_range,
+            &item.attrs.doc_strings,
         )?;
-        let display_span =
-            source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
         let def_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_reference_def_range(doc, dest, link_range),
-            &item.attrs,
+            &item.attrs.doc_strings,
         )?;
 
         cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs
index 256958d7160..8b7fdd6ab1f 100644
--- a/src/librustdoc/passes/lint/unescaped_backticks.rs
+++ b/src/librustdoc/passes/lint/unescaped_backticks.rs
@@ -3,10 +3,10 @@
 use crate::clean::Item;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 use pulldown_cmark::{BrokenLink, Event, Parser};
 use rustc_errors::DiagnosticBuilder;
 use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use std::ops::Range;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
@@ -52,7 +52,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
                     tcx,
                     &dox,
                     &(backtick_index..backtick_index + 1),
-                    &item.attrs,
+                    &item.attrs.doc_strings,
                 )
                 .unwrap_or_else(|| item.attr_span(tcx));
 
@@ -378,9 +378,12 @@ fn suggest_insertion(
     /// Maximum bytes of context to show around the insertion.
     const CONTEXT_MAX_LEN: usize = 80;
 
-    if let Some(span) =
-        source_span_for_markdown_range(cx.tcx, &dox, &(insert_index..insert_index), &item.attrs)
-    {
+    if let Some(span) = source_span_for_markdown_range(
+        cx.tcx,
+        &dox,
+        &(insert_index..insert_index),
+        &item.attrs.doc_strings,
+    ) {
         lint.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
     } else {
         let line_start = dox[..insert_index].rfind('\n').map_or(0, |idx| idx + 1);
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 4b1ff68df50..bb678e33888 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -1,11 +1,6 @@
 //! Contains information about "passes", used to modify crate information during the documentation
 //! process.
 
-use rustc_middle::ty::TyCtxt;
-use rustc_resolve::rustdoc::DocFragmentKind;
-use rustc_span::{InnerSpan, Span, DUMMY_SP};
-use std::ops::Range;
-
 use self::Condition::*;
 use crate::clean;
 use crate::core::DocContext;
@@ -115,89 +110,3 @@ impl ConditionalPass {
 pub(crate) fn defaults(show_coverage: bool) -> &'static [ConditionalPass] {
     if show_coverage { COVERAGE_PASSES } else { DEFAULT_PASSES }
 }
-
-/// Returns a span encompassing all the given attributes.
-pub(crate) fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
-    if attrs.doc_strings.is_empty() {
-        return None;
-    }
-    let start = attrs.doc_strings[0].span;
-    if start == DUMMY_SP {
-        return None;
-    }
-    let end = attrs.doc_strings.last().expect("no doc strings provided").span;
-    Some(start.to(end))
-}
-
-/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
-///
-/// This method will return `None` if we cannot construct a span from the source map or if the
-/// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
-/// that case due to escaping and other source features.
-pub(crate) fn source_span_for_markdown_range(
-    tcx: TyCtxt<'_>,
-    markdown: &str,
-    md_range: &Range<usize>,
-    attrs: &clean::Attributes,
-) -> Option<Span> {
-    let is_all_sugared_doc =
-        attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
-
-    if !is_all_sugared_doc {
-        return None;
-    }
-
-    let snippet = tcx.sess.source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?;
-
-    let starting_line = markdown[..md_range.start].matches('\n').count();
-    let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
-
-    // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
-    // CRLF and LF line endings the same way.
-    let mut src_lines = snippet.split_terminator('\n');
-    let md_lines = markdown.split_terminator('\n');
-
-    // The number of bytes from the source span to the markdown span that are not part
-    // of the markdown, like comment markers.
-    let mut start_bytes = 0;
-    let mut end_bytes = 0;
-
-    'outer: for (line_no, md_line) in md_lines.enumerate() {
-        loop {
-            let source_line = src_lines.next()?;
-            match source_line.find(md_line) {
-                Some(offset) => {
-                    if line_no == starting_line {
-                        start_bytes += offset;
-
-                        if starting_line == ending_line {
-                            break 'outer;
-                        }
-                    } else if line_no == ending_line {
-                        end_bytes += offset;
-                        break 'outer;
-                    } else if line_no < starting_line {
-                        start_bytes += source_line.len() - md_line.len();
-                    } else {
-                        end_bytes += source_line.len() - md_line.len();
-                    }
-                    break;
-                }
-                None => {
-                    // Since this is a source line that doesn't include a markdown line,
-                    // we have to count the newline that we split from earlier.
-                    if line_no <= starting_line {
-                        start_bytes += source_line.len() + 1;
-                    } else {
-                        end_bytes += source_line.len() + 1;
-                    }
-                }
-            }
-        }
-    }
-
-    Some(span_of_attrs(attrs)?.from_inner(InnerSpan::new(
-        md_range.start + start_bytes,
-        md_range.end + start_bytes + end_bytes,
-    )))
-}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject d14c85f4e6e7671673b1a1bc87231ff7164761e
+Subproject 2fc85d15a542bfb610aff7682073412cf635352
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 798782340ee..c05c6ecc115 100644
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -30,7 +30,7 @@ unset CARGO_MANIFEST_DIR
 # Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
 # FIXME: How to match the clippy invocation in compile-test.rs?
 ./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/double_neg.rs 2>double_neg.stderr && exit 1
-sed -e "s,tests/ui,\$DIR," -e "/= help/d" double_neg.stderr >normalized.stderr
+sed -e "s,tests/ui,\$DIR," -e "/= help: for/d" double_neg.stderr > normalized.stderr
 diff -u normalized.stderr tests/ui/double_neg.stderr
 
 # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 5c69714bc1e..9b96f8dc253 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -52,24 +52,14 @@ jobs:
     needs: changelog
     strategy:
       matrix:
-        os: [ubuntu-latest, windows-latest, macos-latest]
-        host: [x86_64-unknown-linux-gnu, i686-unknown-linux-gnu, x86_64-apple-darwin, x86_64-pc-windows-msvc]
-        exclude:
+        include:
         - os: ubuntu-latest
-          host: x86_64-apple-darwin
-        - os: ubuntu-latest
-          host: x86_64-pc-windows-msvc
-        - os: macos-latest
-          host: x86_64-unknown-linux-gnu
-        - os: macos-latest
-          host: i686-unknown-linux-gnu
-        - os: macos-latest
-          host: x86_64-pc-windows-msvc
-        - os: windows-latest
           host: x86_64-unknown-linux-gnu
-        - os: windows-latest
+        - os: ubuntu-latest
           host: i686-unknown-linux-gnu
         - os: windows-latest
+          host: x86_64-pc-windows-msvc
+        - os: macos-latest
           host: x86_64-apple-darwin
 
     runs-on: ${{ matrix.os }}
@@ -84,8 +74,17 @@ jobs:
     - name: Checkout
       uses: actions/checkout@v3
 
+    - name: Install i686 dependencies
+      if: matrix.host == 'i686-unknown-linux-gnu'
+      run: |
+        sudo dpkg --add-architecture i386
+        sudo apt-get update
+        sudo apt-get install gcc-multilib zlib1g-dev:i386
+
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        rustup set default-host ${{ matrix.host }}
+        rustup show active-toolchain
 
     # Run
     - name: Set LD_LIBRARY_PATH (Linux)
@@ -109,11 +108,11 @@ jobs:
       run: cargo build --tests --features deny-warnings,internal
 
     - name: Test
-      if: runner.os == 'Linux'
+      if: matrix.host == 'x86_64-unknown-linux-gnu'
       run: cargo test --features deny-warnings,internal
 
     - name: Test
-      if: runner.os != 'Linux'
+      if: matrix.host != 'x86_64-unknown-linux-gnu'
       run: cargo test --features deny-warnings,internal -- --skip dogfood
 
     - name: Test clippy_lints
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 92cc19edb05..a7ae4a0ee2c 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5031,6 +5031,7 @@ Released 2018-09-13
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 [`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
 [`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
+[`iter_out_of_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_out_of_bounds
 [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 [`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
@@ -5131,6 +5132,7 @@ Released 2018-09-13
 [`misnamed_getters`]: https://rust-lang.github.io/rust-clippy/master/index.html#misnamed_getters
 [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message
+[`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing
 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
@@ -5204,6 +5206,8 @@ Released 2018-09-13
 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 [`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
+[`non_canonical_clone_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_canonical_clone_impl
+[`non_canonical_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_canonical_partial_ord_impl
 [`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg
 [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
@@ -5570,4 +5574,5 @@ Released 2018-09-13
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
 [`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments
 [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates
+[`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 7c78beb5dde..2d8b590dbe3 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -27,7 +27,7 @@ tempfile = { version = "3.2", optional = true }
 termize = "0.1"
 
 [dev-dependencies]
-ui_test = "0.18.1"
+ui_test = "0.20"
 tester = "0.9"
 regex = "1.5"
 toml = "0.7.3"
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index daaefd06a97..b02457307d7 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -14,8 +14,11 @@
     - [Basics](development/basics.md)
     - [Adding Lints](development/adding_lints.md)
     - [Defining Lints](development/defining_lints.md)
+    - [Writing tests](development/writing_tests.md)
     - [Lint Passes](development/lint_passes.md)
+    - [Emitting lints](development/emitting_lints.md)
     - [Type Checking](development/type_checking.md)
+    - [Trait Checking](development/trait_checking.md)
     - [Method Checking](development/method_checking.md)
     - [Macro Expansions](development/macro_expansions.md)
     - [Common Tools](development/common_tools_writing_lints.md)
diff --git a/src/tools/clippy/book/src/development/emitting_lints.md b/src/tools/clippy/book/src/development/emitting_lints.md
new file mode 100644
index 00000000000..a12f6aa91b3
--- /dev/null
+++ b/src/tools/clippy/book/src/development/emitting_lints.md
@@ -0,0 +1,217 @@
+# Emitting a lint
+
+Once we have [defined a lint](defining_lints.md), written [UI
+tests](writing_tests.md) and chosen [the lint pass](lint_passes.md) for the lint,
+we can begin the implementation of the lint logic so that we can emit it and
+gradually work towards a lint that behaves as expected.
+
+Note that we will not go into concrete implementation of a lint logic in this
+chapter. We will go into details in later chapters as well as in two examples of
+real Clippy lints.
+
+To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for
+the lint that we have declared. In this example we'll implement a "late" lint,
+so take a look at the [LateLintPass][late_lint_pass] documentation, which
+provides an abundance of methods that we can implement for our lint.
+
+```rust
+pub trait LateLintPass<'tcx>: LintPass {
+    // Trait methods
+}
+```
+
+By far the most common method used for Clippy lints is [`check_expr`
+method][late_check_expr], this is because Rust is an expression language and,
+more often than not, the lint we want to work on must examine expressions.
+
+> _Note:_ If you don't fully understand what expressions are in Rust, take a
+> look at the official documentation on [expressions][rust_expressions]
+
+Other common ones include the [`check_fn` method][late_check_fn] and the
+[`check_item` method][late_check_item].
+
+### Emitting a lint
+
+Inside the trait method that we implement, we can write down the lint logic and
+emit the lint with suggestions.
+
+Clippy's [diagnostics] provides quite a few diagnostic functions that we can use
+to emit lints. Take a look at the documentation to pick one that suits your
+lint's needs the best. Some common ones you will encounter in the Clippy
+repository includes:
+
+- [`span_lint`]: Emits a lint without providing any other information
+- [`span_lint_and_note`]: Emits a lint and adds a note
+- [`span_lint_and_help`]: Emits a lint and provides a helpful message
+- [`span_lint_and_sugg`]: Emits a lint and provides a suggestion to fix the code
+- [`span_lint_and_then`]: Like `span_lint`, but allows for a lot of output
+  customization.
+
+```rust
+impl<'tcx> LateLintPass<'tcx> for LintName {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)  {
+        // Imagine that `some_lint_expr_logic` checks for requirements for emitting the lint
+        if some_lint_expr_logic(expr) {
+            span_lint_and_help(
+                cx, // < The context
+                LINT_NAME, // < The name of the lint in ALL CAPS
+                expr.span, // < The span to lint
+                "message on why the lint is emitted",
+                None, // < An optional help span (to highlight something in the lint)
+                "message that provides a helpful suggestion",
+            );
+        }
+    }
+}
+```
+
+> Note: The message should be matter of fact and avoid capitalization and
+> punctuation. If multiple sentences are needed, the messages should probably be
+> split up into an error + a help / note / suggestion message.
+
+## Suggestions: Automatic fixes
+
+Some lints know what to change in order to fix the code. For example, the lint
+[`range_plus_one`][range_plus_one] warns for ranges where the user wrote `x..y +
+1` instead of using an [inclusive range][inclusive_range] (`x..=y`). The fix to
+this code would be changing the `x..y + 1` expression to `x..=y`. **This is
+where suggestions come in**.
+
+A suggestion is a change that the lint provides to fix the issue it is linting.
+The output looks something like this (from the example earlier):
+
+```text
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:37:14
+   |
+LL |     for _ in 1..1 + 1 {}
+   |              ^^^^^^^^ help: use: `1..=1`
+```
+
+**Not all suggestions are always right**, some of them require human
+supervision, that's why we have [Applicability][applicability].
+
+Applicability indicates confidence in the correctness of the suggestion, some
+are always right (`Applicability::MachineApplicable`), but we use
+`Applicability::MaybeIncorrect` and others when talking about a suggestion that
+may be incorrect.
+
+### Example
+
+The same lint `LINT_NAME` but that emits a suggestion would look something like this:
+
+```rust
+impl<'tcx> LateLintPass<'tcx> for LintName {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)  {
+        // Imagine that `some_lint_expr_logic` checks for requirements for emitting the lint
+        if some_lint_expr_logic(expr) {
+            span_lint_and_sugg( // < Note this change
+                cx,
+                LINT_NAME,
+                span,
+                "message on why the lint is emitted",
+                "use",
+                format!("foo + {} * bar", snippet(cx, expr.span, "<default>")), // < Suggestion
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+```
+
+Suggestions generally use the [`format!`][format_macro] macro to interpolate the
+old values with the new ones. To get code snippets, use one of the `snippet*`
+functions from `clippy_utils::source`.
+
+## How to choose between notes, help messages and suggestions
+
+Notes are presented separately from the main lint message, they provide useful
+information that the user needs to understand why the lint was activated. They
+are the most helpful when attached to a span.
+
+Examples:
+
+### Notes
+
+```text
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/drop_forget_ref.rs:10:5
+   |
+10 |     forget(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::forget-ref` implied by `-D warnings`
+note: argument has type &SomeStruct
+  --> $DIR/drop_forget_ref.rs:10:12
+   |
+10 |     forget(&SomeStruct);
+   |            ^^^^^^^^^^^
+```
+
+### Help Messages
+
+Help messages are specifically to help the user. These are used in situation
+where you can't provide a specific machine applicable suggestion. They can also
+be attached to a span.
+
+Example:
+
+```text
+error: constant division of 0.0 with 0.0 will always result in NaN
+  --> $DIR/zero_div_zero.rs:6:25
+   |
+6  |     let other_f64_nan = 0.0f64 / 0.0;
+   |                         ^^^^^^^^^^^^
+   |
+   = help: consider using `f64::NAN` if you would like a constant representing NaN
+```
+
+### Suggestions
+
+Suggestions are the most helpful, they are changes to the source code to fix the
+error. The magic in suggestions is that tools like `rustfix` can detect them and
+automatically fix your code.
+
+Example:
+
+```text
+error: This `.fold` can be more succinctly expressed as `.any`
+--> $DIR/methods.rs:390:13
+    |
+390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
+    |
+```
+
+### Snippets
+
+Snippets are pieces of the source code (as a string), they are extracted
+generally using the [`snippet`][snippet_fn] function.
+
+For example, if you want to know how an item looks (and you know the item's
+span), you could use `snippet(cx, span, "..")`.
+
+## Final: Run UI Tests to Emit the Lint
+
+Now, if we run our [UI test](writing_tests.md), we should see that Clippy now
+produces output that contains the lint message we designed.
+
+The next step is to implement the logic properly, which is a detail that we will
+cover in the next chapters.
+
+[diagnostics]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/index.html
+[late_check_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_expr
+[late_check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_fn
+[late_check_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_item
+[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
+[rust_expressions]: https://doc.rust-lang.org/reference/expressions.html
+[`span_lint`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint.html
+[`span_lint_and_note`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_note.html
+[`span_lint_and_help`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_help.html
+[`span_lint_and_sugg`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_sugg.html
+[`span_lint_and_then`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_then.html
+[range_plus_one]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
+[inclusive_range]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html
+[applicability]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_errors/enum.Applicability.html
+[snippet_fn]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/source/fn.snippet.html
+[format_macro]: https://doc.rust-lang.org/std/macro.format.html
diff --git a/src/tools/clippy/book/src/development/trait_checking.md b/src/tools/clippy/book/src/development/trait_checking.md
new file mode 100644
index 00000000000..fb263922cf8
--- /dev/null
+++ b/src/tools/clippy/book/src/development/trait_checking.md
@@ -0,0 +1,105 @@
+# Trait Checking
+
+Besides [type checking](type_checking.md), we might want to examine if
+a specific type `Ty` implements certain trait when implementing a lint.
+There are three approaches to achieve this, depending on if the target trait
+that we want to examine has a [diagnostic item][diagnostic_items],
+[lang item][lang_items], or neither.
+
+## Using Diagnostic Items
+
+As explained in the [Rust Compiler Development Guide][rustc_dev_guide], diagnostic items
+are introduced for identifying types via [Symbols][symbol].
+
+For instance, if we want to examine whether an expression implements
+the `Iterator` trait, we could simply write the following code,
+providing the `LateContext` (`cx`), our expression at hand, and
+the symbol of the trait in question:
+
+```rust
+use clippy_utils::is_trait_method;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_span::symbol::sym;
+
+impl LateLintPass<'_> for CheckIteratorTraitLint {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+		let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
+    		implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
+		});
+		if implements_iterator {
+			// [...]
+		}
+
+    }
+}
+```
+
+> **Note**: Refer to [this index][symbol_index] for all the defined `Symbol`s.
+
+## Using Lang Items
+
+Besides diagnostic items, we can also use [`lang_items`][lang_items].
+Take a look at the documentation to find that `LanguageItems` contains
+all language items defined in the compiler.
+
+Using one of its `*_trait` method, we could obtain the [DefId] of any
+specific item, such as `Clone`, `Copy`, `Drop`, `Eq`, which are familiar
+to many Rustaceans.
+
+For instance, if we want to examine whether an expression `expr` implements
+`Drop` trait, we could access `LanguageItems` via our `LateContext`'s
+[TyCtxt], which provides a `lang_items` method that will return the id of
+`Drop` trait to us. Then, by calling Clippy utils function `implements_trait`
+we can check that the `Ty` of the `expr` implements the trait:
+
+```rust
+use clippy_utils::implements_trait;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+impl LateLintPass<'_> for CheckDropTraitLint {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let ty = cx.typeck_results().expr_ty(expr);
+        if cx.tcx.lang_items()
+            .drop_trait()
+            .map_or(false, |id| implements_trait(cx, ty, id, &[])) {
+                println!("`expr` implements `Drop` trait!");
+            }
+    }
+}
+```
+
+## Using Type Path
+
+If neither diagnostic item nor a language item is available, we can use
+[`clippy_utils::paths`][paths] with the `match_trait_method` to determine trait
+implementation.
+
+> **Note**: This approach should be avoided if possible, the best thing to do would be to make a PR to [`rust-lang/rust`][rust] adding a diagnostic item.
+
+Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` :
+
+```rust
+use clippy_utils::{match_trait_method, paths};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) {
+            println!("`expr` implements `CORE_ITER_CLONED` trait!");
+        }
+    }
+}
+```
+
+[DefId]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
+[diagnostic_items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
+[lang_items]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/lang_items/struct.LanguageItems.html
+[paths]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/paths.rs
+[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/
+[symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
+[symbol_index]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
+[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
+[rust]: https://github.com/rust-lang/rust
diff --git a/src/tools/clippy/book/src/development/writing_tests.md b/src/tools/clippy/book/src/development/writing_tests.md
new file mode 100644
index 00000000000..8937e0d8e94
--- /dev/null
+++ b/src/tools/clippy/book/src/development/writing_tests.md
@@ -0,0 +1,218 @@
+# Testing
+
+Developing lints for Clippy is a Test-Driven Development (TDD) process because
+our first task before implementing any logic for a new lint is to write some test cases.
+
+## Develop Lints with Tests
+
+When we develop Clippy, we enter a complex and chaotic realm full of
+programmatic issues, stylistic errors, illogical code and non-adherence to convention.
+Tests are the first layer of order we can leverage to define when and where
+we want a new lint to trigger or not.
+
+Moreover, writing tests first help Clippy developers to find a balance for
+the first iteration of and further enhancements for a lint.
+With test cases on our side, we will not have to worry about over-engineering
+a lint on its first version nor missing out some obvious edge cases of the lint.
+This approach empowers us to iteratively enhance each lint.
+
+## Clippy UI Tests
+
+We use **UI tests** for testing in Clippy. These UI tests check that the output
+of Clippy is exactly as we expect it to be. Each test is just a plain Rust file
+that contains the code we want to check.
+
+The output of Clippy is compared against a `.stderr` file. Note that you don't
+have to create this file yourself. We'll get to generating the `.stderr` files
+with the command [`cargo bless`](#cargo-bless) (seen later on).
+
+### Write Test Cases
+
+Let us now think about some tests for our imaginary `foo_functions` lint. We
+start by opening the test file `tests/ui/foo_functions.rs` that was created by
+`cargo dev new_lint`.
+
+Update the file with some examples to get started:
+
+```rust
+#![warn(clippy::foo_functions)] // < Add this, so the lint is guaranteed to be enabled in this file
+
+// Impl methods
+struct A;
+impl A {
+    pub fn fo(&self) {}
+    pub fn foo(&self) {} //~ ERROR: function called "foo"
+    pub fn food(&self) {}
+}
+
+// Default trait methods
+trait B {
+    fn fo(&self) {}
+    fn foo(&self) {} //~ ERROR: function called "foo"
+    fn food(&self) {}
+}
+
+// Plain functions
+fn fo() {}
+fn foo() {} //~ ERROR: function called "foo"
+fn food() {}
+
+fn main() {
+    // We also don't want to lint method calls
+    foo();
+    let a = A;
+    a.foo();
+}
+```
+
+Without actual lint logic to emit the lint when we see a `foo` function name,
+this test will just pass, because no lint will be emitted. However, we can now
+run the test with the following command:
+
+```sh
+$ TESTNAME=foo_functions cargo uitest
+```
+
+Clippy will compile and it will conclude with an `ok` for the tests:
+
+```
+...Clippy warnings and test outputs...
+test compile_test ... ok
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s
+```
+
+This is normal. After all, we wrote a bunch of Rust code but we haven't really
+implemented any logic for Clippy to detect `foo` functions and emit a lint.
+
+As we gradually implement our lint logic, we will keep running this UI test command.
+Clippy will begin outputting information that allows us to check if the output is
+turning into what we want it to be.
+
+### Example output
+
+As our `foo_functions` lint is tested, the output would look something like this:
+
+```
+failures:
+---- compile_test stdout ----
+normalized stderr:
+error: function called "foo"
+  --> $DIR/foo_functions.rs:6:12
+   |
+LL |     pub fn foo(&self) {}
+   |            ^^^
+   |
+   = note: `-D clippy::foo-functions` implied by `-D warnings`
+error: function called "foo"
+  --> $DIR/foo_functions.rs:13:8
+   |
+LL |     fn foo(&self) {}
+   |        ^^^
+error: function called "foo"
+  --> $DIR/foo_functions.rs:19:4
+   |
+LL | fn foo() {}
+   |    ^^^
+error: aborting due to 3 previous errors
+```
+
+Note the *failures* label at the top of the fragment, we'll get rid of it
+(saving this output) in the next section.
+
+> _Note:_ You can run multiple test files by specifying a comma separated list:
+> `TESTNAME=foo_functions,bar_methods,baz_structs`.
+
+### `cargo bless`
+
+Once we are satisfied with the output, we need to run this command to
+generate or update the `.stderr` file for our lint:
+
+```sh
+$ TESTNAME=foo_functions cargo uibless
+```
+
+This writes the emitted lint suggestions and fixes to the `.stderr` file, with
+the reason for the lint, suggested fixes, and line numbers, etc.
+
+Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
+our lint, we need to commit the generated `.stderr` files, too.
+
+In general, you should only commit files changed by `cargo bless` for the
+specific lint you are creating/editing.
+
+> _Note:_ If the generated `.stderr`, and `.fixed` files are empty,
+> they should be removed.
+
+## `toml` Tests
+
+Some lints can be configured through a `clippy.toml` file. Those configuration
+values are tested in `tests/ui-toml`.
+
+To add a new test there, create a new directory and add the files:
+
+- `clippy.toml`: Put here the configuration value you want to test.
+- `lint_name.rs`: A test file where you put the testing code, that should see a
+  different lint behavior according to the configuration set in the
+  `clippy.toml` file.
+
+The potential `.stderr` and `.fixed` files can again be generated with `cargo
+bless`.
+
+## Cargo Lints
+
+The process of testing is different for Cargo lints in that now we are
+interested in the `Cargo.toml` manifest file. In this case, we also need a
+minimal crate associated with that manifest. Those tests are generated in
+`tests/ui-cargo`.
+
+Imagine we have a new example lint that is named `foo_categories`, we can run:
+
+```sh
+$ cargo dev new_lint --name=foo_categories --pass=late --category=cargo
+```
+
+After running `cargo dev new_lint` we will find by default two new crates,
+each with its manifest file:
+
+* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
+  new lint to raise an error.
+* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger
+  the lint.
+
+If you need more cases, you can copy one of those crates (under
+`foo_categories`) and rename it.
+
+The process of generating the `.stderr` file is the same as for other lints
+and prepending the `TESTNAME` variable to `cargo uitest` works for Cargo lints too.
+
+## Rustfix Tests
+
+If the lint you are working on is making use of structured suggestions,
+[`rustfix`] will apply the suggestions from the lint to the test file code and
+compare that to the contents of a `.fixed` file.
+
+Structured suggestions tell a user how to fix or re-write certain code that has
+been linted with [`span_lint_and_sugg`].
+
+Should `span_lint_and_sugg` be used to generate a suggestion, but not all
+suggestions lead to valid code, you can use the `//@no-rustfix` comment on top
+of the test file, to not run `rustfix` on that file.
+
+We'll talk about suggestions more in depth in a [later chapter](emitting_lints.md).
+
+Use `cargo bless` to automatically generate the `.fixed` file after running
+the tests.
+
+[`rustfix`]: https://github.com/rust-lang/rustfix
+[`span_lint_and_sugg`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_sugg.html
+
+## Testing Manually
+
+Manually testing against an example file can be useful if you have added some
+`println!`s and the test suite output becomes unreadable.
+
+To try Clippy with your local modifications, run from the working copy root.
+
+```sh
+$ cargo dev lint input.rs
+```
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index caaad6d1173..52c795e04fe 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -751,3 +751,27 @@ Which crates to allow absolute paths from
 * [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
 
 
+## `enforce-iter-loop-reborrow`
+#### Example
+```
+let mut vec = vec![1, 2, 3];
+let rmvec = &mut vec;
+for _ in rmvec.iter() {}
+for _ in rmvec.iter_mut() {}
+```
+
+Use instead:
+```
+let mut vec = vec![1, 2, 3];
+let rmvec = &mut vec;
+for _ in &*rmvec {}
+for _ in &mut *rmvec {}
+```
+
+**Default Value:** `false` (`bool`)
+
+---
+**Affected lints:**
+* [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop)
+
+
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index c0a9f466e7b..dcd9a4adcbd 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -15,7 +15,6 @@ clippy_utils = { path = "../clippy_utils" }
 declare_clippy_lint = { path = "../declare_clippy_lint" }
 if_chain = "1.0"
 itertools = "0.10.1"
-pulldown-cmark = { version = "0.9", default-features = false }
 quine-mc_cluskey = "0.2"
 regex-syntax = "0.7"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index f73f1ed18f8..a4d40df52e7 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -211,8 +211,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
     crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO,
     crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
-    crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
-    crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO,
     crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
     crate::indexing_slicing::INDEXING_SLICING_INFO,
     crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
@@ -365,6 +363,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_NTH_ZERO_INFO,
     crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO,
     crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
+    crate::methods::ITER_OUT_OF_BOUNDS_INFO,
     crate::methods::ITER_OVEREAGER_CLONED_INFO,
     crate::methods::ITER_SKIP_NEXT_INFO,
     crate::methods::ITER_SKIP_ZERO_INFO,
@@ -456,6 +455,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
     crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
     crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
+    crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,
     crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
     crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
     crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
@@ -496,6 +496,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
     crate::no_effect::UNNECESSARY_OPERATION_INFO,
     crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO,
+    crate::non_canonical_impls::NON_CANONICAL_CLONE_IMPL_INFO,
+    crate::non_canonical_impls::NON_CANONICAL_PARTIAL_ORD_IMPL_INFO,
     crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
     crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
     crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 03b5a2d6d08..bbce6e1dd8f 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -69,6 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
 }
 
 /// Returns true if the given item is a union with at least two non-ZST fields.
+/// (ZST fields having an arbitrary offset is completely inconsequential, and
+/// if there is only one field left after ignoring ZST fields then the offset
+/// of that field does not matter either.)
 fn is_union_with_two_non_zst_fields(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Union(data, _) = &item.kind {
         data.fields().iter().filter(|f| !is_zst(cx, f.ty)).count() >= 2
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 58c27855000..8090f821d1f 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{is_copy, peel_mid_ty_refs};
+use clippy_utils::ty::{implements_trait, is_copy, peel_mid_ty_refs};
 use clippy_utils::{
     expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
 };
@@ -33,7 +33,6 @@ use rustc_middle::ty::{
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
-use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::collections::VecDeque;
@@ -452,13 +451,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                         // Trait methods taking `self`
                                         arg_ty
                                     } && impl_ty.is_ref()
-                                    && cx.tcx.infer_ctxt().build()
-                                        .type_implements_trait(
-                                            trait_id,
-                                            [impl_ty.into()].into_iter().chain(args.iter().copied()),
-                                            cx.param_env,
-                                        )
-                                        .must_apply_modulo_regions()
+                                    && implements_trait(
+                                        cx,
+                                        impl_ty,
+                                        trait_id,
+                                        &args[..cx.tcx.generics_of(trait_id).params.len() - 1],
+                                    )
                                 {
                                     false
                                 } else {
@@ -609,12 +607,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             adjusted_ty,
                         },
                     ));
-                } else if stability.is_deref_stable() {
+                } else if stability.is_deref_stable()
+                    && let Some(parent) = get_parent_expr(cx, expr)
+                {
                     self.state = Some((
                         State::ExplicitDeref { mutability: None },
                         StateData {
-                            span: expr.span,
-                            hir_id: expr.hir_id,
+                            span: parent.span,
+                            hir_id: parent.hir_id,
                             adjusted_ty,
                         },
                     ));
@@ -1399,6 +1399,13 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 return;
             }
 
+            if let ExprKind::Field(parent_expr, _) = expr.kind
+                && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(parent_expr).kind()
+                && adt.is_union()
+            {
+                // Auto deref does not apply on union field
+                return;
+            }
             span_lint_hir_and_then(
                 cx,
                 EXPLICIT_AUTO_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 9a85cc4ce2d..d2bfc4f8e27 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -217,8 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             if let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind();
             if let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|attr| attr.doc_str().is_some());
-            if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
-            if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
+            if cx.tcx.hir().attrs(impl_item_hir).is_empty();
 
             then {
                 if adt_def.is_struct() {
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 1971cab64ef..7469f813ef8 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::macro_backtrace;
+use rustc_ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefIdMap;
-use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
+use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{ExpnId, Span};
@@ -111,6 +112,10 @@ impl LateLintPass<'_> for DisallowedMacros {
 
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         self.check(cx, expr.span);
+        // `$t + $t` can have the context of $t, check also the span of the binary operator
+        if let ExprKind::Binary(op, ..) = expr.kind {
+            self.check(cx, op.span);
+        }
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -147,4 +152,8 @@ impl LateLintPass<'_> for DisallowedMacros {
     fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
         self.check(cx, path.span);
     }
+
+    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) {
+        self.check(cx, attr.span);
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index e29ab634c97..4498e9ccdec 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -1,18 +1,16 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 use if_chain::if_chain;
-use itertools::Itertools;
 use pulldown_cmark::Event::{
     Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
-use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
-use rustc_ast::token::CommentKind;
+use rustc_ast::ast::{Async, Attribute, Fn, FnRetTy, ItemKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
@@ -26,6 +24,9 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::ForceCollect;
+use rustc_resolve::rustdoc::{
+    add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment,
+};
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::edition::Edition;
@@ -450,53 +451,16 @@ fn lint_for_missing_headers(
     }
 }
 
-/// Cleanup documentation decoration.
-///
-/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
-/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
-/// need to keep track of
-/// the spans but this function is inspired from the later.
-#[expect(clippy::cast_possible_truncation)]
-#[must_use]
-pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
-    // one-line comments lose their prefix
-    if comment_kind == CommentKind::Line {
-        let mut doc = doc.to_owned();
-        doc.push('\n');
-        let len = doc.len();
-        // +3 skips the opening delimiter
-        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
-    }
+#[derive(Copy, Clone)]
+struct Fragments<'a> {
+    doc: &'a str,
+    fragments: &'a [DocFragment],
+}
 
-    let mut sizes = vec![];
-    let mut contains_initial_stars = false;
-    for line in doc.lines() {
-        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
-        debug_assert_eq!(offset as u32 as usize, offset);
-        contains_initial_stars |= line.trim_start().starts_with('*');
-        // +1 adds the newline, +3 skips the opening delimiter
-        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
-    }
-    if !contains_initial_stars {
-        return (doc.to_string(), sizes);
-    }
-    // remove the initial '*'s if any
-    let mut no_stars = String::with_capacity(doc.len());
-    for line in doc.lines() {
-        let mut chars = line.chars();
-        for c in &mut chars {
-            if c.is_whitespace() {
-                no_stars.push(c);
-            } else {
-                no_stars.push(if c == '*' { ' ' } else { c });
-                break;
-            }
-        }
-        no_stars.push_str(chars.as_str());
-        no_stars.push('\n');
+impl Fragments<'_> {
+    fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
+        source_span_for_markdown_range(cx.tcx, &self.doc, &range, &self.fragments)
     }
-
-    (no_stars, sizes)
 }
 
 #[derive(Copy, Clone, Default)]
@@ -508,34 +472,19 @@ struct DocHeaders {
 
 fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
     /// We don't want the parser to choke on intra doc links. Since we don't
-    /// actually care about rendering them, just pretend that all broken links are
+    /// actually care about rendering them, just pretend that all broken links
     /// point to a fake address.
     #[expect(clippy::unnecessary_wraps)] // we're following a type signature
     fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
         Some(("fake".into(), "fake".into()))
     }
 
+    let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
     let mut doc = String::new();
-    let mut spans = vec![];
-
-    for attr in attrs {
-        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
-            let (comment, current_spans) = strip_doc_comment_decoration(comment.as_str(), comment_kind, attr.span);
-            spans.extend_from_slice(&current_spans);
-            doc.push_str(&comment);
-        } else if attr.has_name(sym::doc) {
-            // ignore mix of sugared and non-sugared doc
-            // don't trigger the safety or errors check
-            return None;
-        }
-    }
-
-    let mut current = 0;
-    for &mut (ref mut offset, _) in &mut spans {
-        let offset_copy = *offset;
-        *offset = current;
-        current += offset_copy;
+    for fragment in &fragments {
+        add_doc_fragment(&mut doc, fragment);
     }
+    doc.pop();
 
     if doc.is_empty() {
         return Some(DocHeaders::default());
@@ -543,23 +492,19 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     let mut cb = fake_broken_link_callback;
 
-    let parser =
-        pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
-    // Iterate over all `Events` and combine consecutive events into one
-    let events = parser.coalesce(|previous, current| {
-        let previous_range = previous.1;
-        let current_range = current.1;
-
-        match (previous.0, current.0) {
-            (Text(previous), Text(current)) => {
-                let mut previous = previous.to_string();
-                previous.push_str(&current);
-                Ok((Text(previous.into()), previous_range))
-            },
-            (previous, current) => Err(((previous, previous_range), (current, current_range))),
-        }
-    });
-    Some(check_doc(cx, valid_idents, events, &spans))
+    // disable smart punctuation to pick up ['link'] more easily
+    let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION;
+    let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb));
+
+    Some(check_doc(
+        cx,
+        valid_idents,
+        parser.into_offset_iter(),
+        Fragments {
+            fragments: &fragments,
+            doc: &doc,
+        },
+    ))
 }
 
 const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
@@ -568,7 +513,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
     events: Events,
-    spans: &[(usize, Span)],
+    fragments: Fragments<'_>,
 ) -> DocHeaders {
     // true if a safety header was found
     let mut headers = DocHeaders::default();
@@ -579,8 +524,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut no_test = false;
     let mut edition = None;
     let mut ticks_unbalanced = false;
-    let mut text_to_check: Vec<(CowStr<'_>, Span)> = Vec::new();
-    let mut paragraph_span = spans.get(0).expect("function isn't called if doc comment is empty").1;
+    let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new();
+    let mut paragraph_range = 0..0;
     for (event, range) in events {
         match event {
             Start(CodeBlock(ref kind)) => {
@@ -613,25 +558,28 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     in_heading = true;
                 }
                 ticks_unbalanced = false;
-                let (_, span) = get_current_span(spans, range.start);
-                paragraph_span = first_line_of_span(cx, span);
+                paragraph_range = range;
             },
             End(Heading(_, _, _) | Paragraph | Item) => {
                 if let End(Heading(_, _, _)) = event {
                     in_heading = false;
                 }
-                if ticks_unbalanced {
+                if ticks_unbalanced
+                    && let Some(span) = fragments.span(cx, paragraph_range.clone())
+                {
                     span_lint_and_help(
                         cx,
                         DOC_MARKDOWN,
-                        paragraph_span,
+                        span,
                         "backticks are unbalanced",
                         None,
                         "a backtick may be missing a pair",
                     );
                 } else {
-                    for (text, span) in text_to_check {
-                        check_text(cx, valid_idents, &text, span);
+                    for (text, range) in text_to_check {
+                        if let Some(span) = fragments.span(cx, range) {
+                            check_text(cx, valid_idents, &text, span);
+                        }
                     }
                 }
                 text_to_check = Vec::new();
@@ -640,8 +588,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             Html(_html) => (),             // HTML is weird, just ignore it
             SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
             FootnoteReference(text) | Text(text) => {
-                let (begin, span) = get_current_span(spans, range.start);
-                paragraph_span = paragraph_span.with_hi(span.hi());
+                paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
                 if Some(&text) == in_link.as_ref() || ticks_unbalanced {
                     // Probably a link of the form `<http://example.com>`
@@ -658,19 +605,19 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 if in_code {
                     if is_rust && !no_test {
                         let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
-                        check_code(cx, &text, edition, span);
+                        check_code(cx, &text, edition, range.clone(), fragments);
                     }
                 } else {
-                    check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
-                    // Adjust for the beginning of the current `Event`
-                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
+                    if in_link.is_some() {
+                        check_link_quotes(cx, trimmed_text, range.clone(), fragments);
+                    }
                     if let Some(link) = in_link.as_ref()
                       && let Ok(url) = Url::parse(link)
                       && (url.scheme() == "https" || url.scheme() == "http") {
                         // Don't check the text associated with external URLs
                         continue;
                     }
-                    text_to_check.push((text, span));
+                    text_to_check.push((text, range));
                 }
             },
         }
@@ -678,36 +625,21 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     headers
 }
 
-fn check_link_quotes(
-    cx: &LateContext<'_>,
-    in_link: bool,
-    trimmed_text: &str,
-    span: Span,
-    range: &Range<usize>,
-    begin: usize,
-    text_len: usize,
-) {
-    if in_link && trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'') {
-        // fix the span to only point at the text within the link
-        let lo = span.lo() + BytePos::from_usize(range.start - begin);
+fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
+    if trimmed_text.starts_with('\'')
+        && trimmed_text.ends_with('\'')
+        && let Some(span) = fragments.span(cx, range)
+    {
         span_lint(
             cx,
             DOC_LINK_WITH_QUOTES,
-            span.with_lo(lo).with_hi(lo + BytePos::from_usize(text_len)),
+            span,
             "possible intra-doc link using quotes instead of backticks",
         );
     }
 }
 
-fn get_current_span(spans: &[(usize, Span)], idx: usize) -> (usize, Span) {
-    let index = match spans.binary_search_by(|c| c.0.cmp(&idx)) {
-        Ok(o) => o,
-        Err(e) => e - 1,
-    };
-    spans[index]
-}
-
-fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
+fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
     fn has_needless_main(code: String, edition: Edition) -> bool {
         rustc_driver::catch_fatal_errors(|| {
             rustc_span::create_session_globals_then(edition, || {
@@ -774,12 +706,13 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
         .unwrap_or_default()
     }
 
+    let trailing_whitespace = text.len() - text.trim_end().len();
+
     // Because of the global session, we need to create a new session in a different thread with
     // the edition we need.
     let text = text.to_owned();
-    if thread::spawn(move || has_needless_main(text, edition))
-        .join()
-        .expect("thread::spawn failed")
+    if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed")
+        && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
     {
         span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
     }
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index ab6ad3f3b3a..e2d19e24557 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -6,7 +6,7 @@ use clippy_utils::sugg::Sugg;
 use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && then_expr.span.ctxt() == ctxt
             && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
-            && !stmts_contains_early_return(then_block.stmts)
+            && !contains_return(then_block.stmts)
         {
             let mut app = Applicability::Unspecified;
             let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string();
@@ -116,17 +116,3 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
 
     extract_msrv_attr!(LateContext);
 }
-
-fn stmts_contains_early_return(stmts: &[Stmt<'_>]) -> bool {
-    stmts.iter().any(|stmt| {
-        let Stmt {
-            kind: StmtKind::Semi(e),
-            ..
-        } = stmt
-        else {
-            return false;
-        };
-
-        contains_return(e)
-    })
-}
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index c635120b882..d8ead1c9d9f 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use hir::PatKind;
+use hir::{Node, PatKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -37,6 +37,17 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
 
 impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+        match cx.tcx.hir().get_parent(pat.hir_id) {
+            Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
+                // Ignore function parameters
+                return;
+            },
+            Node::Local(local) if local.ty.is_some() => {
+                // Ignore let bindings with explicit type
+                return;
+            },
+            _ => {},
+        }
         if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index c6d1acad3a0..ec9044bba5c 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_errors::{Applicability, SuggestionStyle};
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Body, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, ItemKind, TraitBoundModifier, TraitItem,
@@ -9,7 +9,7 @@ use rustc_hir::{
 };
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, ClauseKind, TyCtxt};
+use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
@@ -45,52 +45,169 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub IMPLIED_BOUNDS_IN_IMPLS,
-    complexity,
+    nursery,
     "specifying bounds that are implied by other bounds in `impl Trait` type"
 }
 declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
 
-/// This function tries to, for all type parameters in a supertype predicate `GenericTrait<U>`,
-/// check if the substituted type in the implied-by bound matches with what's subtituted in the
-/// implied type.
+#[allow(clippy::too_many_arguments)]
+fn emit_lint(
+    cx: &LateContext<'_>,
+    poly_trait: &rustc_hir::PolyTraitRef<'_>,
+    opaque_ty: &rustc_hir::OpaqueTy<'_>,
+    index: usize,
+    // The bindings that were implied
+    implied_bindings: &[rustc_hir::TypeBinding<'_>],
+    // The original bindings that `implied_bindings` are implied from
+    implied_by_bindings: &[rustc_hir::TypeBinding<'_>],
+    implied_by_args: &[GenericArg<'_>],
+    implied_by_span: Span,
+) {
+    let implied_by = snippet(cx, implied_by_span, "..");
+
+    span_lint_and_then(
+        cx,
+        IMPLIED_BOUNDS_IN_IMPLS,
+        poly_trait.span,
+        &format!("this bound is already specified as the supertrait of `{implied_by}`"),
+        |diag| {
+            // If we suggest removing a bound, we may also need to extend the span
+            // to include the `+` token that is ahead or behind,
+            // so we don't end up with something like `impl + B` or `impl A + `
+
+            let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) {
+                poly_trait.span.to(next_bound.span().shrink_to_lo())
+            } else if index > 0
+                && let Some(prev_bound) = opaque_ty.bounds.get(index - 1)
+            {
+                prev_bound.span().shrink_to_hi().to(poly_trait.span.shrink_to_hi())
+            } else {
+                poly_trait.span
+            };
+
+            let mut sugg = vec![(implied_span_extended, String::new())];
+
+            // We also might need to include associated type binding that were specified in the implied bound,
+            // but omitted in the implied-by bound:
+            // `fn f() -> impl Deref<Target = u8> + DerefMut`
+            // If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
+            let omitted_assoc_tys: Vec<_> = implied_bindings
+                .iter()
+                .filter(|binding| !implied_by_bindings.iter().any(|b| b.ident == binding.ident))
+                .collect();
+
+            if !omitted_assoc_tys.is_empty() {
+                // `<>` needs to be added if there aren't yet any generic arguments or bindings
+                let needs_angle_brackets = implied_by_args.is_empty() && implied_by_bindings.is_empty();
+                let insert_span = match (implied_by_args, implied_by_bindings) {
+                    ([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(),
+                    ([.., arg], []) => arg.span().shrink_to_hi(),
+                    ([], [.., binding]) => binding.span.shrink_to_hi(),
+                    ([], []) => implied_by_span.shrink_to_hi(),
+                };
+
+                let mut associated_tys_sugg = if needs_angle_brackets {
+                    "<".to_owned()
+                } else {
+                    // If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
+                    // we need to add a comma:
+                    // `impl A<B, C >`
+                    //             ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
+                    // `impl A<B, C Assoc=i32>`
+                    ", ".to_owned()
+                };
+
+                for (index, binding) in omitted_assoc_tys.into_iter().enumerate() {
+                    if index > 0 {
+                        associated_tys_sugg += ", ";
+                    }
+                    associated_tys_sugg += &snippet(cx, binding.span, "..");
+                }
+                if needs_angle_brackets {
+                    associated_tys_sugg += ">";
+                }
+                sugg.push((insert_span, associated_tys_sugg));
+            }
+
+            diag.multipart_suggestion_with_style(
+                "try removing this bound",
+                sugg,
+                Applicability::MachineApplicable,
+                SuggestionStyle::ShowAlways,
+            );
+        },
+    );
+}
+
+/// Tries to "resolve" a type.
+/// The index passed to this function must start with `Self=0`, i.e. it must be a valid
+/// type parameter index.
+/// If the index is out of bounds, it means that the generic parameter has a default type.
+fn try_resolve_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    args: &'tcx [GenericArg<'tcx>],
+    generics: &'tcx Generics,
+    index: usize,
+) -> Option<Ty<'tcx>> {
+    match args.get(index - 1) {
+        Some(GenericArg::Type(ty)) => Some(hir_ty_to_ty(tcx, ty)),
+        Some(_) => None,
+        None => Some(tcx.type_of(generics.params[index].def_id).skip_binder()),
+    }
+}
+
+/// This function tries to, for all generic type parameters in a supertrait predicate `trait ...<U>:
+/// GenericTrait<U>`, check if the substituted type in the implied-by bound matches with what's
+/// subtituted in the implied bound.
 ///
 /// Consider this example.
 /// ```rust,ignore
 /// trait GenericTrait<T> {}
 /// trait GenericSubTrait<T, U, V>: GenericTrait<U> {}
-///                                              ^ trait_predicate_args: [Self#0, U#2]
+///                                 ^^^^^^^^^^^^^^^ trait_predicate_args: [Self#0, U#2]
+///                                                 (the Self#0 is implicit: `<Self as GenericTrait<U>>`)
 /// impl GenericTrait<i32> for () {}
 /// impl GenericSubTrait<(), i32, ()> for () {}
-/// impl GenericSubTrait<(), [u8; 8], ()> for () {}
+/// impl GenericSubTrait<(), i64, ()> for () {}
 ///
-/// fn f() -> impl GenericTrait<i32> + GenericSubTrait<(), [u8; 8], ()> {
-///                             ^^^ implied_args       ^^^^^^^^^^^^^^^ implied_by_args
-///                                                                    (we are interested in `[u8; 8]` specifically, as that
-///                                                                     is what `U` in `GenericTrait<U>` is substituted with)
-///     ()
+/// fn f() -> impl GenericTrait<i32> + GenericSubTrait<(), i64, ()> {
+///                             ^^^ implied_args       ^^^^^^^^^^^ implied_by_args
+///                                                                (we are interested in `i64` specifically, as that
+///                                                                 is what `U` in `GenericTrait<U>` is substituted with)
 /// }
 /// ```
-/// Here i32 != [u8; 8], so this will return false.
-fn is_same_generics(
-    tcx: TyCtxt<'_>,
-    trait_predicate_args: &[ty::GenericArg<'_>],
-    implied_by_args: &[GenericArg<'_>],
-    implied_args: &[GenericArg<'_>],
+/// Here i32 != i64, so this will return false.
+fn is_same_generics<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_predicate_args: &'tcx [ty::GenericArg<'tcx>],
+    implied_by_args: &'tcx [GenericArg<'tcx>],
+    implied_args: &'tcx [GenericArg<'tcx>],
+    implied_by_def_id: DefId,
+    implied_def_id: DefId,
 ) -> bool {
+    // Get the generics of the two traits to be able to get default generic parameter.
+    let implied_by_generics = tcx.generics_of(implied_by_def_id);
+    let implied_generics = tcx.generics_of(implied_def_id);
+
     trait_predicate_args
         .iter()
         .enumerate()
         .skip(1) // skip `Self` implicit arg
         .all(|(arg_index, arg)| {
-            if let Some(ty) = arg.as_type()
-                && let &ty::Param(ty::ParamTy{ index, .. }) = ty.kind()
-                // Since `trait_predicate_args` and type params in traits start with `Self=0`
-                // and generic argument lists `GenericTrait<i32>` don't have `Self`,
-                // we need to subtract 1 from the index.
-                && let GenericArg::Type(ty_a) = implied_by_args[index as usize - 1]
-                && let GenericArg::Type(ty_b) = implied_args[arg_index - 1]
-            {
-                hir_ty_to_ty(tcx, ty_a) == hir_ty_to_ty(tcx, ty_b)
+            if let Some(ty) = arg.as_type() {
+                if let &ty::Param(ty::ParamTy { index, .. }) = ty.kind()
+                    // `index == 0` means that it's referring to `Self`,
+                    // in which case we don't try to substitute it
+                    && index != 0
+                    && let Some(ty_a) = try_resolve_type(tcx, implied_by_args, implied_by_generics, index as usize)
+                    && let Some(ty_b) = try_resolve_type(tcx, implied_args, implied_generics, arg_index)
+                {
+                    ty_a == ty_b
+                } else if let Some(ty_b) = try_resolve_type(tcx, implied_args, implied_generics, arg_index) {
+                    ty == ty_b
+                } else {
+                    false
+                }
             } else {
                 false
             }
@@ -121,7 +238,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
                 && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
                 && !predicates.is_empty() // If the trait has no supertrait, there is nothing to add.
             {
-                Some((bound.span(), path.args.map_or([].as_slice(), |a| a.args), predicates))
+                Some((bound.span(), path, predicates, trait_def_id))
             } else {
                 None
             }
@@ -134,43 +251,42 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
             if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
                 && let [.., path] = poly_trait.trait_ref.path.segments
                 && let implied_args = path.args.map_or([].as_slice(), |a| a.args)
+                && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings)
                 && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
-                && let Some(implied_by_span) = implied_bounds.iter().find_map(|&(span, implied_by_args, preds)| {
-                    preds.iter().find_map(|(clause, _)| {
-                        if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
-                            && tr.def_id() == def_id
-                            && is_same_generics(cx.tcx, tr.trait_ref.args, implied_by_args, implied_args)
-                        {
-                            Some(span)
-                        } else {
-                            None
-                        }
+                && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds
+                    .iter()
+                    .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| {
+                        let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args);
+                        let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings);
+
+                        preds.iter().find_map(|(clause, _)| {
+                            if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
+                                && tr.def_id() == def_id
+                                && is_same_generics(
+                                    cx.tcx,
+                                    tr.trait_ref.args,
+                                    implied_by_args,
+                                    implied_args,
+                                    implied_by_def_id,
+                                    def_id,
+                                )
+                            {
+                                Some((span, implied_by_args, implied_by_bindings))
+                            } else {
+                                None
+                            }
+                        })
                     })
-                })
             {
-                let implied_by = snippet(cx, implied_by_span, "..");
-                span_lint_and_then(
-                    cx, IMPLIED_BOUNDS_IN_IMPLS,
-                    poly_trait.span,
-                    &format!("this bound is already specified as the supertrait of `{implied_by}`"),
-                    |diag| {
-                        // If we suggest removing a bound, we may also need extend the span
-                        // to include the `+` token, so we don't end up with something like `impl + B`
-
-                        let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) {
-                            poly_trait.span.to(next_bound.span().shrink_to_lo())
-                        } else {
-                            poly_trait.span
-                        };
-
-                        diag.span_suggestion_with_style(
-                            implied_span_extended,
-                            "try removing this bound",
-                            "",
-                            Applicability::MachineApplicable,
-                            SuggestionStyle::ShowAlways
-                        );
-                    }
+                emit_lint(
+                    cx,
+                    poly_trait,
+                    opaque_ty,
+                    index,
+                    implied_bindings,
+                    implied_by_bindings,
+                    implied_by_args,
+                    implied_by_span
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index ab71bfbdc58..f52614b6208 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -21,6 +21,7 @@
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
+extern crate pulldown_cmark;
 extern crate rustc_arena;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
@@ -37,6 +38,7 @@ extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
 extern crate rustc_parse;
+extern crate rustc_resolve;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -154,7 +156,6 @@ mod implicit_saturating_add;
 mod implicit_saturating_sub;
 mod implied_bounds_in_impls;
 mod inconsistent_struct_constructor;
-mod incorrect_impls;
 mod index_refutable_slice;
 mod indexing_slicing;
 mod infinite_iter;
@@ -210,6 +211,7 @@ mod misc;
 mod misc_early;
 mod mismatching_type_param_order;
 mod missing_assert_message;
+mod missing_asserts_for_indexing;
 mod missing_const_for_fn;
 mod missing_doc;
 mod missing_enforced_import_rename;
@@ -243,6 +245,7 @@ mod neg_multiply;
 mod new_without_default;
 mod no_effect;
 mod no_mangle_with_rust_abi;
+mod non_canonical_impls;
 mod non_copy_const;
 mod non_expressive_names;
 mod non_octal_unix_permissions;
@@ -695,7 +698,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_late_pass(|_| Box::<shadow::Shadow>::default());
     store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
-    store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv())));
+    let enforce_iter_loop_reborrow = conf.enforce_iter_loop_reborrow;
+    store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv(), enforce_iter_loop_reborrow)));
     store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
     store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
     store.register_late_pass(|_| Box::new(entry::HashMapPass));
@@ -1068,7 +1072,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             avoid_breaking_exported_api,
         ))
     });
-    store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls));
+    store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
     store.register_late_pass(move |_| {
         Box::new(single_call_fn::SingleCallFn {
             avoid_breaking_exported_api,
@@ -1099,6 +1103,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
     store.register_late_pass(|_| Box::<reserve_after_initialization::ReserveAfterInitialization>::default());
     store.register_late_pass(|_| Box::new(implied_bounds_in_impls::ImpliedBoundsInImpls));
+    store.register_late_pass(|_| Box::new(missing_asserts_for_indexing::MissingAssertsForIndexing));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 7b8c88235a9..6ab256ef001 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -13,8 +13,14 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMut
 use rustc_middle::ty::{self, EarlyBinder, Ty, TypeAndMut};
 use rustc_span::sym;
 
-pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>, msrv: &Msrv) {
-    let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr) else {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    self_arg: &Expr<'_>,
+    call_expr: &Expr<'_>,
+    msrv: &Msrv,
+    enforce_iter_loop_reborrow: bool,
+) {
+    let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow) else {
         return;
     };
     if let ty::Array(_, count) = *ty.peel_refs().kind() {
@@ -102,6 +108,7 @@ fn is_ref_iterable<'tcx>(
     cx: &LateContext<'tcx>,
     self_arg: &Expr<'_>,
     call_expr: &Expr<'_>,
+    enforce_iter_loop_reborrow: bool,
 ) -> Option<(AdjustKind, Ty<'tcx>)> {
     let typeck = cx.typeck_results();
     if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
@@ -142,7 +149,8 @@ fn is_ref_iterable<'tcx>(
                 {
                     return Some((AdjustKind::None, self_ty));
                 }
-            } else if let ty::Ref(region, ty, Mutability::Mut) = *self_ty.kind()
+            } else if enforce_iter_loop_reborrow
+                && let ty::Ref(region, ty, Mutability::Mut) = *self_ty.kind()
                 && let Some(mutbl) = mutbl
             {
                 // Attempt to reborrow the mutable reference
@@ -186,7 +194,8 @@ fn is_ref_iterable<'tcx>(
                 },
                 ..
             ] => {
-                if target != self_ty
+                if enforce_iter_loop_reborrow
+                    && target != self_ty
                     && implements_trait(cx, target, trait_id, &[])
                     && let Some(ty) =
                         make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index ffd29ab7630..1fb16adad7a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -609,10 +609,14 @@ declare_clippy_lint! {
 
 pub struct Loops {
     msrv: Msrv,
+    enforce_iter_loop_reborrow: bool,
 }
 impl Loops {
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(msrv: Msrv, enforce_iter_loop_reborrow: bool) -> Self {
+        Self {
+            msrv,
+            enforce_iter_loop_reborrow,
+        }
     }
 }
 impl_lint_pass!(Loops => [
@@ -719,7 +723,7 @@ impl Loops {
         if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
             match method.ident.as_str() {
                 "iter" | "iter_mut" => {
-                    explicit_iter_loop::check(cx, self_arg, arg, &self.msrv);
+                    explicit_iter_loop::check(cx, self_arg, arg, &self.msrv, self.enforce_iter_loop_reborrow);
                 },
                 "into_iter" => {
                     explicit_into_iter_loop::check(cx, self_arg, arg);
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index cc19ac55e5e..3d8a4cd948a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -1,13 +1,13 @@
 use super::utils::make_iterator_snippet;
 use super::NEVER_LOOP;
-use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
+use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use std::iter::{once, Iterator};
 
 pub(super) fn check<'tcx>(
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
     for_loop: Option<&ForLoop<'_>>,
 ) {
     match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
-        NeverLoopResult::AlwaysBreak => {
+        NeverLoopResult::Diverging => {
             span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
                 if let Some(ForLoop {
                     arg: iterator,
@@ -39,67 +39,76 @@ pub(super) fn check<'tcx>(
                 }
             });
         },
-        NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
-        NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
+        NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Normal => (),
     }
 }
 
+/// The `never_loop` analysis keeps track of three things:
+///
+/// * Has any (reachable) code path hit a `continue` of the main loop?
+/// * Is the current code path diverging (that is, the next expression is not reachable)
+/// * For each block label `'a` inside the main loop, has any (reachable) code path encountered a
+///   `break 'a`?
+///
+/// The first two bits of information are in this enum, and the last part is in the
+/// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
+/// scope.
 #[derive(Copy, Clone)]
 enum NeverLoopResult {
-    // A break/return always get triggered but not necessarily for the main loop.
-    AlwaysBreak,
-    // A continue may occur for the main loop.
+    /// A continue may occur for the main loop.
     MayContinueMainLoop,
-    // Ignore everything until the end of the block with this id
-    IgnoreUntilEnd(HirId),
-    Otherwise,
+    /// We have not encountered any main loop continue,
+    /// but we are diverging (subsequent control flow is not reachable)
+    Diverging,
+    /// We have not encountered any main loop continue,
+    /// and subsequent control flow is (possibly) reachable
+    Normal,
 }
 
 #[must_use]
 fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
     match arg {
-        NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
+        NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
         NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
-        NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
     }
 }
 
 // Combine two results for parts that are called in order.
 #[must_use]
-fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
+fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) -> NeverLoopResult {
     match first {
-        NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
-            first
-        },
-        NeverLoopResult::Otherwise => second,
+        NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop => first,
+        NeverLoopResult::Normal => second(),
+    }
+}
+
+// Combine an iterator of results for parts that are called in order.
+#[must_use]
+fn combine_seq_many(iter: impl IntoIterator<Item = NeverLoopResult>) -> NeverLoopResult {
+    for e in iter {
+        if let NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop = e {
+            return e;
+        }
     }
+    NeverLoopResult::Normal
 }
 
 // Combine two results where only one of the part may have been executed.
 #[must_use]
-fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
+fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
     match (b1, b2) {
-        (NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => {
-            if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a {
-                NeverLoopResult::IgnoreUntilEnd(b)
-            } else {
-                NeverLoopResult::IgnoreUntilEnd(a)
-            }
-        },
-        (i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak)
-        | (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i,
-        (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
         (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
             NeverLoopResult::MayContinueMainLoop
         },
-        (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
+        (NeverLoopResult::Normal, _) | (_, NeverLoopResult::Normal) => NeverLoopResult::Normal,
+        (NeverLoopResult::Diverging, NeverLoopResult::Diverging) => NeverLoopResult::Diverging,
     }
 }
 
 fn never_loop_block<'tcx>(
     cx: &LateContext<'tcx>,
     block: &Block<'tcx>,
-    ignore_ids: &mut Vec<HirId>,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
     let iter = block
@@ -107,15 +116,21 @@ fn never_loop_block<'tcx>(
         .iter()
         .filter_map(stmt_to_expr)
         .chain(block.expr.map(|expr| (expr, None)));
-
-    iter.map(|(e, els)| {
-        let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
+    combine_seq_many(iter.map(|(e, els)| {
+        let e = never_loop_expr(cx, e, local_labels, main_loop_id);
         // els is an else block in a let...else binding
         els.map_or(e, |els| {
-            combine_branches(e, never_loop_block(cx, els, ignore_ids, main_loop_id), ignore_ids)
+            combine_seq(e, || match never_loop_block(cx, els, local_labels, main_loop_id) {
+                // Returning MayContinueMainLoop here means that
+                // we will not evaluate the rest of the body
+                NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
+                // An else block always diverges, so the Normal case should not happen,
+                // but the analysis is approximate so it might return Normal anyway.
+                // Returning Normal here says that nothing more happens on the main path
+                NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
+            })
         })
-    })
-    .fold(NeverLoopResult::Otherwise, combine_seq)
+    }))
 }
 
 fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
@@ -131,76 +146,69 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
 fn never_loop_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'tcx>,
-    ignore_ids: &mut Vec<HirId>,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    match expr.kind {
+    let result = match expr.kind {
         ExprKind::Unary(_, e)
         | ExprKind::Cast(e, _)
         | ExprKind::Type(e, _)
         | ExprKind::Field(e, _)
         | ExprKind::AddrOf(_, _, e)
         | ExprKind::Repeat(e, _)
-        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, ignore_ids, main_loop_id),
-        ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, ignore_ids, main_loop_id),
-        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, &mut es.iter(), ignore_ids, main_loop_id),
+        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
+        ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
+        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
             cx,
-            &mut std::iter::once(receiver).chain(es.iter()),
-            ignore_ids,
+            std::iter::once(receiver).chain(es.iter()),
+            local_labels,
             main_loop_id,
         ),
         ExprKind::Struct(_, fields, base) => {
-            let fields = never_loop_expr_all(cx, &mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
+            let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id);
             if let Some(base) = base {
-                combine_seq(fields, never_loop_expr(cx, base, ignore_ids, main_loop_id))
+                combine_seq(fields, || never_loop_expr(cx, base, local_labels, main_loop_id))
             } else {
                 fields
             }
         },
-        ExprKind::Call(e, es) => never_loop_expr_all(cx, &mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
+        ExprKind::Call(e, es) => never_loop_expr_all(cx, once(e).chain(es.iter()), local_labels, main_loop_id),
         ExprKind::Binary(_, e1, e2)
         | ExprKind::Assign(e1, e2, _)
         | ExprKind::AssignOp(_, e1, e2)
-        | ExprKind::Index(e1, e2, _) => {
-            never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
-        },
+        | ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, [e1, e2].iter().copied(), local_labels, main_loop_id),
         ExprKind::Loop(b, _, _, _) => {
-            // Break can come from the inner loop so remove them.
-            absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
+            // We don't attempt to track reachability after a loop,
+            // just assume there may have been a break somewhere
+            absorb_break(never_loop_block(cx, b, local_labels, main_loop_id))
         },
         ExprKind::If(e, e2, e3) => {
-            let e1 = never_loop_expr(cx, e, ignore_ids, main_loop_id);
-            let e2 = never_loop_expr(cx, e2, ignore_ids, main_loop_id);
-            // If we know the `if` condition evaluates to `true`, don't check everything past it; it
-            // should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable
-            if let Some(Constant::Bool(true)) = constant(cx, cx.typeck_results(), e) {
-                return combine_seq(e1, e2);
-            }
-            let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
-                never_loop_expr(cx, e, ignore_ids, main_loop_id)
-            });
-            combine_seq(e1, combine_branches(e2, e3, ignore_ids))
+            let e1 = never_loop_expr(cx, e, local_labels, main_loop_id);
+            combine_seq(e1, || {
+                let e2 = never_loop_expr(cx, e2, local_labels, main_loop_id);
+                let e3 = e3.as_ref().map_or(NeverLoopResult::Normal, |e| {
+                    never_loop_expr(cx, e, local_labels, main_loop_id)
+                });
+                combine_branches(e2, e3)
+            })
         },
         ExprKind::Match(e, arms, _) => {
-            let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
-            if arms.is_empty() {
-                e
-            } else {
-                let arms = never_loop_expr_branch(cx, &mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
-                combine_seq(e, arms)
-            }
+            let e = never_loop_expr(cx, e, local_labels, main_loop_id);
+            combine_seq(e, || {
+                arms.iter().fold(NeverLoopResult::Diverging, |a, b| {
+                    combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
+                })
+            })
         },
         ExprKind::Block(b, l) => {
             if l.is_some() {
-                ignore_ids.push(b.hir_id);
-            }
-            let ret = never_loop_block(cx, b, ignore_ids, main_loop_id);
-            if l.is_some() {
-                ignore_ids.pop();
+                local_labels.push((b.hir_id, false));
             }
+            let ret = never_loop_block(cx, b, local_labels, main_loop_id);
+            let jumped_to = l.is_some() && local_labels.pop().unwrap().1;
             match ret {
-                NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
+                NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal,
                 _ => ret,
             }
         },
@@ -211,74 +219,78 @@ fn never_loop_expr<'tcx>(
             if id == main_loop_id {
                 NeverLoopResult::MayContinueMainLoop
             } else {
-                NeverLoopResult::AlwaysBreak
+                NeverLoopResult::Diverging
             }
         },
-        // checks if break targets a block instead of a loop
-        ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
-            .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
-                never_loop_expr(cx, e, ignore_ids, main_loop_id)
-            }),
-        ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
-            combine_seq(
-                never_loop_expr(cx, e, ignore_ids, main_loop_id),
-                NeverLoopResult::AlwaysBreak,
-            )
-        }),
-        ExprKind::Become(e) => combine_seq(
-            never_loop_expr(cx, e, ignore_ids, main_loop_id),
-            NeverLoopResult::AlwaysBreak,
-        ),
-        ExprKind::InlineAsm(asm) => asm
-            .operands
-            .iter()
-            .map(|(o, _)| match o {
-                InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
-                    never_loop_expr(cx, expr, ignore_ids, main_loop_id)
-                },
-                InlineAsmOperand::Out { expr, .. } => {
-                    never_loop_expr_all(cx, &mut expr.iter().copied(), ignore_ids, main_loop_id)
-                },
-                InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
-                    cx,
-                    &mut once(*in_expr).chain(out_expr.iter().copied()),
-                    ignore_ids,
-                    main_loop_id,
-                ),
-                InlineAsmOperand::Const { .. }
-                | InlineAsmOperand::SymFn { .. }
-                | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
+        ExprKind::Break(_, e) | ExprKind::Ret(e) => {
+            let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| {
+                never_loop_expr(cx, e, local_labels, main_loop_id)
+            });
+            combine_seq(first, || {
+                // checks if break targets a block instead of a loop
+                if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind {
+                    if let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) {
+                        *reachable = true;
+                    }
+                }
+                NeverLoopResult::Diverging
             })
-            .fold(NeverLoopResult::Otherwise, combine_seq),
+        },
+        ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
+            NeverLoopResult::Diverging
+        }),
+        ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
+            InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
+                never_loop_expr(cx, expr, local_labels, main_loop_id)
+            },
+            InlineAsmOperand::Out { expr, .. } => {
+                never_loop_expr_all(cx, expr.iter().copied(), local_labels, main_loop_id)
+            },
+            InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
+                cx,
+                once(*in_expr).chain(out_expr.iter().copied()),
+                local_labels,
+                main_loop_id,
+            ),
+            InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => {
+                NeverLoopResult::Normal
+            },
+        })),
         ExprKind::OffsetOf(_, _)
         | ExprKind::Yield(_, _)
         | ExprKind::Closure { .. }
         | ExprKind::Path(_)
         | ExprKind::ConstBlock(_)
         | ExprKind::Lit(_)
-        | ExprKind::Err(_) => NeverLoopResult::Otherwise,
+        | ExprKind::Err(_) => NeverLoopResult::Normal,
+    };
+    let result = combine_seq(result, || {
+        if cx.typeck_results().expr_ty(expr).is_never() {
+            NeverLoopResult::Diverging
+        } else {
+            NeverLoopResult::Normal
+        }
+    });
+    if  let NeverLoopResult::Diverging = result &&
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) &&
+        let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+    {
+        // We return MayContinueMainLoop here because we treat `todo!()`
+        // as potentially containing any code, including a continue of the main loop.
+        // This effectively silences the lint whenever a loop contains this macro anywhere.
+        NeverLoopResult::MayContinueMainLoop
+    } else {
+        result
     }
 }
 
 fn never_loop_expr_all<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
     cx: &LateContext<'tcx>,
-    es: &mut T,
-    ignore_ids: &mut Vec<HirId>,
-    main_loop_id: HirId,
-) -> NeverLoopResult {
-    es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id))
-        .fold(NeverLoopResult::Otherwise, combine_seq)
-}
-
-fn never_loop_expr_branch<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
-    cx: &LateContext<'tcx>,
-    e: &mut T,
-    ignore_ids: &mut Vec<HirId>,
+    es: T,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
-        combine_branches(a, never_loop_expr(cx, b, ignore_ids, main_loop_id), ignore_ids)
-    })
+    combine_seq_many(es.map(|e| never_loop_expr(cx, e, local_labels, main_loop_id)))
 }
 
 fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index 39d8b20d38d..90557b55560 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -1,4 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_opt;
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -6,6 +7,7 @@ use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{Span, DUMMY_SP};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -49,6 +51,29 @@ fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
     }
 }
 
+#[derive(Copy, Clone)]
+struct Num {
+    val: i128,
+    span: Span,
+}
+
+impl Num {
+    fn new(expr: &Expr<'_>) -> Option<Self> {
+        Some(Self {
+            val: expr_as_i128(expr)?,
+            span: expr.span,
+        })
+    }
+
+    fn dummy(val: i128) -> Self {
+        Self { val, span: DUMMY_SP }
+    }
+
+    fn min(self, other: Self) -> Self {
+        if self.val < other.val { self } else { other }
+    }
+}
+
 impl LateLintPass<'_> for ManualRangePatterns {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
         if in_external_macro(cx.sess(), pat.span) {
@@ -56,71 +81,83 @@ impl LateLintPass<'_> for ManualRangePatterns {
         }
 
         // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
+        // or at least one range
         if let PatKind::Or(pats) = pat.kind
-            && pats.len() >= 3
+            && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
         {
-            let mut min = i128::MAX;
-            let mut max = i128::MIN;
+            let mut min = Num::dummy(i128::MAX);
+            let mut max = Num::dummy(i128::MIN);
+            let mut range_kind = RangeEnd::Included;
             let mut numbers_found = FxHashSet::default();
             let mut ranges_found = Vec::new();
 
             for pat in pats {
                 if let PatKind::Lit(lit) = pat.kind
-                    && let Some(num) = expr_as_i128(lit)
+                    && let Some(num) = Num::new(lit)
                 {
-                    numbers_found.insert(num);
+                    numbers_found.insert(num.val);
 
                     min = min.min(num);
-                    max = max.max(num);
+                    if num.val >= max.val {
+                        max = num;
+                        range_kind = RangeEnd::Included;
+                    }
                 } else if let PatKind::Range(Some(left), Some(right), end) = pat.kind
-                    && let Some(left) = expr_as_i128(left)
-                    && let Some(right) = expr_as_i128(right)
-                    && right >= left
+                    && let Some(left) = Num::new(left)
+                    && let Some(mut right) = Num::new(right)
                 {
+                    if let RangeEnd::Excluded = end {
+                        right.val -= 1;
+                    }
+
                     min = min.min(left);
-                    max = max.max(right);
-                    ranges_found.push(left..=match end {
-                        RangeEnd::Included => right,
-                        RangeEnd::Excluded => right - 1,
-                    });
+                    if right.val > max.val {
+                        max = right;
+                        range_kind = end;
+                    }
+                    ranges_found.push(left.val..=right.val);
                 } else {
                     return;
                 }
             }
 
-            let contains_whole_range = 'contains: {
-                let mut num = min;
-                while num <= max {
-                    if numbers_found.contains(&num) {
-                        num += 1;
-                    }
-                    // Given a list of (potentially overlapping) ranges like:
-                    // 1..=5, 3..=7, 6..=10
-                    // We want to find the range with the highest end that still contains the current number
-                    else if let Some(range) = ranges_found
-                        .iter()
-                        .filter(|range| range.contains(&num))
-                        .max_by_key(|range| range.end())
-                    {
-                        num = range.end() + 1;
-                    } else {
-                        break 'contains false;
-                    }
+            let mut num = min.val;
+            while num <= max.val {
+                if numbers_found.contains(&num) {
+                    num += 1;
+                }
+                // Given a list of (potentially overlapping) ranges like:
+                // 1..=5, 3..=7, 6..=10
+                // We want to find the range with the highest end that still contains the current number
+                else if let Some(range) = ranges_found
+                    .iter()
+                    .filter(|range| range.contains(&num))
+                    .max_by_key(|range| range.end())
+                {
+                    num = range.end() + 1;
+                } else {
+                    return;
                 }
-                break 'contains true;
-            };
-
-            if contains_whole_range {
-                span_lint_and_sugg(
-                    cx,
-                    MANUAL_RANGE_PATTERNS,
-                    pat.span,
-                    "this OR pattern can be rewritten using a range",
-                    "try",
-                    format!("{min}..={max}"),
-                    Applicability::MachineApplicable,
-                );
             }
+
+            span_lint_and_then(
+                cx,
+                MANUAL_RANGE_PATTERNS,
+                pat.span,
+                "this OR pattern can be rewritten using a range",
+                |diag| {
+                    if let Some(min) = snippet_opt(cx, min.span)
+                        && let Some(max) = snippet_opt(cx, max.span)
+                    {
+                        diag.span_suggestion(
+                            pat.span,
+                            "try",
+                            format!("{min}{range_kind}{max}"),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 8be3c178a29..6e13148f2fc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -37,22 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                         Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
                         None => {
                             let min_val_const = ty.numeric_min_val(cx.tcx)?;
-                            let min_constant = mir::ConstantKind::from_value(
-                                cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
-                                ty,
-                            );
-                            miri_to_const(cx, min_constant)?
+                            miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))?
                         },
                     };
                     let rhs_const = match rhs {
                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
                         None => {
                             let max_val_const = ty.numeric_max_val(cx.tcx)?;
-                            let max_constant = mir::ConstantKind::from_value(
-                                cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
-                                ty,
-                            );
-                            miri_to_const(cx, max_constant)?
+                            miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))?
                         },
                     };
                     let lhs_val = lhs_const.int_value(cx, ty)?;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
new file mode 100644
index 00000000000..79c6d63254b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -0,0 +1,106 @@
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::higher::VecArgs;
+use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths};
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self};
+use rustc_span::sym;
+
+use super::ITER_OUT_OF_BOUNDS;
+
+fn expr_as_u128(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<u128> {
+    if let ExprKind::Lit(lit) = expr_or_init(cx, e).kind
+        && let LitKind::Int(n, _) = lit.node
+    {
+        Some(n)
+    } else {
+        None
+    }
+}
+
+/// Attempts to extract the length out of an iterator expression.
+fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> Option<u128> {
+    let ty::Adt(adt, substs) = cx.typeck_results().expr_ty(iter).kind() else {
+        return None;
+    };
+    let did = adt.did();
+
+    if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) {
+        // For array::IntoIter<T, const N: usize>, the length is the second generic
+        // parameter.
+        substs
+            .const_at(1)
+            .try_eval_target_usize(cx.tcx, cx.param_env)
+            .map(u128::from)
+    } else if match_def_path(cx, did, &paths::SLICE_ITER)
+        && let ExprKind::MethodCall(_, recv, ..) = iter.kind
+    {
+        if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
+            // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..)
+            len.try_eval_target_usize(cx.tcx, cx.param_env).map(u128::from)
+        } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) {
+            match args {
+                VecArgs::Vec(vec) => vec.len().try_into().ok(),
+                VecArgs::Repeat(_, len) => expr_as_u128(cx, len),
+            }
+        } else {
+            None
+        }
+    } else if match_def_path(cx, did, &paths::ITER_EMPTY) {
+        Some(0)
+    } else if match_def_path(cx, did, &paths::ITER_ONCE) {
+        Some(1)
+    }  else {
+        None
+    }
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &'tcx Expr<'tcx>,
+    arg: &'tcx Expr<'tcx>,
+    message: &'static str,
+    note: &'static str,
+) {
+    if is_trait_method(cx, expr, sym::Iterator)
+        && let Some(len) = get_iterator_length(cx, recv)
+        && let Some(skipped) = expr_as_u128(cx, arg)
+        && skipped > len
+    {
+        span_lint_and_note(cx, ITER_OUT_OF_BOUNDS, expr.span, message, None, note);
+    }
+}
+
+pub(super) fn check_skip<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &'tcx Expr<'tcx>,
+    arg: &'tcx Expr<'tcx>,
+) {
+    check(
+        cx,
+        expr,
+        recv,
+        arg,
+        "this `.skip()` call skips more items than the iterator will produce",
+        "this operation is useless and will create an empty iterator",
+    );
+}
+
+pub(super) fn check_take<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &'tcx Expr<'tcx>,
+    arg: &'tcx Expr<'tcx>,
+) {
+    check(
+        cx,
+        expr,
+        recv,
+        arg,
+        "this `.take()` call takes more items than the iterator will produce",
+        "this operation is useless and the returned iterator will simply yield the same items",
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index ee405a3e30c..a49dd98db87 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -21,7 +21,7 @@ pub(super) enum Op<'a> {
     RmCloned,
 
     // rm `.cloned()`
-    // e.g. `map` `for_each`
+    // e.g. `map` `for_each` `all` `any`
     NeedlessMove(&'a str, &'a Expr<'a>),
 
     // later `.cloned()`
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 5075137caa0..81223fa8d95 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -43,6 +43,7 @@ mod iter_next_slice;
 mod iter_nth;
 mod iter_nth_zero;
 mod iter_on_single_or_empty_collections;
+mod iter_out_of_bounds;
 mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iter_skip_zero;
@@ -3054,12 +3055,12 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+    /// vec![1, 2, 3, 4, 5].resize(0, 5)
     /// ```
     ///
     /// Use instead:
     /// ```rust
-    /// vec!(1, 2, 3, 4, 5).clear()
+    /// vec![1, 2, 3, 4, 5].clear()
     /// ```
     #[clippy::version = "1.46.0"]
     pub VEC_RESIZE_TO_ZERO,
@@ -3538,6 +3539,30 @@ declare_clippy_lint! {
     "acquiring a write lock when a read lock would work"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for iterator combinator calls such as `.take(x)` or `.skip(x)`
+    /// where `x` is greater than the amount of items that an iterator will produce.
+    ///
+    /// ### Why is this bad?
+    /// Taking or skipping more items than there are in an iterator either creates an iterator
+    /// with all items from the original iterator or an iterator with no items at all.
+    /// This is most likely not what the user intended to do.
+    ///
+    /// ### Example
+    /// ```rust
+    /// for _ in [1, 2, 3].iter().take(4) {}
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// for _ in [1, 2, 3].iter() {}
+    /// ```
+    #[clippy::version = "1.74.0"]
+    pub ITER_OUT_OF_BOUNDS,
+    suspicious,
+    "calls to `.take()` or `.skip()` that are out of bounds"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3676,7 +3701,8 @@ impl_lint_pass!(Methods => [
     STRING_LIT_CHARS_ANY,
     ITER_SKIP_ZERO,
     FILTER_MAP_BOOL_THEN,
-    READONLY_WRITE_LOCK
+    READONLY_WRITE_LOCK,
+    ITER_OUT_OF_BOUNDS,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3873,6 +3899,12 @@ impl Methods {
                 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                     zst_offset::check(cx, expr, recv);
                 },
+                ("all", [arg]) => {
+                    if let Some(("cloned", recv2, [], _, _)) = method_call(recv) {
+                        iter_overeager_cloned::check(cx, expr, recv, recv2,
+                                iter_overeager_cloned::Op::NeedlessMove(name, arg), false);
+                    }
+                }
                 ("and_then", [arg]) => {
                     let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
                     let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
@@ -3880,12 +3912,16 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
-                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
-                    && let body = cx.tcx.hir().body(arg.body)
-                    && let [param] = body.params
-                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
-                {
-                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                ("any", [arg]) => {
+                    match method_call(recv) {
+                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false),
+                        Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind
+                        && let body = cx.tcx.hir().body(arg.body)
+                        && let [param] = body.params => {
+                            string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                        }
+                        _ => {}
+                    }
                 }
                 ("arg", [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
@@ -4136,6 +4172,7 @@ impl Methods {
                 },
                 ("skip", [arg]) => {
                     iter_skip_zero::check(cx, expr, arg);
+                    iter_out_of_bounds::check_skip(cx, expr, recv, arg);
 
                     if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(cx, expr, recv, recv2,
@@ -4163,7 +4200,8 @@ impl Methods {
                     }
                 },
                 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
-                ("take", [_arg]) => {
+                ("take", [arg]) => {
+                    iter_out_of_bounds::check_take(cx, expr, recv, arg);
                     if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(cx, expr, recv, recv2,
                                 iter_overeager_cloned::Op::LaterCloned, false);
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
new file mode 100644
index 00000000000..08fec2b8ec8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -0,0 +1,391 @@
+use std::mem;
+use std::ops::ControlFlow;
+
+use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{eq_expr_value, hash_expr, higher};
+use rustc_ast::{LitKind, RangeLimits};
+use rustc_data_structures::unhash::UnhashMap;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::{BinOp, Block, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for repeated slice indexing without asserting beforehand that the length
+    /// is greater than the largest index used to index into the slice.
+    ///
+    /// ### Why is this bad?
+    /// In the general case where the compiler does not have a lot of information
+    /// about the length of a slice, indexing it repeatedly will generate a bounds check
+    /// for every single index.
+    ///
+    /// Asserting that the length of the slice is at least as large as the largest value
+    /// to index beforehand gives the compiler enough information to elide the bounds checks,
+    /// effectively reducing the number of bounds checks from however many times
+    /// the slice was indexed to just one (the assert).
+    ///
+    /// ### Drawbacks
+    /// False positives. It is, in general, very difficult to predict how well
+    /// the optimizer will be able to elide bounds checks and it very much depends on
+    /// the surrounding code. For example, indexing into the slice yielded by the
+    /// [`slice::chunks_exact`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.chunks_exact)
+    /// iterator will likely have all of the bounds checks elided even without an assert
+    /// if the `chunk_size` is a constant.
+    ///
+    /// Asserts are not tracked across function calls. Asserting the length of a slice
+    /// in a different function likely gives the optimizer enough information
+    /// about the length of a slice, but this lint will not detect that.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn sum(v: &[u8]) -> u8 {
+    ///     // 4 bounds checks
+    ///     v[0] + v[1] + v[2] + v[3]
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn sum(v: &[u8]) -> u8 {
+    ///     assert!(v.len() > 4);
+    ///     // no bounds checks
+    ///     v[0] + v[1] + v[2] + v[3]
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MISSING_ASSERTS_FOR_INDEXING,
+    restriction,
+    "indexing into a slice multiple times without an `assert`"
+}
+declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]);
+
+fn report_lint<F>(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F)
+where
+    F: FnOnce(&mut Diagnostic),
+{
+    span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, full_span, msg, |diag| {
+        f(diag);
+        for span in indexes {
+            diag.span_note(*span, "slice indexed here");
+        }
+        diag.note("asserting the length before indexing will elide bounds checks");
+    });
+}
+
+#[derive(Copy, Clone, Debug)]
+enum LengthComparison {
+    /// `v.len() < 5`
+    LengthLessThanInt,
+    /// `5 < v.len()`
+    IntLessThanLength,
+    /// `v.len() <= 5`
+    LengthLessThanOrEqualInt,
+    /// `5 <= v.len()`
+    IntLessThanOrEqualLength,
+}
+
+/// Extracts parts out of a length comparison expression.
+///
+/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, `v.len()`))`
+fn len_comparison<'hir>(
+    bin_op: BinOp,
+    left: &'hir Expr<'hir>,
+    right: &'hir Expr<'hir>,
+) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
+    macro_rules! int_lit_pat {
+        ($id:ident) => {
+            ExprKind::Lit(Spanned {
+                node: LitKind::Int($id, _),
+                ..
+            })
+        };
+    }
+
+    // normalize comparison, `v.len() > 4` becomes `4 < v.len()`
+    // this simplifies the logic a bit
+    let (op, left, right) = normalize_comparison(bin_op.node, left, right)?;
+    match (op, &left.kind, &right.kind) {
+        (Rel::Lt, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanLength, *left as usize, right)),
+        (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)),
+        (Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)),
+        (Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)),
+        _ => None,
+    }
+}
+
+/// Attempts to extract parts out of an `assert!`-like expression
+/// in the form `assert!(some_slice.len() > 5)`.
+///
+/// `assert!` has expanded to an if expression at the HIR, so this
+/// actually works not just with `assert!` specifically, but anything
+/// that has a never type expression in the `then` block (e.g. `panic!`).
+fn assert_len_expr<'hir>(
+    cx: &LateContext<'_>,
+    expr: &'hir Expr<'hir>,
+) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
+    if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
+        && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
+        && let ExprKind::Binary(bin_op, left, right) = &condition.kind
+
+        && let Some((cmp, asserted_len, slice_len)) = len_comparison(*bin_op, left, right)
+        && let ExprKind::MethodCall(method, recv, ..) = &slice_len.kind
+        && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
+        && method.ident.name == sym::len
+
+        // check if `then` block has a never type expression
+        && let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
+        && cx.typeck_results().expr_ty(then_expr).is_never()
+    {
+        Some((cmp, asserted_len, recv))
+    } else {
+        None
+    }
+}
+
+#[derive(Debug)]
+enum IndexEntry<'hir> {
+    /// `assert!` without any indexing (so far)
+    StrayAssert {
+        asserted_len: usize,
+        comparison: LengthComparison,
+        assert_span: Span,
+        slice: &'hir Expr<'hir>,
+    },
+    /// `assert!` with indexing
+    ///
+    /// We also store the highest index to be able to check
+    /// if the `assert!` asserts the right length.
+    AssertWithIndex {
+        highest_index: usize,
+        asserted_len: usize,
+        assert_span: Span,
+        slice: &'hir Expr<'hir>,
+        indexes: Vec<Span>,
+        comparison: LengthComparison,
+    },
+    /// Indexing without an `assert!`
+    IndexWithoutAssert {
+        highest_index: usize,
+        indexes: Vec<Span>,
+        slice: &'hir Expr<'hir>,
+    },
+}
+
+impl<'hir> IndexEntry<'hir> {
+    pub fn slice(&self) -> &'hir Expr<'hir> {
+        match self {
+            IndexEntry::StrayAssert { slice, .. }
+            | IndexEntry::AssertWithIndex { slice, .. }
+            | IndexEntry::IndexWithoutAssert { slice, .. } => slice,
+        }
+    }
+
+    pub fn index_spans(&self) -> Option<&[Span]> {
+        match self {
+            IndexEntry::StrayAssert { .. } => None,
+            IndexEntry::AssertWithIndex { indexes, .. } | IndexEntry::IndexWithoutAssert { indexes, .. } => {
+                Some(indexes)
+            },
+        }
+    }
+}
+
+/// Extracts the upper index of a slice indexing expression.
+///
+/// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`,
+/// for `..=5` this returns `Some(5)`
+fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
+    if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node {
+        Some(index as usize)
+    } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr)
+        && let ExprKind::Lit(lit) = &end.kind
+        && let LitKind::Int(index @ 1.., _) = lit.node
+    {
+        match limits {
+            RangeLimits::HalfOpen => Some(index as usize - 1),
+            RangeLimits::Closed => Some(index as usize),
+        }
+    } else {
+        None
+    }
+}
+
+/// Checks if the expression is an index into a slice and adds it to `indexes`
+fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnhashMap<u64, Vec<IndexEntry<'hir>>>) {
+    if let ExprKind::Index(slice, index_lit, _) = expr.kind
+        && cx.typeck_results().expr_ty_adjusted(slice).peel_refs().is_slice()
+        && let Some(index) = upper_index_expr(index_lit)
+    {
+        let hash = hash_expr(cx, slice);
+
+        let indexes = map.entry(hash).or_default();
+        let entry = indexes.iter_mut().find(|entry| eq_expr_value(cx, entry.slice(), slice));
+
+        if let Some(entry) = entry {
+            match entry {
+                IndexEntry::StrayAssert { asserted_len, comparison, assert_span, slice } => {
+                    *entry = IndexEntry::AssertWithIndex {
+                        highest_index: index,
+                        asserted_len: *asserted_len,
+                        assert_span: *assert_span,
+                        slice,
+                        indexes: vec![expr.span],
+                        comparison: *comparison,
+                    };
+                },
+                IndexEntry::IndexWithoutAssert { highest_index, indexes, .. }
+                | IndexEntry::AssertWithIndex { highest_index, indexes, .. } => {
+                    indexes.push(expr.span);
+                    *highest_index = (*highest_index).max(index);
+                },
+            }
+        } else {
+            indexes.push(IndexEntry::IndexWithoutAssert {
+                highest_index: index,
+                indexes: vec![expr.span],
+                slice,
+            });
+        }
+    }
+}
+
+/// Checks if the expression is an `assert!` expression and adds it to `asserts`
+fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnhashMap<u64, Vec<IndexEntry<'hir>>>) {
+    if let Some((comparison, asserted_len, slice)) = assert_len_expr(cx, expr) {
+        let hash = hash_expr(cx, slice);
+        let indexes = map.entry(hash).or_default();
+
+        let entry = indexes.iter_mut().find(|entry| eq_expr_value(cx, entry.slice(), slice));
+
+        if let Some(entry) = entry {
+            if let IndexEntry::IndexWithoutAssert {
+                highest_index,
+                indexes,
+                slice,
+            } = entry
+            {
+                *entry = IndexEntry::AssertWithIndex {
+                    highest_index: *highest_index,
+                    indexes: mem::take(indexes),
+                    slice,
+                    assert_span: expr.span,
+                    comparison,
+                    asserted_len,
+                };
+            }
+        } else {
+            indexes.push(IndexEntry::StrayAssert {
+                asserted_len,
+                comparison,
+                assert_span: expr.span,
+                slice,
+            });
+        }
+    }
+}
+
+/// Inspects indexes and reports lints.
+///
+/// Called at the end of this lint after all indexing and `assert!` expressions have been collected.
+fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>>) {
+    for bucket in map.values() {
+        for entry in bucket {
+            let Some(full_span) = entry
+                .index_spans()
+                .and_then(|spans| spans.first().zip(spans.last()))
+                .map(|(low, &high)| low.to(high))
+            else {
+                continue;
+            };
+
+            match entry {
+                IndexEntry::AssertWithIndex {
+                    highest_index,
+                    asserted_len,
+                    indexes,
+                    comparison,
+                    assert_span,
+                    slice,
+                } if indexes.len() > 1 => {
+                    // if we have found an `assert!`, let's also check that it's actually right
+                    // and if it convers the highest index and if not, suggest the correct length
+                    let sugg = match comparison {
+                        // `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks.
+                        // The user probably meant `v.len() > 5`
+                        LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => Some(
+                            format!("assert!({}.len() > {highest_index})", snippet(cx, slice.span, "..")),
+                        ),
+                        // `5 < v.len()` == `v.len() > 5`
+                        LengthComparison::IntLessThanLength if asserted_len < highest_index => Some(format!(
+                            "assert!({}.len() > {highest_index})",
+                            snippet(cx, slice.span, "..")
+                        )),
+                        // `5 <= v.len() == `v.len() >= 5`
+                        LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => Some(format!(
+                            "assert!({}.len() > {highest_index})",
+                            snippet(cx, slice.span, "..")
+                        )),
+                        _ => None,
+                    };
+
+                    if let Some(sugg) = sugg {
+                        report_lint(
+                            cx,
+                            full_span,
+                            "indexing into a slice multiple times with an `assert` that does not cover the highest index",
+                            indexes,
+                            |diag| {
+                                diag.span_suggestion(
+                                    *assert_span,
+                                    "provide the highest index that is indexed with",
+                                    sugg,
+                                    Applicability::MachineApplicable,
+                                );
+                            },
+                        );
+                    }
+                },
+                IndexEntry::IndexWithoutAssert {
+                    indexes,
+                    highest_index,
+                    slice,
+                } if indexes.len() > 1 => {
+                    // if there was no `assert!` but more than one index, suggest
+                    // adding an `assert!` that covers the highest index
+                    report_lint(
+                        cx,
+                        full_span,
+                        "indexing into a slice multiple times without an `assert`",
+                        indexes,
+                        |diag| {
+                            diag.help(format!(
+                                "consider asserting the length before indexing: `assert!({}.len() > {highest_index});`",
+                                snippet(cx, slice.span, "..")
+                            ));
+                        },
+                    );
+                },
+                _ => {},
+            }
+        }
+    }
+}
+
+impl LateLintPass<'_> for MissingAssertsForIndexing {
+    fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
+        let mut map = UnhashMap::default();
+
+        for_each_expr(block, |expr| {
+            check_index(cx, expr, &mut map);
+            check_assert(cx, expr, &mut map);
+            ControlFlow::<!, ()>::Continue(())
+        });
+
+        report_indexes(cx, &map);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 3c59b839a39..4b24f059afd 100644
--- a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -13,11 +13,12 @@ use rustc_span::symbol::kw;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for manual implementations of `Clone` when `Copy` is already implemented.
+    /// Checks for non-canonical implementations of `Clone` when `Copy` is already implemented.
     ///
     /// ### Why is this bad?
-    /// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing
-    /// `self` in `Clone`'s implementation. Anything else is incorrect.
+    /// If both `Clone` and `Copy` are implemented, they must agree. This can done by dereferencing
+    /// `self` in `Clone`'s implementation, which will avoid any possibility of the implementations
+    /// becoming out of sync.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -46,14 +47,13 @@ declare_clippy_lint! {
     /// impl Copy for A {}
     /// ```
     #[clippy::version = "1.72.0"]
-    pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
-    correctness,
-    "manual implementation of `Clone` on a `Copy` type"
+    pub NON_CANONICAL_CLONE_IMPL,
+    suspicious,
+    "non-canonical implementation of `Clone` on a `Copy` type"
 }
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
-    /// necessary.
+    /// Checks for non-canonical implementations of `PartialOrd` when `Ord` is already implemented.
     ///
     /// ### Why is this bad?
     /// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
@@ -61,11 +61,8 @@ declare_clippy_lint! {
     /// introduce an error upon refactoring.
     ///
     /// ### Known issues
-    /// Code that calls the `.into()` method instead will be flagged as incorrect, despite `.into()`
-    /// wrapping it in `Some`.
-    ///
-    /// ### Limitations
-    /// Will not lint if `Self` and `Rhs` do not have the same type.
+    /// Code that calls the `.into()` method instead will be flagged, despite `.into()` wrapping it
+    /// in `Some`.
     ///
     /// ### Example
     /// ```rust
@@ -107,13 +104,13 @@ declare_clippy_lint! {
     /// }
     /// ```
     #[clippy::version = "1.72.0"]
-    pub INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
-    correctness,
-    "manual implementation of `PartialOrd` when `Ord` is already implemented"
+    pub NON_CANONICAL_PARTIAL_ORD_IMPL,
+    suspicious,
+    "non-canonical implementation of `PartialOrd` on an `Ord` type"
 }
-declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE]);
+declare_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL_PARTIAL_ORD_IMPL]);
 
-impl LateLintPass<'_> for IncorrectImpls {
+impl LateLintPass<'_> for NonCanonicalImpls {
     #[expect(clippy::too_many_lines)]
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
         let Some(Node::Item(item)) = get_parent_node(cx.tcx, impl_item.hir_id()) else {
@@ -154,9 +151,9 @@ impl LateLintPass<'_> for IncorrectImpls {
                 {} else {
                     span_lint_and_sugg(
                         cx,
-                        INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
+                        NON_CANONICAL_CLONE_IMPL,
                         block.span,
-                        "incorrect implementation of `clone` on a `Copy` type",
+                        "non-canonical implementation of `clone` on a `Copy` type",
                         "change this to",
                         "{ *self }".to_owned(),
                         Applicability::MaybeIncorrect,
@@ -169,9 +166,9 @@ impl LateLintPass<'_> for IncorrectImpls {
             if impl_item.ident.name == sym::clone_from {
                 span_lint_and_sugg(
                     cx,
-                    INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
+                    NON_CANONICAL_CLONE_IMPL,
                     impl_item.span,
-                    "incorrect implementation of `clone_from` on a `Copy` type",
+                    "unnecessary implementation of `clone_from` on a `Copy` type",
                     "remove it",
                     String::new(),
                     Applicability::MaybeIncorrect,
@@ -222,9 +219,9 @@ impl LateLintPass<'_> for IncorrectImpls {
 
                 span_lint_and_then(
                     cx,
-                    INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
+                    NON_CANONICAL_PARTIAL_ORD_IMPL,
                     item.span,
-                    "incorrect implementation of `partial_cmp` on an `Ord` type",
+                    "non-canonical implementation of `partial_cmp` on an `Ord` type",
                     |diag| {
                         let [_, other] = body.params else {
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index a687c7d29b5..8072aded851 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -14,7 +14,12 @@ use {rustc_ast as ast, rustc_hir as hir};
 
 const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]];
 const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
-const INTEGER_METHODS: &[Symbol] = &[sym::saturating_div, sym::wrapping_div, sym::wrapping_rem, sym::wrapping_rem_euclid];
+const INTEGER_METHODS: &[Symbol] = &[
+    sym::saturating_div,
+    sym::wrapping_div,
+    sym::wrapping_rem,
+    sym::wrapping_rem_euclid,
+];
 
 #[derive(Debug)]
 pub struct ArithmeticSideEffects {
@@ -93,7 +98,14 @@ impl ArithmeticSideEffects {
         let is_non_zero_u = |symbol: Option<Symbol>| {
             matches!(
                 symbol,
-                Some(sym::NonZeroU128 | sym::NonZeroU16 | sym::NonZeroU32 | sym::NonZeroU64 | sym::NonZeroU8 | sym::NonZeroUsize)
+                Some(
+                    sym::NonZeroU128
+                        | sym::NonZeroU16
+                        | sym::NonZeroU32
+                        | sym::NonZeroU64
+                        | sym::NonZeroU8
+                        | sym::NonZeroUsize
+                )
             )
         };
         let is_sat_or_wrap = |ty: Ty<'_>| {
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index f3e0c58a787..bce6bdcaf61 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
     left: &'tcx Expr<'_>,
     right: &'tcx Expr<'_>,
 ) {
-    if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
+    if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) {
         let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index ccabb577cb7..e8018462d75 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -1,7 +1,7 @@
 use std::iter::once;
 use std::ops::ControlFlow;
 
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::token::LitKind;
@@ -9,6 +9,7 @@ use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{BytePos, Pos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -76,14 +77,33 @@ impl EarlyLintPass for RawStrings {
             }
 
             if !str.contains(['\\', '"']) {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     NEEDLESS_RAW_STRINGS,
                     expr.span,
                     "unnecessary raw string literal",
-                    "try",
-                    format!("{}\"{}\"", prefix.replace('r', ""), lit.symbol),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        let (start, end) = hash_spans(expr.span, prefix, 0, max);
+
+                        // BytePos: skip over the `b` in `br`, we checked the prefix appears in the source text
+                        let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
+                        let start = start.with_lo(r_pos);
+
+                        if end.is_empty() {
+                            diag.span_suggestion(
+                                start,
+                                "use a string literal instead",
+                                format!("\"{}\"", str),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            diag.multipart_suggestion(
+                                "try",
+                                vec![(start, String::new()), (end, String::new())],
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    },
                 );
 
                 return;
@@ -96,13 +116,6 @@ impl EarlyLintPass for RawStrings {
                 let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| {
                     match b {
                         b'"' if !following_quote => (following_quote, req) = (true, 1),
-                        // I'm a bit surprised the compiler didn't optimize this out, there's no
-                        // branch but it still ends up doing an unnecessary comparison, it's:
-                        // - cmp r9b,1h
-                        // - sbb cl,-1h
-                        // which will add 1 if it's true. With this change, it becomes:
-                        // - add cl,r9b
-                        // isn't that so much nicer?
                         b'#' => req += u8::from(following_quote),
                         _ => {
                             if following_quote {
@@ -126,18 +139,58 @@ impl EarlyLintPass for RawStrings {
             };
 
             if req < max {
-                let hashes = "#".repeat(req as usize);
-
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     NEEDLESS_RAW_STRING_HASHES,
                     expr.span,
                     "unnecessary hashes around raw string literal",
-                    "try",
-                    format!(r#"{prefix}{hashes}"{}"{hashes}"#, lit.symbol),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        let (start, end) = hash_spans(expr.span, prefix, req, max);
+
+                        let message = match max - req {
+                            _ if req == 0 => "remove all the hashes around the literal".to_string(),
+                            1 => "remove one hash from both sides of the literal".to_string(),
+                            n => format!("remove {n} hashes from both sides of the literal"),
+                        };
+
+                        diag.multipart_suggestion(
+                            message,
+                            vec![(start, String::new()), (end, String::new())],
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
         }
     }
 }
+
+/// Returns spans pointing at the unneeded hashes, e.g. for a `req` of `1` and `max` of `3`:
+///
+/// ```ignore
+/// r###".."###
+///   ^^    ^^
+/// ```
+fn hash_spans(literal_span: Span, prefix: &str, req: u8, max: u8) -> (Span, Span) {
+    let literal_span = literal_span.data();
+
+    // BytePos: we checked prefix appears literally in the source text
+    let hash_start = literal_span.lo + BytePos::from_usize(prefix.len());
+    let hash_end = literal_span.hi;
+
+    // BytePos: req/max are counts of the ASCII character #
+    let start = Span::new(
+        hash_start + BytePos(req.into()),
+        hash_start + BytePos(max.into()),
+        literal_span.ctxt,
+        None,
+    );
+    let end = Span::new(
+        hash_end - BytePos(req.into()),
+        hash_end - BytePos(max.into()),
+        literal_span.ctxt,
+        None,
+    );
+
+    (start, end)
+}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index fc1fabcc0ae..613f1ecc6fb 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -15,6 +15,8 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"),
+    ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"),
     ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
     ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
@@ -38,12 +40,12 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::drop_bounds", "drop_bounds"),
     ("clippy::drop_copy", "dropping_copy_types"),
     ("clippy::drop_ref", "dropping_references"),
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
     ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
     ("clippy::forget_copy", "forgetting_copy_types"),
     ("clippy::forget_ref", "forgetting_references"),
-    ("clippy::fn_null_check", "useless_ptr_null_checks"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
     ("clippy::invalid_ref", "invalid_value"),
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 c9ab622ad25..9db18c2976c 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
@@ -148,6 +149,15 @@ impl SlowVectorInit {
     /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()`
     /// - `None` for other, unrelated kinds of expressions
     fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<InitializedSize<'tcx>> {
+        // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro.
+        // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an
+        // empty vec
+        if expr.span.from_expansion()
+            && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro)
+        {
+            return None;
+        }
+
         if let ExprKind::Call(func, [len_expr]) = expr.kind
             && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
         {
@@ -205,7 +215,7 @@ impl SlowVectorInit {
 
         span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
             diag.span_suggestion(
-                vec_alloc.allocation_expr.span,
+                vec_alloc.allocation_expr.span.source_callsite(),
                 "consider replacing this with",
                 format!("vec![0; {len_expr}]"),
                 Applicability::Unspecified,
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index f239165276f..5f54a10d1c4 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,4 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, Path, PathSegment};
@@ -99,17 +100,17 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
             && let Some(first_segment) = get_first_segment(path)
             && is_stable(cx, def_id)
         {
-            let (lint, msg, help) = match first_segment.ident.name {
+            let (lint, used_mod, replace_with) = match first_segment.ident.name {
                 sym::std => match cx.tcx.crate_name(def_id.krate) {
                     sym::core => (
                         STD_INSTEAD_OF_CORE,
-                        "used import from `std` instead of `core`",
-                        "consider importing the item from `core`",
+                        "std",
+                        "core",
                     ),
                     sym::alloc => (
                         STD_INSTEAD_OF_ALLOC,
-                        "used import from `std` instead of `alloc`",
-                        "consider importing the item from `alloc`",
+                        "std",
+                        "alloc",
                     ),
                     _ => {
                         self.prev_span = path.span;
@@ -120,8 +121,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                     if cx.tcx.crate_name(def_id.krate) == sym::core {
                         (
                             ALLOC_INSTEAD_OF_CORE,
-                            "used import from `alloc` instead of `core`",
-                            "consider importing the item from `core`",
+                            "alloc",
+                            "core",
                         )
                     } else {
                         self.prev_span = path.span;
@@ -131,7 +132,14 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                 _ => return,
             };
             if path.span != self.prev_span {
-                span_lint_and_help(cx, lint, path.span, msg, None, help);
+                span_lint_and_sugg(
+                    cx,
+                    lint,
+                    first_segment.ident.span,
+                    &format!("used import from `{used_mod}` instead of `{replace_with}`"),
+                    &format!("consider importing the item from `{replace_with}`"),
+                    replace_with.to_string(),
+                    Applicability::MachineApplicable);
                 self.prev_span = path.span;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index da8d8ed4c0f..6193fdeb433 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -341,44 +341,21 @@ fn block_parents_have_safety_comment(
     id: hir::HirId,
 ) -> bool {
     if let Some(node) = get_parent_node(cx.tcx, id) {
-        return match node {
-            Node::Expr(expr) => {
-                if let Some(
-                    Node::Local(hir::Local { span, .. })
-                    | Node::Item(hir::Item {
-                        kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
-                        span,
-                        ..
-                    }),
-                ) = get_parent_node(cx.tcx, expr.hir_id)
-                {
-                    let hir_id = match get_parent_node(cx.tcx, expr.hir_id) {
-                        Some(Node::Local(hir::Local { hir_id, .. })) => *hir_id,
-                        Some(Node::Item(hir::Item { owner_id, .. })) => {
-                            cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)
-                        },
-                        _ => unreachable!(),
-                    };
-
-                    // if unsafe block is part of a let/const/static statement,
-                    // and accept_comment_above_statement is set to true
-                    // we accept the safety comment in the line the precedes this statement.
-                    accept_comment_above_statement
-                        && span_with_attrs_in_body_has_safety_comment(
-                            cx,
-                            *span,
-                            hir_id,
-                            accept_comment_above_attributes,
-                        )
-                } else {
-                    !is_branchy(expr)
-                        && span_with_attrs_in_body_has_safety_comment(
-                            cx,
-                            expr.span,
-                            expr.hir_id,
-                            accept_comment_above_attributes,
-                        )
-                }
+        let (span, hir_id) = match node {
+            Node::Expr(expr) => match get_parent_node(cx.tcx, expr.hir_id) {
+                Some(Node::Local(hir::Local { span, hir_id, .. })) => (*span, *hir_id),
+                Some(Node::Item(hir::Item {
+                    kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+                    span,
+                    owner_id,
+                    ..
+                })) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)),
+                _ => {
+                    if is_branchy(expr) {
+                        return false;
+                    }
+                    (expr.span, expr.hir_id)
+                },
             },
             Node::Stmt(hir::Stmt {
                 kind:
@@ -387,28 +364,27 @@ fn block_parents_have_safety_comment(
                     | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
                 ..
             })
-            | Node::Local(hir::Local { span, hir_id, .. }) => {
-                span_with_attrs_in_body_has_safety_comment(cx, *span, *hir_id, accept_comment_above_attributes)
-            },
+            | Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 span,
                 owner_id,
                 ..
-            }) => span_with_attrs_in_body_has_safety_comment(
-                cx,
-                *span,
-                cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id),
-                accept_comment_above_attributes,
-            ),
-            _ => false,
+            }) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)),
+            _ => return false,
         };
+        // if unsafe block is part of a let/const/static statement,
+        // and accept_comment_above_statement is set to true
+        // we accept the safety comment in the line the precedes this statement.
+        accept_comment_above_statement
+            && span_with_attrs_has_safety_comment(cx, span, hir_id, accept_comment_above_attributes)
+    } else {
+        false
     }
-    false
 }
 
 /// Extends `span` to also include its attributes, then checks if that span has a safety comment.
-fn span_with_attrs_in_body_has_safety_comment(
+fn span_with_attrs_has_safety_comment(
     cx: &LateContext<'_>,
     span: Span,
     hir_id: HirId,
@@ -420,7 +396,7 @@ fn span_with_attrs_in_body_has_safety_comment(
         span
     };
 
-    span_in_body_has_safety_comment(cx, span)
+    span_has_safety_comment(cx, span)
 }
 
 /// Checks if an expression is "branchy", e.g. loop, match/if/etc.
@@ -444,7 +420,7 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     matches!(
         span_from_macro_expansion_has_safety_comment(cx, span),
         HasSafetyComment::Yes(_)
-    ) || span_in_body_has_safety_comment(cx, span)
+    ) || span_has_safety_comment(cx, span)
 }
 
 fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span {
@@ -633,29 +609,36 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     let body = cx.enclosing_body?;
     let map = cx.tcx.hir();
     let mut span = map.body(body).value.span;
+    let mut maybe_global_var = false;
     for (_, node) in map.parent_iter(body.hir_id) {
         match node {
             Node::Expr(e) => span = e.span,
-            Node::Block(_)
-            | Node::Arm(_)
-            | Node::Stmt(_)
-            | Node::Local(_)
-            | Node::Item(hir::Item {
+            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
+            Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 ..
-            }) => (),
+            }) => maybe_global_var = true,
+            Node::Item(hir::Item {
+                kind: hir::ItemKind::Mod(_),
+                span: item_span,
+                ..
+            }) => {
+                span = *item_span;
+                break;
+            },
+            Node::Crate(mod_) if maybe_global_var => {
+                span = mod_.spans.inner_span;
+            },
             _ => break,
         }
     }
     Some(span)
 }
 
-fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     let source_map = cx.sess().source_map();
     let ctxt = span.ctxt();
-    if ctxt == SyntaxContext::root()
-        && let Some(search_span) = get_body_search_span(cx)
-    {
+    if ctxt.is_root() && let Some(search_span) = get_body_search_span(cx) {
         if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
             && let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root())
             && let Ok(body_line) = source_map.lookup_line(body_span.lo())
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index dd829ded0d0..de4b8738e35 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// let mut twins = vec!((1, 1), (2, 2));
+    /// let mut twins = vec![(1, 1), (2, 2)];
     /// twins.sort_by_key(|x| { x.1; });
     /// ```
     #[clippy::version = "1.47.0"]
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index c99b0290c0c..9a0d83d83f1 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,15 +1,18 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::usage::is_potentially_mutated;
+use clippy_utils::usage::is_potentially_local_place;
 use clippy_utils::{higher, path_to_local};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, PathSegment, UnOp};
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::Ty;
+use rustc_middle::mir::FakeReadCause;
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -192,6 +195,55 @@ fn collect_unwrap_info<'tcx>(
     Vec::new()
 }
 
+/// A HIR visitor delegate that checks if a local variable of type `Option<_>` is mutated,
+/// *except* for if `Option::as_mut` is called.
+/// The reason for why we allow that one specifically is that `.as_mut()` cannot change
+/// the option to `None`, and that is important because this lint relies on the fact that
+/// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if
+/// the option is changed to None between `is_some` and `unwrap`.
+/// (And also `.as_mut()` is a somewhat common method that is still worth linting on.)
+struct MutationVisitor<'tcx> {
+    is_mutated: bool,
+    local_id: HirId,
+    tcx: TyCtxt<'tcx>,
+}
+
+/// Checks if the parent of the expression pointed at by the given `HirId` is a call to
+/// `Option::as_mut`.
+///
+/// Used by the mutation visitor to specifically allow `.as_mut()` calls.
+/// In particular, the `HirId` that the visitor receives is the id of the local expression
+/// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
+/// expression: that will be where the actual method call is.
+fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
+    if let Node::Expr(mutating_expr) = tcx.hir().get_parent(expr_id)
+        && let ExprKind::MethodCall(path, ..) = mutating_expr.kind
+    {
+        path.ident.name.as_str() == "as_mut"
+    } else {
+        false
+    }
+}
+
+impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
+    fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
+        if let ty::BorrowKind::MutBorrow = bk
+            && is_potentially_local_place(self.local_id, &cat.place)
+            && !is_option_as_mut_use(self.tcx, diag_expr_id)
+        {
+            self.is_mutated = true;
+        }
+    }
+
+    fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {
+        self.is_mutated = true;
+    }
+
+    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+    fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+}
+
 impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
     fn visit_branch(
         &mut self,
@@ -202,10 +254,26 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
     ) {
         let prev_len = self.unwrappables.len();
         for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
-            if is_potentially_mutated(unwrap_info.local_id, cond, self.cx)
-                || is_potentially_mutated(unwrap_info.local_id, branch, self.cx)
-            {
-                // if the variable is mutated, we don't know whether it can be unwrapped:
+            let mut delegate = MutationVisitor {
+                tcx: self.cx.tcx,
+                is_mutated: false,
+                local_id: unwrap_info.local_id,
+            };
+
+            let infcx = self.cx.tcx.infer_ctxt().build();
+            let mut vis = ExprUseVisitor::new(
+                &mut delegate,
+                &infcx,
+                cond.hir_id.owner.def_id,
+                self.cx.param_env,
+                self.cx.typeck_results(),
+            );
+            vis.walk_expr(cond);
+            vis.walk_expr(branch);
+
+            if delegate.is_mutated {
+                // if the variable is mutated, we don't know whether it can be unwrapped.
+                // it might have been changed to `None` in between `is_some` + `unwrap`.
                 continue;
             }
             self.unwrappables.push(unwrap_info);
@@ -215,6 +283,27 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
     }
 }
 
+enum AsRefKind {
+    AsRef,
+    AsMut,
+}
+
+/// Checks if the expression is a method call to `as_{ref,mut}` and returns the receiver of it.
+/// If it isn't, the expression itself is returned.
+fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Option<AsRefKind>) {
+    if let ExprKind::MethodCall(path, recv, ..) = expr.kind {
+        if path.ident.name == sym::as_ref {
+            (recv, Some(AsRefKind::AsRef))
+        } else if path.ident.name.as_str() == "as_mut" {
+            (recv, Some(AsRefKind::AsMut))
+        } else {
+            (expr, None)
+        }
+    } else {
+        (expr, None)
+    }
+}
+
 impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
@@ -233,6 +322,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
             // find `unwrap[_err]()` calls:
             if_chain! {
                 if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
+                let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg);
                 if let Some(id) = path_to_local(self_arg);
                 if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
                 let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
@@ -268,7 +358,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
                                         unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
                                         "try",
                                         format!(
-                                            "if let {suggested_pattern} = {unwrappable_variable_name}",
+                                            "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}",
+                                            borrow_prefix = match as_ref_kind {
+                                                Some(AsRefKind::AsRef) => "&",
+                                                Some(AsRefKind::AsMut) => "&mut ",
+                                                None => "",
+                                            },
                                         ),
                                         // We don't track how the unwrapped value is used inside the
                                         // block or suggest deleting the unwrap, so we can't offer a
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 58ae0656db7..26889475522 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -561,6 +561,26 @@ define_Conf! {
     /// Which crates to allow absolute paths from
     (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
         rustc_data_structures::fx::FxHashSet::default()),
+    /// Lint: EXPLICIT_ITER_LOOP
+    ///
+    /// Whether to recommend using implicit into iter for reborrowed values.
+    ///
+    /// #### Example
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// let rmvec = &mut vec;
+    /// for _ in rmvec.iter() {}
+    /// for _ in rmvec.iter_mut() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// let rmvec = &mut vec;
+    /// for _ in &*rmvec {}
+    /// for _ in &mut *rmvec {}
+    /// ```
+    (enforce_iter_loop_reborrow: bool = false),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6c4cec59524..4ef3ec19647 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -5,6 +5,7 @@
 #![feature(lint_reasons)]
 #![feature(never_type)]
 #![feature(rustc_private)]
+#![feature(assert_matches)]
 #![recursion_limit = "512"]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
@@ -110,6 +111,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{sym, Span};
 use rustc_target::abi::Integer;
+use visitors::Visitable;
 
 use crate::consts::{constant, miri_to_const, Constant};
 use crate::higher::Range;
@@ -1286,7 +1288,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<
 }
 
 /// Returns `true` if `expr` contains a return expression
-pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
+pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
     for_each_expr(expr, |e| {
         if matches!(e.kind, hir::ExprKind::Ret(..)) {
             ControlFlow::Break(())
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index a567c5cbdc9..2fb24b5c7ed 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -49,6 +49,7 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
+pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"];
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -163,3 +164,4 @@ pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
 pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
 #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
 pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
+pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"];
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 600cd084c19..31cb421095e 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -362,7 +362,7 @@ pub fn snippet_block_with_context<'a>(
 }
 
 /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This
-/// will result in the macro call, rather then the expansion, if the span is from a child context.
+/// will result in the macro call, rather than the expansion, if the span is from a child context.
 /// If the span is not from a child context, it will be used directly instead.
 ///
 /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index ee5a49a2073..ae8ee371ffa 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -88,7 +88,7 @@ impl<'a> Sugg<'a> {
     }
 
     /// Same as `hir`, but first walks the span up to the given context. This will result in the
-    /// macro call, rather then the expansion, if the span is from a child context. If the span is
+    /// macro call, rather than the expansion, if the span is from a child context. If the span is
     /// not from a child context, it will be used directly instead.
     ///
     /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a05f682aa8c..f0b4ede35fb 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -27,6 +27,7 @@ use rustc_target::abi::{Size, VariantIdx};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
+use std::assert_matches::debug_assert_matches;
 use std::iter;
 
 use crate::{match_def_path, path_res, paths};
@@ -259,7 +260,11 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
             })),
     );
 
-    debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait);
+    debug_assert_matches!(
+        tcx.def_kind(trait_id),
+        DefKind::Trait | DefKind::TraitAlias,
+        "`DefId` must belong to a trait or trait alias"
+    );
     #[cfg(debug_assertions)]
     assert_generic_args_match(tcx, trait_id, trait_ref.args);
 
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 06fd9529044..dc7756533ac 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -150,7 +150,7 @@ fn generic_args_certainty(cx: &LateContext<'_>, args: &GenericArgs<'_>) -> Certa
 }
 
 /// Tries to tell whether a `QPath` resolves to something certain, e.g., whether all of its path
-/// segments generic arguments are are instantiated.
+/// segments generic arguments are instantiated.
 ///
 /// `qpath` could refer to either a type or a value. The heuristic never needs the `DefId` of a
 /// value. So `DefId`s are retained only when `resolves_to_type` is true.
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 39ef76348d7..ec131c7f6a3 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -4,7 +4,7 @@ use core::ops::ControlFlow;
 use hir::def::Res;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
-use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -37,6 +37,17 @@ pub fn is_potentially_mutated<'tcx>(variable: HirId, expr: &'tcx Expr<'_>, cx: &
     mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&variable))
 }
 
+pub fn is_potentially_local_place(local_id: HirId, place: &Place<'_>) -> bool {
+    match place.base {
+        PlaceBase::Local(id) => id == local_id,
+        PlaceBase::Upvar(_) => {
+            // Conservatively assume yes.
+            true
+        },
+        _ => false,
+    }
+}
+
 struct MutVarsDelegate {
     used_mutably: HirIdSet,
     skip: bool,
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 19c09b58b98..9f5116eb73b 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-08-24"
+channel = "nightly-2023-09-07"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index e329a94ff6a..9fcc269dbf8 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -4,7 +4,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
-use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling, RustfixMode};
+use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling};
 
 use std::collections::BTreeMap;
 use std::env::{self, set_var, var_os};
@@ -114,34 +114,26 @@ fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
 }
 
 fn base_config(test_dir: &str) -> (Config, Args) {
-    let bless = var_os("RUSTC_BLESS").is_some_and(|v| v != "0") || env::args().any(|arg| arg == "--bless");
-
-    let args = Args {
-        filters: env::var("TESTNAME")
-            .map(|filters| filters.split(',').map(str::to_string).collect())
-            .unwrap_or_default(),
-        quiet: false,
-        check: !bless,
-        threads: match std::env::var_os("RUST_TEST_THREADS") {
-            Some(n) => n.to_str().unwrap().parse().unwrap(),
-            None => std::thread::available_parallelism().unwrap(),
-        },
-        skip: Vec::new(),
-    };
+    let mut args = Args::test().unwrap();
+    args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
 
     let mut config = Config {
-        mode: Mode::Yolo { rustfix: RustfixMode::Everything },
+        mode: Mode::Yolo {
+            rustfix: ui_test::RustfixMode::Everything,
+        },
         stderr_filters: vec![(Match::PathBackslash, b"/")],
         stdout_filters: vec![],
-        output_conflict_handling: if bless {
-            OutputConflictHandling::Bless
-        } else {
-            OutputConflictHandling::Error("cargo uibless".into())
-        },
+        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"),
         ..Config::rustc(Path::new("tests").join(test_dir))
     };
+    config.with_args(&args, /* bless by default */ false);
+    if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
+        *err = "cargo uibless".into();
+    }
     let current_exe_path = env::current_exe().unwrap();
     let deps_path = current_exe_path.parent().unwrap();
     let profile_path = deps_path.parent().unwrap();
@@ -184,7 +176,6 @@ fn run_ui() {
 
     ui_test::run_tests_generic(
         vec![config],
-        args,
         ui_test::default_file_filter,
         ui_test::default_per_file_config,
         if quiet {
@@ -209,7 +200,6 @@ fn run_internal_tests() {
 
     ui_test::run_tests_generic(
         vec![config],
-        args,
         ui_test::default_file_filter,
         ui_test::default_per_file_config,
         if quiet {
@@ -243,7 +233,6 @@ fn run_ui_toml() {
 
     ui_test::run_tests_generic(
         vec![config],
-        args,
         ui_test::default_file_filter,
         |config, path, _file_contents| {
             config
@@ -300,10 +289,16 @@ fn run_ui_cargo() {
 
     let quiet = args.quiet;
 
+    let ignored_32bit = |path: &Path| {
+        // FIXME: for some reason the modules are linted in a different order for this test
+        cfg!(target_pointer_width = "32") && path.ends_with("tests/ui-cargo/module_style/fail_mod/Cargo.toml")
+    };
+
     ui_test::run_tests_generic(
         vec![config],
-        args,
-        |path, args, _config| path.ends_with("Cargo.toml") && ui_test::default_filter_by_arg(path, args),
+        |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()
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr
index e161507b533..4d97d54963d 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr
@@ -1,6 +1,7 @@
 error: package `cargo_common_metadata_fail` is missing `package.description` metadata
   |
   = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::cargo_common_metadata)]`
 
 error: package `cargo_common_metadata_fail` is missing `either package.license or package.license_file` metadata
 
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr
index dbf494cc342..9eb884f0890 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr
@@ -1,6 +1,7 @@
 error: package `cargo_common_metadata_fail_publish` is missing `package.description` metadata
   |
   = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::cargo_common_metadata)]`
 
 error: package `cargo_common_metadata_fail_publish` is missing `either package.license or package.license_file` metadata
 
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr
index ae5967406f6..f9685a784a3 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr
@@ -1,6 +1,7 @@
 error: package `cargo_common_metadata_fail_publish_true` is missing `package.description` metadata
   |
   = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::cargo_common_metadata)]`
 
 error: package `cargo_common_metadata_fail_publish_true` is missing `either package.license or package.license_file` metadata
 
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
index fde3a1e6599..912ea9bb4d1 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
@@ -9,6 +9,7 @@ error: file is loaded as a module multiple times: `src/b.rs`
   |
   = help: replace all but one `mod` item with `use` items
   = note: `-D clippy::duplicate-mod` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::duplicate_mod)]`
 
 error: file is loaded as a module multiple times: `src/c.rs`
   --> src/main.rs:9:1
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.stderr
index da2db45d3b8..388f49fb213 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.stderr
@@ -2,6 +2,7 @@ error: the "no-" prefix in the feature name "no-qaq" is negative
   |
   = help: consider renaming the feature to "qaq", but make sure the feature adds functionality
   = note: `-D clippy::negative-feature-names` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::negative_feature_names)]`
 
 error: the "no_" prefix in the feature name "no_qaq" is negative
   |
@@ -19,6 +20,7 @@ error: the "-support" suffix in the feature name "qvq-support" is redundant
   |
   = help: consider renaming the feature to "qvq"
   = note: `-D clippy::redundant-feature-names` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::redundant_feature_names)]`
 
 error: the "_support" suffix in the feature name "qvq_support" is redundant
   |
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.stderr
index c2907f319e6..902330e1785 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.stderr
@@ -6,6 +6,7 @@ error: `mod.rs` files are required, found `src/bad/inner.rs`
   |
   = help: move `src/bad/inner.rs` to `src/bad/inner/mod.rs`
   = note: `-D clippy::self-named-module-files` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]`
 
 error: `mod.rs` files are required, found `src/bad/inner/stuff.rs`
  --> src/bad/inner/stuff.rs:1:1
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr
index fcf1a3c5e66..d776feb7f2e 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr
@@ -6,5 +6,6 @@ error: `mod.rs` files are required, found `src/bad.rs`
   |
   = help: move `src/bad.rs` to `src/bad/mod.rs`
   = note: `-D clippy::self-named-module-files` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]`
 
 error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to previous error
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr
index f61642ca2ef..22558bc4ce8 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr
@@ -6,5 +6,6 @@ error: `mod.rs` files are not allowed, found `src/bad/mod.rs`
   |
   = help: move `src/bad/mod.rs` to `src/bad.rs`
   = note: `-D clippy::mod-module-files` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::mod_module_files)]`
 
 error: could not compile `fail-no-mod` (bin "fail-no-mod") due to previous error
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr
index 5bcce920455..4beedc10830 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr
@@ -1,5 +1,6 @@
 error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9
   |
   = note: `-D clippy::multiple-crate-versions` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]`
 
 error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to previous error
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr
index b1578c9f324..65a19bb0718 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr
@@ -1,5 +1,6 @@
 error: wildcard dependency for `regex`
   |
   = note: `-D clippy::wildcard-dependencies` implied by `-D warnings`
+  = help: to override `-D warnings` add `#[allow(clippy::wildcard_dependencies)]`
 
 error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to previous error
diff --git a/src/tools/clippy/tests/ui-internal/check_formulation.stderr b/src/tools/clippy/tests/ui-internal/check_formulation.stderr
index 10eabca4b9d..96fa617601f 100644
--- a/src/tools/clippy/tests/ui-internal/check_formulation.stderr
+++ b/src/tools/clippy/tests/ui-internal/check_formulation.stderr
@@ -6,6 +6,7 @@ LL |     /// Check for lint formulations that are correct
    |
    = help: try using `Checks for` instead
    = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]`
 
 error: non-standard lint formulation
   --> $DIR/check_formulation.rs:33:5
diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
index b12df278652..ea04955323d 100644
--- a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
+++ b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
@@ -16,6 +16,7 @@ help: this `let` statement can also be in the `if_chain!`
 LL |         let x = "";
    |         ^^^^^^^^^^^
    = note: `-D clippy::if-chain-style` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::if_chain_style)]`
 
 error: `if a && b;` should be `if a; if b;`
   --> $DIR/if_chain_style.rs:24:12
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
index 0e850886917..988d32d5259 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
@@ -5,6 +5,7 @@ LL |     pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::invalid-paths` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::invalid_paths)]`
 
 error: invalid path
   --> $DIR/invalid_paths.rs:18:5
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 3ca45404e44..58b1fd92b5d 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -6,6 +6,7 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    |
    = help: convert all references to use `sym::Deref`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]`
 
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
index fcaeace0e98..f4166b227fc 100644
--- a/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
@@ -30,3 +30,18 @@ macro_rules! item {
         const ITEM: usize = 1;
     };
 }
+
+#[macro_export]
+macro_rules! binop {
+    ($t:tt) => {
+        $t + $t
+    };
+}
+
+#[macro_export]
+macro_rules! attr {
+    ($i:item) => {
+        #[repr(C)]
+        $i
+    };
+}
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml
index c8fe8be9a77..85f1b71eb66 100644
--- a/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml
@@ -8,4 +8,6 @@ disallowed-macros = [
     "macros::ty",
     "macros::pat",
     "macros::item",
+    "macros::binop",
+    "macros::attr",
 ]
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs
index ba919b48788..4a3d55e13c9 100644
--- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs
@@ -20,11 +20,14 @@ fn main() {
     let macros::pat!() = 1;
     let _: macros::ty!() = "";
     macros::item!();
+    let _ = macros::binop!(1);
 
     eprintln!("allowed");
 }
 
-struct S;
+macros::attr! {
+    struct S;
+}
 
 impl S {
     macros::item!();
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
index 0eebd587a5f..3c6f59b16e7 100644
--- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
@@ -63,23 +63,37 @@ error: use of a disallowed macro `macros::item`
 LL |     macros::item!();
    |     ^^^^^^^^^^^^^^^
 
+error: use of a disallowed macro `macros::binop`
+  --> $DIR/disallowed_macros.rs:23:13
+   |
+LL |     let _ = macros::binop!(1);
+   |             ^^^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::attr`
+  --> $DIR/disallowed_macros.rs:28:1
+   |
+LL | / macros::attr! {
+LL | |     struct S;
+LL | | }
+   | |_^
+
 error: use of a disallowed macro `macros::item`
-  --> $DIR/disallowed_macros.rs:30:5
+  --> $DIR/disallowed_macros.rs:33:5
    |
 LL |     macros::item!();
    |     ^^^^^^^^^^^^^^^
 
 error: use of a disallowed macro `macros::item`
-  --> $DIR/disallowed_macros.rs:34:5
+  --> $DIR/disallowed_macros.rs:37:5
    |
 LL |     macros::item!();
    |     ^^^^^^^^^^^^^^^
 
 error: use of a disallowed macro `macros::item`
-  --> $DIR/disallowed_macros.rs:38:5
+  --> $DIR/disallowed_macros.rs:41:5
    |
 LL |     macros::item!();
    |     ^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs
deleted file mode 100644
index 60fbaaea3d3..00000000000
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs
+++ /dev/null
@@ -1,469 +0,0 @@
-// NOTE: Copied from `ui/auxiliary/proc_macros.rs`, couldn't get `../` to work for some reason
-
-#![feature(let_chains)]
-#![feature(proc_macro_span)]
-#![allow(clippy::excessive_nesting, dead_code)]
-
-extern crate proc_macro;
-
-use core::mem;
-use proc_macro::token_stream::IntoIter;
-use proc_macro::Delimiter::{self, Brace, Parenthesis};
-use proc_macro::Spacing::{self, Alone, Joint};
-use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT};
-
-type Result<T> = core::result::Result<T, TokenStream>;
-
-/// Make a `compile_error!` pointing to the given span.
-fn make_error(msg: &str, span: Span) -> TokenStream {
-    TokenStream::from_iter([
-        TT::Ident(Ident::new("compile_error", span)),
-        TT::Punct(punct_with_span('!', Alone, span)),
-        TT::Group({
-            let mut msg = Literal::string(msg);
-            msg.set_span(span);
-            group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span)
-        }),
-    ])
-}
-
-fn expect_tt<T>(tt: Option<TT>, f: impl FnOnce(TT) -> Option<T>, expected: &str, span: Span) -> Result<T> {
-    match tt {
-        None => Err(make_error(
-            &format!("unexpected end of input, expected {expected}"),
-            span,
-        )),
-        Some(tt) => {
-            let span = tt.span();
-            match f(tt) {
-                Some(x) => Ok(x),
-                None => Err(make_error(&format!("unexpected token, expected {expected}"), span)),
-            }
-        },
-    }
-}
-
-fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct {
-    let mut p = Punct::new(c, spacing);
-    p.set_span(span);
-    p
-}
-
-fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group {
-    let mut g = Group::new(delimiter, stream);
-    g.set_span(span);
-    g
-}
-
-/// Token used to escape the following token from the macro's span rules.
-const ESCAPE_CHAR: char = '$';
-
-/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their
-/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`.
-#[proc_macro]
-pub fn with_span(input: TokenStream) -> TokenStream {
-    let mut iter = input.into_iter();
-    let span = iter.next().unwrap().span();
-    let mut res = TokenStream::new();
-    if let Err(e) = write_with_span(span, iter, &mut res) {
-        e
-    } else {
-        res
-    }
-}
-
-/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be
-/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`.
-#[proc_macro]
-pub fn external(input: TokenStream) -> TokenStream {
-    let mut res = TokenStream::new();
-    if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) {
-        e
-    } else {
-        res
-    }
-}
-
-/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped
-/// either by `#ident` or `#(tokens)`.
-fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> {
-    while let Some(tt) = input.next() {
-        match tt {
-            TT::Punct(p) if p.as_char() == ESCAPE_CHAR => {
-                expect_tt(
-                    input.next(),
-                    |tt| match tt {
-                        tt @ (TT::Ident(_) | TT::Literal(_)) => {
-                            out.extend([tt]);
-                            Some(())
-                        },
-                        TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => {
-                            p.set_span(s);
-                            out.extend([TT::Punct(p)]);
-                            Some(())
-                        },
-                        TT::Group(g) if g.delimiter() == Parenthesis => {
-                            out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]);
-                            Some(())
-                        },
-                        _ => None,
-                    },
-                    "an ident, a literal, or parenthesized tokens",
-                    p.span(),
-                )?;
-            },
-            TT::Group(g) => {
-                let mut stream = TokenStream::new();
-                write_with_span(s, g.stream().into_iter(), &mut stream)?;
-                out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]);
-            },
-            mut tt => {
-                tt.set_span(s);
-                out.extend([tt]);
-            },
-        }
-    }
-    Ok(())
-}
-
-/// Within the item this attribute is attached to, an `inline!` macro is available which expands the
-/// contained tokens as though they came from a macro expansion.
-///
-/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument
-/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or
-/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will
-/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another
-/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will
-/// expand the remaining tokens as a single argument.
-///
-/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro
-/// calls. However, any arguments will be passed as though they came from the outermost context.
-#[proc_macro_attribute]
-pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream {
-    let mut args = args.into_iter();
-    let mac_name = match args.next() {
-        Some(TT::Ident(name)) => Some(name),
-        Some(tt) => {
-            return make_error(
-                "unexpected argument, expected either an ident or no arguments",
-                tt.span(),
-            );
-        },
-        None => None,
-    };
-    if let Some(tt) = args.next() {
-        return make_error(
-            "unexpected argument, expected either an ident or no arguments",
-            tt.span(),
-        );
-    };
-
-    let mac_name = if let Some(mac_name) = mac_name {
-        Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site())
-    } else {
-        let mut input = match LookaheadIter::new(input.clone().into_iter()) {
-            Some(x) => x,
-            None => return input,
-        };
-        loop {
-            match input.next() {
-                None => break Ident::new("__inline_mac", Span::call_site()),
-                Some(TT::Ident(kind)) => match &*kind.to_string() {
-                    "impl" => break Ident::new("__inline_mac_impl", Span::call_site()),
-                    kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => {
-                        if let TT::Ident(name) = &input.tt {
-                            break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site());
-                        } else {
-                            break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site());
-                        }
-                    },
-                    _ => {},
-                },
-                _ => {},
-            }
-        }
-    };
-
-    let mut expander = Expander::default();
-    let mut mac = MacWriter::new(mac_name);
-    if let Err(e) = expander.expand(input.into_iter(), &mut mac) {
-        return e;
-    }
-    let mut out = TokenStream::new();
-    mac.finish(&mut out);
-    out.extend(expander.expn);
-    out
-}
-
-/// Wraps a `TokenStream` iterator with a single token lookahead.
-struct LookaheadIter {
-    tt: TT,
-    iter: IntoIter,
-}
-impl LookaheadIter {
-    fn new(mut iter: IntoIter) -> Option<Self> {
-        iter.next().map(|tt| Self { tt, iter })
-    }
-
-    /// Get's the lookahead token, replacing it with the next token in the stream.
-    /// Note: If there isn't a next token, this will not return the lookahead token.
-    fn next(&mut self) -> Option<TT> {
-        self.iter.next().map(|tt| mem::replace(&mut self.tt, tt))
-    }
-}
-
-/// Builds the macro used to implement all the `inline!` macro calls.
-struct MacWriter {
-    name: Ident,
-    macros: TokenStream,
-    next_idx: usize,
-}
-impl MacWriter {
-    fn new(name: Ident) -> Self {
-        Self {
-            name,
-            macros: TokenStream::new(),
-            next_idx: 0,
-        }
-    }
-
-    /// Inserts a new `inline!` call.
-    fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> {
-        let idx = self.next_idx;
-        self.next_idx += 1;
-
-        let mut inner = Expander::for_arm(idx);
-        inner.expand(body.stream().into_iter(), self)?;
-        let new_arm = inner.arm.unwrap();
-
-        self.macros.extend([
-            TT::Group(Group::new(Parenthesis, new_arm.args_def)),
-            TT::Punct(Punct::new('=', Joint)),
-            TT::Punct(Punct::new('>', Alone)),
-            TT::Group(Group::new(Parenthesis, inner.expn)),
-            TT::Punct(Punct::new(';', Alone)),
-        ]);
-
-        expander.expn.extend([
-            TT::Ident({
-                let mut name = self.name.clone();
-                name.set_span(name_span);
-                name
-            }),
-            TT::Punct(punct_with_span('!', Alone, bang_span)),
-        ]);
-        let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]);
-        if let Some(arm) = expander.arm.as_mut() {
-            if !new_arm.args.is_empty() {
-                arm.add_sub_args(new_arm.args, &mut call_body);
-            }
-        } else {
-            call_body.extend(new_arm.args);
-        }
-        let mut g = Group::new(body.delimiter(), call_body);
-        g.set_span(body.span());
-        expander.expn.extend([TT::Group(g)]);
-        Ok(())
-    }
-
-    /// Creates the macro definition.
-    fn finish(self, out: &mut TokenStream) {
-        if self.next_idx != 0 {
-            out.extend([
-                TT::Ident(Ident::new("macro_rules", Span::call_site())),
-                TT::Punct(Punct::new('!', Alone)),
-                TT::Ident(self.name),
-                TT::Group(Group::new(Brace, self.macros)),
-            ])
-        }
-    }
-}
-
-struct MacroArm {
-    args_def: TokenStream,
-    args: Vec<TT>,
-}
-impl MacroArm {
-    fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
-        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
-        self.args_def.extend([
-            TT::Punct(Punct::new('$', Alone)),
-            TT::Ident(name.clone()),
-            TT::Punct(Punct::new(':', Alone)),
-            TT::Ident(Ident::new(kind, Span::call_site())),
-        ]);
-        name.set_span(arg_span);
-        out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
-    }
-
-    fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
-        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
-        self.args_def.extend([TT::Group(Group::new(
-            Parenthesis,
-            TokenStream::from_iter([
-                TT::Punct(Punct::new('$', Alone)),
-                TT::Ident(name.clone()),
-                TT::Punct(Punct::new(':', Alone)),
-                TT::Ident(kind),
-            ]),
-        ))]);
-        name.set_span(arg_span);
-        out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
-    }
-
-    fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
-        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
-        self.args_def.extend([TT::Group(Group::new(
-            Parenthesis,
-            TokenStream::from_iter([
-                TT::Punct(Punct::new('$', Alone)),
-                TT::Group(Group::new(
-                    Parenthesis,
-                    TokenStream::from_iter([
-                        TT::Punct(Punct::new('$', Alone)),
-                        TT::Ident(name.clone()),
-                        TT::Punct(Punct::new(':', Alone)),
-                        TT::Ident(Ident::new("tt", Span::call_site())),
-                    ]),
-                )),
-                TT::Punct(Punct::new('*', Alone)),
-            ]),
-        ))]);
-        name.set_span(arg_span);
-        out.extend([
-            TT::Punct(punct_with_span('$', Alone, dollar_span)),
-            TT::Group(group_with_span(
-                Parenthesis,
-                TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]),
-                dollar_span,
-            )),
-            TT::Punct(punct_with_span('*', Alone, dollar_span)),
-        ]);
-    }
-
-    fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> {
-        match tt {
-            TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]),
-            TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => {
-                let lt_name = expect_tt(
-                    input.next(),
-                    |tt| match tt {
-                        TT::Ident(x) => Some(x),
-                        _ => None,
-                    },
-                    "lifetime name",
-                    p.span(),
-                )?;
-                let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span());
-                self.add_single_arg_def("lifetime", dollar_span, arg_span, out);
-                self.args.extend([TT::Punct(p), TT::Ident(lt_name)]);
-            },
-            TT::Ident(x) => {
-                self.add_single_arg_def("ident", dollar_span, x.span(), out);
-                self.args.push(TT::Ident(x));
-            },
-            TT::Literal(x) => {
-                self.add_single_arg_def("literal", dollar_span, x.span(), out);
-                self.args.push(TT::Literal(x));
-            },
-            TT::Group(g) if g.delimiter() == Parenthesis => {
-                let mut inner = g.stream().into_iter();
-                if let Some(TT::Punct(p)) = inner.next()
-                    && p.as_char() == '@'
-                {
-                    let kind = expect_tt(
-                        inner.next(),
-                        |tt| match tt {
-                            TT::Ident(kind) => Some(kind),
-                            _ => None,
-                        },
-                        "a macro fragment specifier",
-                        p.span(),
-                    )?;
-                    self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out);
-                    self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span())))
-                } else {
-                    self.add_multi_arg_def(dollar_span, g.span(), out);
-                    self.args.push(TT::Group(g));
-                }
-            },
-            tt => return Err(make_error("unsupported escape", tt.span())),
-        };
-        Ok(())
-    }
-
-    fn add_sub_args(&mut self, args: Vec<TT>, out: &mut TokenStream) {
-        self.add_multi_arg_def(Span::call_site(), Span::call_site(), out);
-        self.args
-            .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]);
-    }
-}
-
-#[derive(Default)]
-struct Expander {
-    arm: Option<MacroArm>,
-    expn: TokenStream,
-}
-impl Expander {
-    fn for_arm(idx: usize) -> Self {
-        Self {
-            arm: Some(MacroArm {
-                args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]),
-                args: Vec::new(),
-            }),
-            expn: TokenStream::new(),
-        }
-    }
-
-    fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> {
-        match tt {
-            TT::Group(g) => {
-                let outer = mem::take(&mut self.expn);
-                self.expand(g.stream().into_iter(), mac)?;
-                let inner = mem::replace(&mut self.expn, outer);
-                self.expn
-                    .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]);
-            },
-            tt => self.expn.extend([tt]),
-        }
-        Ok(())
-    }
-
-    fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> {
-        let Some(mut input) = LookaheadIter::new(input) else {
-            return Ok(());
-        };
-        while let Some(tt) = input.next() {
-            if let TT::Punct(p) = &tt
-                && p.as_char() == ESCAPE_CHAR
-                && let Some(arm) = self.arm.as_mut()
-            {
-                arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?;
-                if input.next().is_none() {
-                    return Ok(());
-                }
-            } else if let TT::Punct(p) = &input.tt
-                && p.as_char() == '!'
-                && let TT::Ident(name) = &tt
-                && name.to_string() == "inline"
-            {
-                let g = expect_tt(
-                    input.iter.next(),
-                    |tt| match tt {
-                        TT::Group(g) => Some(g),
-                        _ => None,
-                    },
-                    "macro arguments",
-                    p.span(),
-                )?;
-                mac.insert(name.span(), p.span(), g, self)?;
-                if input.next().is_none() {
-                    return Ok(());
-                }
-            } else {
-                self.write_tt(tt, mac)?;
-            }
-        }
-        self.write_tt(input.tt, mac)
-    }
-}
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
index 25f0d0d6230..d737a832dd1 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
@@ -1,4 +1,4 @@
-//@aux-build:proc_macros.rs
+//@aux-build:../../ui/auxiliary/proc_macros.rs
 #![rustfmt::skip]
 #![feature(custom_inner_attributes)]
 #![allow(unused)]
@@ -156,7 +156,7 @@ fn main() {
     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
 
     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
-    
+
     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
 
     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
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 cdabe6460cd..b97bb144468 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
@@ -28,6 +28,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            disallowed-types
            doc-valid-idents
            enable-raw-pointer-heuristic-for-send
+           enforce-iter-loop-reborrow
            enforced-import-renames
            enum-variant-name-threshold
            enum-variant-size-threshold
@@ -99,6 +100,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            disallowed-types
            doc-valid-idents
            enable-raw-pointer-heuristic-for-send
+           enforce-iter-loop-reborrow
            enforced-import-renames
            enum-variant-name-threshold
            enum-variant-size-threshold
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs
deleted file mode 100644
index 1c591fc76f3..00000000000
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-extern crate proc_macro;
-
-use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree};
-
-#[proc_macro]
-pub fn unsafe_block(input: TokenStream) -> TokenStream {
-    let span = input.into_iter().next().unwrap().span();
-    TokenStream::from_iter([TokenTree::Ident(Ident::new("unsafe", span)), {
-        let mut group = Group::new(Delimiter::Brace, TokenStream::new());
-        group.set_span(span);
-        TokenTree::Group(group)
-    }])
-}
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
index c0976f0d600..b28e1b7d180 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
@@ -1,4 +1,4 @@
-//@aux-build:proc_macro_unsafe.rs
+//@aux-build:../../ui/auxiliary/proc_macro_unsafe.rs
 
 #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
 #![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)]
@@ -564,4 +564,18 @@ fn issue_8679<T: Copy>() {
     unsafe {}
 }
 
+mod issue_11246 {
+    // Safety: foo
+    const _: () = unsafe {};
+
+    // Safety: A safety comment
+    const FOO: () = unsafe {};
+
+    // Safety: bar
+    static BAR: u8 = unsafe { 0 };
+}
+
+// Safety: Another safety comment
+const FOO: () = unsafe {};
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed
index 945ba83611c..b506a9890f5 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.fixed
+++ b/src/tools/clippy/tests/ui/allow_attributes.fixed
@@ -22,6 +22,13 @@ struct T4;
 #[cfg_attr(panic = "unwind", expect(dead_code))]
 struct CfgT;
 
+#[allow(clippy::allow_attributes, unused)]
+struct Allowed;
+
+#[expect(clippy::allow_attributes)]
+#[allow(unused)]
+struct Expected;
+
 fn ignore_external() {
     external! {
         #[allow(clippy::needless_borrow)] // Should not lint
diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs
index 8afa61c7002..c7daa7abd9d 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.rs
+++ b/src/tools/clippy/tests/ui/allow_attributes.rs
@@ -22,6 +22,13 @@ struct T4;
 #[cfg_attr(panic = "unwind", allow(dead_code))]
 struct CfgT;
 
+#[allow(clippy::allow_attributes, unused)]
+struct Allowed;
+
+#[expect(clippy::allow_attributes)]
+#[allow(unused)]
+struct Expected;
+
 fn ignore_external() {
     external! {
         #[allow(clippy::needless_borrow)] // Should not lint
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
index d04ea7151c2..afb634f34b4 100644
--- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
@@ -1,17 +1,12 @@
 error: `clippy::restriction` is not meant to be enabled as a group
-   |
-   = note: because of the command line `--warn clippy::restriction`
-   = help: enable the restriction lints you need individually
-   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]`
-
-error: `clippy::restriction` is not meant to be enabled as a group
   --> $DIR/blanket_clippy_restriction_lints.rs:6:9
    |
 LL | #![warn(clippy::restriction)]
    |         ^^^^^^^^^^^^^^^^^^^
    |
    = help: enable the restriction lints you need individually
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]`
 
 error: `clippy::restriction` is not meant to be enabled as a group
   --> $DIR/blanket_clippy_restriction_lints.rs:8:9
@@ -29,5 +24,10 @@ LL | #![forbid(clippy::restriction)]
    |
    = help: enable the restriction lints you need individually
 
+error: `clippy::restriction` is not meant to be enabled as a group
+   |
+   = note: because of the command line `--warn clippy::restriction`
+   = help: enable the restriction lints you need individually
+
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed
index db85247f47d..e3f2ca72d1c 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_comparison.fixed
@@ -1,6 +1,6 @@
 #![allow(clippy::needless_if)]
 #![warn(clippy::bool_comparison)]
-#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 
 fn main() {
     let x = true;
diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs
index 0915f88544b..d1bc20d6831 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_comparison.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::needless_if)]
 #![warn(clippy::bool_comparison)]
-#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 
 fn main() {
     let x = true;
diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.stderr b/src/tools/clippy/tests/ui/cast_size.32bit.stderr
index fb51783a487..379ca60862b 100644
--- a/src/tools/clippy/tests/ui/cast_size_32bit.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.32bit.stderr
@@ -1,44 +1,46 @@
 error: casting `isize` to `i8` may truncate the value
-  --> $DIR/cast_size_32bit.rs:12:5
+  --> $DIR/cast_size.rs:15:5
    |
 LL |     1isize as i8;
    |     ^^^^^^^^^^^^
    |
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
    = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     i8::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> $DIR/cast_size_32bit.rs:15:5
+  --> $DIR/cast_size.rs:18:5
    |
 LL |     x0 as f64;
    |     ^^^^^^^^^
    |
    = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> $DIR/cast_size_32bit.rs:16:5
+  --> $DIR/cast_size.rs:19:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size_32bit.rs:17:5
+  --> $DIR/cast_size.rs:20:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
 
 error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size_32bit.rs:18:5
+  --> $DIR/cast_size.rs:21:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:19:5
+  --> $DIR/cast_size.rs:22:5
    |
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
@@ -50,7 +52,7 @@ LL |     i32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:20:5
+  --> $DIR/cast_size.rs:23:5
    |
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
@@ -62,7 +64,7 @@ LL |     u32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:21:5
+  --> $DIR/cast_size.rs:24:5
    |
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
@@ -74,7 +76,7 @@ LL |     u32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:22:5
+  --> $DIR/cast_size.rs:25:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -86,15 +88,16 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:22:5
+  --> $DIR/cast_size.rs:25:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
    |
    = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:24:5
+  --> $DIR/cast_size.rs:26:5
    |
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
@@ -106,7 +109,7 @@ LL |     isize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:25:5
+  --> $DIR/cast_size.rs:27:5
    |
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
@@ -118,7 +121,7 @@ LL |     usize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:26:5
+  --> $DIR/cast_size.rs:28:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -130,13 +133,13 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:26:5
+  --> $DIR/cast_size.rs:28:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:27:5
+  --> $DIR/cast_size.rs:29:5
    |
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
@@ -148,24 +151,31 @@ LL |     usize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size_32bit.rs:28:5
+  --> $DIR/cast_size.rs:30:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size_32bit.rs:33:5
+  --> $DIR/cast_size.rs:35:5
    |
 LL |     999_999_999 as f32;
    |     ^^^^^^^^^^^^^^^^^^
 
-error: casting integer literal to `f64` is unnecessary
-  --> $DIR/cast_size_32bit.rs:34:5
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size.rs:36:5
+   |
+LL |     9_999_999_999_999_999usize as f64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: literal out of range for `usize`
+  --> $DIR/cast_size.rs:36:5
    |
-LL |     3_999_999_999usize as f64;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `3_999_999_999_f64`
+LL |     9_999_999_999_999_999usize as f64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+   = note: the literal `9_999_999_999_999_999usize` does not fit into the type `usize` whose range is `0..=4294967295`
+   = note: `#[deny(overflowing_literals)]` on by default
 
-error: aborting due to 18 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.64bit.stderr
index bc9224be644..7fae92b1250 100644
--- a/src/tools/clippy/tests/ui/cast_size.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.64bit.stderr
@@ -1,5 +1,5 @@
 error: casting `isize` to `i8` may truncate the value
-  --> $DIR/cast_size.rs:12:5
+  --> $DIR/cast_size.rs:15:5
    |
 LL |     1isize as i8;
    |     ^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     i8::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> $DIR/cast_size.rs:16:5
+  --> $DIR/cast_size.rs:18:5
    |
 LL |     x0 as f64;
    |     ^^^^^^^^^
@@ -28,19 +28,19 @@ LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size.rs:21:5
+  --> $DIR/cast_size.rs:20:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
 
 error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size.rs:23:5
+  --> $DIR/cast_size.rs:21:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:25:5
+  --> $DIR/cast_size.rs:22:5
    |
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     i32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:27:5
+  --> $DIR/cast_size.rs:23:5
    |
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     u32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:29:5
+  --> $DIR/cast_size.rs:24:5
    |
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     u32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:31:5
+  --> $DIR/cast_size.rs:25:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:31:5
+  --> $DIR/cast_size.rs:25:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     1usize as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:36:5
+  --> $DIR/cast_size.rs:26:5
    |
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     isize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:38:5
+  --> $DIR/cast_size.rs:27:5
    |
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL |     usize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:40:5
+  --> $DIR/cast_size.rs:28:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -133,13 +133,13 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:40:5
+  --> $DIR/cast_size.rs:28:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:43:5
+  --> $DIR/cast_size.rs:29:5
    |
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
@@ -151,19 +151,19 @@ LL |     usize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:45:5
+  --> $DIR/cast_size.rs:30:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> $DIR/cast_size.rs:51:5
+  --> $DIR/cast_size.rs:35:5
    |
 LL |     999_999_999 as f32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> $DIR/cast_size.rs:53:5
+  --> $DIR/cast_size.rs:36:5
    |
 LL |     9_999_999_999_999_999usize as f64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs
index 95626b20b27..d063a70ccdf 100644
--- a/src/tools/clippy/tests/ui/cast_size.rs
+++ b/src/tools/clippy/tests/ui/cast_size.rs
@@ -1,56 +1,37 @@
-//@ignore-32bit
-#[warn(
+//@stderr-per-bitwidth
+//@no-rustfix
+
+#![warn(
     clippy::cast_precision_loss,
     clippy::cast_possible_truncation,
     clippy::cast_sign_loss,
     clippy::cast_possible_wrap,
     clippy::cast_lossless
 )]
-#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
 fn main() {
     // Casting from *size
     1isize as i8;
-    //~^ ERROR: casting `isize` to `i8` may truncate the value
     let x0 = 1isize;
     let x1 = 1usize;
     x0 as f64;
-    //~^ ERROR: casting `isize` to `f64` causes a loss of precision on targets with 64-bit
-    //~| NOTE: `-D clippy::cast-precision-loss` implied by `-D warnings`
     x1 as f64;
-    //~^ ERROR: casting `usize` to `f64` causes a loss of precision on targets with 64-bit
     x0 as f32;
-    //~^ ERROR: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 b
     x1 as f32;
-    //~^ ERROR: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 b
     1isize as i32;
-    //~^ ERROR: casting `isize` to `i32` may truncate the value on targets with 64-bit wid
     1isize as u32;
-    //~^ ERROR: casting `isize` to `u32` may truncate the value on targets with 64-bit wid
     1usize as u32;
-    //~^ ERROR: casting `usize` to `u32` may truncate the value on targets with 64-bit wid
     1usize as i32;
-    //~^ ERROR: casting `usize` to `i32` may truncate the value on targets with 64-bit wid
-    //~| ERROR: casting `usize` to `i32` may wrap around the value on targets with 32-bit
-    //~| NOTE: `-D clippy::cast-possible-wrap` implied by `-D warnings`
-    // Casting to *size
     1i64 as isize;
-    //~^ ERROR: casting `i64` to `isize` may truncate the value on targets with 32-bit wid
     1i64 as usize;
-    //~^ ERROR: casting `i64` to `usize` may truncate the value on targets with 32-bit wid
     1u64 as isize;
-    //~^ ERROR: casting `u64` to `isize` may truncate the value on targets with 32-bit wid
-    //~| ERROR: casting `u64` to `isize` may wrap around the value on targets with 64-bit
     1u64 as usize;
-    //~^ ERROR: casting `u64` to `usize` may truncate the value on targets with 32-bit wid
     1u32 as isize;
-    //~^ ERROR: casting `u32` to `isize` may wrap around the value on targets with 32-bit
     1u32 as usize; // Should not trigger any lint
     1i32 as isize; // Neither should this
     1i32 as usize;
     // Big integer literal to float
     999_999_999 as f32;
-    //~^ ERROR: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide,
     9_999_999_999_999_999usize as f64;
-    //~^ ERROR: casting `usize` to `f64` causes a loss of precision on targets with 64-bit
 }
-//@no-rustfix
diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.rs b/src/tools/clippy/tests/ui/cast_size_32bit.rs
deleted file mode 100644
index 5a06e34bdb8..00000000000
--- a/src/tools/clippy/tests/ui/cast_size_32bit.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-//@ignore-64bit
-#[warn(
-    clippy::cast_precision_loss,
-    clippy::cast_possible_truncation,
-    clippy::cast_sign_loss,
-    clippy::cast_possible_wrap,
-    clippy::cast_lossless
-)]
-#[allow(clippy::no_effect, clippy::unnecessary_operation)]
-fn main() {
-    // Casting from *size
-    1isize as i8;
-    //~^ ERROR: casting `isize` to `i8` may truncate the value
-    let x0 = 1isize;
-    let x1 = 1usize;
-    x0 as f64;
-    //~^ ERROR: casting `isize` to `f64` causes a loss of precision on targets with 64-bit
-    //~| NOTE: `-D clippy::cast-precision-loss` implied by `-D warnings`
-    x1 as f64;
-    //~^ ERROR: casting `usize` to `f64` causes a loss of precision on targets with 64-bit
-    x0 as f32;
-    //~^ ERROR: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 b
-    x1 as f32;
-    //~^ ERROR: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 b
-    1isize as i32;
-    //~^ ERROR: casting `isize` to `i32` may truncate the value on targets with 64-bit wid
-    1isize as u32;
-    //~^ ERROR: casting `isize` to `u32` may truncate the value on targets with 64-bit wid
-    1usize as u32;
-    //~^ ERROR: casting `usize` to `u32` may truncate the value on targets with 64-bit wid
-    1usize as i32;
-    //~^ ERROR: casting `usize` to `i32` may truncate the value on targets with 64-bit wid
-    //~| ERROR: casting `usize` to `i32` may wrap around the value on targets with 32-bit
-    //~| NOTE: `-D clippy::cast-possible-wrap` implied by `-D warnings`
-    // Casting to *size
-    1i64 as isize;
-    //~^ ERROR: casting `i64` to `isize` may truncate the value on targets with 32-bit wid
-    1i64 as usize;
-    //~^ ERROR: casting `i64` to `usize` may truncate the value on targets with 32-bit wid
-    1u64 as isize;
-    //~^ ERROR: casting `u64` to `isize` may truncate the value on targets with 32-bit wid
-    //~| ERROR: casting `u64` to `isize` may wrap around the value on targets with 64-bit
-    1u64 as usize;
-    //~^ ERROR: casting `u64` to `usize` may truncate the value on targets with 32-bit wid
-    1u32 as isize;
-    //~^ ERROR: casting `u32` to `isize` may wrap around the value on targets with 32-bit
-    1u32 as usize; // Should not trigger any lint
-    1i32 as isize; // Neither should this
-    1i32 as usize;
-    // Big integer literal to float
-    999_999_999 as f32;
-    //~^ ERROR: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide,
-    3_999_999_999usize as f64;
-    //~^ ERROR: casting integer literal to `f64` is unnecessary
-    //~| NOTE: `-D clippy::unnecessary-cast` implied by `-D warnings`
-}
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index e82e7bcb06c..02f80cc52ac 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -128,6 +128,57 @@ fn main() {
     assert!(x.is_ok(), "{:?}", x.unwrap_err());
 }
 
+fn issue11371() {
+    let option = Some(());
+
+    if option.is_some() {
+        option.as_ref().unwrap();
+        //~^ ERROR: called `unwrap` on `option` after checking its variant with `is_some`
+    } else {
+        option.as_ref().unwrap();
+        //~^ ERROR: this call to `unwrap()` will always panic
+    }
+
+    let result = Ok::<(), ()>(());
+
+    if result.is_ok() {
+        result.as_ref().unwrap();
+        //~^ ERROR: called `unwrap` on `result` after checking its variant with `is_ok`
+    } else {
+        result.as_ref().unwrap();
+        //~^ ERROR: this call to `unwrap()` will always panic
+    }
+
+    let mut option = Some(());
+    if option.is_some() {
+        option.as_mut().unwrap();
+        //~^ ERROR: called `unwrap` on `option` after checking its variant with `is_some`
+    } else {
+        option.as_mut().unwrap();
+        //~^ ERROR: this call to `unwrap()` will always panic
+    }
+
+    let mut result = Ok::<(), ()>(());
+    if result.is_ok() {
+        result.as_mut().unwrap();
+        //~^ ERROR: called `unwrap` on `result` after checking its variant with `is_ok`
+    } else {
+        result.as_mut().unwrap();
+        //~^ ERROR: this call to `unwrap()` will always panic
+    }
+
+    // This should not lint. Statics are, at the time of writing, not linted on anyway,
+    // but if at some point they are supported by this lint, it should correctly see that
+    // `X` is being mutated and not suggest `if let Some(..) = X {}`
+    static mut X: Option<i32> = Some(123);
+    unsafe {
+        if X.is_some() {
+            X = None;
+            X.unwrap();
+        }
+    }
+}
+
 fn check_expect() {
     let x = Some(());
     if x.is_some() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index ed603581ecd..a5afbba7317 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -168,5 +168,73 @@ LL |     if x.is_err() {
 LL |         x.unwrap_err();
    |         ^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> $DIR/simple_conditionals.rs:135:9
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some(..) = &option`
+LL |         option.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> $DIR/simple_conditionals.rs:138:9
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         option.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> $DIR/simple_conditionals.rs:145:9
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok(..) = &result`
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> $DIR/simple_conditionals.rs:148:9
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> $DIR/simple_conditionals.rs:154:9
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some(..) = &mut option`
+LL |         option.as_mut().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> $DIR/simple_conditionals.rs:157:9
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         option.as_mut().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> $DIR/simple_conditionals.rs:163:9
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok(..) = &mut result`
+LL |         result.as_mut().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> $DIR/simple_conditionals.rs:166:9
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         result.as_mut().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy_impl.rs b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs
index b7c186bef77..2d03544ad8b 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy_impl.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::incorrect_clone_impl_on_copy_type)]
+#![allow(clippy::non_canonical_clone_impl)]
 
 use std::fmt;
 use std::marker::PhantomData;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11337.rs b/src/tools/clippy/tests/ui/crashes/ice-11337.rs
new file mode 100644
index 00000000000..0bed4035f6b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11337.rs
@@ -0,0 +1,9 @@
+#![feature(trait_alias)]
+
+trait Confusing<F> = Fn(i32) where F: Fn(u32);
+
+fn alias<T: Confusing<F>, F>(_: T, _: F) {}
+
+fn main() {
+    alias(|_| {}, |_| {});
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.fixed b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed
new file mode 100644
index 00000000000..ca5721cbb2b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed
@@ -0,0 +1,25 @@
+#![warn(clippy::implied_bounds_in_impls)]
+
+use std::fmt::Debug;
+use std::ops::*;
+
+fn gen() -> impl PartialOrd + Debug {}
+
+struct Bar {}
+trait Foo<T = Self> {}
+trait FooNested<T = Option<Self>> {}
+impl Foo for Bar {}
+impl FooNested for Bar {}
+
+fn foo() -> impl Foo + FooNested {
+    Bar {}
+}
+
+fn test_impl_ops() -> impl Add + Sub + Mul + Div {
+    1
+}
+fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign {
+    1
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.rs b/src/tools/clippy/tests/ui/crashes/ice-11422.rs
new file mode 100644
index 00000000000..355ec2480bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11422.rs
@@ -0,0 +1,25 @@
+#![warn(clippy::implied_bounds_in_impls)]
+
+use std::fmt::Debug;
+use std::ops::*;
+
+fn gen() -> impl PartialOrd + PartialEq + Debug {}
+
+struct Bar {}
+trait Foo<T = Self> {}
+trait FooNested<T = Option<Self>> {}
+impl Foo for Bar {}
+impl FooNested for Bar {}
+
+fn foo() -> impl Foo + FooNested {
+    Bar {}
+}
+
+fn test_impl_ops() -> impl Add + Sub + Mul + Div {
+    1
+}
+fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign {
+    1
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.stderr b/src/tools/clippy/tests/ui/crashes/ice-11422.stderr
new file mode 100644
index 00000000000..fb80b5b147f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11422.stderr
@@ -0,0 +1,16 @@
+error: this bound is already specified as the supertrait of `PartialOrd`
+  --> $DIR/ice-11422.rs:6:31
+   |
+LL | fn gen() -> impl PartialOrd + PartialEq + Debug {}
+   |                               ^^^^^^^^^
+   |
+   = note: `-D clippy::implied-bounds-in-impls` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::implied_bounds_in_impls)]`
+help: try removing this bound
+   |
+LL - fn gen() -> impl PartialOrd + PartialEq + Debug {}
+LL + fn gen() -> impl PartialOrd + Debug {}
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.rs b/src/tools/clippy/tests/ui/crashes/ice-360.rs
index 28589e1efed..0d10932b098 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-360.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-360.rs
@@ -3,7 +3,8 @@ fn main() {}
 fn no_panic<T>(slice: &[T]) {
     let mut iter = slice.iter();
     loop {
-        //~^ ERROR: this loop could be written as a `while let` loop
+        //~^ ERROR: this loop never actually loops
+        //~| ERROR: this loop could be written as a `while let` loop
         //~| NOTE: `-D clippy::while-let-loop` implied by `-D warnings`
         let _ = match iter.next() {
             Some(ele) => ele,
diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.stderr b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
index dd016355b53..a84697a9f29 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-360.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
@@ -1,10 +1,24 @@
+error: this loop never actually loops
+  --> $DIR/ice-360.rs:5:5
+   |
+LL | /     loop {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | |     }
+   | |_____^
+   |
+   = note: `#[deny(clippy::never_loop)]` on by default
+
 error: this loop could be written as a `while let` loop
   --> $DIR/ice-360.rs:5:5
    |
 LL | /     loop {
 LL | |
 LL | |
-LL | |         let _ = match iter.next() {
+LL | |
 ...  |
 LL | |
 LL | |     }
@@ -14,7 +28,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::while_let_loop)]`
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/ice-360.rs:12:9
+  --> $DIR/ice-360.rs:13:9
    |
 LL |         loop {}
    |         ^^^^^^^
@@ -23,5 +37,5 @@ LL |         loop {}
    = note: `-D clippy::empty-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed
index 6cc202414f5..68c5a5c5ca4 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.fixed
+++ b/src/tools/clippy/tests/ui/derivable_impls.fixed
@@ -287,4 +287,17 @@ mod issue10158 {
     }
 }
 
+mod issue11368 {
+    pub struct A {
+        a: u32,
+    }
+
+    impl Default for A {
+        #[track_caller]
+        fn default() -> Self {
+            Self { a: 0 }
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs
index 0aa9acd752d..21d73ba8b77 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.rs
+++ b/src/tools/clippy/tests/ui/derivable_impls.rs
@@ -323,4 +323,17 @@ mod issue10158 {
     }
 }
 
+mod issue11368 {
+    pub struct A {
+        a: u32,
+    }
+
+    impl Default for A {
+        #[track_caller]
+        fn default() -> Self {
+            Self { a: 0 }
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index 310c701765b..20ac8a6e6be 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -1,8 +1,4 @@
-#![allow(
-    clippy::incorrect_clone_impl_on_copy_type,
-    clippy::incorrect_partial_ord_impl_on_ord_type,
-    dead_code
-)]
+#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
 #![warn(clippy::expl_impl_clone_on_copy)]
 
 
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index e9b2ee34760..88942d95432 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -1,5 +1,5 @@
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:12:1
+  --> $DIR/derive.rs:8:1
    |
 LL | / impl Clone for Qux {
 LL | |
@@ -10,7 +10,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:12:1
+  --> $DIR/derive.rs:8:1
    |
 LL | / impl Clone for Qux {
 LL | |
@@ -23,7 +23,7 @@ LL | | }
    = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:37:1
+  --> $DIR/derive.rs:33:1
    |
 LL | / impl<'a> Clone for Lt<'a> {
 LL | |
@@ -34,7 +34,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:37:1
+  --> $DIR/derive.rs:33:1
    |
 LL | / impl<'a> Clone for Lt<'a> {
 LL | |
@@ -45,7 +45,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:49:1
+  --> $DIR/derive.rs:45:1
    |
 LL | / impl Clone for BigArray {
 LL | |
@@ -56,7 +56,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:49:1
+  --> $DIR/derive.rs:45:1
    |
 LL | / impl Clone for BigArray {
 LL | |
@@ -67,7 +67,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:61:1
+  --> $DIR/derive.rs:57:1
    |
 LL | / impl Clone for FnPtr {
 LL | |
@@ -78,7 +78,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:61:1
+  --> $DIR/derive.rs:57:1
    |
 LL | / impl Clone for FnPtr {
 LL | |
@@ -89,7 +89,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:82:1
+  --> $DIR/derive.rs:78:1
    |
 LL | / impl<T: Clone> Clone for Generic2<T> {
 LL | |
@@ -100,7 +100,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:82:1
+  --> $DIR/derive.rs:78:1
    |
 LL | / impl<T: Clone> Clone for Generic2<T> {
 LL | |
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
index 2c19942d420..1c7e6d1c202 100644
--- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::derive_ord_xor_partial_ord)]
 #![allow(clippy::unnecessary_wraps)]
-#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 
 use std::cmp::Ordering;
 
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index f7c2f14a482..47b56960a00 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -198,6 +198,16 @@ fn pulldown_cmark_crash() {}
 /// [plain text][path::to::item]
 fn intra_doc_link() {}
 
+/// Ignore escaped\_underscores
+///
+/// \\[
+///     \\prod\_{x\\in X} p\_x
+/// \\]
+fn issue_2581() {}
+
+/// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
+fn lint_after_escaped_chars() {}
+
 // issue #7033 - generic_const_exprs ICE
 struct S<T, const N: usize>
 where [(); N.checked_next_power_of_two().unwrap()]: {
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 51961e75b84..4d9a4eafa5f 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -198,6 +198,16 @@ fn pulldown_cmark_crash() {}
 /// [plain text][path::to::item]
 fn intra_doc_link() {}
 
+/// Ignore escaped\_underscores
+///
+/// \\[
+///     \\prod\_{x\\in X} p\_x
+/// \\]
+fn issue_2581() {}
+
+/// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
+fn lint_after_escaped_chars() {}
+
 // issue #7033 - generic_const_exprs ICE
 struct S<T, const N: usize>
 where [(); N.checked_next_power_of_two().unwrap()]: {
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index a30ded81385..4c9ff41d918 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -308,5 +308,16 @@ help: try
 LL | /// An iterator over `mycrate::Collection`'s values.
    |                      ~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 28 previous errors
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:208:34
+   |
+LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
+   |                                  ^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
+   |                                  ~~~~~~~~~~~~~~~~~
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 4a1711f79a0..6f7bab72040 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -48,4 +48,4 @@ fn other_markdown() {}
 ///   /// `lol`
 ///   pub struct Struct;
 ///   ```
-fn iss_7421() {}
+fn issue_7421() {}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 92b6f8536c8..89ad8db3916 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -1,7 +1,8 @@
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:7:1
+  --> $DIR/unbalanced_ticks.rs:7:5
    |
-LL | / /// This is a doc comment with `unbalanced_tick marks and several words that
+LL |   /// This is a doc comment with `unbalanced_tick marks and several words that
+   |  _____^
 LL | |
 LL | | /// should be `encompassed_by` tick marks because they `contain_underscores`.
 LL | | /// Because of the initial `unbalanced_tick` pair, the error message is
@@ -13,10 +14,10 @@ LL | | /// very `confusing_and_misleading`.
    = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]`
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:14:1
+  --> $DIR/unbalanced_ticks.rs:14:5
    |
 LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
@@ -32,10 +33,10 @@ LL | /// This paragraph is fine and `should_be` linted normally.
    |                                ~~~~~~~~~~~
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:20:1
+  --> $DIR/unbalanced_ticks.rs:20:5
    |
 LL | /// Double unbalanced backtick from ``here to here` should lint.
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
@@ -51,18 +52,18 @@ LL | /// ## `not_fine`
    |        ~~~~~~~~~~
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:37:1
+  --> $DIR/unbalanced_ticks.rs:37:5
    |
 LL | /// ### `unbalanced
-   | ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:40:1
+  --> $DIR/unbalanced_ticks.rs:40:5
    |
 LL | /// - This `item has unbalanced tick marks
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs
index 86721f61d19..d661231c59e 100644
--- a/src/tools/clippy/tests/ui/doc_errors.rs
+++ b/src/tools/clippy/tests/ui/doc_errors.rs
@@ -85,6 +85,22 @@ impl Struct1 {
     async fn async_priv_method_missing_errors_header() -> Result<(), ()> {
         unimplemented!();
     }
+
+    /**
+    # Errors
+    A description of the errors goes here.
+    */
+    fn block_comment() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /**
+     * # Errors
+     * A description of the errors goes here.
+     */
+    fn block_comment_leading_asterisks() -> Result<(), ()> {
+        unimplemented!();
+    }
 }
 
 pub trait Trait1 {
diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr
index 9cea864f1d8..28b2db2440b 100644
--- a/src/tools/clippy/tests/ui/doc_errors.stderr
+++ b/src/tools/clippy/tests/ui/doc_errors.stderr
@@ -38,7 +38,7 @@ LL |     pub async fn async_pub_method_missing_errors_header() -> Result<(), ()>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:92:5
+  --> $DIR/doc_errors.rs:108:5
    |
 LL |     fn trait_method_missing_errors_header() -> Result<(), ()>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/empty_loop.rs b/src/tools/clippy/tests/ui/empty_loop.rs
index 54e8fb4907c..be347563135 100644
--- a/src/tools/clippy/tests/ui/empty_loop.rs
+++ b/src/tools/clippy/tests/ui/empty_loop.rs
@@ -7,10 +7,12 @@ use proc_macros::{external, inline_macros};
 
 fn should_trigger() {
     loop {}
+    #[allow(clippy::never_loop)]
     loop {
         loop {}
     }
 
+    #[allow(clippy::never_loop)]
     'outer: loop {
         'inner: loop {}
     }
@@ -18,6 +20,7 @@ fn should_trigger() {
 
 #[inline_macros]
 fn should_not_trigger() {
+    #[allow(clippy::never_loop)]
     loop {
         panic!("This is fine")
     }
diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr
index 84d7d61c7da..113556f673c 100644
--- a/src/tools/clippy/tests/ui/empty_loop.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop.stderr
@@ -9,7 +9,7 @@ LL |     loop {}
    = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]`
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop.rs:11:9
+  --> $DIR/empty_loop.rs:12:9
    |
 LL |         loop {}
    |         ^^^^^^^
@@ -17,7 +17,7 @@ LL |         loop {}
    = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop.rs:15:9
+  --> $DIR/empty_loop.rs:17:9
    |
 LL |         'inner: loop {}
    |         ^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs
index 964e5634ddb..c50404c5047 100644
--- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs
+++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs
@@ -1,4 +1,4 @@
-//@ignore-target-x86
+//@ignore-32bit
 
 #![warn(clippy::enum_clike_unportable_variant)]
 #![allow(unused, non_upper_case_globals)]
diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
index 5935eea5e03..93ad4daa97f 100644
--- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
+++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
@@ -5,51 +5,52 @@ LL |     X = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::enum_clike_unportable_variant)]`
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:15:5
+  --> $DIR/enum_clike_unportable_variant.rs:17:5
    |
 LL |     X = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:18:5
+  --> $DIR/enum_clike_unportable_variant.rs:21:5
    |
 LL |     A = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:25:5
+  --> $DIR/enum_clike_unportable_variant.rs:29:5
    |
 LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:26:5
+  --> $DIR/enum_clike_unportable_variant.rs:31:5
    |
 LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:28:5
+  --> $DIR/enum_clike_unportable_variant.rs:34:5
    |
 LL |     C = (i32::MIN as isize) - 1,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:34:5
+  --> $DIR/enum_clike_unportable_variant.rs:41:5
    |
 LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:35:5
+  --> $DIR/enum_clike_unportable_variant.rs:43:5
    |
 LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: C-like enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enum_clike_unportable_variant.rs:40:5
+  --> $DIR/enum_clike_unportable_variant.rs:49:5
    |
 LL |     X = <usize as Trait>::Number,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index 86bee11eb87..12158d0d12a 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -205,7 +205,7 @@ fn main() {
         }
     }
 
-    f_str(&&ref_str); // `needless_borrow` will suggest removing both references
+    f_str(&ref_str); // `needless_borrow` will suggest removing both references
     f_str(&ref_str); // `needless_borrow` will suggest removing only one reference
 
     let x = &&40;
@@ -293,4 +293,32 @@ fn main() {
     fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
         *x
     }
+
+    // Issue #11366
+    let _: &mut u32 = match &mut Some(&mut 0u32) {
+        Some(x) => x,
+        None => panic!(),
+    };
+
+    // Issue #11474
+    pub struct Variant {
+        pub anonymous: Variant0,
+    }
+
+    pub union Variant0 {
+        pub anonymous: std::mem::ManuallyDrop<Variant00>,
+    }
+
+    pub struct Variant00 {
+        pub anonymous: Variant000,
+    }
+
+    pub union Variant000 {
+        pub val: i32,
+    }
+
+    unsafe {
+        let mut p = core::mem::zeroed::<Variant>();
+        (*p.anonymous.anonymous).anonymous.val = 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 7a505bdf558..dec021c1834 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -293,4 +293,32 @@ fn main() {
     fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
         *x
     }
+
+    // Issue #11366
+    let _: &mut u32 = match &mut Some(&mut 0u32) {
+        Some(x) => &mut *x,
+        None => panic!(),
+    };
+
+    // Issue #11474
+    pub struct Variant {
+        pub anonymous: Variant0,
+    }
+
+    pub union Variant0 {
+        pub anonymous: std::mem::ManuallyDrop<Variant00>,
+    }
+
+    pub struct Variant00 {
+        pub anonymous: Variant000,
+    }
+
+    pub union Variant000 {
+        pub val: i32,
+    }
+
+    unsafe {
+        let mut p = core::mem::zeroed::<Variant>();
+        (*p.anonymous.anonymous).anonymous.val = 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index bea014d8ad5..3d2a7b0d9f4 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -194,10 +194,10 @@ LL |     let _ = f_str(**ref_ref_str);
    |                   ^^^^^^^^^^^^^ help: try: `ref_ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:208:13
+  --> $DIR/explicit_auto_deref.rs:208:12
    |
 LL |     f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
-   |             ^^^^^^^^ help: try: `ref_str`
+   |            ^^^^^^^^^ help: try: `ref_str`
 
 error: deref which would be done by auto-deref
   --> $DIR/explicit_auto_deref.rs:209:12
@@ -235,5 +235,11 @@ error: deref which would be done by auto-deref
 LL |         *x
    |         ^^ help: try: `x`
 
-error: aborting due to 39 previous errors
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:299:20
+   |
+LL |         Some(x) => &mut *x,
+   |                    ^^^^^^^ help: try: `x`
+
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
index 57292114e38..f08397defa5 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
@@ -4,6 +4,7 @@
     clippy::similar_names,
     clippy::needless_borrow,
     clippy::deref_addrof,
+    clippy::unnecessary_mut_passed,
     dead_code
 )]
 
@@ -20,15 +21,15 @@ fn main() {
     for _ in rvec {}
 
     let rmvec = &mut vec;
-    for _ in &*rmvec {}
-    for _ in &mut *rmvec {}
+    for _ in rmvec.iter() {}
+    for _ in rmvec.iter_mut() {}
 
     for _ in &vec {} // these are fine
     for _ in &mut vec {} // these are fine
 
     for _ in &[1, 2, 3] {}
 
-    for _ in &*(&mut [1, 2, 3]) {}
+    for _ in (&mut [1, 2, 3]).iter() {}
 
     for _ in &[0; 32] {}
     for _ in &[0; 33] {}
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
index 66280c23843..2ee6825d445 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
@@ -4,6 +4,7 @@
     clippy::similar_names,
     clippy::needless_borrow,
     clippy::deref_addrof,
+    clippy::unnecessary_mut_passed,
     dead_code
 )]
 
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
index af46d74e989..725d9b63cf8 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
@@ -1,5 +1,5 @@
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:16:14
+  --> $DIR/explicit_iter_loop.rs:17:14
    |
 LL |     for _ in vec.iter() {}
    |              ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
@@ -11,133 +11,106 @@ LL | #![deny(clippy::explicit_iter_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:17:14
+  --> $DIR/explicit_iter_loop.rs:18:14
    |
 LL |     for _ in vec.iter_mut() {}
    |              ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:20:14
+  --> $DIR/explicit_iter_loop.rs:21:14
    |
 LL |     for _ in rvec.iter() {}
    |              ^^^^^^^^^^^ help: to write this more concisely, try: `rvec`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:23:14
-   |
-LL |     for _ in rmvec.iter() {}
-   |              ^^^^^^^^^^^^ help: to write this more concisely, try: `&*rmvec`
-
-error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:24:14
-   |
-LL |     for _ in rmvec.iter_mut() {}
-   |              ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *rmvec`
-
-error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:29:14
+  --> $DIR/explicit_iter_loop.rs:30:14
    |
 LL |     for _ in [1, 2, 3].iter() {}
    |              ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:31:14
-   |
-LL |     for _ in (&mut [1, 2, 3]).iter() {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*(&mut [1, 2, 3])`
-
-error: the method `iter` doesn't need a mutable reference
-  --> $DIR/explicit_iter_loop.rs:31:14
-   |
-LL |     for _ in (&mut [1, 2, 3]).iter() {}
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
-
-error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:33:14
+  --> $DIR/explicit_iter_loop.rs:34:14
    |
 LL |     for _ in [0; 32].iter() {}
    |              ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:34:14
+  --> $DIR/explicit_iter_loop.rs:35:14
    |
 LL |     for _ in [0; 33].iter() {}
    |              ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 33]`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:37:14
+  --> $DIR/explicit_iter_loop.rs:38:14
    |
 LL |     for _ in ll.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&ll`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:39:14
+  --> $DIR/explicit_iter_loop.rs:40:14
    |
 LL |     for _ in rll.iter() {}
    |              ^^^^^^^^^^ help: to write this more concisely, try: `rll`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:42:14
+  --> $DIR/explicit_iter_loop.rs:43:14
    |
 LL |     for _ in vd.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&vd`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:44:14
+  --> $DIR/explicit_iter_loop.rs:45:14
    |
 LL |     for _ in rvd.iter() {}
    |              ^^^^^^^^^^ help: to write this more concisely, try: `rvd`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:47:14
+  --> $DIR/explicit_iter_loop.rs:48:14
    |
 LL |     for _ in bh.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&bh`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:50:14
+  --> $DIR/explicit_iter_loop.rs:51:14
    |
 LL |     for _ in hm.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&hm`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:53:14
+  --> $DIR/explicit_iter_loop.rs:54:14
    |
 LL |     for _ in bt.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&bt`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:56:14
+  --> $DIR/explicit_iter_loop.rs:57:14
    |
 LL |     for _ in hs.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&hs`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:59:14
+  --> $DIR/explicit_iter_loop.rs:60:14
    |
 LL |     for _ in bs.iter() {}
    |              ^^^^^^^^^ help: to write this more concisely, try: `&bs`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:148:14
+  --> $DIR/explicit_iter_loop.rs:149:14
    |
 LL |     for _ in x.iter() {}
    |              ^^^^^^^^ help: to write this more concisely, try: `&x`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:149:14
+  --> $DIR/explicit_iter_loop.rs:150:14
    |
 LL |     for _ in x.iter_mut() {}
    |              ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut x`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/explicit_iter_loop.rs:152:14
+  --> $DIR/explicit_iter_loop.rs:153:14
    |
 LL |     for _ in r.iter() {}
    |              ^^^^^^^^ help: to write this more concisely, try: `r`
 
-error: aborting due to 22 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
index a547a67430f..5057c643732 100644
--- a/src/tools/clippy/tests/ui/float_cmp.rs
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -41,6 +41,16 @@ impl PartialEq for X {
     }
 }
 
+impl PartialEq<f32> for X {
+    fn eq(&self, o: &f32) -> bool {
+        if self.val.is_nan() {
+            o.is_nan()
+        } else {
+            self.val == *o // no error, inside "eq" fn
+        }
+    }
+}
+
 fn main() {
     ZERO == 0f32; //no error, comparison with zero is ok
     1.0f32 != f32::INFINITY; // also comparison with infinity
@@ -48,6 +58,9 @@ fn main() {
     ZERO == 0.0; //no error, comparison with zero is ok
     ZERO + ZERO != 1.0; //no error, comparison with zero is ok
 
+    let x = X { val: 1.0 };
+    x == 1.0; // no error, custom type that implement PartialOrder for float is not checked
+
     ONE == 1f32;
     ONE == 1.0 + 0.0;
     ONE + ONE == ZERO + ONE + ONE;
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
index cbe529954d0..217e2987917 100644
--- a/src/tools/clippy/tests/ui/float_cmp.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -1,5 +1,5 @@
 error: strict comparison of `f32` or `f64`
-  --> $DIR/float_cmp.rs:57:5
+  --> $DIR/float_cmp.rs:70:5
    |
 LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
@@ -9,7 +9,7 @@ LL |     ONE as f64 != 2.0;
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]`
 
 error: strict comparison of `f32` or `f64`
-  --> $DIR/float_cmp.rs:64:5
+  --> $DIR/float_cmp.rs:77:5
    |
 LL |     x == 1.0;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
@@ -17,7 +17,7 @@ LL |     x == 1.0;
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> $DIR/float_cmp.rs:69:5
+  --> $DIR/float_cmp.rs:82:5
    |
 LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
@@ -25,7 +25,7 @@ LL |     twice(x) != twice(ONE as f64);
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> $DIR/float_cmp.rs:91:5
+  --> $DIR/float_cmp.rs:104:5
    |
 LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
@@ -33,7 +33,7 @@ LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` arrays
-  --> $DIR/float_cmp.rs:98:5
+  --> $DIR/float_cmp.rs:111:5
    |
 LL |     a1 == a2;
    |     ^^^^^^^^
@@ -41,7 +41,7 @@ LL |     a1 == a2;
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> $DIR/float_cmp.rs:101:5
+  --> $DIR/float_cmp.rs:114:5
    |
 LL |     a1[0] == a2[0];
    |     ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr
index 671347d2bcd..ea08d8c9cc1 100644
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr
@@ -1,141 +1,143 @@
 error: casting function pointer `foo` to `i8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:10:13
+  --> $DIR/fn_to_numeric_cast.rs:10:13
    |
 LL |     let _ = foo as i8;
    |             ^^^^^^^^^ help: try: `foo as usize`
    |
    = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_with_truncation)]`
 
 error: casting function pointer `foo` to `i16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:11:13
+  --> $DIR/fn_to_numeric_cast.rs:11:13
    |
 LL |     let _ = foo as i16;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
-error: casting function pointer `foo` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:12:13
+error: casting function pointer `foo` to `i32`
+  --> $DIR/fn_to_numeric_cast.rs:12:13
    |
 LL |     let _ = foo as i32;
    |             ^^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast)]`
 
 error: casting function pointer `foo` to `i64`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:13:13
+  --> $DIR/fn_to_numeric_cast.rs:13:13
    |
 LL |     let _ = foo as i64;
    |             ^^^^^^^^^^ help: try: `foo as usize`
-   |
-   = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
 
 error: casting function pointer `foo` to `i128`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:14:13
+  --> $DIR/fn_to_numeric_cast.rs:14:13
    |
 LL |     let _ = foo as i128;
    |             ^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `isize`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:15:13
+  --> $DIR/fn_to_numeric_cast.rs:15:13
    |
 LL |     let _ = foo as isize;
    |             ^^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:17:13
+  --> $DIR/fn_to_numeric_cast.rs:17:13
    |
 LL |     let _ = foo as u8;
    |             ^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:18:13
+  --> $DIR/fn_to_numeric_cast.rs:18:13
    |
 LL |     let _ = foo as u16;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
-error: casting function pointer `foo` to `u32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:19:13
+error: casting function pointer `foo` to `u32`
+  --> $DIR/fn_to_numeric_cast.rs:19:13
    |
 LL |     let _ = foo as u32;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u64`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:20:13
+  --> $DIR/fn_to_numeric_cast.rs:20:13
    |
 LL |     let _ = foo as u64;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u128`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:21:13
+  --> $DIR/fn_to_numeric_cast.rs:21:13
    |
 LL |     let _ = foo as u128;
    |             ^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `abc` to `i8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:34:13
+  --> $DIR/fn_to_numeric_cast.rs:34:13
    |
 LL |     let _ = abc as i8;
    |             ^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:35:13
+  --> $DIR/fn_to_numeric_cast.rs:35:13
    |
 LL |     let _ = abc as i16;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
-error: casting function pointer `abc` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:36:13
+error: casting function pointer `abc` to `i32`
+  --> $DIR/fn_to_numeric_cast.rs:36:13
    |
 LL |     let _ = abc as i32;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i64`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:37:13
+  --> $DIR/fn_to_numeric_cast.rs:37:13
    |
 LL |     let _ = abc as i64;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i128`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:38:13
+  --> $DIR/fn_to_numeric_cast.rs:38:13
    |
 LL |     let _ = abc as i128;
    |             ^^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `isize`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:39:13
+  --> $DIR/fn_to_numeric_cast.rs:39:13
    |
 LL |     let _ = abc as isize;
    |             ^^^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:41:13
+  --> $DIR/fn_to_numeric_cast.rs:41:13
    |
 LL |     let _ = abc as u8;
    |             ^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:42:13
+  --> $DIR/fn_to_numeric_cast.rs:42:13
    |
 LL |     let _ = abc as u16;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
-error: casting function pointer `abc` to `u32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:43:13
+error: casting function pointer `abc` to `u32`
+  --> $DIR/fn_to_numeric_cast.rs:43:13
    |
 LL |     let _ = abc as u32;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u64`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:44:13
+  --> $DIR/fn_to_numeric_cast.rs:44:13
    |
 LL |     let _ = abc as u64;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u128`
-  --> $DIR/fn_to_numeric_cast_32bit.rs:45:13
+  --> $DIR/fn_to_numeric_cast.rs:45:13
    |
 LL |     let _ = abc as u128;
    |             ^^^^^^^^^^^ help: try: `abc as usize`
 
-error: casting function pointer `f` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast_32bit.rs:52:5
+error: casting function pointer `f` to `i32`
+  --> $DIR/fn_to_numeric_cast.rs:52:5
    |
 LL |     f as i32
    |     ^^^^^^^^ help: try: `f as usize`
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr
index 53e8ac3c4b4..62f3bfa70ea 100644
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr
@@ -8,19 +8,19 @@ LL |     let _ = foo as i8;
    = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_with_truncation)]`
 
 error: casting function pointer `foo` to `i16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:13:13
+  --> $DIR/fn_to_numeric_cast.rs:11:13
    |
 LL |     let _ = foo as i16;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:15:13
+  --> $DIR/fn_to_numeric_cast.rs:12:13
    |
 LL |     let _ = foo as i32;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `i64`
-  --> $DIR/fn_to_numeric_cast.rs:17:13
+  --> $DIR/fn_to_numeric_cast.rs:13:13
    |
 LL |     let _ = foo as i64;
    |             ^^^^^^^^^^ help: try: `foo as usize`
@@ -29,115 +29,115 @@ LL |     let _ = foo as i64;
    = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast)]`
 
 error: casting function pointer `foo` to `i128`
-  --> $DIR/fn_to_numeric_cast.rs:20:13
+  --> $DIR/fn_to_numeric_cast.rs:14:13
    |
 LL |     let _ = foo as i128;
    |             ^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `isize`
-  --> $DIR/fn_to_numeric_cast.rs:22:13
+  --> $DIR/fn_to_numeric_cast.rs:15:13
    |
 LL |     let _ = foo as isize;
    |             ^^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:25:13
+  --> $DIR/fn_to_numeric_cast.rs:17:13
    |
 LL |     let _ = foo as u8;
    |             ^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:27:13
+  --> $DIR/fn_to_numeric_cast.rs:18:13
    |
 LL |     let _ = foo as u16;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:29:13
+  --> $DIR/fn_to_numeric_cast.rs:19:13
    |
 LL |     let _ = foo as u32;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u64`
-  --> $DIR/fn_to_numeric_cast.rs:31:13
+  --> $DIR/fn_to_numeric_cast.rs:20:13
    |
 LL |     let _ = foo as u64;
    |             ^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `foo` to `u128`
-  --> $DIR/fn_to_numeric_cast.rs:33:13
+  --> $DIR/fn_to_numeric_cast.rs:21:13
    |
 LL |     let _ = foo as u128;
    |             ^^^^^^^^^^^ help: try: `foo as usize`
 
 error: casting function pointer `abc` to `i8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:47:13
+  --> $DIR/fn_to_numeric_cast.rs:34:13
    |
 LL |     let _ = abc as i8;
    |             ^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:49:13
+  --> $DIR/fn_to_numeric_cast.rs:35:13
    |
 LL |     let _ = abc as i16;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:51:13
+  --> $DIR/fn_to_numeric_cast.rs:36:13
    |
 LL |     let _ = abc as i32;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i64`
-  --> $DIR/fn_to_numeric_cast.rs:53:13
+  --> $DIR/fn_to_numeric_cast.rs:37:13
    |
 LL |     let _ = abc as i64;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `i128`
-  --> $DIR/fn_to_numeric_cast.rs:55:13
+  --> $DIR/fn_to_numeric_cast.rs:38:13
    |
 LL |     let _ = abc as i128;
    |             ^^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `isize`
-  --> $DIR/fn_to_numeric_cast.rs:57:13
+  --> $DIR/fn_to_numeric_cast.rs:39:13
    |
 LL |     let _ = abc as isize;
    |             ^^^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u8`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:60:13
+  --> $DIR/fn_to_numeric_cast.rs:41:13
    |
 LL |     let _ = abc as u8;
    |             ^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u16`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:62:13
+  --> $DIR/fn_to_numeric_cast.rs:42:13
    |
 LL |     let _ = abc as u16;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:64:13
+  --> $DIR/fn_to_numeric_cast.rs:43:13
    |
 LL |     let _ = abc as u32;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u64`
-  --> $DIR/fn_to_numeric_cast.rs:66:13
+  --> $DIR/fn_to_numeric_cast.rs:44:13
    |
 LL |     let _ = abc as u64;
    |             ^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `abc` to `u128`
-  --> $DIR/fn_to_numeric_cast.rs:68:13
+  --> $DIR/fn_to_numeric_cast.rs:45:13
    |
 LL |     let _ = abc as u128;
    |             ^^^^^^^^^^^ help: try: `abc as usize`
 
 error: casting function pointer `f` to `i32`, which truncates the value
-  --> $DIR/fn_to_numeric_cast.rs:76:5
+  --> $DIR/fn_to_numeric_cast.rs:52:5
    |
 LL |     f as i32
    |     ^^^^^^^^ help: try: `f as usize`
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs
index 09128d8176e..9501eb5da4b 100644
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs
@@ -1,4 +1,4 @@
-//@ignore-32bit
+//@stderr-per-bitwidth
 //@no-rustfix
 #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
 
@@ -8,30 +8,17 @@ fn foo() -> String {
 
 fn test_function_to_numeric_cast() {
     let _ = foo as i8;
-    //~^ ERROR: casting function pointer `foo` to `i8`, which truncates the value
-    //~| NOTE: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
     let _ = foo as i16;
-    //~^ ERROR: casting function pointer `foo` to `i16`, which truncates the value
     let _ = foo as i32;
-    //~^ ERROR: casting function pointer `foo` to `i32`, which truncates the value
     let _ = foo as i64;
-    //~^ ERROR: casting function pointer `foo` to `i64`
-    //~| NOTE: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
     let _ = foo as i128;
-    //~^ ERROR: casting function pointer `foo` to `i128`
     let _ = foo as isize;
-    //~^ ERROR: casting function pointer `foo` to `isize`
 
     let _ = foo as u8;
-    //~^ ERROR: casting function pointer `foo` to `u8`, which truncates the value
     let _ = foo as u16;
-    //~^ ERROR: casting function pointer `foo` to `u16`, which truncates the value
     let _ = foo as u32;
-    //~^ ERROR: casting function pointer `foo` to `u32`, which truncates the value
     let _ = foo as u64;
-    //~^ ERROR: casting function pointer `foo` to `u64`
     let _ = foo as u128;
-    //~^ ERROR: casting function pointer `foo` to `u128`
 
     // Casting to usize is OK and should not warn
     let _ = foo as usize;
@@ -45,28 +32,17 @@ fn test_function_var_to_numeric_cast() {
     let abc: fn() -> String = foo;
 
     let _ = abc as i8;
-    //~^ ERROR: casting function pointer `abc` to `i8`, which truncates the value
     let _ = abc as i16;
-    //~^ ERROR: casting function pointer `abc` to `i16`, which truncates the value
     let _ = abc as i32;
-    //~^ ERROR: casting function pointer `abc` to `i32`, which truncates the value
     let _ = abc as i64;
-    //~^ ERROR: casting function pointer `abc` to `i64`
     let _ = abc as i128;
-    //~^ ERROR: casting function pointer `abc` to `i128`
     let _ = abc as isize;
-    //~^ ERROR: casting function pointer `abc` to `isize`
 
     let _ = abc as u8;
-    //~^ ERROR: casting function pointer `abc` to `u8`, which truncates the value
     let _ = abc as u16;
-    //~^ ERROR: casting function pointer `abc` to `u16`, which truncates the value
     let _ = abc as u32;
-    //~^ ERROR: casting function pointer `abc` to `u32`, which truncates the value
     let _ = abc as u64;
-    //~^ ERROR: casting function pointer `abc` to `u64`
     let _ = abc as u128;
-    //~^ ERROR: casting function pointer `abc` to `u128`
 
     // Casting to usize is OK and should not warn
     let _ = abc as usize;
@@ -74,7 +50,6 @@ fn test_function_var_to_numeric_cast() {
 
 fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
     f as i32
-    //~^ ERROR: casting function pointer `f` to `i32`, which truncates the value
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs
deleted file mode 100644
index 93e9361f4dc..00000000000
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-//@ignore-64bit
-
-#![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
-
-fn foo() -> String {
-    String::new()
-}
-
-fn test_function_to_numeric_cast() {
-    let _ = foo as i8;
-    //~^ ERROR: casting function pointer `foo` to `i8`, which truncates the value
-    //~| NOTE: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
-    let _ = foo as i16;
-    //~^ ERROR: casting function pointer `foo` to `i16`, which truncates the value
-    let _ = foo as i32;
-    //~^ ERROR: casting function pointer `foo` to `i32`, which truncates the value
-    let _ = foo as i64;
-    //~^ ERROR: casting function pointer `foo` to `i64`
-    //~| NOTE: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
-    let _ = foo as i128;
-    //~^ ERROR: casting function pointer `foo` to `i128`
-    let _ = foo as isize;
-    //~^ ERROR: casting function pointer `foo` to `isize`
-
-    let _ = foo as u8;
-    //~^ ERROR: casting function pointer `foo` to `u8`, which truncates the value
-    let _ = foo as u16;
-    //~^ ERROR: casting function pointer `foo` to `u16`, which truncates the value
-    let _ = foo as u32;
-    //~^ ERROR: casting function pointer `foo` to `u32`, which truncates the value
-    let _ = foo as u64;
-    //~^ ERROR: casting function pointer `foo` to `u64`
-    let _ = foo as u128;
-    //~^ ERROR: casting function pointer `foo` to `u128`
-
-    // Casting to usize is OK and should not warn
-    let _ = foo as usize;
-
-    // Cast `f` (a `FnDef`) to `fn()` should not warn
-    fn f() {}
-    let _ = f as fn();
-}
-
-fn test_function_var_to_numeric_cast() {
-    let abc: fn() -> String = foo;
-
-    let _ = abc as i8;
-    //~^ ERROR: casting function pointer `abc` to `i8`, which truncates the value
-    let _ = abc as i16;
-    //~^ ERROR: casting function pointer `abc` to `i16`, which truncates the value
-    let _ = abc as i32;
-    //~^ ERROR: casting function pointer `abc` to `i32`, which truncates the value
-    let _ = abc as i64;
-    //~^ ERROR: casting function pointer `abc` to `i64`
-    let _ = abc as i128;
-    //~^ ERROR: casting function pointer `abc` to `i128`
-    let _ = abc as isize;
-    //~^ ERROR: casting function pointer `abc` to `isize`
-
-    let _ = abc as u8;
-    //~^ ERROR: casting function pointer `abc` to `u8`, which truncates the value
-    let _ = abc as u16;
-    //~^ ERROR: casting function pointer `abc` to `u16`, which truncates the value
-    let _ = abc as u32;
-    //~^ ERROR: casting function pointer `abc` to `u32`, which truncates the value
-    let _ = abc as u64;
-    //~^ ERROR: casting function pointer `abc` to `u64`
-    let _ = abc as u128;
-    //~^ ERROR: casting function pointer `abc` to `u128`
-
-    // Casting to usize is OK and should not warn
-    let _ = abc as usize;
-}
-
-fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
-    f as i32
-    //~^ ERROR: casting function pointer `f` to `i32`, which truncates the value
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index 8fa0f34a6c4..77abd663e0a 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -117,3 +117,15 @@ fn f(b: bool, v: Option<()>) -> Option<()> {
         None
     }
 }
+
+fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
+    let x = if b {
+        #[allow(clippy::let_unit_value)]
+        let _ = v?;
+        Some(())
+    } else {
+        None
+    };
+
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
index 2912eede4d9..6c6f21fee16 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::ignored_unit_patterns)]
-#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
 
 fn foo() -> Result<(), ()> {
     unimplemented!()
@@ -7,9 +7,19 @@ fn foo() -> Result<(), ()> {
 
 fn main() {
     match foo() {
-        Ok(()) => {},
-        Err(()) => {},
+        Ok(()) => {},  //~ ERROR: matching over `()` is more explicit
+        Err(()) => {}, //~ ERROR: matching over `()` is more explicit
     }
     if let Ok(()) = foo() {}
+    //~^ ERROR: matching over `()` is more explicit
     let _ = foo().map_err(|()| todo!());
+    //~^ ERROR: matching over `()` is more explicit
+}
+
+#[allow(unused)]
+pub fn moo(_: ()) {
+    let () = foo().unwrap();
+    //~^ ERROR: matching over `()` is more explicit
+    let _: () = foo().unwrap();
+    let _: () = ();
 }
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
index d180cd8d2fd..5e8c2e03ba2 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::ignored_unit_patterns)]
-#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
 
 fn foo() -> Result<(), ()> {
     unimplemented!()
@@ -7,9 +7,19 @@ fn foo() -> Result<(), ()> {
 
 fn main() {
     match foo() {
-        Ok(_) => {},
-        Err(_) => {},
+        Ok(_) => {},  //~ ERROR: matching over `()` is more explicit
+        Err(_) => {}, //~ ERROR: matching over `()` is more explicit
     }
     if let Ok(_) = foo() {}
+    //~^ ERROR: matching over `()` is more explicit
     let _ = foo().map_err(|_| todo!());
+    //~^ ERROR: matching over `()` is more explicit
+}
+
+#[allow(unused)]
+pub fn moo(_: ()) {
+    let _ = foo().unwrap();
+    //~^ ERROR: matching over `()` is more explicit
+    let _: () = foo().unwrap();
+    let _: () = ();
 }
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
index a8ced22397d..df5e1d89e90 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -20,10 +20,16 @@ LL |     if let Ok(_) = foo() {}
    |               ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:14:28
+  --> $DIR/ignored_unit_patterns.rs:15:28
    |
 LL |     let _ = foo().map_err(|_| todo!());
    |                            ^ help: use `()` instead of `_`: `()`
 
-error: aborting due to 4 previous errors
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:21:9
+   |
+LL |     let _ = foo().unwrap();
+   |         ^ help: use `()` instead of `_`: `()`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
index 952c2b70619..a50fa0ccf6e 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
@@ -65,4 +65,61 @@ impl SomeTrait for SomeStruct {
     }
 }
 
+mod issue11422 {
+    use core::fmt::Debug;
+    // Some additional tests that would cause ICEs:
+
+    // `PartialOrd` has a default generic parameter and does not need to be explicitly specified.
+    // This needs special handling.
+    fn default_generic_param1() -> impl PartialOrd + Debug {}
+    fn default_generic_param2() -> impl PartialOrd + Debug {}
+
+    // Referring to `Self` in the supertrait clause needs special handling.
+    trait Trait1<X: ?Sized> {}
+    trait Trait2: Trait1<Self> {}
+    impl Trait1<()> for () {}
+    impl Trait2 for () {}
+
+    fn f() -> impl Trait1<()> + Trait2 {}
+}
+
+mod issue11435 {
+    // Associated type needs to be included on DoubleEndedIterator in the suggestion
+    fn my_iter() -> impl DoubleEndedIterator<Item = u32> {
+        0..5
+    }
+
+    // Removing the `Clone` bound should include the `+` behind it in its remove suggestion
+    fn f() -> impl Copy {
+        1
+    }
+
+    trait Trait1<T> {
+        type U;
+    }
+    impl Trait1<i32> for () {
+        type U = i64;
+    }
+    trait Trait2<T>: Trait1<T> {}
+    impl Trait2<i32> for () {}
+
+    // When the other trait has generics, it shouldn't add another pair of `<>`
+    fn f2() -> impl Trait2<i32, U = i64> {}
+
+    trait Trait3<T, U, V> {
+        type X;
+        type Y;
+    }
+    trait Trait4<T>: Trait3<T, i16, i64> {}
+    impl Trait3<i8, i16, i64> for () {
+        type X = i32;
+        type Y = i128;
+    }
+    impl Trait4<i8> for () {}
+
+    // Associated type `X` is specified, but `Y` is not, so only that associated type should be moved
+    // over
+    fn f3() -> impl Trait4<i8, X = i32, Y = i128> {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
index 475f2621bbf..e74ed4425b8 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
@@ -65,4 +65,61 @@ impl SomeTrait for SomeStruct {
     }
 }
 
+mod issue11422 {
+    use core::fmt::Debug;
+    // Some additional tests that would cause ICEs:
+
+    // `PartialOrd` has a default generic parameter and does not need to be explicitly specified.
+    // This needs special handling.
+    fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {}
+    fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {}
+
+    // Referring to `Self` in the supertrait clause needs special handling.
+    trait Trait1<X: ?Sized> {}
+    trait Trait2: Trait1<Self> {}
+    impl Trait1<()> for () {}
+    impl Trait2 for () {}
+
+    fn f() -> impl Trait1<()> + Trait2 {}
+}
+
+mod issue11435 {
+    // Associated type needs to be included on DoubleEndedIterator in the suggestion
+    fn my_iter() -> impl Iterator<Item = u32> + DoubleEndedIterator {
+        0..5
+    }
+
+    // Removing the `Clone` bound should include the `+` behind it in its remove suggestion
+    fn f() -> impl Copy + Clone {
+        1
+    }
+
+    trait Trait1<T> {
+        type U;
+    }
+    impl Trait1<i32> for () {
+        type U = i64;
+    }
+    trait Trait2<T>: Trait1<T> {}
+    impl Trait2<i32> for () {}
+
+    // When the other trait has generics, it shouldn't add another pair of `<>`
+    fn f2() -> impl Trait1<i32, U = i64> + Trait2<i32> {}
+
+    trait Trait3<T, U, V> {
+        type X;
+        type Y;
+    }
+    trait Trait4<T>: Trait3<T, i16, i64> {}
+    impl Trait3<i8, i16, i64> for () {
+        type X = i32;
+        type Y = i128;
+    }
+    impl Trait4<i8> for () {}
+
+    // Associated type `X` is specified, but `Y` is not, so only that associated type should be moved
+    // over
+    fn f3() -> impl Trait3<i8, i16, i64, X = i32, Y = i128> + Trait4<i8, X = i32> {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
index e2b1ecb9f1e..72dc2a183a3 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
@@ -120,5 +120,77 @@ LL -     fn f() -> impl Deref + DerefMut<Target = u8> {
 LL +     fn f() -> impl DerefMut<Target = u8> {
    |
 
-error: aborting due to 10 previous errors
+error: this bound is already specified as the supertrait of `PartialOrd`
+  --> $DIR/implied_bounds_in_impls.rs:74:41
+   |
+LL |     fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {}
+   |                                         ^^^^^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {}
+LL +     fn default_generic_param1() -> impl PartialOrd + Debug {}
+   |
+
+error: this bound is already specified as the supertrait of `PartialOrd`
+  --> $DIR/implied_bounds_in_impls.rs:75:54
+   |
+LL |     fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {}
+   |                                                      ^^^^^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {}
+LL +     fn default_generic_param2() -> impl PartialOrd + Debug {}
+   |
+
+error: this bound is already specified as the supertrait of `DoubleEndedIterator`
+  --> $DIR/implied_bounds_in_impls.rs:88:26
+   |
+LL |     fn my_iter() -> impl Iterator<Item = u32> + DoubleEndedIterator {
+   |                          ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn my_iter() -> impl Iterator<Item = u32> + DoubleEndedIterator {
+LL +     fn my_iter() -> impl DoubleEndedIterator<Item = u32> {
+   |
+
+error: this bound is already specified as the supertrait of `Copy`
+  --> $DIR/implied_bounds_in_impls.rs:93:27
+   |
+LL |     fn f() -> impl Copy + Clone {
+   |                           ^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn f() -> impl Copy + Clone {
+LL +     fn f() -> impl Copy {
+   |
+
+error: this bound is already specified as the supertrait of `Trait2<i32>`
+  --> $DIR/implied_bounds_in_impls.rs:107:21
+   |
+LL |     fn f2() -> impl Trait1<i32, U = i64> + Trait2<i32> {}
+   |                     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn f2() -> impl Trait1<i32, U = i64> + Trait2<i32> {}
+LL +     fn f2() -> impl Trait2<i32, U = i64> {}
+   |
+
+error: this bound is already specified as the supertrait of `Trait4<i8, X = i32>`
+  --> $DIR/implied_bounds_in_impls.rs:122:21
+   |
+LL |     fn f3() -> impl Trait3<i8, i16, i64, X = i32, Y = i128> + Trait4<i8, X = i32> {}
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try removing this bound
+   |
+LL -     fn f3() -> impl Trait3<i8, i16, i64, X = i32, Y = i128> + Trait4<i8, X = i32> {}
+LL +     fn f3() -> impl Trait4<i8, X = i32, Y = i128> {}
+   |
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
new file mode 100644
index 00000000000..3cfe6e82fc1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
@@ -0,0 +1,71 @@
+//@no-rustfix
+
+#![deny(clippy::iter_out_of_bounds)]
+#![allow(clippy::useless_vec)]
+
+fn opaque_empty_iter() -> impl Iterator<Item = ()> {
+    std::iter::empty()
+}
+
+fn main() {
+    #[allow(clippy::never_loop)]
+    for _ in [1, 2, 3].iter().skip(4) {
+        //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+        unreachable!();
+    }
+    for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
+        //~^ ERROR: this `.take()` call takes more items than the iterator will produce
+        assert!(i <= 2);
+    }
+
+    #[allow(clippy::needless_borrow)]
+    for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
+    //~^ ERROR: this `.take()` call takes more items than the iterator will produce
+
+    for _ in [1, 2, 3].iter().skip(4) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    for _ in [1; 3].iter().skip(4) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    // Should not lint
+    for _ in opaque_empty_iter().skip(1) {}
+
+    for _ in vec![1, 2, 3].iter().skip(4) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    for _ in vec![1; 3].iter().skip(4) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    let x = [1, 2, 3];
+    for _ in x.iter().skip(4) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    let n = 4;
+    for _ in x.iter().skip(n) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    let empty = std::iter::empty::<i8>;
+
+    for _ in empty().skip(1) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    for _ in empty().take(1) {}
+    //~^ ERROR: this `.take()` call takes more items than the iterator will produce
+
+    for _ in std::iter::once(1).skip(2) {}
+    //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
+
+    for _ in std::iter::once(1).take(2) {}
+    //~^ ERROR: this `.take()` call takes more items than the iterator will produce
+
+    for x in [].iter().take(1) {
+        //~^ ERROR: this `.take()` call takes more items than the iterator will produce
+        let _: &i32 = x;
+    }
+
+    // ok, not out of bounds
+    for _ in [1].iter().take(1) {}
+    for _ in [1, 2, 3].iter().take(2) {}
+    for _ in [1, 2, 3].iter().skip(2) {}
+}
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
new file mode 100644
index 00000000000..f235faec8e5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
@@ -0,0 +1,119 @@
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:12:14
+   |
+LL |     for _ in [1, 2, 3].iter().skip(4) {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+note: the lint level is defined here
+  --> $DIR/iter_out_of_bounds.rs:3:9
+   |
+LL | #![deny(clippy::iter_out_of_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this `.take()` call takes more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:16:19
+   |
+LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and the returned iterator will simply yield the same items
+
+error: this `.take()` call takes more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:22:14
+   |
+LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and the returned iterator will simply yield the same items
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:25:14
+   |
+LL |     for _ in [1, 2, 3].iter().skip(4) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:28:14
+   |
+LL |     for _ in [1; 3].iter().skip(4) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:34:14
+   |
+LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:37:14
+   |
+LL |     for _ in vec![1; 3].iter().skip(4) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:41:14
+   |
+LL |     for _ in x.iter().skip(4) {}
+   |              ^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:45:14
+   |
+LL |     for _ in x.iter().skip(n) {}
+   |              ^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:50:14
+   |
+LL |     for _ in empty().skip(1) {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.take()` call takes more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:53:14
+   |
+LL |     for _ in empty().take(1) {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and the returned iterator will simply yield the same items
+
+error: this `.skip()` call skips more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:56:14
+   |
+LL |     for _ in std::iter::once(1).skip(2) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and will create an empty iterator
+
+error: this `.take()` call takes more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:59:14
+   |
+LL |     for _ in std::iter::once(1).take(2) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and the returned iterator will simply yield the same items
+
+error: this `.take()` call takes more items than the iterator will produce
+  --> $DIR/iter_out_of_bounds.rs:62:14
+   |
+LL |     for x in [].iter().take(1) {
+   |              ^^^^^^^^^^^^^^^^^
+   |
+   = note: this operation is useless and the returned iterator will simply yield the same items
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index 9dd046fec1f..7d8a584b022 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -63,11 +63,9 @@ fn main() {
 
     let _ = vec.iter().for_each(|x| assert!(!x.is_empty()));
 
-    // Not implemented yet
-    let _ = vec.iter().cloned().all(|x| x.len() == 1);
+    let _ = vec.iter().all(|x| x.len() == 1);
 
-    // Not implemented yet
-    let _ = vec.iter().cloned().any(|x| x.len() == 1);
+    let _ = vec.iter().any(|x| x.len() == 1);
 
     // Should probably stay as it is.
     let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index 3cab3669554..58c374ab8cd 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -64,10 +64,8 @@ fn main() {
 
     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
 
-    // Not implemented yet
     let _ = vec.iter().cloned().all(|x| x.len() == 1);
 
-    // Not implemented yet
     let _ = vec.iter().cloned().any(|x| x.len() == 1);
 
     // Should probably stay as it is.
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index fbcd33066d8..a9a739688eb 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -148,5 +148,21 @@ LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |                       |
    |                       help: try: `.for_each(|x| assert!(!x.is_empty()))`
 
-error: aborting due to 17 previous errors
+error: unneeded cloning of iterator items
+  --> $DIR/iter_overeager_cloned.rs:67:13
+   |
+LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
+   |             ^^^^^^^^^^-------------------------------
+   |                       |
+   |                       help: try: `.all(|x| x.len() == 1)`
+
+error: unneeded cloning of iterator items
+  --> $DIR/iter_overeager_cloned.rs:69:13
+   |
+LL |     let _ = vec.iter().cloned().any(|x| x.len() == 1);
+   |             ^^^^^^^^^^-------------------------------
+   |                       |
+   |                       help: try: `.any(|x| x.len() == 1)`
+
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed
index 310b24a9cde..3e41b363249 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.fixed
+++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed
@@ -4,6 +4,7 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(clippy::useless_vec)]
+#![allow(clippy::iter_out_of_bounds)]
 #![allow(unused_mut, dead_code)]
 
 extern crate option_helpers;
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs
index 222d6a2a184..6d96441ca96 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_next.rs
@@ -4,6 +4,7 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(clippy::useless_vec)]
+#![allow(clippy::iter_out_of_bounds)]
 #![allow(unused_mut, dead_code)]
 
 extern crate option_helpers;
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr
index 0b6bf652b1f..39b173e7586 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.stderr
+++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr
@@ -1,5 +1,5 @@
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:16:28
+  --> $DIR/iter_skip_next.rs:17:28
    |
 LL |     let _ = some_vec.iter().skip(42).next();
    |                            ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
@@ -8,37 +8,37 @@ LL |     let _ = some_vec.iter().skip(42).next();
    = help: to override `-D warnings` add `#[allow(clippy::iter_skip_next)]`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:17:36
+  --> $DIR/iter_skip_next.rs:18:36
    |
 LL |     let _ = some_vec.iter().cycle().skip(42).next();
    |                                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:18:20
+  --> $DIR/iter_skip_next.rs:19:20
    |
 LL |     let _ = (1..10).skip(10).next();
    |                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:19:33
+  --> $DIR/iter_skip_next.rs:20:33
    |
 LL |     let _ = &some_vec[..].iter().skip(3).next();
    |                                 ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:27:26
+  --> $DIR/iter_skip_next.rs:28:26
    |
 LL |     let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
    |                          ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:29:29
+  --> $DIR/iter_skip_next.rs:30:29
    |
 LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
    |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
 
 error: called `skip(..).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:35:29
+  --> $DIR/iter_skip_next.rs:36:29
    |
 LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
    |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs
index 9c224f4117d..6c98bdc8c88 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::iter_skip_next)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::iter_out_of_bounds)]
 //@no-rustfix
 /// Checks implementation of `ITER_SKIP_NEXT` lint
 fn main() {
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.fixed b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
index 62a83d5905b..447d07100e9 100644
--- a/src/tools/clippy/tests/ui/iter_skip_zero.fixed
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-#![allow(clippy::useless_vec, unused)]
+#![allow(clippy::useless_vec, clippy::iter_out_of_bounds, unused)]
 #![warn(clippy::iter_skip_zero)]
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.rs b/src/tools/clippy/tests/ui/iter_skip_zero.rs
index c96696dde65..ba63c398180 100644
--- a/src/tools/clippy/tests/ui/iter_skip_zero.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-#![allow(clippy::useless_vec, unused)]
+#![allow(clippy::useless_vec, clippy::iter_out_of_bounds, unused)]
 #![warn(clippy::iter_skip_zero)]
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr
new file mode 100644
index 00000000000..0e0eee21cf3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr
@@ -0,0 +1,280 @@
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:11:1
+   |
+LL | / enum LargeEnum {
+LL | |     A(i32),
+   | |     ------ the second-largest variant contains at least 4 bytes
+LL | |     B([i32; 8000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+   = note: `-D clippy::large-enum-variant` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<[i32; 8000]>),
+   |       ~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:35:1
+   |
+LL | / enum LargeEnum2 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingLargeEnum(LargeEnum),
+   | |     ------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     ContainingLargeEnum(Box<LargeEnum>),
+   |                         ~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:40:1
+   |
+LL | / enum LargeEnum3 {
+LL | |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+   | |     --------------------------------------------------------- the largest variant contains at least 70004 bytes
+LL | |     VoidVariant,
+LL | |     StructLikeLittle { x: i32, y: i32 },
+   | |     ----------------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+   | |_^ the entire enum is at least 70008 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
+   |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:46:1
+   |
+LL | / enum LargeEnum4 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   | |     ------------------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
+   |                          ~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:51:1
+   |
+LL | / enum LargeEnum5 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge2 { x: [i32; 8000] },
+   | |     ----------------------------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
+   |                           ~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:67:1
+   |
+LL | / enum LargeEnum7 {
+LL | |     A,
+LL | |     B([u8; 1255]),
+   | |     ------------- the largest variant contains at least 1255 bytes
+LL | |     C([u8; 200]),
+   | |     ------------ the second-largest variant contains at least 200 bytes
+LL | | }
+   | |_^ the entire enum is at least 1256 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<[u8; 1255]>),
+   |       ~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:73:1
+   |
+LL | / enum LargeEnum8 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
+   | |     ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes
+LL | | }
+   | |_^ the entire enum is at least 70132 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
+   |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:78:1
+   |
+LL | / enum LargeEnum9 {
+LL | |     A(Struct<()>),
+   | |     ------------- the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:83:1
+   |
+LL | / enum LargeEnumOk2<T> {
+LL | |     A(T),
+   | |     ---- the second-largest variant contains at least 0 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:88:1
+   |
+LL | / enum LargeEnumOk3<T> {
+LL | |     A(Struct<T>),
+   | |     ------------ the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:103:1
+   |
+LL | / enum CopyableLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 8000]),
+   | |     -------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64004 bytes
+   |
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:103:6
+   |
+LL | enum CopyableLargeEnum {
+   |      ^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:105:5
+   |
+LL |     B([u64; 8000]),
+   |     ^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:108:1
+   |
+LL | / enum ManuallyCopyLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 8000]),
+   | |     -------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64004 bytes
+   |
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:108:6
+   |
+LL | enum ManuallyCopyLargeEnum {
+   |      ^^^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:110:5
+   |
+LL |     B([u64; 8000]),
+   |     ^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:121:1
+   |
+LL | / enum SomeGenericPossiblyCopyEnum<T> {
+LL | |     A(bool, std::marker::PhantomData<T>),
+   | |     ------------------------------------ the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 4000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:121:6
+   |
+LL | enum SomeGenericPossiblyCopyEnum<T> {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:123:5
+   |
+LL |     B([u64; 4000]),
+   |     ^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:134:1
+   |
+LL | / enum LargeEnumWithGenerics<T> {
+LL | |     Small,
+   | |     ----- the second-largest variant carries no data at all
+LL | |     Large((T, [u8; 512])),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | | }
+   | |_^ the entire enum is at least 512 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<(T, [u8; 512])>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:143:1
+   |
+LL | / enum WithGenerics {
+LL | |     Large([Foo<u64>; 64]),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | |     Small(u8),
+   | |     --------- the second-largest variant contains at least 1 bytes
+LL | | }
+   | |_^ the entire enum is at least 516 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[Foo<u64>; 64]>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:153:1
+   |
+LL | / enum LargeEnumOfConst {
+LL | |     Ok,
+   | |     -- the second-largest variant carries no data at all
+LL | |     Error(PossiblyLargeEnumWithConst<256>),
+   | |     -------------------------------------- the largest variant contains at least 514 bytes
+LL | | }
+   | |_^ the entire enum is at least 514 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.stderr b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr
index 7026ca785f3..3eba43e05ec 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.stderr
+++ b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr
@@ -1,5 +1,5 @@
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:10:1
+  --> $DIR/large_enum_variant.rs:11:1
    |
 LL | / enum LargeEnum {
 LL | |     A(i32),
@@ -17,7 +17,7 @@ LL |     B(Box<[i32; 8000]>),
    |       ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:34:1
+  --> $DIR/large_enum_variant.rs:35:1
    |
 LL | / enum LargeEnum2 {
 LL | |     VariantOk(i32, u32),
@@ -33,7 +33,7 @@ LL |     ContainingLargeEnum(Box<LargeEnum>),
    |                         ~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:39:1
+  --> $DIR/large_enum_variant.rs:40:1
    |
 LL | / enum LargeEnum3 {
 LL | |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
@@ -50,7 +50,7 @@ LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
    |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:45:1
+  --> $DIR/large_enum_variant.rs:46:1
    |
 LL | / enum LargeEnum4 {
 LL | |     VariantOk(i32, u32),
@@ -66,7 +66,7 @@ LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
    |                          ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:50:1
+  --> $DIR/large_enum_variant.rs:51:1
    |
 LL | / enum LargeEnum5 {
 LL | |     VariantOk(i32, u32),
@@ -82,7 +82,7 @@ LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
    |                           ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:66:1
+  --> $DIR/large_enum_variant.rs:67:1
    |
 LL | / enum LargeEnum7 {
 LL | |     A,
@@ -99,7 +99,7 @@ LL |     B(Box<[u8; 1255]>),
    |       ~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:72:1
+  --> $DIR/large_enum_variant.rs:73:1
    |
 LL | / enum LargeEnum8 {
 LL | |     VariantOk(i32, u32),
@@ -115,7 +115,7 @@ LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>
    |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:77:1
+  --> $DIR/large_enum_variant.rs:78:1
    |
 LL | / enum LargeEnum9 {
 LL | |     A(Struct<()>),
@@ -131,7 +131,7 @@ LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:82:1
+  --> $DIR/large_enum_variant.rs:83:1
    |
 LL | / enum LargeEnumOk2<T> {
 LL | |     A(T),
@@ -147,7 +147,7 @@ LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:87:1
+  --> $DIR/large_enum_variant.rs:88:1
    |
 LL | / enum LargeEnumOk3<T> {
 LL | |     A(Struct<T>),
@@ -163,7 +163,7 @@ LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:102:1
+  --> $DIR/large_enum_variant.rs:103:1
    |
 LL | / enum CopyableLargeEnum {
 LL | |     A(bool),
@@ -174,18 +174,18 @@ LL | | }
    | |_^ the entire enum is at least 64008 bytes
    |
 note: boxing a variant would require the type no longer be `Copy`
-  --> $DIR/large_enum_variant.rs:102:6
+  --> $DIR/large_enum_variant.rs:103:6
    |
 LL | enum CopyableLargeEnum {
    |      ^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:104:5
+  --> $DIR/large_enum_variant.rs:105:5
    |
 LL |     B([u64; 8000]),
    |     ^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:107:1
+  --> $DIR/large_enum_variant.rs:108:1
    |
 LL | / enum ManuallyCopyLargeEnum {
 LL | |     A(bool),
@@ -196,18 +196,18 @@ LL | | }
    | |_^ the entire enum is at least 64008 bytes
    |
 note: boxing a variant would require the type no longer be `Copy`
-  --> $DIR/large_enum_variant.rs:107:6
+  --> $DIR/large_enum_variant.rs:108:6
    |
 LL | enum ManuallyCopyLargeEnum {
    |      ^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:109:5
+  --> $DIR/large_enum_variant.rs:110:5
    |
 LL |     B([u64; 8000]),
    |     ^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:120:1
+  --> $DIR/large_enum_variant.rs:121:1
    |
 LL | / enum SomeGenericPossiblyCopyEnum<T> {
 LL | |     A(bool, std::marker::PhantomData<T>),
@@ -218,18 +218,18 @@ LL | | }
    | |_^ the entire enum is at least 32008 bytes
    |
 note: boxing a variant would require the type no longer be `Copy`
-  --> $DIR/large_enum_variant.rs:120:6
+  --> $DIR/large_enum_variant.rs:121:6
    |
 LL | enum SomeGenericPossiblyCopyEnum<T> {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:122:5
+  --> $DIR/large_enum_variant.rs:123:5
    |
 LL |     B([u64; 4000]),
    |     ^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:133:1
+  --> $DIR/large_enum_variant.rs:134:1
    |
 LL | / enum LargeEnumWithGenerics<T> {
 LL | |     Small,
@@ -245,7 +245,7 @@ LL |     Large(Box<(T, [u8; 512])>),
    |           ~~~~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:142:1
+  --> $DIR/large_enum_variant.rs:143:1
    |
 LL | / enum WithGenerics {
 LL | |     Large([Foo<u64>; 64]),
@@ -261,7 +261,7 @@ LL |     Large(Box<[Foo<u64>; 64]>),
    |           ~~~~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:152:1
+  --> $DIR/large_enum_variant.rs:153:1
    |
 LL | / enum LargeEnumOfConst {
 LL | |     Ok,
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs
index f101bda76a8..3625c011dbf 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.rs
+++ b/src/tools/clippy/tests/ui/large_enum_variant.rs
@@ -1,3 +1,4 @@
+//@stderr-per-bitwidth
 //@aux-build:proc_macros.rs
 //@no-rustfix
 #![allow(dead_code)]
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.fixed b/src/tools/clippy/tests/ui/manual_range_patterns.fixed
index ea06e27d153..b348d7071f6 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.fixed
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.fixed
@@ -13,8 +13,8 @@ fn main() {
     let _ = matches!(f, 1 | 2147483647);
     let _ = matches!(f, 0 | 2147483647);
     let _ = matches!(f, -2147483647 | 2147483647);
-    let _ = matches!(f, 1 | (2..=4));
-    let _ = matches!(f, 1 | (2..4));
+    let _ = matches!(f, 1..=4);
+    let _ = matches!(f, 1..4);
     let _ = matches!(f, 1..=48324729);
     let _ = matches!(f, 0..=48324730);
     let _ = matches!(f, 0..=3);
@@ -25,9 +25,20 @@ fn main() {
     };
     let _ = matches!(f, -5..=3);
     let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing
-    let _ = matches!(f, -1000001..=1000001);
+    let _ = matches!(f, -1_000_001..=1_000_001);
     let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
 
+    matches!(f, 0x00..=0x03);
+    matches!(f, 0x00..=0x07);
+    matches!(f, -0x09..=0x00);
+
+    matches!(f, 0..=5);
+    matches!(f, 0..5);
+
+    matches!(f, 0..10);
+    matches!(f, 0..=10);
+    matches!(f, 0..=10);
+
     macro_rules! mac {
         ($e:expr) => {
             matches!($e, 1..=10)
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.rs b/src/tools/clippy/tests/ui/manual_range_patterns.rs
index eb29987b89f..a0750f54b73 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.rs
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.rs
@@ -28,6 +28,17 @@ fn main() {
     let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
     let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
 
+    matches!(f, 0x00 | 0x01 | 0x02 | 0x03);
+    matches!(f, 0x00..=0x05 | 0x06 | 0x07);
+    matches!(f, -0x09 | -0x08 | -0x07..=0x00);
+
+    matches!(f, 0..5 | 5);
+    matches!(f, 0 | 1..5);
+
+    matches!(f, 0..=5 | 6..10);
+    matches!(f, 0..5 | 5..=10);
+    matches!(f, 5..=10 | 0..5);
+
     macro_rules! mac {
         ($e:expr) => {
             matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10)
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.stderr b/src/tools/clippy/tests/ui/manual_range_patterns.stderr
index 3eee39af86e..fbeb9455769 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.stderr
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.stderr
@@ -14,6 +14,18 @@ LL |     let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
 
 error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:16:25
+   |
+LL |     let _ = matches!(f, 1 | (2..=4));
+   |                         ^^^^^^^^^^^ help: try: `1..=4`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:17:25
+   |
+LL |     let _ = matches!(f, 1 | (2..4));
+   |                         ^^^^^^^^^^ help: try: `1..4`
+
+error: this OR pattern can be rewritten using a range
   --> $DIR/manual_range_patterns.rs:18:25
    |
 LL |     let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729);
@@ -47,10 +59,58 @@ error: this OR pattern can be rewritten using a range
   --> $DIR/manual_range_patterns.rs:28:25
    |
 LL |     let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1000001..=1000001`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1_000_001..=1_000_001`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:31:17
+   |
+LL |     matches!(f, 0x00 | 0x01 | 0x02 | 0x03);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x03`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:32:17
+   |
+LL |     matches!(f, 0x00..=0x05 | 0x06 | 0x07);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x07`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:33:17
+   |
+LL |     matches!(f, -0x09 | -0x08 | -0x07..=0x00);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-0x09..=0x00`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:35:17
+   |
+LL |     matches!(f, 0..5 | 5);
+   |                 ^^^^^^^^ help: try: `0..=5`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:36:17
+   |
+LL |     matches!(f, 0 | 1..5);
+   |                 ^^^^^^^^ help: try: `0..5`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:38:17
+   |
+LL |     matches!(f, 0..=5 | 6..10);
+   |                 ^^^^^^^^^^^^^ help: try: `0..10`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:39:17
+   |
+LL |     matches!(f, 0..5 | 5..=10);
+   |                 ^^^^^^^^^^^^^ help: try: `0..=10`
+
+error: this OR pattern can be rewritten using a range
+  --> $DIR/manual_range_patterns.rs:40:17
+   |
+LL |     matches!(f, 5..=10 | 0..5);
+   |                 ^^^^^^^^^^^^^ help: try: `0..=10`
 
 error: this OR pattern can be rewritten using a range
-  --> $DIR/manual_range_patterns.rs:33:26
+  --> $DIR/manual_range_patterns.rs:44:26
    |
 LL |             matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10)
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
@@ -60,5 +120,5 @@ LL |     mac!(f);
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 9 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed
new file mode 100644
index 00000000000..a96827259f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed
@@ -0,0 +1,121 @@
+#![allow(unused)]
+#![warn(clippy::missing_asserts_for_indexing)]
+
+// ok
+fn sum_with_assert(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_other_way(v: &[u8]) -> u8 {
+    assert!(5 <= v.len());
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_ge(v: &[u8]) -> u8 {
+    assert!(v.len() >= 5);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_ge_other_way(v: &[u8]) -> u8 {
+    assert!(4 < v.len());
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+fn sum_with_assert_lt(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_assert_le(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_incorrect_assert_len(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_incorrect_assert_len2(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+// ok, don't lint for single array access
+fn single_access(v: &[u8]) -> u8 {
+    v[0]
+}
+
+// ok
+fn subslice_ok(v: &[u8]) {
+    assert!(v.len() > 3);
+    let _ = v[0];
+    let _ = v[1..4];
+}
+
+fn subslice_bad(v: &[u8]) {
+    assert!(v.len() > 3);
+    let _ = v[0];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v[1..4];
+}
+
+// ok
+fn subslice_inclusive_ok(v: &[u8]) {
+    assert!(v.len() > 4);
+    let _ = v[0];
+    let _ = v[1..=4];
+}
+
+fn subslice_inclusive_bad(v: &[u8]) {
+    assert!(v.len() > 4);
+    let _ = v[0];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v[1..=4];
+}
+
+fn index_different_slices_ok(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() > 12);
+    assert!(v2.len() > 15);
+    let _ = v1[0] + v1[12];
+    let _ = v2[5] + v2[15];
+}
+
+fn index_different_slices_wrong_len(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() > 12);
+    assert!(v2.len() > 15);
+    let _ = v1[0] + v1[12];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v2[5] + v2[15];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+fn index_different_slices_one_wrong_len(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() > 12);
+    assert!(v2.len() > 15);
+    let _ = v1[0] + v1[12];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v2[5] + v2[15];
+}
+
+fn side_effect() -> &'static [u8] {
+    &[]
+}
+
+fn index_side_effect_expr() {
+    let _ = side_effect()[0] + side_effect()[1];
+}
+
+// ok, single access for different slices
+fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
+    let _ = v1[0] + v2[1];
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs
new file mode 100644
index 00000000000..0b4b883acf8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs
@@ -0,0 +1,121 @@
+#![allow(unused)]
+#![warn(clippy::missing_asserts_for_indexing)]
+
+// ok
+fn sum_with_assert(v: &[u8]) -> u8 {
+    assert!(v.len() > 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_other_way(v: &[u8]) -> u8 {
+    assert!(5 <= v.len());
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_ge(v: &[u8]) -> u8 {
+    assert!(v.len() >= 5);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+// ok
+fn sum_with_assert_ge_other_way(v: &[u8]) -> u8 {
+    assert!(4 < v.len());
+    v[0] + v[1] + v[2] + v[3] + v[4]
+}
+
+fn sum_with_assert_lt(v: &[u8]) -> u8 {
+    assert!(v.len() < 5);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_assert_le(v: &[u8]) -> u8 {
+    assert!(v.len() <= 5);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_incorrect_assert_len(v: &[u8]) -> u8 {
+    assert!(v.len() > 3);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+fn sum_with_incorrect_assert_len2(v: &[u8]) -> u8 {
+    assert!(v.len() >= 4);
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+
+// ok, don't lint for single array access
+fn single_access(v: &[u8]) -> u8 {
+    v[0]
+}
+
+// ok
+fn subslice_ok(v: &[u8]) {
+    assert!(v.len() > 3);
+    let _ = v[0];
+    let _ = v[1..4];
+}
+
+fn subslice_bad(v: &[u8]) {
+    assert!(v.len() >= 3);
+    let _ = v[0];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v[1..4];
+}
+
+// ok
+fn subslice_inclusive_ok(v: &[u8]) {
+    assert!(v.len() > 4);
+    let _ = v[0];
+    let _ = v[1..=4];
+}
+
+fn subslice_inclusive_bad(v: &[u8]) {
+    assert!(v.len() >= 4);
+    let _ = v[0];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v[1..=4];
+}
+
+fn index_different_slices_ok(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() > 12);
+    assert!(v2.len() > 15);
+    let _ = v1[0] + v1[12];
+    let _ = v2[5] + v2[15];
+}
+
+fn index_different_slices_wrong_len(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() >= 12);
+    assert!(v2.len() >= 15);
+    let _ = v1[0] + v1[12];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v2[5] + v2[15];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+}
+fn index_different_slices_one_wrong_len(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() >= 12);
+    assert!(v2.len() > 15);
+    let _ = v1[0] + v1[12];
+    //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
+    let _ = v2[5] + v2[15];
+}
+
+fn side_effect() -> &'static [u8] {
+    &[]
+}
+
+fn index_side_effect_expr() {
+    let _ = side_effect()[0] + side_effect()[1];
+}
+
+// ok, single access for different slices
+fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
+    let _ = v1[0] + v2[1];
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr
new file mode 100644
index 00000000000..a3e66d7958e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr
@@ -0,0 +1,253 @@
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:30:5
+   |
+LL |     assert!(v.len() < 5);
+   |     -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)`
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:30:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:30:12
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |            ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:30:19
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                   ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:30:26
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                          ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:30:33
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                                 ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+   = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]`
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:36:5
+   |
+LL |     assert!(v.len() <= 5);
+   |     --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)`
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:36:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:36:12
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |            ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:36:19
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                   ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:36:26
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                          ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:36:33
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                                 ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:42:5
+   |
+LL |     assert!(v.len() > 3);
+   |     -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)`
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:42:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:42:12
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |            ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:42:19
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                   ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:42:26
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                          ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:42:33
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                                 ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:48:5
+   |
+LL |     assert!(v.len() >= 4);
+   |     --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)`
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:48:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:48:12
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |            ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:48:19
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                   ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:48:26
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                          ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:48:33
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                                 ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:66:13
+   |
+LL |       assert!(v.len() >= 3);
+   |       --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)`
+LL |       let _ = v[0];
+   |  _____________^
+LL | |
+LL | |     let _ = v[1..4];
+   | |___________________^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:66:13
+   |
+LL |     let _ = v[0];
+   |             ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:68:13
+   |
+LL |     let _ = v[1..4];
+   |             ^^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:80:13
+   |
+LL |       assert!(v.len() >= 4);
+   |       --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)`
+LL |       let _ = v[0];
+   |  _____________^
+LL | |
+LL | |     let _ = v[1..=4];
+   | |____________________^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:80:13
+   |
+LL |     let _ = v[0];
+   |             ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:82:13
+   |
+LL |     let _ = v[1..=4];
+   |             ^^^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:95:13
+   |
+LL |     assert!(v1.len() >= 12);
+   |     ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)`
+LL |     assert!(v2.len() >= 15);
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:95:13
+   |
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:95:21
+   |
+LL |     let _ = v1[0] + v1[12];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:97:13
+   |
+LL |     assert!(v2.len() >= 15);
+   |     ----------------------- help: provide the highest index that is indexed with: `assert!(v2.len() > 15)`
+...
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:97:13
+   |
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:97:21
+   |
+LL |     let _ = v2[5] + v2[15];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+  --> $DIR/missing_asserts_for_indexing.rs:103:13
+   |
+LL |     assert!(v1.len() >= 12);
+   |     ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)`
+LL |     assert!(v2.len() > 15);
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^^^^^^^^^^
+   |
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:103:13
+   |
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing.rs:103:21
+   |
+LL |     let _ = v1[0] + v1[12];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs
new file mode 100644
index 00000000000..4346ed892f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs
@@ -0,0 +1,49 @@
+#![allow(unused)]
+#![warn(clippy::missing_asserts_for_indexing)]
+
+fn sum(v: &[u8]) -> u8 {
+    v[0] + v[1] + v[2] + v[3] + v[4]
+    //~^ ERROR: indexing into a slice multiple times without an `assert`
+}
+
+fn subslice(v: &[u8]) {
+    let _ = v[0];
+    //~^ ERROR: indexing into a slice multiple times without an `assert`
+    let _ = v[1..4];
+}
+
+fn variables(v: &[u8]) -> u8 {
+    let a = v[0];
+    //~^ ERROR: indexing into a slice multiple times without an `assert`
+    let b = v[1];
+    let c = v[2];
+    a + b + c
+}
+
+fn index_different_slices(v1: &[u8], v2: &[u8]) {
+    let _ = v1[0] + v1[12];
+    let _ = v2[5] + v2[15];
+}
+
+fn index_different_slices2(v1: &[u8], v2: &[u8]) {
+    assert!(v1.len() > 12);
+    let _ = v1[0] + v1[12];
+    let _ = v2[5] + v2[15];
+}
+
+struct Foo<'a> {
+    v: &'a [u8],
+    v2: &'a [u8],
+}
+
+fn index_struct_field(f: &Foo<'_>) {
+    let _ = f.v[0] + f.v[1];
+    //~^ ERROR: indexing into a slice multiple times without an `assert`
+}
+
+fn index_struct_different_fields(f: &Foo<'_>) {
+    // ok, different fields
+    let _ = f.v[0] + f.v2[1];
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr
new file mode 100644
index 00000000000..12c9eed5d66
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr
@@ -0,0 +1,164 @@
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider asserting the length before indexing: `assert!(v.len() > 4);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:5
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |     ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:12
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |            ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:19
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                   ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:26
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                          ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:5:33
+   |
+LL |     v[0] + v[1] + v[2] + v[3] + v[4]
+   |                                 ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+   = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]`
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:10:13
+   |
+LL |       let _ = v[0];
+   |  _____________^
+LL | |
+LL | |     let _ = v[1..4];
+   | |___________________^
+   |
+   = help: consider asserting the length before indexing: `assert!(v.len() > 3);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:10:13
+   |
+LL |     let _ = v[0];
+   |             ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:12:13
+   |
+LL |     let _ = v[1..4];
+   |             ^^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:16:13
+   |
+LL |       let a = v[0];
+   |  _____________^
+LL | |
+LL | |     let b = v[1];
+LL | |     let c = v[2];
+   | |________________^
+   |
+   = help: consider asserting the length before indexing: `assert!(v.len() > 2);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:16:13
+   |
+LL |     let a = v[0];
+   |             ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:18:13
+   |
+LL |     let b = v[1];
+   |             ^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:19:13
+   |
+LL |     let c = v[2];
+   |             ^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:24:13
+   |
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^^^^^^^^^^
+   |
+   = help: consider asserting the length before indexing: `assert!(v1.len() > 12);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:24:13
+   |
+LL |     let _ = v1[0] + v1[12];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:24:21
+   |
+LL |     let _ = v1[0] + v1[12];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
+   |
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^^^^^^^^^^
+   |
+   = help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
+   |
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:25:21
+   |
+LL |     let _ = v2[5] + v2[15];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:31:13
+   |
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^^^^^^^^^^
+   |
+   = help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:31:13
+   |
+LL |     let _ = v2[5] + v2[15];
+   |             ^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:31:21
+   |
+LL |     let _ = v2[5] + v2[15];
+   |                     ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:40:13
+   |
+LL |     let _ = f.v[0] + f.v[1];
+   |             ^^^^^^^^^^^^^^^
+   |
+   = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);`
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:40:13
+   |
+LL |     let _ = f.v[0] + f.v[1];
+   |             ^^^^^^
+note: slice indexed here
+  --> $DIR/missing_asserts_for_indexing_unfixable.rs:40:22
+   |
+LL |     let _ = f.v[0] + f.v[1];
+   |                      ^^^^^^
+   = note: asserting the length before indexing will elide bounds checks
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index ee67224b4a8..0a52b25229d 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -503,3 +503,16 @@ mod issue_10535 {
     {
     }
 }
+
+mod issue_10253 {
+    struct S;
+    trait X {
+        fn f<T>(&self);
+    }
+    impl X for &S {
+        fn f<T>(&self) {}
+    }
+    fn f() {
+        (&S).f::<()>();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 1444f47d920..34a95d18463 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -503,3 +503,16 @@ mod issue_10535 {
     {
     }
 }
+
+mod issue_10253 {
+    struct S;
+    trait X {
+        fn f<T>(&self);
+    }
+    impl X for &S {
+        fn f<T>(&self) {}
+    }
+    fn f() {
+        (&S).f::<()>();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.rs b/src/tools/clippy/tests/ui/needless_doc_main.rs
index d31b9047eaa..fee05926ce4 100644
--- a/src/tools/clippy/tests/ui/needless_doc_main.rs
+++ b/src/tools/clippy/tests/ui/needless_doc_main.rs
@@ -10,7 +10,7 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// With an explicit return type it should lint too
 /// ```edition2015
 /// fn main() -> () {
@@ -18,7 +18,7 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// This should, too.
 /// ```rust
 /// fn main() {
@@ -26,11 +26,12 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// This one too.
 /// ```no_run
-/// fn main() {
+/// // the fn is not always the first line
 //~^ ERROR: needless `fn main` in doctest
+/// fn main() {
 ///     unimplemented!();
 /// }
 /// ```
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.stderr b/src/tools/clippy/tests/ui/needless_doc_main.stderr
index 8dd93bb05dd..84256548671 100644
--- a/src/tools/clippy/tests/ui/needless_doc_main.stderr
+++ b/src/tools/clippy/tests/ui/needless_doc_main.stderr
@@ -1,29 +1,47 @@
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:7:4
+  --> $DIR/needless_doc_main.rs:7:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
    |
    = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]`
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:16:4
+  --> $DIR/needless_doc_main.rs:16:5
    |
-LL | /// fn main() -> () {
-   |    ^^^^^^^^^^^^^^^^^^
+LL |   /// fn main() -> () {
+   |  _____^
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:24:4
+  --> $DIR/needless_doc_main.rs:24:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:32:4
+  --> $DIR/needless_doc_main.rs:32:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// // the fn is not always the first line
+   |  _____^
+LL | |
+LL | | /// fn main() {
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.fixed b/src/tools/clippy/tests/ui/needless_raw_string.fixed
index 4db375178b4..85549810513 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.fixed
+++ b/src/tools/clippy/tests/ui/needless_raw_string.fixed
@@ -9,8 +9,13 @@ fn main() {
     b"aaa";
     br#""aaa""#;
     br#"\s"#;
-    // currently disabled: https://github.com/rust-lang/rust/issues/113333
-    // cr#"aaa"#;
-    // cr#""aaa""#;
-    // cr#"\s"#;
+    c"aaa";
+    cr#""aaa""#;
+    cr#"\s"#;
+
+    "
+        a
+        multiline
+        string
+    ";
 }
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.rs b/src/tools/clippy/tests/ui/needless_raw_string.rs
index 59c75fda41b..06d49730387 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.rs
+++ b/src/tools/clippy/tests/ui/needless_raw_string.rs
@@ -9,8 +9,13 @@ fn main() {
     br#"aaa"#;
     br#""aaa""#;
     br#"\s"#;
-    // currently disabled: https://github.com/rust-lang/rust/issues/113333
-    // cr#"aaa"#;
-    // cr#""aaa""#;
-    // cr#"\s"#;
+    cr#"aaa"#;
+    cr#""aaa""#;
+    cr#"\s"#;
+
+    r#"
+        a
+        multiline
+        string
+    "#;
 }
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr
index 83cc6d332ee..e6806b31b1d 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.stderr
+++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr
@@ -2,16 +2,58 @@ error: unnecessary raw string literal
   --> $DIR/needless_raw_string.rs:6:5
    |
 LL |     r#"aaa"#;
-   |     ^^^^^^^^ help: try: `"aaa"`
+   |     ^^^^^^^^
    |
    = note: `-D clippy::needless-raw-strings` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
+help: try
+   |
+LL -     r#"aaa"#;
+LL +     "aaa";
+   |
 
 error: unnecessary raw string literal
   --> $DIR/needless_raw_string.rs:9:5
    |
 LL |     br#"aaa"#;
-   |     ^^^^^^^^^ help: try: `b"aaa"`
+   |     ^^^^^^^^^
+   |
+help: try
+   |
+LL -     br#"aaa"#;
+LL +     b"aaa";
+   |
+
+error: unnecessary raw string literal
+  --> $DIR/needless_raw_string.rs:12:5
+   |
+LL |     cr#"aaa"#;
+   |     ^^^^^^^^^
+   |
+help: try
+   |
+LL -     cr#"aaa"#;
+LL +     c"aaa";
+   |
+
+error: unnecessary raw string literal
+  --> $DIR/needless_raw_string.rs:16:5
+   |
+LL | /     r#"
+LL | |         a
+LL | |         multiline
+LL | |         string
+LL | |     "#;
+   | |______^
+   |
+help: try
+   |
+LL ~     "
+LL |         a
+LL |         multiline
+LL |         string
+LL ~     ";
+   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed
index 84902157ab4..e980adeeff4 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed
+++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed
@@ -3,17 +3,22 @@
 #![feature(c_str_literals)]
 
 fn main() {
-    r#"aaa"#;
+    r"\aaa";
     r#"Hello "world"!"#;
     r####" "### "## "# "####;
     r###" "aa" "# "## "###;
-    br#"aaa"#;
+    br"\aaa";
     br#"Hello "world"!"#;
     br####" "### "## "# "####;
     br###" "aa" "# "## "###;
-    // currently disabled: https://github.com/rust-lang/rust/issues/113333
-    // cr#"aaa"#;
-    // cr##"Hello "world"!"##;
-    // cr######" "### "## "# "######;
-    // cr######" "aa" "# "## "######;
+    cr"\aaa";
+    cr#"Hello "world"!"#;
+    cr####" "### "## "# "####;
+    cr###" "aa" "# "## "###;
+
+    r"
+        \a
+        multiline
+        string
+    ";
 }
diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs
index 62abae83859..6113c5f25ae 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs
+++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs
@@ -3,17 +3,22 @@
 #![feature(c_str_literals)]
 
 fn main() {
-    r#"aaa"#;
+    r#"\aaa"#;
     r##"Hello "world"!"##;
     r######" "### "## "# "######;
     r######" "aa" "# "## "######;
-    br#"aaa"#;
+    br#"\aaa"#;
     br##"Hello "world"!"##;
     br######" "### "## "# "######;
     br######" "aa" "# "## "######;
-    // currently disabled: https://github.com/rust-lang/rust/issues/113333
-    // cr#"aaa"#;
-    // cr##"Hello "world"!"##;
-    // cr######" "### "## "# "######;
-    // cr######" "aa" "# "## "######;
+    cr#"\aaa"#;
+    cr##"Hello "world"!"##;
+    cr######" "### "## "# "######;
+    cr######" "aa" "# "## "######;
+
+    r#"
+        \a
+        multiline
+        string
+    "#;
 }
diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
index 94c51c423b8..5a8e3d04543 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
+++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
@@ -1,41 +1,167 @@
 error: unnecessary hashes around raw string literal
-  --> $DIR/needless_raw_string_hashes.rs:7:5
+  --> $DIR/needless_raw_string_hashes.rs:6:5
    |
-LL |     r##"Hello "world"!"##;
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: try: `r#"Hello "world"!"#`
+LL |     r#"\aaa"#;
+   |     ^^^^^^^^^
    |
    = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]`
+help: remove all the hashes around the literal
+   |
+LL -     r#"\aaa"#;
+LL +     r"\aaa";
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:7:5
+   |
+LL |     r##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove one hash from both sides of the literal
+   |
+LL -     r##"Hello "world"!"##;
+LL +     r#"Hello "world"!"#;
+   |
 
 error: unnecessary hashes around raw string literal
   --> $DIR/needless_raw_string_hashes.rs:8:5
    |
 LL |     r######" "### "## "# "######;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r####" "### "## "# "####`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 2 hashes from both sides of the literal
+   |
+LL -     r######" "### "## "# "######;
+LL +     r####" "### "## "# "####;
+   |
 
 error: unnecessary hashes around raw string literal
   --> $DIR/needless_raw_string_hashes.rs:9:5
    |
 LL |     r######" "aa" "# "## "######;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r###" "aa" "# "## "###`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 3 hashes from both sides of the literal
+   |
+LL -     r######" "aa" "# "## "######;
+LL +     r###" "aa" "# "## "###;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:10:5
+   |
+LL |     br#"\aaa"#;
+   |     ^^^^^^^^^^
+   |
+help: remove all the hashes around the literal
+   |
+LL -     br#"\aaa"#;
+LL +     br"\aaa";
+   |
 
 error: unnecessary hashes around raw string literal
   --> $DIR/needless_raw_string_hashes.rs:11:5
    |
 LL |     br##"Hello "world"!"##;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `br#"Hello "world"!"#`
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove one hash from both sides of the literal
+   |
+LL -     br##"Hello "world"!"##;
+LL +     br#"Hello "world"!"#;
+   |
 
 error: unnecessary hashes around raw string literal
   --> $DIR/needless_raw_string_hashes.rs:12:5
    |
 LL |     br######" "### "## "# "######;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br####" "### "## "# "####`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 2 hashes from both sides of the literal
+   |
+LL -     br######" "### "## "# "######;
+LL +     br####" "### "## "# "####;
+   |
 
 error: unnecessary hashes around raw string literal
   --> $DIR/needless_raw_string_hashes.rs:13:5
    |
 LL |     br######" "aa" "# "## "######;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 3 hashes from both sides of the literal
+   |
+LL -     br######" "aa" "# "## "######;
+LL +     br###" "aa" "# "## "###;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:14:5
+   |
+LL |     cr#"\aaa"#;
+   |     ^^^^^^^^^^
+   |
+help: remove all the hashes around the literal
+   |
+LL -     cr#"\aaa"#;
+LL +     cr"\aaa";
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:15:5
+   |
+LL |     cr##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove one hash from both sides of the literal
+   |
+LL -     cr##"Hello "world"!"##;
+LL +     cr#"Hello "world"!"#;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:16:5
+   |
+LL |     cr######" "### "## "# "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 2 hashes from both sides of the literal
+   |
+LL -     cr######" "### "## "# "######;
+LL +     cr####" "### "## "# "####;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:17:5
+   |
+LL |     cr######" "aa" "# "## "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 3 hashes from both sides of the literal
+   |
+LL -     cr######" "aa" "# "## "######;
+LL +     cr###" "aa" "# "## "###;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:19:5
+   |
+LL | /     r#"
+LL | |         \a
+LL | |         multiline
+LL | |         string
+LL | |     "#;
+   | |______^
+   |
+help: remove all the hashes around the literal
+   |
+LL ~     r"
+LL |         \a
+LL |         multiline
+LL |         string
+LL ~     ";
+   |
 
-error: aborting due to 6 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 001b94391ca..c67a6d4494e 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -337,10 +337,8 @@ pub fn test26() {
 
 pub fn test27() {
     loop {
-        //~^ ERROR: this loop never actually loops
         'label: {
             let x = true;
-            // Lints because we cannot prove it's always `true`
             if x {
                 break 'label;
             }
@@ -349,6 +347,59 @@ pub fn test27() {
     }
 }
 
+// issue 11004
+pub fn test29() {
+    loop {
+        'label: {
+            if true {
+                break 'label;
+            }
+            return;
+        }
+    }
+}
+
+pub fn test30() {
+    'a: loop {
+        'b: {
+            for j in 0..2 {
+                if j == 1 {
+                    break 'b;
+                }
+            }
+            break 'a;
+        }
+    }
+}
+
+pub fn test31(b: bool) {
+    'a: loop {
+        'b: {
+            'c: loop {
+                //~^ ERROR: this loop never actually loops
+                if b { break 'c } else { break 'b }
+            }
+            continue 'a;
+        }
+        break 'a;
+    }
+}
+
+pub fn test32() {
+    loop {
+        //~^ ERROR: this loop never actually loops
+        panic!("oh no");
+    }
+    loop {
+        //~^ ERROR: this loop never actually loops
+        unimplemented!("not yet");
+    }
+    loop {
+        // no error
+        todo!("maybe later");
+    }
+}
+
 fn main() {
     test1();
     test2();
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index 234780007b1..3982f36cea9 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -154,16 +154,31 @@ LL |             if let Some(_) = (0..20).next() {
    |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:339:5
+  --> $DIR/never_loop.rs:378:13
+   |
+LL | /             'c: loop {
+LL | |
+LL | |                 if b { break 'c } else { break 'b }
+LL | |             }
+   | |_____________^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:389:5
    |
 LL | /     loop {
 LL | |
-LL | |         'label: {
-LL | |             let x = true;
-...  |
-LL | |         }
+LL | |         panic!("oh no");
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:393:5
+   |
+LL | /     loop {
+LL | |
+LL | |         unimplemented!("not yet");
 LL | |     }
    | |_____^
 
-error: aborting due to 14 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.fixed b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed
index 165702b3041..165702b3041 100644
--- a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed
diff --git a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.rs b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs
index 3b07dd5ce62..3b07dd5ce62 100644
--- a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs
diff --git a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr
index 566a1a4b14b..44196751b05 100644
--- a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr
@@ -1,5 +1,5 @@
-error: incorrect implementation of `clone` on a `Copy` type
-  --> $DIR/incorrect_clone_impl_on_copy_type.rs:9:29
+error: non-canonical implementation of `clone` on a `Copy` type
+  --> $DIR/non_canonical_clone_impl.rs:9:29
    |
 LL |       fn clone(&self) -> Self {
    |  _____________________________^
@@ -7,10 +7,11 @@ LL | |         Self(self.0)
 LL | |     }
    | |_____^ help: change this to: `{ *self }`
    |
-   = note: `#[deny(clippy::incorrect_clone_impl_on_copy_type)]` on by default
+   = note: `-D clippy::non-canonical-clone-impl` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]`
 
-error: incorrect implementation of `clone_from` on a `Copy` type
-  --> $DIR/incorrect_clone_impl_on_copy_type.rs:13:5
+error: unnecessary implementation of `clone_from` on a `Copy` type
+  --> $DIR/non_canonical_clone_impl.rs:13:5
    |
 LL | /     fn clone_from(&mut self, source: &Self) {
 LL | |         source.clone();
@@ -18,8 +19,8 @@ LL | |         *self = source.clone();
 LL | |     }
    | |_____^ help: remove it
 
-error: incorrect implementation of `clone` on a `Copy` type
-  --> $DIR/incorrect_clone_impl_on_copy_type.rs:80:29
+error: non-canonical implementation of `clone` on a `Copy` type
+  --> $DIR/non_canonical_clone_impl.rs:80:29
    |
 LL |       fn clone(&self) -> Self {
    |  _____________________________^
@@ -27,8 +28,8 @@ LL | |         Self(self.0)
 LL | |     }
    | |_____^ help: change this to: `{ *self }`
 
-error: incorrect implementation of `clone_from` on a `Copy` type
-  --> $DIR/incorrect_clone_impl_on_copy_type.rs:84:5
+error: unnecessary implementation of `clone_from` on a `Copy` type
+  --> $DIR/non_canonical_clone_impl.rs:84:5
    |
 LL | /     fn clone_from(&mut self, source: &Self) {
 LL | |         source.clone();
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
index db55cc094e3..db55cc094e3 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
index 52f4b85b917..52f4b85b917 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
index 1f706984662..05cc717b9ba 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
@@ -1,5 +1,5 @@
-error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:16:1
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/non_canonical_partial_ord_impl.rs:16:1
    |
 LL | /  impl PartialOrd for A {
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -10,10 +10,11 @@ LL | ||     }
 LL | |  }
    | |__^
    |
-   = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+   = note: `-D clippy::non-canonical-partial-ord-impl` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::non_canonical_partial_ord_impl)]`
 
-error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:50:1
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/non_canonical_partial_ord_impl.rs:50:1
    |
 LL | / impl PartialOrd for C {
 LL | |     fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs
index 1173a95d065..2f8d5cf30c7 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs
@@ -21,8 +21,6 @@ impl cmp::Ord for A {
 }
 
 impl PartialOrd for A {
-    //~^ ERROR: incorrect implementation of `partial_cmp` on an `Ord` type
-    //~| NOTE: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
         // automatically applied
@@ -46,7 +44,6 @@ impl cmp::Ord for B {
 }
 
 impl PartialOrd for B {
-    //~^ ERROR: incorrect implementation of `partial_cmp` on an `Ord` type
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         // This calls `B.cmp`, not `Ord::cmp`!
         Some(self.cmp(other))
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr
index 09d7a32e334..4978d7a8739 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr
@@ -1,9 +1,7 @@
-error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:23:1
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/non_canonical_partial_ord_impl_fully_qual.rs:23:1
    |
 LL | /  impl PartialOrd for A {
-LL | |
-LL | |
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    | | _____________________________________________________________-
 LL | ||         // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
@@ -14,13 +12,13 @@ LL | ||     }
 LL | |  }
    | |__^
    |
-   = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+   = note: `-D clippy::non-canonical-partial-ord-impl` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::non_canonical_partial_ord_impl)]`
 
-error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:48:1
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/non_canonical_partial_ord_impl_fully_qual.rs:46:1
    |
 LL | /  impl PartialOrd for B {
-LL | |
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    | | _____________________________________________________________-
 LL | ||         // This calls `B.cmp`, not `Ord::cmp`!
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 0fd68eb92b1..4df9be2c21d 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -14,6 +14,8 @@
 #![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::non_canonical_clone_impl)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
 #![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
@@ -33,10 +35,10 @@
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
+#![allow(useless_ptr_null_checks)]
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -62,6 +64,8 @@
 #![warn(clippy::mixed_read_write_in_expression)]
 #![warn(clippy::useless_conversion)]
 #![warn(clippy::match_result_ok)]
+#![warn(clippy::non_canonical_clone_impl)]
+#![warn(clippy::non_canonical_partial_ord_impl)]
 #![warn(clippy::arithmetic_side_effects)]
 #![warn(clippy::overly_complex_bool_expr)]
 #![warn(clippy::new_without_default)]
@@ -85,12 +89,12 @@
 #![warn(drop_bounds)]
 #![warn(dropping_copy_types)]
 #![warn(dropping_references)]
+#![warn(useless_ptr_null_checks)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
 #![warn(forgetting_copy_types)]
 #![warn(forgetting_references)]
-#![warn(useless_ptr_null_checks)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
 #![warn(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 927937fba83..940e60068e7 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -14,6 +14,8 @@
 #![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::non_canonical_clone_impl)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
 #![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
@@ -33,10 +35,10 @@
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
+#![allow(useless_ptr_null_checks)]
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -62,6 +64,8 @@
 #![warn(clippy::eval_order_dependence)]
 #![warn(clippy::identity_conversion)]
 #![warn(clippy::if_let_some_result)]
+#![warn(clippy::incorrect_clone_impl_on_copy_type)]
+#![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
 #![warn(clippy::integer_arithmetic)]
 #![warn(clippy::logic_bug)]
 #![warn(clippy::new_without_default_derive)]
@@ -85,12 +89,12 @@
 #![warn(clippy::drop_bounds)]
 #![warn(clippy::drop_copy)]
 #![warn(clippy::drop_ref)]
+#![warn(clippy::fn_null_check)]
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::forget_copy)]
 #![warn(clippy::forget_ref)]
-#![warn(clippy::fn_null_check)]
 #![warn(clippy::into_iter_on_array)]
 #![warn(clippy::invalid_atomic_ordering)]
 #![warn(clippy::invalid_ref)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index d98fc7b30db..30824e154b8 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,322 +8,334 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
+error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
+  --> $DIR/rename.rs:67:9
+   |
+LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
+
+error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
+  --> $DIR/rename.rs:68:9
+   |
+LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
+
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
+  --> $DIR/rename.rs:92:9
+   |
+LL | #![warn(clippy::fn_null_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
+
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:93:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:94:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> $DIR/rename.rs:91:9
+  --> $DIR/rename.rs:96:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> $DIR/rename.rs:92:9
+  --> $DIR/rename.rs:97:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
-error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> $DIR/rename.rs:93:9
-   |
-LL | #![warn(clippy::fn_null_check)]
-   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
-
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:94:9
+  --> $DIR/rename.rs:98:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:95:9
+  --> $DIR/rename.rs:99:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:96:9
+  --> $DIR/rename.rs:100:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> $DIR/rename.rs:97:9
+  --> $DIR/rename.rs:101:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:98:9
+  --> $DIR/rename.rs:102:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:99:9
+  --> $DIR/rename.rs:103:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:100:9
+  --> $DIR/rename.rs:104:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:101:9
+  --> $DIR/rename.rs:105:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:102:9
+  --> $DIR/rename.rs:106:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> $DIR/rename.rs:103:9
+  --> $DIR/rename.rs:107:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:104:9
+  --> $DIR/rename.rs:108:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:105:9
+  --> $DIR/rename.rs:109:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 54 previous errors
+error: aborting due to 56 previous errors
 
diff --git a/src/tools/clippy/tests/ui/result_large_err.rs b/src/tools/clippy/tests/ui/result_large_err.rs
index 14a1f7e1db5..b25348bf996 100644
--- a/src/tools/clippy/tests/ui/result_large_err.rs
+++ b/src/tools/clippy/tests/ui/result_large_err.rs
@@ -1,3 +1,5 @@
+//@ignore-32bit
+
 #![warn(clippy::result_large_err)]
 #![allow(clippy::large_enum_variant)]
 
diff --git a/src/tools/clippy/tests/ui/result_large_err.stderr b/src/tools/clippy/tests/ui/result_large_err.stderr
index d42dd6600a3..6602f396a9c 100644
--- a/src/tools/clippy/tests/ui/result_large_err.stderr
+++ b/src/tools/clippy/tests/ui/result_large_err.stderr
@@ -1,5 +1,5 @@
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:8:23
+  --> $DIR/result_large_err.rs:10:23
    |
 LL | pub fn large_err() -> Result<(), [u8; 512]> {
    |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -9,7 +9,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> {
    = help: to override `-D warnings` add `#[allow(clippy::result_large_err)]`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:20:21
+  --> $DIR/result_large_err.rs:22:21
    |
 LL |     pub fn ret() -> Result<(), Self> {
    |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -17,7 +17,7 @@ LL |     pub fn ret() -> Result<(), Self> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:26:26
+  --> $DIR/result_large_err.rs:28:26
    |
 LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -25,7 +25,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:32:45
+  --> $DIR/result_large_err.rs:34:45
    |
 LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -33,7 +33,7 @@ LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:41:34
+  --> $DIR/result_large_err.rs:43:34
    |
 LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
@@ -41,7 +41,7 @@ LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeErro
    = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:53:34
+  --> $DIR/result_large_err.rs:55:34
    |
 LL |     _Omg([u8; 512]),
    |     --------------- the largest variant contains at least 512 bytes
@@ -52,7 +52,7 @@ LL |     pub fn large_enum_error() -> Result<(), Self> {
    = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:66:30
+  --> $DIR/result_large_err.rs:68:30
    |
 LL |     _Biggest([u8; 1024]),
    |     -------------------- the largest variant contains at least 1024 bytes
@@ -65,7 +65,7 @@ LL |     fn large_enum_error() -> Result<(), Self> {
    = help: try reducing the size of `MultipleLargeVariants`, for example by boxing large elements or replacing it with `Box<MultipleLargeVariants>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:73:25
+  --> $DIR/result_large_err.rs:75:25
    |
 LL |     fn large_error() -> Result<(), [u8; 512]> {
    |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -73,7 +73,7 @@ LL |     fn large_error() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:93:29
+  --> $DIR/result_large_err.rs:95:29
    |
 LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -81,7 +81,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:103:40
+  --> $DIR/result_large_err.rs:105:40
    |
 LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -89,7 +89,7 @@ LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:113:34
+  --> $DIR/result_large_err.rs:115:34
    |
 LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
@@ -97,7 +97,7 @@ LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:118:31
+  --> $DIR/result_large_err.rs:120:31
    |
 LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs
index c5a941316da..f46af56c6e2 100644
--- a/src/tools/clippy/tests/ui/similar_names.rs
+++ b/src/tools/clippy/tests/ui/similar_names.rs
@@ -3,6 +3,7 @@
     unused,
     clippy::println_empty_string,
     clippy::empty_loop,
+    clippy::never_loop,
     clippy::diverging_sub_expression,
     clippy::let_unit_value
 )]
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
index 011dbe679c0..44ae3532a48 100644
--- a/src/tools/clippy/tests/ui/similar_names.stderr
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -1,11 +1,11 @@
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:21:9
+  --> $DIR/similar_names.rs:22:9
    |
 LL |     let bpple: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:19:9
+  --> $DIR/similar_names.rs:20:9
    |
 LL |     let apple: i32;
    |         ^^^^^
@@ -13,73 +13,73 @@ LL |     let apple: i32;
    = help: to override `-D warnings` add `#[allow(clippy::similar_names)]`
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:24:9
+  --> $DIR/similar_names.rs:25:9
    |
 LL |     let cpple: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:19:9
+  --> $DIR/similar_names.rs:20:9
    |
 LL |     let apple: i32;
    |         ^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:49:9
+  --> $DIR/similar_names.rs:50:9
    |
 LL |     let bluby: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:48:9
+  --> $DIR/similar_names.rs:49:9
    |
 LL |     let blubx: i32;
    |         ^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:54:9
+  --> $DIR/similar_names.rs:55:9
    |
 LL |     let coke: i32;
    |         ^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:52:9
+  --> $DIR/similar_names.rs:53:9
    |
 LL |     let cake: i32;
    |         ^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:73:9
+  --> $DIR/similar_names.rs:74:9
    |
 LL |     let xyzeabc: i32;
    |         ^^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:71:9
+  --> $DIR/similar_names.rs:72:9
    |
 LL |     let xyz1abc: i32;
    |         ^^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:78:9
+  --> $DIR/similar_names.rs:79:9
    |
 LL |     let parsee: i32;
    |         ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:76:9
+  --> $DIR/similar_names.rs:77:9
    |
 LL |     let parser: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:100:16
+  --> $DIR/similar_names.rs:101:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:99:16
+  --> $DIR/similar_names.rs:100:16
    |
 LL |         apple: spring,
    |                ^^^^^^
diff --git a/src/tools/clippy/tests/ui/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs
index d6493f23413..3cc8061647d 100644
--- a/src/tools/clippy/tests/ui/single_call_fn.rs
+++ b/src/tools/clippy/tests/ui/single_call_fn.rs
@@ -1,3 +1,4 @@
+//@ignore-32bit
 //@aux-build:proc_macros.rs
 #![allow(clippy::redundant_closure_call, unused)]
 #![warn(clippy::single_call_fn)]
diff --git a/src/tools/clippy/tests/ui/single_call_fn.stderr b/src/tools/clippy/tests/ui/single_call_fn.stderr
index 4acb383c408..d5cd707754c 100644
--- a/src/tools/clippy/tests/ui/single_call_fn.stderr
+++ b/src/tools/clippy/tests/ui/single_call_fn.stderr
@@ -1,5 +1,5 @@
 error: this function is only used once
-  --> $DIR/single_call_fn.rs:33:1
+  --> $DIR/single_call_fn.rs:34:1
    |
 LL | / fn c() {
 LL | |     println!("really");
@@ -9,7 +9,7 @@ LL | | }
    | |_^
    |
 help: used here
-  --> $DIR/single_call_fn.rs:40:5
+  --> $DIR/single_call_fn.rs:41:5
    |
 LL |     c();
    |     ^
@@ -17,37 +17,37 @@ LL |     c();
    = help: to override `-D warnings` add `#[allow(clippy::single_call_fn)]`
 
 error: this function is only used once
-  --> $DIR/single_call_fn.rs:12:1
+  --> $DIR/single_call_fn.rs:13:1
    |
 LL | fn i() {}
    | ^^^^^^^^^
    |
 help: used here
-  --> $DIR/single_call_fn.rs:17:13
+  --> $DIR/single_call_fn.rs:18:13
    |
 LL |     let a = i;
    |             ^
 
 error: this function is only used once
-  --> $DIR/single_call_fn.rs:43:1
+  --> $DIR/single_call_fn.rs:44:1
    |
 LL | fn a() {}
    | ^^^^^^^^^
    |
 help: used here
-  --> $DIR/single_call_fn.rs:46:5
+  --> $DIR/single_call_fn.rs:47:5
    |
 LL |     a();
    |     ^
 
 error: this function is only used once
-  --> $DIR/single_call_fn.rs:13:1
+  --> $DIR/single_call_fn.rs:14:1
    |
 LL | fn j() {}
    | ^^^^^^^^^
    |
 help: used here
-  --> $DIR/single_call_fn.rs:24:9
+  --> $DIR/single_call_fn.rs:25:9
    |
 LL |         j();
    |         ^
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index f8d85ed38cd..5c3086c9d69 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -1,5 +1,5 @@
-use std::iter::repeat;
 //@no-rustfix
+use std::iter::repeat;
 fn main() {
     resize_vector();
     extend_vector();
@@ -86,6 +86,20 @@ fn from_empty_vec() {
     vec1 = Vec::new();
     vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+
+    vec1 = vec![];
+    vec1.resize(10, 0);
+    //~^ ERROR: slow zero-filling initialization
+
+    macro_rules! x {
+        () => {
+            vec![]
+        };
+    }
+
+    // `vec![]` comes from another macro, don't warn
+    vec1 = x!();
+    vec1.resize(10, 0);
 }
 
 fn do_stuff(vec: &mut [u8]) {}
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index f4501551656..4d24400ecb5 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -97,8 +97,16 @@ LL |     vec1 = Vec::new();
 LL |     vec1.resize(10, 0);
    |     ^^^^^^^^^^^^^^^^^^
 
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:91:5
+   |
+LL |     vec1 = vec![];
+   |            ------ help: consider replacing this with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
 error: this argument is a mutable reference, but not used mutably
-  --> $DIR/slow_vector_initialization.rs:91:18
+  --> $DIR/slow_vector_initialization.rs:105:18
    |
 LL | fn do_stuff(vec: &mut [u8]) {}
    |                  ^^^^^^^^^ help: consider changing to: `&[u8]`
@@ -106,5 +114,5 @@ LL | fn do_stuff(vec: &mut [u8]) {}
    = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
new file mode 100644
index 00000000000..8027c053fb5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -0,0 +1,62 @@
+#![warn(clippy::std_instead_of_core)]
+#![allow(unused_imports)]
+
+extern crate alloc;
+
+#[warn(clippy::std_instead_of_core)]
+fn std_instead_of_core() {
+    // Regular import
+    use core::hash::Hasher;
+    //~^ ERROR: used import from `std` instead of `core`
+    // Absolute path
+    use ::core::hash::Hash;
+    //~^ ERROR: used import from `std` instead of `core`
+    // Don't lint on `env` macro
+    use std::env;
+
+    // Multiple imports
+    use core::fmt::{Debug, Result};
+    //~^ ERROR: used import from `std` instead of `core`
+
+    // Function calls
+    let ptr = core::ptr::null::<u32>();
+    //~^ ERROR: used import from `std` instead of `core`
+    let ptr_mut = ::core::ptr::null_mut::<usize>();
+    //~^ ERROR: used import from `std` instead of `core`
+
+    // Types
+    let cell = core::cell::Cell::new(8u32);
+    //~^ ERROR: used import from `std` instead of `core`
+    let cell_absolute = ::core::cell::Cell::new(8u32);
+    //~^ ERROR: used import from `std` instead of `core`
+
+    let _ = std::env!("PATH");
+
+    // do not lint until `error_in_core` is stable
+    use std::error::Error;
+
+    // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator`
+    use core::iter::Iterator;
+    //~^ ERROR: used import from `std` instead of `core`
+}
+
+#[warn(clippy::std_instead_of_alloc)]
+fn std_instead_of_alloc() {
+    // Only lint once.
+    use alloc::vec;
+    //~^ ERROR: used import from `std` instead of `alloc`
+    use alloc::vec::Vec;
+    //~^ ERROR: used import from `std` instead of `alloc`
+}
+
+#[warn(clippy::alloc_instead_of_core)]
+fn alloc_instead_of_core() {
+    use core::slice::from_ref;
+    //~^ ERROR: used import from `alloc` instead of `core`
+}
+
+fn main() {
+    std_instead_of_core();
+    std_instead_of_alloc();
+    alloc_instead_of_core();
+}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index 2e44487d77e..63a096384d7 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -17,7 +17,6 @@ fn std_instead_of_core() {
     // Multiple imports
     use std::fmt::{Debug, Result};
     //~^ ERROR: used import from `std` instead of `core`
-    //~| ERROR: used import from `std` instead of `core`
 
     // Function calls
     let ptr = std::ptr::null::<u32>();
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index 7435d716157..ca26f77bd37 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -2,103 +2,76 @@ error: used import from `std` instead of `core`
   --> $DIR/std_instead_of_core.rs:9:9
    |
 LL |     use std::hash::Hasher;
-   |         ^^^^^^^^^^^^^^^^^
+   |         ^^^ help: consider importing the item from `core`: `core`
    |
-   = help: consider importing the item from `core`
    = note: `-D clippy::std-instead-of-core` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:12:9
+  --> $DIR/std_instead_of_core.rs:12:11
    |
 LL |     use ::std::hash::Hash;
-   |         ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |           ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:18:20
+  --> $DIR/std_instead_of_core.rs:18:9
    |
 LL |     use std::fmt::{Debug, Result};
-   |                    ^^^^^
-   |
-   = help: consider importing the item from `core`
-
-error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:18:27
-   |
-LL |     use std::fmt::{Debug, Result};
-   |                           ^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |         ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:23:15
+  --> $DIR/std_instead_of_core.rs:22:15
    |
 LL |     let ptr = std::ptr::null::<u32>();
-   |               ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |               ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:25:19
+  --> $DIR/std_instead_of_core.rs:24:21
    |
 LL |     let ptr_mut = ::std::ptr::null_mut::<usize>();
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |                     ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:29:16
+  --> $DIR/std_instead_of_core.rs:28:16
    |
 LL |     let cell = std::cell::Cell::new(8u32);
-   |                ^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |                ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:31:25
+  --> $DIR/std_instead_of_core.rs:30:27
    |
 LL |     let cell_absolute = ::std::cell::Cell::new(8u32);
-   |                         ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |                           ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> $DIR/std_instead_of_core.rs:40:9
+  --> $DIR/std_instead_of_core.rs:39:9
    |
 LL |     use std::iter::Iterator;
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `core`
+   |         ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `alloc`
-  --> $DIR/std_instead_of_core.rs:47:9
+  --> $DIR/std_instead_of_core.rs:46:9
    |
 LL |     use std::vec;
-   |         ^^^^^^^^
+   |         ^^^ help: consider importing the item from `alloc`: `alloc`
    |
-   = help: consider importing the item from `alloc`
    = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]`
 
 error: used import from `std` instead of `alloc`
-  --> $DIR/std_instead_of_core.rs:49:9
+  --> $DIR/std_instead_of_core.rs:48:9
    |
 LL |     use std::vec::Vec;
-   |         ^^^^^^^^^^^^^
-   |
-   = help: consider importing the item from `alloc`
+   |         ^^^ help: consider importing the item from `alloc`: `alloc`
 
 error: used import from `alloc` instead of `core`
-  --> $DIR/std_instead_of_core.rs:55:9
+  --> $DIR/std_instead_of_core.rs:54:9
    |
 LL |     use alloc::slice::from_ref;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^ help: consider importing the item from `core`: `core`
    |
-   = help: consider importing the item from `core`
    = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]`
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute_32bit.stderr b/src/tools/clippy/tests/ui/transmute_32bit.stderr
index 75ddca60d2a..baa819e30fd 100644
--- a/src/tools/clippy/tests/ui/transmute_32bit.stderr
+++ b/src/tools/clippy/tests/ui/transmute_32bit.stderr
@@ -1,39 +1,29 @@
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+error: transmute from a `f32` to a pointer
   --> $DIR/transmute_32bit.rs:6:31
    |
 LL |         let _: *const usize = std::mem::transmute(6.0f32);
-   |                               ^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `f32` (32 bits)
-   = note: target type: `*const usize` (64 bits)
+   = note: `-D clippy::wrong-transmute` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::wrong_transmute)]`
 
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+error: transmute from a `f32` to a pointer
   --> $DIR/transmute_32bit.rs:8:29
    |
 LL |         let _: *mut usize = std::mem::transmute(6.0f32);
-   |                             ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: source type: `f32` (32 bits)
-   = note: target type: `*mut usize` (64 bits)
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+error: transmute from a `char` to a pointer
   --> $DIR/transmute_32bit.rs:10:31
    |
 LL |         let _: *const usize = std::mem::transmute('x');
-   |                               ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: source type: `char` (32 bits)
-   = note: target type: `*const usize` (64 bits)
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+error: transmute from a `char` to a pointer
   --> $DIR/transmute_32bit.rs:12:29
    |
 LL |         let _: *mut usize = std::mem::transmute('x');
-   |                             ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: source type: `char` (32 bits)
-   = note: target type: `*mut usize` (64 bits)
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0512`.
diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed
index b5dedef5f4c..f3cf65da2d6 100644
--- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::incorrect_clone_impl_on_copy_type, unused)]
+#![allow(clippy::non_canonical_clone_impl, unused)]
 #![warn(clippy::unnecessary_struct_initialization)]
 
 struct S {
diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs
index 2222c3ddf37..bd5302f9d85 100644
--- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::incorrect_clone_impl_on_copy_type, unused)]
+#![allow(clippy::non_canonical_clone_impl, unused)]
 #![warn(clippy::unnecessary_struct_initialization)]
 
 struct S {
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index 3ff2acbe28f..bcbca971a78 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -120,6 +120,7 @@ fn issue11075() {
             stringify!($e)
         };
     }
+    #[allow(clippy::never_loop)]
     for _string in [repro!(true), repro!(null)] {
         unimplemented!();
     }
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index 2ab025f424a..087425585de 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -120,6 +120,7 @@ fn issue11075() {
             stringify!($e)
         };
     }
+    #[allow(clippy::never_loop)]
     for _string in vec![repro!(true), repro!(null)] {
         unimplemented!();
     }
diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr
index a28024d236a..fc261838fe3 100644
--- a/src/tools/clippy/tests/ui/vec.stderr
+++ b/src/tools/clippy/tests/ui/vec.stderr
@@ -86,31 +86,31 @@ LL |     for _ in vec![1, 2, 3] {}
    |              ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:123:20
+  --> $DIR/vec.rs:124:20
    |
 LL |     for _string in vec![repro!(true), repro!(null)] {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:140:18
+  --> $DIR/vec.rs:141:18
    |
 LL |     in_macro!(1, vec![1, 2], vec![1; 2]);
    |                  ^^^^^^^^^^ help: you can use an array directly: `[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:140:30
+  --> $DIR/vec.rs:141:30
    |
 LL |     in_macro!(1, vec![1, 2], vec![1; 2]);
    |                              ^^^^^^^^^^ help: you can use an array directly: `[1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:159:14
+  --> $DIR/vec.rs:160:14
    |
 LL |     for a in vec![1, 2, 3] {
    |              ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:163:14
+  --> $DIR/vec.rs:164:14
    |
 LL |     for a in vec![String::new(), String::new()] {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]`
diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr
index fc24dba4543..6d382a267ad 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.stderr
+++ b/src/tools/clippy/tests/ui/write_literal_2.stderr
@@ -2,7 +2,9 @@ error: unnecessary raw string literal
   --> $DIR/write_literal_2.rs:13:24
    |
 LL |     writeln!(v, r"{}", r"{hello}");
-   |                        ^^^^^^^^^^ help: try: `"{hello}"`
+   |                        -^^^^^^^^^
+   |                        |
+   |                        help: use a string literal instead: `"{hello}"`
    |
    = note: `-D clippy::needless-raw-strings` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index a455a1badc0..3f1921cb6bd 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -9,7 +9,16 @@ use std::io::{self, Write};
 use std::mem::replace;
 use std::process::{Child, Output};
 
-pub fn read2_abbreviated(mut child: Child, filter_paths_from_len: &[String]) -> io::Result<Output> {
+#[derive(Copy, Clone, Debug)]
+pub enum Truncated {
+    Yes,
+    No,
+}
+
+pub fn read2_abbreviated(
+    mut child: Child,
+    filter_paths_from_len: &[String],
+) -> io::Result<(Output, Truncated)> {
     let mut stdout = ProcOutput::new();
     let mut stderr = ProcOutput::new();
 
@@ -24,11 +33,12 @@ pub fn read2_abbreviated(mut child: Child, filter_paths_from_len: &[String]) ->
     )?;
     let status = child.wait()?;
 
-    Ok(Output { status, stdout: stdout.into_bytes(), stderr: stderr.into_bytes() })
+    let truncated =
+        if stdout.truncated() || stderr.truncated() { Truncated::Yes } else { Truncated::No };
+    Ok((Output { status, stdout: stdout.into_bytes(), stderr: stderr.into_bytes() }, truncated))
 }
 
-const HEAD_LEN: usize = 160 * 1024;
-const TAIL_LEN: usize = 256 * 1024;
+const MAX_OUT_LEN: usize = 512 * 1024;
 
 // Whenever a path is filtered when counting the length of the output, we need to add some
 // placeholder length to ensure a compiler emitting only filtered paths doesn't cause a OOM.
@@ -39,7 +49,7 @@ const FILTERED_PATHS_PLACEHOLDER_LEN: usize = 32;
 
 enum ProcOutput {
     Full { bytes: Vec<u8>, filtered_len: usize },
-    Abbreviated { head: Vec<u8>, skipped: usize, tail: Box<[u8]> },
+    Abbreviated { head: Vec<u8>, skipped: usize },
 }
 
 impl ProcOutput {
@@ -47,6 +57,10 @@ impl ProcOutput {
         ProcOutput::Full { bytes: Vec::new(), filtered_len: 0 }
     }
 
+    fn truncated(&self) -> bool {
+        matches!(self, Self::Abbreviated { .. })
+    }
+
     fn extend(&mut self, data: &[u8], filter_paths_from_len: &[String]) {
         let new_self = match *self {
             ProcOutput::Full { ref mut bytes, ref mut filtered_len } => {
@@ -83,24 +97,21 @@ impl ProcOutput {
                 }
 
                 let new_len = bytes.len();
-                if (*filtered_len).min(new_len) <= HEAD_LEN + TAIL_LEN {
+                if (*filtered_len).min(new_len) <= MAX_OUT_LEN {
                     return;
                 }
 
                 let mut head = replace(bytes, Vec::new());
-                let mut middle = head.split_off(HEAD_LEN);
-                let tail = middle.split_off(middle.len() - TAIL_LEN).into_boxed_slice();
-                let skipped = new_len - HEAD_LEN - TAIL_LEN;
-                ProcOutput::Abbreviated { head, skipped, tail }
+                // Don't truncate if this as a whole line.
+                // That should make it less likely that we cut a JSON line in half.
+                if head.last() != Some(&('\n' as u8)) {
+                    head.truncate(MAX_OUT_LEN);
+                }
+                let skipped = new_len - head.len();
+                ProcOutput::Abbreviated { head, skipped }
             }
-            ProcOutput::Abbreviated { ref mut skipped, ref mut tail, .. } => {
+            ProcOutput::Abbreviated { ref mut skipped, .. } => {
                 *skipped += data.len();
-                if data.len() <= TAIL_LEN {
-                    tail[..data.len()].copy_from_slice(data);
-                    tail.rotate_left(data.len());
-                } else {
-                    tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]);
-                }
                 return;
             }
         };
@@ -110,18 +121,12 @@ impl ProcOutput {
     fn into_bytes(self) -> Vec<u8> {
         match self {
             ProcOutput::Full { bytes, .. } => bytes,
-            ProcOutput::Abbreviated { mut head, mut skipped, tail } => {
-                let mut tail = &*tail;
-
-                // Skip over '{' at the start of the tail, so we don't later wrongfully consider this as json.
-                // See <https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Weird.20CI.20failure/near/321797811>
-                while tail.get(0) == Some(&b'{') {
-                    tail = &tail[1..];
-                    skipped += 1;
-                }
-
-                write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap();
-                head.extend_from_slice(tail);
+            ProcOutput::Abbreviated { mut head, skipped } => {
+                let head_note =
+                    format!("<<<<<< TRUNCATED, SHOWING THE FIRST {} BYTES >>>>>>\n\n", head.len());
+                head.splice(0..0, head_note.into_bytes());
+                write!(&mut head, "\n\n<<<<<< TRUNCATED, DROPPED {} BYTES >>>>>>", skipped)
+                    .unwrap();
                 head
             }
         }
diff --git a/src/tools/compiletest/src/read2/tests.rs b/src/tools/compiletest/src/read2/tests.rs
index 1ca682a46aa..5ad2db3cb83 100644
--- a/src/tools/compiletest/src/read2/tests.rs
+++ b/src/tools/compiletest/src/read2/tests.rs
@@ -1,4 +1,6 @@
-use crate::read2::{ProcOutput, FILTERED_PATHS_PLACEHOLDER_LEN, HEAD_LEN, TAIL_LEN};
+use std::io::Write;
+
+use crate::read2::{ProcOutput, FILTERED_PATHS_PLACEHOLDER_LEN, MAX_OUT_LEN};
 
 #[test]
 fn test_abbreviate_short_string() {
@@ -21,35 +23,13 @@ fn test_abbreviate_short_string_multiple_steps() {
 fn test_abbreviate_long_string() {
     let mut out = ProcOutput::new();
 
-    let data = vec![b'.'; HEAD_LEN + TAIL_LEN + 16];
+    let data = vec![b'.'; MAX_OUT_LEN + 16];
     out.extend(&data, &[]);
 
-    let mut expected = vec![b'.'; HEAD_LEN];
-    expected.extend_from_slice(b"\n\n<<<<<< SKIPPED 16 BYTES >>>>>>\n\n");
-    expected.extend_from_slice(&vec![b'.'; TAIL_LEN]);
-
-    // We first check the length to avoid endless terminal output if the length differs, since
-    // `out` is hundreds of KBs in size.
-    let out = out.into_bytes();
-    assert_eq!(expected.len(), out.len());
-    assert_eq!(expected, out);
-}
-
-#[test]
-fn test_abbreviate_long_string_multiple_steps() {
-    let mut out = ProcOutput::new();
-
-    out.extend(&vec![b'.'; HEAD_LEN], &[]);
-    out.extend(&vec![b'.'; TAIL_LEN], &[]);
-    // Also test whether the rotation works
-    out.extend(&vec![b'!'; 16], &[]);
-    out.extend(&vec![b'?'; 16], &[]);
-
-    let mut expected = vec![b'.'; HEAD_LEN];
-    expected.extend_from_slice(b"\n\n<<<<<< SKIPPED 32 BYTES >>>>>>\n\n");
-    expected.extend_from_slice(&vec![b'.'; TAIL_LEN - 32]);
-    expected.extend_from_slice(&vec![b'!'; 16]);
-    expected.extend_from_slice(&vec![b'?'; 16]);
+    let mut expected = Vec::new();
+    write!(expected, "<<<<<< TRUNCATED, SHOWING THE FIRST {MAX_OUT_LEN} BYTES >>>>>>\n\n").unwrap();
+    expected.extend_from_slice(&[b'.'; MAX_OUT_LEN]);
+    expected.extend_from_slice(b"\n\n<<<<<< TRUNCATED, DROPPED 16 BYTES >>>>>>");
 
     // We first check the length to avoid endless terminal output if the length differs, since
     // `out` is hundreds of KBs in size.
@@ -86,9 +66,8 @@ fn test_abbreviate_filters_avoid_abbreviations() {
     let mut out = ProcOutput::new();
     let filters = &[std::iter::repeat('a').take(64).collect::<String>()];
 
-    let mut expected = vec![b'.'; HEAD_LEN - FILTERED_PATHS_PLACEHOLDER_LEN as usize];
+    let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN as usize];
     expected.extend_from_slice(filters[0].as_bytes());
-    expected.extend_from_slice(&vec![b'.'; TAIL_LEN]);
 
     out.extend(&expected, filters);
 
@@ -104,14 +83,13 @@ fn test_abbreviate_filters_can_still_cause_abbreviations() {
     let mut out = ProcOutput::new();
     let filters = &[std::iter::repeat('a').take(64).collect::<String>()];
 
-    let mut input = vec![b'.'; HEAD_LEN];
-    input.extend_from_slice(&vec![b'.'; TAIL_LEN]);
+    let mut input = vec![b'.'; MAX_OUT_LEN];
     input.extend_from_slice(filters[0].as_bytes());
 
-    let mut expected = vec![b'.'; HEAD_LEN];
-    expected.extend_from_slice(b"\n\n<<<<<< SKIPPED 64 BYTES >>>>>>\n\n");
-    expected.extend_from_slice(&vec![b'.'; TAIL_LEN - 64]);
-    expected.extend_from_slice(&vec![b'a'; 64]);
+    let mut expected = Vec::new();
+    write!(expected, "<<<<<< TRUNCATED, SHOWING THE FIRST {MAX_OUT_LEN} BYTES >>>>>>\n\n").unwrap();
+    expected.extend_from_slice(&[b'.'; MAX_OUT_LEN]);
+    expected.extend_from_slice(b"\n\n<<<<<< TRUNCATED, DROPPED 64 BYTES >>>>>>");
 
     out.extend(&input, filters);
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 670441aacbd..65af650f6e5 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -12,7 +12,7 @@ use crate::compute_diff::{write_diff, write_filtered_diff};
 use crate::errors::{self, Error, ErrorKind};
 use crate::header::TestProps;
 use crate::json;
-use crate::read2::read2_abbreviated;
+use crate::read2::{read2_abbreviated, Truncated};
 use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt};
 use crate::ColorConfig;
 use regex::{Captures, Regex};
@@ -701,6 +701,7 @@ impl<'test> TestCx<'test> {
             status: output.status,
             stdout: String::from_utf8(output.stdout).unwrap(),
             stderr: String::from_utf8(output.stderr).unwrap(),
+            truncated: Truncated::No,
             cmdline: format!("{cmd:?}"),
         };
         self.dump_output(&proc_res.stdout, &proc_res.stderr);
@@ -1275,6 +1276,7 @@ impl<'test> TestCx<'test> {
                 status,
                 stdout: String::from_utf8(stdout).unwrap(),
                 stderr: String::from_utf8(stderr).unwrap(),
+                truncated: Truncated::No,
                 cmdline,
             };
             if adb.kill().is_err() {
@@ -1475,6 +1477,15 @@ impl<'test> TestCx<'test> {
             "^core::num::([a-z_]+::)*NonZero.+$",
         ];
 
+        // In newer versions of lldb, persistent results (the `$N =` part at the start of
+        // expressions you have evaluated that let you re-use the result) aren't printed, but lots
+        // of rustc's debuginfo tests rely on these, so re-enable this.
+        // See <https://reviews.llvm.org/rG385496385476fc9735da5fa4acabc34654e8b30d>.
+        script_str.push_str("command unalias print\n");
+        script_str.push_str("command alias print expr --\n");
+        script_str.push_str("command unalias p\n");
+        script_str.push_str("command alias p expr --\n");
+
         script_str
             .push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]);
         script_str.push_str("type synthetic add -l lldb_lookup.synthetic_lookup -x '.*' ");
@@ -1557,7 +1568,13 @@ impl<'test> TestCx<'test> {
         };
 
         self.dump_output(&out, &err);
-        ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
+        ProcRes {
+            status,
+            stdout: out,
+            stderr: err,
+            truncated: Truncated::No,
+            cmdline: format!("{:?}", cmd),
+        }
     }
 
     fn cleanup_debug_info_options(&self, options: &Vec<String>) -> Vec<String> {
@@ -2218,7 +2235,7 @@ impl<'test> TestCx<'test> {
         dylib
     }
 
-    fn read2_abbreviated(&self, child: Child) -> Output {
+    fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) {
         let mut filter_paths_from_len = Vec::new();
         let mut add_path = |path: &Path| {
             let path = path.display().to_string();
@@ -2265,12 +2282,13 @@ impl<'test> TestCx<'test> {
             child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
         }
 
-        let Output { status, stdout, stderr } = self.read2_abbreviated(child);
+        let (Output { status, stdout, stderr }, truncated) = self.read2_abbreviated(child);
 
         let result = ProcRes {
             status,
             stdout: String::from_utf8_lossy(&stdout).into_owned(),
             stderr: String::from_utf8_lossy(&stderr).into_owned(),
+            truncated,
             cmdline,
         };
 
@@ -3601,12 +3619,14 @@ impl<'test> TestCx<'test> {
             }
         }
 
-        let output = self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`"));
+        let (output, truncated) =
+            self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`"));
         if !output.status.success() {
             let res = ProcRes {
                 status: output.status,
                 stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
                 stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
+                truncated,
                 cmdline: format!("{:?}", cmd),
             };
             self.fatal_proc_rec("make failed", &res);
@@ -3768,6 +3788,15 @@ impl<'test> TestCx<'test> {
         let emit_metadata = self.should_emit_metadata(pm);
         let proc_res = self.compile_test(should_run, emit_metadata);
         self.check_if_test_should_compile(&proc_res, pm);
+        if matches!(proc_res.truncated, Truncated::Yes)
+            && !self.props.dont_check_compiler_stdout
+            && !self.props.dont_check_compiler_stderr
+        {
+            self.fatal_proc_rec(
+                &format!("compiler output got truncated, cannot compare with reference file"),
+                &proc_res,
+            );
+        }
 
         // if the user specified a format in the ui test
         // print the output to the stderr file, otherwise extract
@@ -4459,6 +4488,7 @@ pub struct ProcRes {
     status: ExitStatus,
     stdout: String,
     stderr: String,
+    truncated: Truncated,
     cmdline: String,
 }
 
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 5e2abdde6ac..bcbd44a5f38 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -208,7 +208,7 @@ jobs:
           git push -u origin $BRANCH
       - name: Create Pull Request
         run: |
-          PR=$(gh pr create -B master --title 'Automatic sync from rustc' --body '')
+          PR=$(gh pr create -B master --title 'Automatic sync from rustc' --body '' --label subtree-sync)
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
             --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
             --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 938df9799da..e21738c3618 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -e
 # Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
 # rustup (that sets it's own environmental variables), which is undesirable.
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index b7031d9a3ee..124acc95098 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -102,8 +102,8 @@ impl Command {
         cmd.stdout(process::Stdio::null());
         cmd.stderr(process::Stdio::null());
         let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
-        // Give it some time so hopefully the port is open. (10ms was not enough.)
-        thread::sleep(time::Duration::from_millis(100));
+        // Give it some time so hopefully the port is open. (100ms was not enough.)
+        thread::sleep(time::Duration::from_millis(200));
 
         // Create a wrapper that stops it on drop.
         struct Josh(process::Child);
@@ -338,7 +338,11 @@ impl Command {
         println!(
             "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
         );
-        println!("    https://github.com/{github_user}/rust/pull/new/{branch}");
+        println!(
+            // Open PR with `subtree-sync` label to satisfy the `no-merges` triagebot check
+            // See https://github.com/rust-lang/rust/pull/114157
+            "    https://github.com/rust-lang/rust/compare/{github_user}:{branch}?quick_pull=1&labels=subtree-sync"
+        );
 
         drop(josh);
         Ok(())
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index b40e7f83f4f..ab73f33497e 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-a989e25f1b87949a886eab3da10324d14189fe95
+366dab13f711df90a6891411458544199d159cbc
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 97718f1f4a9..1e9219d4bb2 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
 
     fn after_analysis<'tcx>(
         &mut self,
-        handler: &EarlyErrorHandler,
         _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
@@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
 
-            init_late_loggers(handler, tcx);
+            let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
+            init_late_loggers(&handler, tcx);
             if !tcx.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 513cec1f6c3..073b8b6a661 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -1030,8 +1030,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         // <https://github.com/rust-lang/miri/pull/2464#discussion_r939636130> for details.
         // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual
         // access will happen later.
-        let (alloc_id, _offset, _prov) =
-            this.ptr_try_get_alloc_id(place.ptr()).expect("there are no zero-sized atomic accesses");
+        let (alloc_id, _offset, _prov) = this
+            .ptr_try_get_alloc_id(place.ptr())
+            .expect("there are no zero-sized atomic accesses");
         if this.get_alloc_mutability(alloc_id)? == Mutability::Not {
             // FIXME: make this prettier, once these messages have separate title/span/help messages.
             throw_ub_format!(
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 295d86fd240..ef4e7df3aba 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -7,8 +7,8 @@ use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
 use std::task::Poll;
 use std::time::{Duration, SystemTime};
 
-use log::trace;
 use either::Either;
+use log::trace;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 4f249acda1d..cb095f94f35 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>(
     e: InterpErrorInfo<'tcx>,
 ) -> Option<(i64, bool)> {
     use InterpError::*;
+    use UndefinedBehaviorInfo::*;
 
     let mut msg = vec![];
 
@@ -271,7 +272,7 @@ pub fn report_error<'tcx, 'mir>(
         (title, helps)
     } else {
         let title = match e.kind() {
-            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
+            UndefinedBehavior(ValidationError(validation_err))
                 if matches!(
                     validation_err.kind,
                     ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer
@@ -299,7 +300,7 @@ pub fn report_error<'tcx, 'mir>(
         let helps = match e.kind() {
             Unsupported(_) =>
                 vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
-            UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
+            UndefinedBehavior(AlignmentCheckFailed { .. })
                 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
             =>
                 vec![
@@ -311,13 +312,20 @@ pub fn report_error<'tcx, 'mir>(
                     (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                     (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                 ];
-                if let UndefinedBehaviorInfo::PointerUseAfterFree(alloc_id, _) | UndefinedBehaviorInfo::PointerOutOfBounds { alloc_id, .. } = info {
-                    if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
-                        helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
+                match info {
+                    PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
+                        if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
+                            helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
+                        }
+                        if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
+                            helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
+                        }
                     }
-                    if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
-                        helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
+                    AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
+                        helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")));
+                        helps.push((None, format!("if you think this code should be accepted anyway, please report an issue")));
                     }
+                    _ => {},
                 }
                 helps
             }
@@ -339,7 +347,7 @@ pub fn report_error<'tcx, 'mir>(
     // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
     let mut extra = String::new();
     match e.kind() {
-        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
+        UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
             writeln!(
                 extra,
                 "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 47cbd4419f3..0e8eaf450e4 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -1037,6 +1037,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this, link_name, abi, args, dest,
                 );
             }
+            name if name.starts_with("llvm.x86.sse2.") => {
+                return shims::x86::sse2::EvalContextExt::emulate_x86_sse2_intrinsic(
+                    this, link_name, abi, args, dest,
+                );
+            }
 
             // Platform-specific shims
             _ =>
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index f6e76545a4d..62ce2ee58ae 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -159,8 +159,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
-        let (written, _) =
-            self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false).unwrap();
+        let (written, _) = self
+            .write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false)
+            .unwrap();
         assert!(written);
         Ok(arg_place.ptr())
     }
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 3524fd70bcf..0ee3cea05d5 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -112,17 +112,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Access to command-line arguments
             "_NSGetArgc" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.write_pointer(
-                    this.machine.argc.expect("machine must be initialized"),
-                    dest,
-                )?;
+                this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
             }
             "_NSGetArgv" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.write_pointer(
-                    this.machine.argv.expect("machine must be initialized"),
-                    dest,
-                )?;
+                this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
             }
             "_NSGetExecutablePath" => {
                 let [buf, bufsize] =
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 36e673129de..62f5eb1baf7 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1 +1,45 @@
+use crate::InterpResult;
+
 pub(super) mod sse;
+pub(super) mod sse2;
+
+/// Floating point comparison operation
+///
+/// <https://www.felixcloutier.com/x86/cmpss>
+/// <https://www.felixcloutier.com/x86/cmpps>
+/// <https://www.felixcloutier.com/x86/cmpsd>
+/// <https://www.felixcloutier.com/x86/cmppd>
+#[derive(Copy, Clone)]
+enum FloatCmpOp {
+    Eq,
+    Lt,
+    Le,
+    Unord,
+    Neq,
+    /// Not less-than
+    Nlt,
+    /// Not less-or-equal
+    Nle,
+    /// Ordered, i.e. neither of them is NaN
+    Ord,
+}
+
+impl FloatCmpOp {
+    /// Convert from the `imm` argument used to specify the comparison
+    /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
+    fn from_intrinsic_imm(imm: i8, intrinsic: &str) -> InterpResult<'_, Self> {
+        match imm {
+            0 => Ok(Self::Eq),
+            1 => Ok(Self::Lt),
+            2 => Ok(Self::Le),
+            3 => Ok(Self::Unord),
+            4 => Ok(Self::Neq),
+            5 => Ok(Self::Nlt),
+            6 => Ok(Self::Nle),
+            7 => Ok(Self::Ord),
+            imm => {
+                throw_unsup_format!("invalid `imm` parameter of {intrinsic}: {imm}");
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index b18441bb408..ff4bd369706 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -5,6 +5,7 @@ use rustc_target::spec::abi::Abi;
 
 use rand::Rng as _;
 
+use super::FloatCmpOp;
 use crate::*;
 use shims::foreign_items::EmulateByNameResult;
 
@@ -78,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 unary_op_ss(this, which, op, dest)?;
             }
-            // Used to implement _mm_{sqrt,rcp,rsqrt}_ss functions.
+            // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
             // Performs the operations on all components of `op`.
             "sqrt.ps" | "rcp.ps" | "rsqrt.ps" => {
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -100,22 +101,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [left, right, imm] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = match this.read_scalar(imm)?.to_i8()? {
-                    0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
-                    1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
-                    2 => FloatBinOp::Cmp(FloatCmpOp::Le),
-                    3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
-                    4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
-                    5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
-                    6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
-                    7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
-                    imm => {
-                        throw_unsup_format!(
-                            "invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
-                            imm
-                        );
-                    }
-                };
+                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
+                    this.read_scalar(imm)?.to_i8()?,
+                    "llvm.x86.sse.cmp.ss",
+                )?);
 
                 bin_op_ss(this, which, left, right, dest)?;
             }
@@ -127,26 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [left, right, imm] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = match this.read_scalar(imm)?.to_i8()? {
-                    0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
-                    1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
-                    2 => FloatBinOp::Cmp(FloatCmpOp::Le),
-                    3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
-                    4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
-                    5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
-                    6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
-                    7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
-                    imm => {
-                        throw_unsup_format!(
-                            "invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
-                            imm
-                        );
-                    }
-                };
+                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
+                    this.read_scalar(imm)?.to_i8()?,
+                    "llvm.x86.sse.cmp.ps",
+                )?);
 
                 bin_op_ps(this, which, left, right, dest)?;
             }
-            // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ps functions.
+            // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ss functions.
             // Compares the first component of `left` and `right` and returns
             // a scalar value (0 or 1).
             "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
@@ -292,6 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let op = this.read_scalar(&this.project_index(&op, i)?)?;
                     let op = op.to_u32()?;
 
+                    // Extract the highest bit of `op` and place it in the `i`-th bit of `res`
                     res |= (op >> 31) << i;
                 }
 
@@ -303,25 +281,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     }
 }
 
-/// Floating point comparison operation
-///
-/// <https://www.felixcloutier.com/x86/cmpss>
-/// <https://www.felixcloutier.com/x86/cmpps>
-#[derive(Copy, Clone)]
-enum FloatCmpOp {
-    Eq,
-    Lt,
-    Le,
-    Unord,
-    Neq,
-    /// Not less-than
-    Nlt,
-    /// Not less-or-equal
-    Nle,
-    /// Ordered, i.e. neither of them is NaN
-    Ord,
-}
-
 #[derive(Copy, Clone)]
 enum FloatBinOp {
     /// Arithmetic operation
@@ -436,8 +395,8 @@ fn bin_op_ss<'tcx>(
     Ok(())
 }
 
-/// Performs `which` operation on each component of `left`, and
-/// `right` storing the result is stored in `dest`.
+/// Performs `which` operation on each component of `left` and
+/// `right`, storing the result is stored in `dest`.
 fn bin_op_ps<'tcx>(
     this: &mut crate::MiriInterpCx<'_, 'tcx>,
     which: FloatBinOp,
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
new file mode 100644
index 00000000000..5b42339e648
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -0,0 +1,982 @@
+use rustc_apfloat::{
+    ieee::{Double, Single},
+    Float as _, FloatConvert as _,
+};
+use rustc_middle::ty::layout::LayoutOf as _;
+use rustc_middle::ty::Ty;
+use rustc_span::Symbol;
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use super::FloatCmpOp;
+use crate::*;
+use shims::foreign_items::EmulateByNameResult;
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn emulate_x86_sse2_intrinsic(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx, Provenance>],
+        dest: &PlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
+        let this = self.eval_context_mut();
+        // Prefix should have already been checked.
+        let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap();
+
+        // These intrinsics operate on 128-bit (f32x4, f64x2, i8x16, i16x8, i32x4, i64x2) SIMD
+        // vectors unless stated otherwise.
+        // Many intrinsic names are sufixed with "ps" (packed single), "ss" (scalar signle),
+        // "pd" (packed double) or "sd" (scalar double), where single means single precision
+        // floating point (f32) and double means double precision floating point (f64). "ps"
+        // and "pd" means thet the operation is performed on each element of the vector, while
+        // "ss" and "sd" means that the operation is performed only on the first element, copying
+        // the remaining elements from the input vector (for binary operations, from the left-hand
+        // side).
+        // Intrinsincs sufixed with "epiX" or "epuX" operate with X-bit signed or unsigned
+        // vectors.
+        match unprefixed_name {
+            // Used to implement the _mm_avg_epu8 function.
+            // Averages packed unsigned 8-bit integers in `left` and `right`.
+            "pavg.b" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u8()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // Values are expanded from u8 to u16, so adds cannot overflow.
+                    let res = u16::from(left)
+                        .checked_add(u16::from(right))
+                        .unwrap()
+                        .checked_add(1)
+                        .unwrap()
+                        / 2;
+                    this.write_scalar(Scalar::from_u8(res.try_into().unwrap()), &dest)?;
+                }
+            }
+            // Used to implement the _mm_avg_epu16 function.
+            // Averages packed unsigned 16-bit integers in `left` and `right`.
+            "pavg.w" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // Values are expanded from u16 to u32, so adds cannot overflow.
+                    let res = u32::from(left)
+                        .checked_add(u32::from(right))
+                        .unwrap()
+                        .checked_add(1)
+                        .unwrap()
+                        / 2;
+                    this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
+                }
+            }
+            // Used to implement the _mm_mulhi_epi16 function.
+            "pmulh.w" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // Values are expanded from i16 to i32, so multiplication cannot overflow.
+                    let res = i32::from(left).checked_mul(i32::from(right)).unwrap() >> 16;
+                    this.write_scalar(Scalar::from_int(res, Size::from_bits(16)), &dest)?;
+                }
+            }
+            // Used to implement the _mm_mulhi_epu16 function.
+            "pmulhu.w" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // Values are expanded from u16 to u32, so multiplication cannot overflow.
+                    let res = u32::from(left).checked_mul(u32::from(right)).unwrap() >> 16;
+                    this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
+                }
+            }
+            // Used to implement the _mm_mul_epu32 function.
+            // Multiplies the the low unsigned 32-bit integers from each packed
+            // 64-bit element and stores the result as 64-bit unsigned integers.
+            "pmulu.dq" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // left and right are u32x4, dest is u64x2
+                assert_eq!(left_len, 4);
+                assert_eq!(right_len, 4);
+                assert_eq!(dest_len, 2);
+
+                for i in 0..dest_len {
+                    let op_i = i.checked_mul(2).unwrap();
+                    let left = this.read_scalar(&this.project_index(&left, op_i)?)?.to_u32()?;
+                    let right = this.read_scalar(&this.project_index(&right, op_i)?)?.to_u32()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // The multiplication will not overflow because stripping the
+                    // operands are expanded from 32-bit to 64-bit.
+                    let res = u64::from(left).checked_mul(u64::from(right)).unwrap();
+                    this.write_scalar(Scalar::from_u64(res), &dest)?;
+                }
+            }
+            // Used to implement the _mm_sad_epu8 function.
+            // Computes the absolute differences of packed unsigned 8-bit integers in `a`
+            // and `b`, then horizontally sum each consecutive 8 differences to produce
+            // two unsigned 16-bit integers, and pack these unsigned 16-bit integers in
+            // the low 16 bits of 64-bit elements returned.
+            //
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8
+            "psad.bw" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // left and right are u8x16, dest is u64x2
+                assert_eq!(left_len, right_len);
+                assert_eq!(left_len, 16);
+                assert_eq!(dest_len, 2);
+
+                for i in 0..dest_len {
+                    let dest = this.project_index(&dest, i)?;
+
+                    let mut res: u16 = 0;
+                    let n = left_len.checked_div(dest_len).unwrap();
+                    for j in 0..n {
+                        let op_i = j.checked_add(i.checked_mul(n).unwrap()).unwrap();
+                        let left = this.read_scalar(&this.project_index(&left, op_i)?)?.to_u8()?;
+                        let right =
+                            this.read_scalar(&this.project_index(&right, op_i)?)?.to_u8()?;
+
+                        res = res.checked_add(left.abs_diff(right).into()).unwrap();
+                    }
+
+                    this.write_scalar(Scalar::from_u64(res.into()), &dest)?;
+                }
+            }
+            // Used to implement the _mm_{sll,srl,sra}_epi16 functions.
+            // Shifts 16-bit packed integers in left by the amount in right.
+            // Both operands are vectors of 16-bit integers. However, right is
+            // interpreted as a single 64-bit integer (remaining bits are ignored).
+            // For logic shifts, when right is larger than 15, zero is produced.
+            // For arithmetic shifts, when right is larger than 15, the sign bit
+            // is copied to remaining bits.
+            "psll.w" | "psrl.w" | "psra.w" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                enum ShiftOp {
+                    Sll,
+                    Srl,
+                    Sra,
+                }
+                let which = match unprefixed_name {
+                    "psll.w" => ShiftOp::Sll,
+                    "psrl.w" => ShiftOp::Srl,
+                    "psra.w" => ShiftOp::Sra,
+                    _ => unreachable!(),
+                };
+
+                // Get the 64-bit shift operand and convert it to the type expected
+                // by checked_{shl,shr} (u32).
+                // It is ok to saturate the value to u32::MAX because any value
+                // above 15 will produce the same result.
+                let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = match which {
+                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
+                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
+                        #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
+                        ShiftOp::Sra => {
+                            // Convert u16 to i16 to use arithmetic shift
+                            let left = left as i16;
+                            // Copy the sign bit to the remaining bits
+                            left.checked_shr(shift).unwrap_or(left >> 15) as u16
+                        }
+                    };
+
+                    this.write_scalar(Scalar::from_u16(res), &dest)?;
+                }
+            }
+            // Used to implement the _mm_{sll,srl,sra}_epi32 functions.
+            // 32-bit equivalent to the shift functions above.
+            "psll.d" | "psrl.d" | "psra.d" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                enum ShiftOp {
+                    Sll,
+                    Srl,
+                    Sra,
+                }
+                let which = match unprefixed_name {
+                    "psll.d" => ShiftOp::Sll,
+                    "psrl.d" => ShiftOp::Srl,
+                    "psra.d" => ShiftOp::Sra,
+                    _ => unreachable!(),
+                };
+
+                // Get the 64-bit shift operand and convert it to the type expected
+                // by checked_{shl,shr} (u32).
+                // It is ok to saturate the value to u32::MAX because any value
+                // above 31 will produce the same result.
+                let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u32()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = match which {
+                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
+                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
+                        #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
+                        ShiftOp::Sra => {
+                            // Convert u32 to i32 to use arithmetic shift
+                            let left = left as i32;
+                            // Copy the sign bit to the remaining bits
+                            left.checked_shr(shift).unwrap_or(left >> 31) as u32
+                        }
+                    };
+
+                    this.write_scalar(Scalar::from_u32(res), &dest)?;
+                }
+            }
+            // Used to implement the _mm_{sll,srl}_epi64 functions.
+            // 64-bit equivalent to the shift functions above, except _mm_sra_epi64,
+            // which is not available in SSE2.
+            "psll.q" | "psrl.q" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+                assert_eq!(dest_len, right_len);
+
+                enum ShiftOp {
+                    Sll,
+                    Srl,
+                }
+                let which = match unprefixed_name {
+                    "psll.q" => ShiftOp::Sll,
+                    "psrl.q" => ShiftOp::Srl,
+                    _ => unreachable!(),
+                };
+
+                // Get the 64-bit shift operand and convert it to the type expected
+                // by checked_{shl,shr} (u32).
+                // It is ok to saturate the value to u32::MAX because any value
+                // above 63 will produce the same result.
+                let shift = this
+                    .read_scalar(&this.project_index(&right, 0)?)?
+                    .to_u64()?
+                    .try_into()
+                    .unwrap_or(u32::MAX);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u64()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = match which {
+                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
+                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
+                    };
+
+                    this.write_scalar(Scalar::from_u64(res), &dest)?;
+                }
+            }
+            // Used to implement the _mm_cvtepi32_ps function.
+            // Converts packed i32 to packed f32.
+            // FIXME: Can we get rid of this intrinsic and just use simd_as?
+            "cvtdq2ps" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, op_len);
+
+                for i in 0..dest_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_i32()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = Scalar::from_f32(Single::from_i128(op.into()).value);
+                    this.write_scalar(res, &dest)?;
+                }
+            }
+            // Used to implement the _mm_cvtps_epi32 and _mm_cvttps_epi32 functions.
+            // Converts packed f32 to packed i32.
+            "cvtps2dq" | "cvttps2dq" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, op_len);
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtps2dq
+                    "cvtps2dq" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttps2dq
+                    "cvttps2dq" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                for i in 0..dest_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f32()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res =
+                        this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                            // Fallback to minimum acording to SSE2 semantics.
+                            Scalar::from_i32(i32::MIN)
+                        });
+                    this.write_scalar(res, &dest)?;
+                }
+            }
+            // Used to implement the _mm_packs_epi16 function.
+            // Converts two 16-bit integer vectors to a single 8-bit integer
+            // vector with signed saturation.
+            "packsswb.128" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // left and right are i16x8, dest is i8x16
+                assert_eq!(left_len, 8);
+                assert_eq!(right_len, 8);
+                assert_eq!(dest_len, 16);
+
+                for i in 0..left_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
+                    let left_dest = this.project_index(&dest, i)?;
+                    let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?;
+
+                    let left_res =
+                        i8::try_from(left).unwrap_or(if left < 0 { i8::MIN } else { i8::MAX });
+                    let right_res =
+                        i8::try_from(right).unwrap_or(if right < 0 { i8::MIN } else { i8::MAX });
+
+                    this.write_scalar(Scalar::from_int(left_res, Size::from_bits(8)), &left_dest)?;
+                    this.write_scalar(
+                        Scalar::from_int(right_res, Size::from_bits(8)),
+                        &right_dest,
+                    )?;
+                }
+            }
+            // Used to implement the _mm_packus_epi16 function.
+            // Converts two 16-bit signed integer vectors to a single 8-bit
+            // unsigned integer vector with saturation.
+            "packuswb.128" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // left and right are i16x8, dest is u8x16
+                assert_eq!(left_len, 8);
+                assert_eq!(right_len, 8);
+                assert_eq!(dest_len, 16);
+
+                for i in 0..left_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
+                    let left_dest = this.project_index(&dest, i)?;
+                    let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?;
+
+                    let left_res = u8::try_from(left).unwrap_or(if left < 0 { 0 } else { u8::MAX });
+                    let right_res =
+                        u8::try_from(right).unwrap_or(if right < 0 { 0 } else { u8::MAX });
+
+                    this.write_scalar(Scalar::from_u8(left_res), &left_dest)?;
+                    this.write_scalar(Scalar::from_u8(right_res), &right_dest)?;
+                }
+            }
+            // Used to implement the _mm_packs_epi32 function.
+            // Converts two 16-bit integer vectors to a single 8-bit integer
+            // vector with signed saturation.
+            "packssdw.128" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // left and right are i32x4, dest is i16x8
+                assert_eq!(left_len, 4);
+                assert_eq!(right_len, 4);
+                assert_eq!(dest_len, 8);
+
+                for i in 0..left_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i32()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i32()?;
+                    let left_dest = this.project_index(&dest, i)?;
+                    let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?;
+
+                    let left_res =
+                        i16::try_from(left).unwrap_or(if left < 0 { i16::MIN } else { i16::MAX });
+                    let right_res =
+                        i16::try_from(right).unwrap_or(if right < 0 { i16::MIN } else { i16::MAX });
+
+                    this.write_scalar(Scalar::from_int(left_res, Size::from_bits(16)), &left_dest)?;
+                    this.write_scalar(
+                        Scalar::from_int(right_res, Size::from_bits(16)),
+                        &right_dest,
+                    )?;
+                }
+            }
+            // Used to implement _mm_min_sd and _mm_max_sd functions.
+            // Note that the semantics are a bit different from Rust simd_min
+            // and simd_max intrinsics regarding handling of NaN and -0.0: Rust
+            // matches the IEEE min/max operations, while x86 has different
+            // semantics.
+            "min.sd" | "max.sd" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "min.sd" => FloatBinOp::Min,
+                    "max.sd" => FloatBinOp::Max,
+                    _ => unreachable!(),
+                };
+
+                bin_op_sd(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_min_pd and _mm_max_pd functions.
+            // Note that the semantics are a bit different from Rust simd_min
+            // and simd_max intrinsics regarding handling of NaN and -0.0: Rust
+            // matches the IEEE min/max operations, while x86 has different
+            // semantics.
+            "min.pd" | "max.pd" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "min.pd" => FloatBinOp::Min,
+                    "max.pd" => FloatBinOp::Max,
+                    _ => unreachable!(),
+                };
+
+                bin_op_pd(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_sqrt_sd functions.
+            // Performs the operations on the first component of `op` and
+            // copies the remaining components from `op`.
+            "sqrt.sd" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, op_len);
+
+                let op0 = this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()?;
+                // FIXME using host floats
+                let res0 = Scalar::from_u64(f64::from_bits(op0).sqrt().to_bits());
+                this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+                for i in 1..dest_len {
+                    this.copy_op(
+                        &this.project_index(&op, i)?,
+                        &this.project_index(&dest, i)?,
+                        /*allow_transmute*/ false,
+                    )?;
+                }
+            }
+            // Used to implement _mm_sqrt_pd functions.
+            // Performs the operations on all components of `op`.
+            "sqrt.pd" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, op_len);
+
+                for i in 0..dest_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_u64()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    // FIXME using host floats
+                    let res = Scalar::from_u64(f64::from_bits(op).sqrt().to_bits());
+
+                    this.write_scalar(res, &dest)?;
+                }
+            }
+            // Used to implement the _mm_cmp*_sd function.
+            // Performs a comparison operation on the first component of `left`
+            // and `right`, returning 0 if false or `u64::MAX` if true. The remaining
+            // components are copied from `left`.
+            "cmp.sd" => {
+                let [left, right, imm] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
+                    this.read_scalar(imm)?.to_i8()?,
+                    "llvm.x86.sse2.cmp.sd",
+                )?);
+
+                bin_op_sd(this, which, left, right, dest)?;
+            }
+            // Used to implement the _mm_cmp*_pd functions.
+            // Performs a comparison operation on each component of `left`
+            // and `right`. For each component, returns 0 if false or `u64::MAX`
+            // if true.
+            "cmp.pd" => {
+                let [left, right, imm] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
+                    this.read_scalar(imm)?.to_i8()?,
+                    "llvm.x86.sse2.cmp.pd",
+                )?);
+
+                bin_op_pd(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_sd functions.
+            // Compares the first component of `left` and `right` and returns
+            // a scalar value (0 or 1).
+            "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd"
+            | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd"
+            | "ucomineq.sd" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+
+                assert_eq!(left_len, right_len);
+
+                let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f64()?;
+                let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f64()?;
+                // The difference between the com* and *ucom variants is signaling
+                // of exceptions when either argument is a quiet NaN. We do not
+                // support accessing the SSE status register from miri (or from Rust,
+                // for that matter), so we treat equally both variants.
+                let res = match unprefixed_name {
+                    "comieq.sd" | "ucomieq.sd" => left == right,
+                    "comilt.sd" | "ucomilt.sd" => left < right,
+                    "comile.sd" | "ucomile.sd" => left <= right,
+                    "comigt.sd" | "ucomigt.sd" => left > right,
+                    "comige.sd" | "ucomige.sd" => left >= right,
+                    "comineq.sd" | "ucomineq.sd" => left != right,
+                    _ => unreachable!(),
+                };
+                this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
+            }
+            // Used to implement the _mm_cvtpd_ps function.
+            // Converts packed f32 to packed f64.
+            "cvtpd2ps" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // op is f64x2, dest is f32x4
+                assert_eq!(op_len, 2);
+                assert_eq!(dest_len, 4);
+
+                for i in 0..op_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f64()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = op.convert(/*loses_info*/ &mut false).value;
+                    this.write_scalar(Scalar::from_f32(res), &dest)?;
+                }
+                // Fill the remaining with zeros
+                for i in op_len..dest_len {
+                    let dest = this.project_index(&dest, i)?;
+                    this.write_scalar(Scalar::from_u32(0), &dest)?;
+                }
+            }
+            // Used to implement the _mm_cvtps_pd function.
+            // Converts packed f64 to packed f32.
+            "cvtps2pd" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // op is f32x4, dest is f64x2
+                assert_eq!(op_len, 4);
+                assert_eq!(dest_len, 2);
+
+                for i in 0..dest_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f32()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res = op.convert(/*loses_info*/ &mut false).value;
+                    this.write_scalar(Scalar::from_f64(res), &dest)?;
+                }
+                // the two remaining f32 are ignored
+            }
+            // Used to implement the _mm_cvtpd_epi32 and _mm_cvttpd_epi32 functions.
+            // Converts packed f64 to packed i32.
+            "cvtpd2dq" | "cvttpd2dq" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                // op is f64x2, dest is i32x4
+                assert_eq!(op_len, 2);
+                assert_eq!(dest_len, 4);
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtpd2dq
+                    "cvtpd2dq" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttpd2dq
+                    "cvttpd2dq" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                for i in 0..op_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f64()?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    let res =
+                        this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                            // Fallback to minimum acording to SSE2 semantics.
+                            Scalar::from_i32(i32::MIN)
+                        });
+                    this.write_scalar(res, &dest)?;
+                }
+                // Fill the remaining with zeros
+                for i in op_len..dest_len {
+                    let dest = this.project_index(&dest, i)?;
+                    this.write_scalar(Scalar::from_i32(0), &dest)?;
+                }
+            }
+            // Use to implement the _mm_cvtsd_si32 and _mm_cvttsd_si32 functions.
+            // Converts the first component of `op` from f64 to i32.
+            "cvtsd2si" | "cvttsd2si" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, _) = this.operand_to_simd(op)?;
+
+                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f64()?;
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtsd2si
+                    "cvtsd2si" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttsd2si
+                    "cvttsd2si" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                    // Fallback to minimum acording to SSE semantics.
+                    Scalar::from_i32(i32::MIN)
+                });
+
+                this.write_scalar(res, dest)?;
+            }
+            // Use to implement the _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
+            // Converts the first component of `op` from f64 to i64.
+            "cvtsd2si64" | "cvttsd2si64" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, _) = this.operand_to_simd(op)?;
+
+                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f64()?;
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtsd2si
+                    "cvtsd2si64" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttsd2si
+                    "cvttsd2si64" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                    // Fallback to minimum acording to SSE semantics.
+                    Scalar::from_i64(i64::MIN)
+                });
+
+                this.write_scalar(res, dest)?;
+            }
+            // Used to implement the _mm_cvtsd_ss and _mm_cvtss_sd functions.
+            // Converts the first f64/f32 from `right` to f32/f64 and copies
+            // the remaining elements from `left`
+            "cvtsd2ss" | "cvtss2sd" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, _) = this.operand_to_simd(right)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+
+                // Convert first element of `right`
+                let right0 = this.read_immediate(&this.project_index(&right, 0)?)?;
+                let dest0 = this.project_index(&dest, 0)?;
+                // `float_to_float_or_int` here will convert from f64 to f32 (cvtsd2ss) or
+                // from f32 to f64 (cvtss2sd).
+                let res0 = this.float_to_float_or_int(&right0, dest0.layout.ty)?;
+                this.write_immediate(res0, &dest0)?;
+
+                // Copy remianing from `left`
+                for i in 1..dest_len {
+                    this.copy_op(
+                        &this.project_index(&left, i)?,
+                        &this.project_index(&dest, i)?,
+                        /*allow_transmute*/ false,
+                    )?;
+                }
+            }
+            // Used to implement the _mm_movemask_pd function.
+            // Returns a scalar integer where the i-th bit is the highest
+            // bit of the i-th component of `op`.
+            // https://www.felixcloutier.com/x86/movmskpd
+            "movmsk.pd" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, op_len) = this.operand_to_simd(op)?;
+
+                let mut res = 0;
+                for i in 0..op_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?;
+                    let op = op.to_u64()?;
+
+                    // Extract the highest bit of `op` and place it in the `i`-th bit of `res`
+                    res |= (op >> 63) << i;
+                }
+
+                this.write_scalar(Scalar::from_u32(res.try_into().unwrap()), dest)?;
+            }
+            _ => return Ok(EmulateByNameResult::NotSupported),
+        }
+        Ok(EmulateByNameResult::NeedsJumping)
+    }
+}
+
+/// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts
+/// the first value.
+fn extract_first_u64<'tcx>(
+    this: &crate::MiriInterpCx<'_, 'tcx>,
+    op: &MPlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, u64> {
+    // Transmute vector to `[u64; 2]`
+    let u64_array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?;
+    let op = op.transmute(u64_array_layout, this)?;
+
+    // Get the first u64 from the array
+    this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()
+}
+
+#[derive(Copy, Clone)]
+enum FloatBinOp {
+    /// Comparison
+    Cmp(FloatCmpOp),
+    /// Minimum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/minsd>
+    /// <https://www.felixcloutier.com/x86/minpd>
+    Min,
+    /// Maximum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/maxsd>
+    /// <https://www.felixcloutier.com/x86/maxpd>
+    Max,
+}
+
+/// Performs `which` scalar operation on `left` and `right` and returns
+/// the result.
+// FIXME make this generic over apfloat type to reduce code duplicaton with bin_op_f32
+fn bin_op_f64<'tcx>(
+    which: FloatBinOp,
+    left: &ImmTy<'tcx, Provenance>,
+    right: &ImmTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, Scalar<Provenance>> {
+    match which {
+        FloatBinOp::Cmp(which) => {
+            let left = left.to_scalar().to_f64()?;
+            let right = right.to_scalar().to_f64()?;
+            // FIXME: Make sure that these operations match the semantics of cmppd
+            let res = match which {
+                FloatCmpOp::Eq => left == right,
+                FloatCmpOp::Lt => left < right,
+                FloatCmpOp::Le => left <= right,
+                FloatCmpOp::Unord => left.is_nan() || right.is_nan(),
+                FloatCmpOp::Neq => left != right,
+                FloatCmpOp::Nlt => !(left < right),
+                FloatCmpOp::Nle => !(left <= right),
+                FloatCmpOp::Ord => !left.is_nan() && !right.is_nan(),
+            };
+            Ok(Scalar::from_u64(if res { u64::MAX } else { 0 }))
+        }
+        FloatBinOp::Min => {
+            let left = left.to_scalar().to_f64()?;
+            let right = right.to_scalar().to_f64()?;
+            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == Double::ZERO && right == Double::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left >= right
+            {
+                Ok(Scalar::from_f64(right))
+            } else {
+                Ok(Scalar::from_f64(left))
+            }
+        }
+        FloatBinOp::Max => {
+            let left = left.to_scalar().to_f64()?;
+            let right = right.to_scalar().to_f64()?;
+            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == Double::ZERO && right == Double::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left <= right
+            {
+                Ok(Scalar::from_f64(right))
+            } else {
+                Ok(Scalar::from_f64(left))
+            }
+        }
+    }
+}
+
+/// Performs `which` operation on the first component of `left` and `right`
+/// and copies the other components from `left`. The result is stored in `dest`.
+fn bin_op_sd<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    let res0 = bin_op_f64(
+        which,
+        &this.read_immediate(&this.project_index(&left, 0)?)?,
+        &this.read_immediate(&this.project_index(&right, 0)?)?,
+    )?;
+    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+    for i in 1..dest_len {
+        this.copy_op(
+            &this.project_index(&left, i)?,
+            &this.project_index(&dest, i)?,
+            /*allow_transmute*/ false,
+        )?;
+    }
+
+    Ok(())
+}
+
+/// Performs `which` operation on each component of `left` and
+/// `right`, storing the result is stored in `dest`.
+fn bin_op_pd<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    for i in 0..dest_len {
+        let left = this.read_immediate(&this.project_index(&left, i)?)?;
+        let right = this.read_immediate(&this.project_index(&right, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = bin_op_f64(which, &left, &right)?;
+        this.write_scalar(res, &dest)?;
+    }
+
+    Ok(())
+}
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
index 50d4228c111..d1ccaf89974 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
@@ -6,6 +6,8 @@ LL |     g(Default::default())
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
index a53126c733e..3875c2617bb 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
@@ -6,6 +6,8 @@ LL |     g(42)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
index 6eacfeece14..6d1bdfee007 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
@@ -6,6 +6,8 @@ LL |     g(&42 as *const i32)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
index eedc1235773..07d76c90e5e 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
@@ -6,6 +6,8 @@ LL |     g()
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
index bc500a90b77..7ac2bc2739f 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
@@ -6,6 +6,8 @@ LL |     g(42)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
index 7dcca1e85b8..e082eb9e3e3 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
@@ -6,6 +6,8 @@ LL |     g(Default::default())
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
index 08be29115ca..b24fe56cad6 100644
--- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs
+++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
@@ -1,10 +1,20 @@
 use std::mem;
 use std::num;
+use std::ptr;
+use std::rc::Rc;
 
 #[derive(Copy, Clone, Default)]
 struct Zst;
 
-fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+struct Wrapper<T>(T);
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+fn test_abi_compat<T: Clone, U: Clone>(t: T, u: U) {
     fn id<T>(x: T) -> T {
         x
     }
@@ -16,10 +26,10 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
     // in both directions.
     let f: fn(T) -> T = id;
     let f: fn(U) -> U = unsafe { std::mem::transmute(f) };
-    let _val = f(u);
+    let _val = f(u.clone());
     let f: fn(U) -> U = id;
     let f: fn(T) -> T = unsafe { std::mem::transmute(f) };
-    let _val = f(t);
+    let _val = f(t.clone());
 
     // And then we do the same for `extern "C"`.
     let f: extern "C" fn(T) -> T = id_c;
@@ -34,9 +44,6 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
 fn test_abi_newtype<T: Copy + Default>() {
     #[repr(transparent)]
     #[derive(Copy, Clone)]
-    struct Wrapper1<T>(T);
-    #[repr(transparent)]
-    #[derive(Copy, Clone)]
     struct Wrapper2<T>(T, ());
     #[repr(transparent)]
     #[derive(Copy, Clone)]
@@ -46,7 +53,7 @@ fn test_abi_newtype<T: Copy + Default>() {
     struct Wrapper3<T>(Zst, T, [u8; 0]);
 
     let t = T::default();
-    test_abi_compat(t, Wrapper1(t));
+    test_abi_compat(t, Wrapper(t));
     test_abi_compat(t, Wrapper2(t, ()));
     test_abi_compat(t, Wrapper2a((), t));
     test_abi_compat(t, Wrapper3(Zst, t, []));
@@ -54,23 +61,32 @@ fn test_abi_newtype<T: Copy + Default>() {
 }
 
 fn main() {
-    // Here we check:
-    // - u32 vs char is allowed
-    // - u32 vs NonZeroU32/Option<NonZeroU32> is allowed
-    // - reference vs raw pointer is allowed
-    // - references to things of the same size and alignment are allowed
-    // These are very basic tests that should work on all ABIs. However it is not clear that any of
-    // these would be stably guaranteed. Code that relies on this is equivalent to code that relies
-    // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields
-    // of a struct (even with `repr(C)`) will not always be accepted by Miri.
-    // Note that `bool` and `u8` are *not* compatible, at least on x86-64!
-    // One of them has `arg_ext: Zext`, the other does not.
-    // Similarly, `i32` and `u32` are not compatible on s390x due to different `arg_ext`.
-    test_abi_compat(0u32, 'x');
+    // Here we check some of the guaranteed ABI compatibilities:
+    // - Different integer types of the same size and sign.
+    if cfg!(target_pointer_width = "32") {
+        test_abi_compat(0usize, 0u32);
+        test_abi_compat(0isize, 0i32);
+    } else {
+        test_abi_compat(0usize, 0u64);
+        test_abi_compat(0isize, 0i64);
+    }
     test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
-    test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
+    // - Reference/pointer types with the same pointee.
     test_abi_compat(&0u32, &0u32 as *const u32);
+    test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32));
+    test_abi_compat(&(), ptr::NonNull::<()>::dangling());
+    // - Reference/pointer types with different but sized pointees.
     test_abi_compat(&0u32, &([true; 4], [0u32; 0]));
+    // - `fn` types
+    test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
+    // - 1-ZST
+    test_abi_compat((), [0u8; 0]);
+    // - Guaranteed null-pointer-optimizations.
+    test_abi_compat(&0u32 as *const u32, Some(&0u32));
+    test_abi_compat(main as fn(), Some(main as fn()));
+    test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
+    test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32)));
+    test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap())));
 
     // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible
     // with the wrapped field.
@@ -83,4 +99,11 @@ fn main() {
     test_abi_newtype::<[u32; 0]>();
     test_abi_newtype::<[u32; 2]>();
     test_abi_newtype::<[u32; 32]>();
+    test_abi_newtype::<Option<i32>>();
+    test_abi_newtype::<Option<num::NonZeroU32>>();
+
+    // Extra test for assumptions made by arbitrary-self-dyn-receivers.
+    let rc = Rc::new(0);
+    let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) };
+    test_abi_compat(rc, rc_ptr);
 }
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse.rs
index 677d7cc030e..9b1ded94b5d 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse.rs
@@ -1,5 +1,15 @@
-//@only-target-x86_64
-
+// Ignore everything except x86 and x86_64
+// Any additional target are added to CI should be ignored here
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
 use std::arch::x86_64::*;
 use std::f32::NAN;
 use std::mem::transmute;
@@ -987,6 +997,8 @@ unsafe fn test_sse() {
     }
     test_mm_cvtsi32_ss();
 
+    // Intrinsic only available on x86_64
+    #[cfg(target_arch = "x86_64")]
     #[target_feature(enable = "sse")]
     unsafe fn test_mm_cvtss_si64() {
         let inputs = &[
@@ -1007,8 +1019,11 @@ unsafe fn test_sse() {
             assert_eq!(e, r, "TestCase #{} _mm_cvtss_si64({:?}) = {}, expected: {}", i, x, r, e);
         }
     }
+    #[cfg(target_arch = "x86_64")]
     test_mm_cvtss_si64();
 
+    // Intrinsic only available on x86_64
+    #[cfg(target_arch = "x86_64")]
     #[target_feature(enable = "sse")]
     unsafe fn test_mm_cvttss_si64() {
         let inputs = &[
@@ -1032,8 +1047,11 @@ unsafe fn test_sse() {
             assert_eq!(e, r, "TestCase #{} _mm_cvttss_si64({:?}) = {}, expected: {}", i, x, r, e);
         }
     }
+    #[cfg(target_arch = "x86_64")]
     test_mm_cvttss_si64();
 
+    // Intrinsic only available on x86_64
+    #[cfg(target_arch = "x86_64")]
     #[target_feature(enable = "sse")]
     unsafe fn test_mm_cvtsi64_ss() {
         let inputs = &[
@@ -1053,6 +1071,7 @@ unsafe fn test_sse() {
             assert_eq_m128(e, r);
         }
     }
+    #[cfg(target_arch = "x86_64")]
     test_mm_cvtsi64_ss();
 
     #[target_feature(enable = "sse")]
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
new file mode 100644
index 00000000000..1b55a94783a
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
@@ -0,0 +1,828 @@
+// Ignore everything except x86 and x86_64
+// Any additional target are added to CI should be ignored here
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+use std::f64::NAN;
+use std::mem::transmute;
+
+fn main() {
+    assert!(is_x86_feature_detected!("sse2"));
+
+    unsafe {
+        test_sse2();
+    }
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i {
+    _mm_set_epi64x(b, a)
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_sse2() {
+    // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse2.rs
+
+    unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i {
+        _mm_set_epi64x(b, a)
+    }
+
+    #[track_caller]
+    #[target_feature(enable = "sse")]
+    unsafe fn assert_eq_m128(a: __m128, b: __m128) {
+        let r = _mm_cmpeq_ps(a, b);
+        if _mm_movemask_ps(r) != 0b1111 {
+            panic!("{:?} != {:?}", a, b);
+        }
+    }
+
+    #[track_caller]
+    #[target_feature(enable = "sse2")]
+    unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) {
+        assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b))
+    }
+
+    #[track_caller]
+    #[target_feature(enable = "sse2")]
+    unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
+        if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
+            panic!("{:?} != {:?}", a, b);
+        }
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_avg_epu8() {
+        let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9));
+        let r = _mm_avg_epu8(a, b);
+        assert_eq_m128i(r, _mm_set1_epi8(6));
+    }
+    test_mm_avg_epu8();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_avg_epu16() {
+        let (a, b) = (_mm_set1_epi16(3), _mm_set1_epi16(9));
+        let r = _mm_avg_epu16(a, b);
+        assert_eq_m128i(r, _mm_set1_epi16(6));
+    }
+    test_mm_avg_epu16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_mulhi_epi16() {
+        let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(-1001));
+        let r = _mm_mulhi_epi16(a, b);
+        assert_eq_m128i(r, _mm_set1_epi16(-16));
+    }
+    test_mm_mulhi_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_mulhi_epu16() {
+        let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(1001));
+        let r = _mm_mulhi_epu16(a, b);
+        assert_eq_m128i(r, _mm_set1_epi16(15));
+    }
+    test_mm_mulhi_epu16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_mul_epu32() {
+        let a = _mm_setr_epi64x(1_000_000_000, 1 << 34);
+        let b = _mm_setr_epi64x(1_000_000_000, 1 << 35);
+        let r = _mm_mul_epu32(a, b);
+        let e = _mm_setr_epi64x(1_000_000_000 * 1_000_000_000, 0);
+        assert_eq_m128i(r, e);
+    }
+    test_mm_mul_epu32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sad_epu8() {
+        #[rustfmt::skip]
+        let a = _mm_setr_epi8(
+            255u8 as i8, 254u8 as i8, 253u8 as i8, 252u8 as i8,
+            1, 2, 3, 4,
+            155u8 as i8, 154u8 as i8, 153u8 as i8, 152u8 as i8,
+            1, 2, 3, 4,
+        );
+        let b = _mm_setr_epi8(0, 0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2);
+        let r = _mm_sad_epu8(a, b);
+        let e = _mm_setr_epi64x(1020, 614);
+        assert_eq_m128i(r, e);
+    }
+    test_mm_sad_epu8();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sll_epi16() {
+        let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF);
+        let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(
+            r,
+            _mm_setr_epi16(0xCC0, -0xCC0, 0xDD0, -0xDD0, 0xEE0, -0xEE0, 0xFF0, -0xFF0),
+        );
+        let r = _mm_sll_epi16(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 16));
+        assert_eq_m128i(r, _mm_set1_epi16(0));
+        let r = _mm_sll_epi16(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi16(0));
+    }
+    test_mm_sll_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_srl_epi16() {
+        let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF);
+        let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_setr_epi16(0xC, 0xFF3, 0xD, 0xFF2, 0xE, 0xFF1, 0xF, 0xFF0));
+        let r = _mm_srl_epi16(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 16));
+        assert_eq_m128i(r, _mm_set1_epi16(0));
+        let r = _mm_srl_epi16(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi16(0));
+    }
+    test_mm_srl_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sra_epi16() {
+        let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF);
+        let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_setr_epi16(0xC, -0xD, 0xD, -0xE, 0xE, -0xF, 0xF, -0x10));
+        let r = _mm_sra_epi16(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 16));
+        assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1));
+        let r = _mm_sra_epi16(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1));
+    }
+    test_mm_sra_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sll_epi32() {
+        let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF);
+        let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_setr_epi32(0xEEEE0, -0xEEEE0, 0xFFFF0, -0xFFFF0));
+        let r = _mm_sll_epi32(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 32));
+        assert_eq_m128i(r, _mm_set1_epi32(0));
+        let r = _mm_sll_epi32(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi32(0));
+    }
+    test_mm_sll_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_srl_epi32() {
+        let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF);
+        let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_setr_epi32(0xEEE, 0xFFFF111, 0xFFF, 0xFFFF000));
+        let r = _mm_srl_epi32(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 32));
+        assert_eq_m128i(r, _mm_set1_epi32(0));
+        let r = _mm_srl_epi32(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi32(0));
+    }
+    test_mm_srl_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sra_epi32() {
+        let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF);
+        let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_setr_epi32(0xEEE, -0xEEF, 0xFFF, -0x1000));
+        let r = _mm_sra_epi32(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 32));
+        assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1));
+        let r = _mm_sra_epi32(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1));
+    }
+    test_mm_sra_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sll_epi64() {
+        let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF);
+        let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFFF0, -0xFFFFFFFF0));
+        let r = _mm_sll_epi64(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 64));
+        assert_eq_m128i(r, _mm_set1_epi64x(0));
+        let r = _mm_sll_epi64(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi64x(0));
+    }
+    test_mm_sll_epi64();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_srl_epi64() {
+        let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF);
+        let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 4));
+        assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFF, 0xFFFFFFFF0000000));
+        let r = _mm_srl_epi64(a, _mm_set_epi64x(4, 0));
+        assert_eq_m128i(r, a);
+        let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 64));
+        assert_eq_m128i(r, _mm_set1_epi64x(0));
+        let r = _mm_srl_epi64(a, _mm_set_epi64x(0, i64::MAX));
+        assert_eq_m128i(r, _mm_set1_epi64x(0));
+    }
+    test_mm_srl_epi64();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtepi32_ps() {
+        let a = _mm_setr_epi32(1, 2, 3, 4);
+        let r = _mm_cvtepi32_ps(a);
+        assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 3.0, 4.0));
+    }
+    test_mm_cvtepi32_ps();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtps_epi32() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let r = _mm_cvtps_epi32(a);
+        assert_eq_m128i(r, _mm_setr_epi32(1, 2, 3, 4));
+    }
+    test_mm_cvtps_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvttps_epi32() {
+        let a = _mm_setr_ps(-1.1, 2.2, -3.3, 6.6);
+        let r = _mm_cvttps_epi32(a);
+        assert_eq_m128i(r, _mm_setr_epi32(-1, 2, -3, 6));
+
+        let a = _mm_setr_ps(f32::NEG_INFINITY, f32::INFINITY, f32::MIN, f32::MAX);
+        let r = _mm_cvttps_epi32(a);
+        assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, i32::MIN, i32::MIN));
+    }
+    test_mm_cvttps_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_packs_epi16() {
+        let a = _mm_setr_epi16(0x80, -0x81, 0, 0, 0, 0, 0, 0);
+        let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -0x81, 0x80);
+        let r = _mm_packs_epi16(a, b);
+        assert_eq_m128i(
+            r,
+            _mm_setr_epi8(0x7F, -0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0x80, 0x7F),
+        );
+    }
+    test_mm_packs_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_packus_epi16() {
+        let a = _mm_setr_epi16(0x100, -1, 0, 0, 0, 0, 0, 0);
+        let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -1, 0x100);
+        let r = _mm_packus_epi16(a, b);
+        assert_eq_m128i(r, _mm_setr_epi8(!0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, !0));
+    }
+    test_mm_packus_epi16();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_packs_epi32() {
+        let a = _mm_setr_epi32(0x8000, -0x8001, 0, 0);
+        let b = _mm_setr_epi32(0, 0, -0x8001, 0x8000);
+        let r = _mm_packs_epi32(a, b);
+        assert_eq_m128i(r, _mm_setr_epi16(0x7FFF, -0x8000, 0, 0, 0, 0, -0x8000, 0x7FFF));
+    }
+    test_mm_packs_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_min_sd() {
+        let a = _mm_setr_pd(1.0, 2.0);
+        let b = _mm_setr_pd(5.0, 10.0);
+        let r = _mm_min_sd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(1.0, 2.0));
+    }
+    test_mm_min_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_min_pd() {
+        let a = _mm_setr_pd(-1.0, 5.0);
+        let b = _mm_setr_pd(-100.0, 20.0);
+        let r = _mm_min_pd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(-100.0, 5.0));
+
+        // `_mm_min_pd` can **not** be implemented using the `simd_min` rust intrinsic because
+        // the semantics of `simd_min` are different to those of `_mm_min_pd` regarding handling
+        // of `-0.0`.
+        let a = _mm_setr_pd(-0.0, 0.0);
+        let b = _mm_setr_pd(0.0, 0.0);
+        let r1: [u8; 16] = transmute(_mm_min_pd(a, b));
+        let r2: [u8; 16] = transmute(_mm_min_pd(b, a));
+        let a: [u8; 16] = transmute(a);
+        let b: [u8; 16] = transmute(b);
+        assert_eq!(r1, b);
+        assert_eq!(r2, a);
+        assert_ne!(a, b); // sanity check that -0.0 is actually present
+    }
+    test_mm_min_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_max_sd() {
+        let a = _mm_setr_pd(1.0, 2.0);
+        let b = _mm_setr_pd(5.0, 10.0);
+        let r = _mm_max_sd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(5.0, 2.0));
+    }
+    test_mm_max_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_max_pd() {
+        let a = _mm_setr_pd(-1.0, 5.0);
+        let b = _mm_setr_pd(-100.0, 20.0);
+        let r = _mm_max_pd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(-1.0, 20.0));
+
+        // `_mm_max_pd` can **not** be implemented using the `simd_max` rust intrinsic because
+        // the semantics of `simd_max` are different to those of `_mm_max_pd` regarding handling
+        // of `-0.0`.
+        let a = _mm_setr_pd(-0.0, 0.0);
+        let b = _mm_setr_pd(0.0, 0.0);
+        let r1: [u8; 16] = transmute(_mm_max_pd(a, b));
+        let r2: [u8; 16] = transmute(_mm_max_pd(b, a));
+        let a: [u8; 16] = transmute(a);
+        let b: [u8; 16] = transmute(b);
+        assert_eq!(r1, b);
+        assert_eq!(r2, a);
+        assert_ne!(a, b); // sanity check that -0.0 is actually present
+    }
+    test_mm_max_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sqrt_sd() {
+        let a = _mm_setr_pd(1.0, 2.0);
+        let b = _mm_setr_pd(5.0, 10.0);
+        let r = _mm_sqrt_sd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(5.0f64.sqrt(), 2.0));
+    }
+    test_mm_sqrt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_sqrt_pd() {
+        let r = _mm_sqrt_pd(_mm_setr_pd(1.0, 2.0));
+        assert_eq_m128d(r, _mm_setr_pd(1.0f64.sqrt(), 2.0f64.sqrt()));
+    }
+    test_mm_sqrt_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpeq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpeq_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpeq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmplt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmplt_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmplt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmple_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmple_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmple_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpgt_sd() {
+        let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpgt_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpgt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpge_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpge_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpge_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpord_sd() {
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpord_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpord_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpunord_sd() {
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpunord_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpunord_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpneq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(!0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpneq_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpneq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnlt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpnlt_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnlt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnle_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpnle_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnle_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpngt_sd() {
+        let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpngt_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpngt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnge_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, transmute(2.0f64));
+        let r = transmute::<_, __m128i>(_mm_cmpnge_sd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnge_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpeq_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpeq_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpeq_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmplt_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmplt_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmplt_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmple_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmple_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmple_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpgt_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpgt_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpgt_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpge_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(!0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpge_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpge_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpord_pd() {
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmpord_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpord_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpunord_pd() {
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(!0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpunord_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpunord_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpneq_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(!0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmpneq_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpneq_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnlt_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0));
+        let e = _mm_setr_epi64x(0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpnlt_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnlt_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnle_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, 0);
+        let r = transmute::<_, __m128i>(_mm_cmpnle_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnle_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpngt_pd() {
+        let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmpngt_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpngt_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cmpnge_pd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        let e = _mm_setr_epi64x(0, !0);
+        let r = transmute::<_, __m128i>(_mm_cmpnge_pd(a, b));
+        assert_eq_m128i(r, e);
+    }
+    test_mm_cmpnge_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comieq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comieq_sd(a, b) != 0);
+
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comieq_sd(a, b) == 0);
+    }
+    test_mm_comieq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comilt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comilt_sd(a, b) == 0);
+    }
+    test_mm_comilt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comile_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comile_sd(a, b) != 0);
+    }
+    test_mm_comile_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comigt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comigt_sd(a, b) == 0);
+    }
+    test_mm_comigt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comige_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comige_sd(a, b) != 0);
+    }
+    test_mm_comige_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_comineq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_comineq_sd(a, b) == 0);
+    }
+    test_mm_comineq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomieq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomieq_sd(a, b) != 0);
+
+        let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(NAN, 3.0));
+        assert!(_mm_ucomieq_sd(a, b) == 0);
+    }
+    test_mm_ucomieq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomilt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomilt_sd(a, b) == 0);
+    }
+    test_mm_ucomilt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomile_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomile_sd(a, b) != 0);
+    }
+    test_mm_ucomile_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomigt_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomigt_sd(a, b) == 0);
+    }
+    test_mm_ucomigt_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomige_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomige_sd(a, b) != 0);
+    }
+    test_mm_ucomige_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_ucomineq_sd() {
+        let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0));
+        assert!(_mm_ucomineq_sd(a, b) == 0);
+    }
+    test_mm_ucomineq_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtpd_ps() {
+        let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, 5.0));
+        assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, 0.0));
+
+        let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, -5.0));
+        assert_eq_m128(r, _mm_setr_ps(-1.0, -5.0, 0.0, 0.0));
+
+        let r = _mm_cvtpd_ps(_mm_setr_pd(f64::MAX, f64::MIN));
+        assert_eq_m128(r, _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0));
+
+        let r = _mm_cvtpd_ps(_mm_setr_pd(f32::MAX as f64, f32::MIN as f64));
+        assert_eq_m128(r, _mm_setr_ps(f32::MAX, f32::MIN, 0.0, 0.0));
+    }
+    test_mm_cvtpd_ps();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtps_pd() {
+        let r = _mm_cvtps_pd(_mm_setr_ps(-1.0, 2.0, -3.0, 5.0));
+        assert_eq_m128d(r, _mm_setr_pd(-1.0, 2.0));
+
+        let r = _mm_cvtps_pd(_mm_setr_ps(f32::MAX, f32::INFINITY, f32::NEG_INFINITY, f32::MIN));
+        assert_eq_m128d(r, _mm_setr_pd(f32::MAX as f64, f64::INFINITY));
+    }
+    test_mm_cvtps_pd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtpd_epi32() {
+        let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, 5.0));
+        assert_eq_m128i(r, _mm_setr_epi32(-1, 5, 0, 0));
+
+        let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, -5.0));
+        assert_eq_m128i(r, _mm_setr_epi32(-1, -5, 0, 0));
+
+        let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::MAX, f64::MIN));
+        assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0));
+
+        let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::INFINITY, f64::NEG_INFINITY));
+        assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0));
+
+        let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::NAN, f64::NAN));
+        assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0));
+    }
+    test_mm_cvtpd_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvttpd_epi32() {
+        let a = _mm_setr_pd(-1.1, 2.2);
+        let r = _mm_cvttpd_epi32(a);
+        assert_eq_m128i(r, _mm_setr_epi32(-1, 2, 0, 0));
+
+        let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN);
+        let r = _mm_cvttpd_epi32(a);
+        assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0));
+    }
+    test_mm_cvttpd_epi32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtsd_si32() {
+        let r = _mm_cvtsd_si32(_mm_setr_pd(-2.0, 5.0));
+        assert_eq!(r, -2);
+
+        let r = _mm_cvtsd_si32(_mm_setr_pd(f64::MAX, f64::MIN));
+        assert_eq!(r, i32::MIN);
+
+        let r = _mm_cvtsd_si32(_mm_setr_pd(f64::NAN, f64::NAN));
+        assert_eq!(r, i32::MIN);
+    }
+    test_mm_cvtsd_si32();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvttsd_si32() {
+        let a = _mm_setr_pd(-1.1, 2.2);
+        let r = _mm_cvttsd_si32(a);
+        assert_eq!(r, -1);
+
+        let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN);
+        let r = _mm_cvttsd_si32(a);
+        assert_eq!(r, i32::MIN);
+    }
+    test_mm_cvttsd_si32();
+
+    // Intrinsic only available on x86_64
+    #[cfg(target_arch = "x86_64")]
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtsd_si64() {
+        let r = _mm_cvtsd_si64(_mm_setr_pd(-2.0, 5.0));
+        assert_eq!(r, -2_i64);
+
+        let r = _mm_cvtsd_si64(_mm_setr_pd(f64::MAX, f64::MIN));
+        assert_eq!(r, i64::MIN);
+    }
+    #[cfg(target_arch = "x86_64")]
+    test_mm_cvtsd_si64();
+
+    // Intrinsic only available on x86_64
+    #[cfg(target_arch = "x86_64")]
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvttsd_si64() {
+        let a = _mm_setr_pd(-1.1, 2.2);
+        let r = _mm_cvttsd_si64(a);
+        assert_eq!(r, -1_i64);
+    }
+    #[cfg(target_arch = "x86_64")]
+    test_mm_cvttsd_si64();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtsd_ss() {
+        let a = _mm_setr_ps(-1.1, -2.2, 3.3, 4.4);
+        let b = _mm_setr_pd(2.0, -5.0);
+
+        let r = _mm_cvtsd_ss(a, b);
+
+        assert_eq_m128(r, _mm_setr_ps(2.0, -2.2, 3.3, 4.4));
+
+        let a = _mm_setr_ps(-1.1, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY);
+        let b = _mm_setr_pd(f64::INFINITY, -5.0);
+
+        let r = _mm_cvtsd_ss(a, b);
+
+        assert_eq_m128(
+            r,
+            _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY),
+        );
+    }
+    test_mm_cvtsd_ss();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_cvtss_sd() {
+        let a = _mm_setr_pd(-1.1, 2.2);
+        let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+
+        let r = _mm_cvtss_sd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(1.0, 2.2));
+
+        let a = _mm_setr_pd(-1.1, f64::INFINITY);
+        let b = _mm_setr_ps(f32::NEG_INFINITY, 2.0, 3.0, 4.0);
+
+        let r = _mm_cvtss_sd(a, b);
+        assert_eq_m128d(r, _mm_setr_pd(f64::NEG_INFINITY, f64::INFINITY));
+    }
+    test_mm_cvtss_sd();
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn test_mm_movemask_pd() {
+        let r = _mm_movemask_pd(_mm_setr_pd(-1.0, 5.0));
+        assert_eq!(r, 0b01);
+
+        let r = _mm_movemask_pd(_mm_setr_pd(-1.0, -5.0));
+        assert_eq!(r, 0b11);
+    }
+    test_mm_movemask_pd();
+}
diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml
index 21a154cafd4..69f3cd2f810 100644
--- a/src/tools/miri/triagebot.toml
+++ b/src/tools/miri/triagebot.toml
@@ -9,3 +9,6 @@ allow-unauthenticated = [
 
 # Gives us the commands 'ready', 'author', 'blocked'
 [shortcut]
+
+[no-merges]
+exclude_labels = ["rollup", "subtree-sync"]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index cead64a3374..9bd0c30b105 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -239,7 +239,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
         experimental!(no_sanitize)
     ),
-    gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
+    gated!(coverage, Normal, template!(Word, List: "on|off"), WarnFollowing, experimental!(coverage)),
 
     ungated!(
         doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 49b37024a5e..57563a17483 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -3505,8 +3505,8 @@ This serves two purposes:
 "##,
     },
     Lint {
-        label: "no_coverage",
-        description: r##"# `no_coverage`
+        label: "coverage",
+        description: r##"# `coverage`
 
 The tracking issue for this feature is: [#84605]
 
@@ -3514,7 +3514,7 @@ The tracking issue for this feature is: [#84605]
 
 ---
 
-The `no_coverage` attribute can be used to selectively disable coverage
+The `coverage` attribute can be used to selectively disable coverage
 instrumentation in an annotated function. This might be useful to:
 
 -   Avoid instrumentation overhead in a performance critical function
@@ -3524,14 +3524,14 @@ instrumentation in an annotated function. This might be useful to:
 ## Example
 
 ```rust
-#![feature(no_coverage)]
+#![feature(coverage)]
 
 // `foo()` will get coverage instrumentation (by default)
 fn foo() {
   // ...
 }
 
-#[no_coverage]
+#[coverage(off)]
 fn bar() {
   // ...
 }
diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs
new file mode 100644
index 00000000000..b1475ee7931
--- /dev/null
+++ b/tests/codegen/debuginfo-inline-callsite-location.rs
@@ -0,0 +1,28 @@
+// compile-flags: -g -O
+
+// Check that each inline call site for the same function uses the same "sub-program" so that LLVM
+// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail
+// calls to panic.
+
+// CHECK:       tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E
+// CHECK-SAME:  !dbg ![[#first_dbg:]]
+// CHECK:       tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E
+// CHECK-SAME:  !dbg ![[#second_dbg:]]
+
+// CHECK-DAG:   ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap<i32>"
+// CHECK-DAG:   ![[#first_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
+// CHECK:       ![[#second_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
+// CHECK:       ![[#first_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#first_scope]], inlinedAt: ![[#]])
+// CHECK:       ![[#second_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#second_scope]], inlinedAt: ![[#]])
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+extern "C" fn add_numbers(x: &Option<i32>, y: &Option<i32>) -> i32 {
+    let x1 = x.unwrap();
+    let y1 = y.unwrap();
+
+    x1 + y1
+}
diff --git a/tests/codegen/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
new file mode 100644
index 00000000000..142e3596d96
--- /dev/null
+++ b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
@@ -0,0 +1,46 @@
+// compile-flags: -O -Ccodegen-units=1
+
+#![crate_type = "lib"]
+
+#[repr(i64)]
+pub enum Boolean {
+    False = 0,
+    True = 1,
+}
+
+impl Clone for Boolean {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Copy for Boolean {}
+
+extern "C" {
+    fn set_value(foo: *mut i64);
+    fn bar();
+}
+
+pub fn foo(x: bool) {
+    let mut foo = core::mem::MaybeUninit::<i64>::uninit();
+    unsafe {
+        set_value(foo.as_mut_ptr());
+    }
+
+    if x {
+        let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
+        if matches!(l1, Boolean::False) {
+            unsafe {
+                *foo.as_mut_ptr() = 0;
+            }
+        }
+    }
+
+    let l2 = unsafe { *foo.as_mut_ptr() };
+    if l2 == 2 {
+        // CHECK: call void @bar
+        unsafe {
+            bar();
+        }
+    }
+}
diff --git a/tests/coverage-map/status-quo/closure_macro.rs b/tests/coverage-map/status-quo/closure_macro.rs
index 5e3b00d1ef5..9b289141c2e 100644
--- a/tests/coverage-map/status-quo/closure_macro.rs
+++ b/tests/coverage-map/status-quo/closure_macro.rs
@@ -1,5 +1,5 @@
 // compile-flags: --edition=2018
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 
 macro_rules! bail {
     ($msg:literal $(,)?) => {
diff --git a/tests/coverage-map/status-quo/closure_macro_async.rs b/tests/coverage-map/status-quo/closure_macro_async.rs
index 3d6bdb38a2a..b4275599e59 100644
--- a/tests/coverage-map/status-quo/closure_macro_async.rs
+++ b/tests/coverage-map/status-quo/closure_macro_async.rs
@@ -1,5 +1,5 @@
 // compile-flags: --edition=2018
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 
 macro_rules! bail {
     ($msg:literal $(,)?) => {
@@ -39,7 +39,7 @@ pub async fn test() -> Result<(), String> {
     Ok(())
 }
 
-#[no_coverage]
+#[coverage(off)]
 fn main() {
     executor::block_on(test()).unwrap();
 }
@@ -51,18 +51,18 @@ mod executor {
         task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
     };
 
-    #[no_coverage]
+    #[coverage(off)]
     pub fn block_on<F: Future>(mut future: F) -> F::Output {
         let mut future = unsafe { Pin::new_unchecked(&mut future) };
         use std::hint::unreachable_unchecked;
         static VTABLE: RawWakerVTable = RawWakerVTable::new(
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // clone
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // wake
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // wake_by_ref
-            #[no_coverage]
+            #[coverage(off)]
             |_| (),
         );
         let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
diff --git a/tests/coverage-map/status-quo/no_cov_crate.rs b/tests/coverage-map/status-quo/no_cov_crate.rs
index 5b748aeefb7..e12e4bc55e3 100644
--- a/tests/coverage-map/status-quo/no_cov_crate.rs
+++ b/tests/coverage-map/status-quo/no_cov_crate.rs
@@ -1,17 +1,17 @@
-// Enables `no_coverage` on the entire crate
-#![feature(no_coverage)]
+// Enables `coverage(off)` on the entire crate
+#![feature(coverage_attribute)]
 
-#[no_coverage]
+#[coverage(off)]
 fn do_not_add_coverage_1() {
     println!("called but not covered");
 }
 
 fn do_not_add_coverage_2() {
-    #![no_coverage]
+    #![coverage(off)]
     println!("called but not covered");
 }
 
-#[no_coverage]
+#[coverage(off)]
 #[allow(dead_code)]
 fn do_not_add_coverage_not_called() {
     println!("not called and not covered");
@@ -33,7 +33,7 @@ fn add_coverage_not_called() {
 // FIXME: These test-cases illustrate confusing results of nested functions.
 // See https://github.com/rust-lang/rust/issues/93319
 mod nested_fns {
-    #[no_coverage]
+    #[coverage(off)]
     pub fn outer_not_covered(is_true: bool) {
         fn inner(is_true: bool) {
             if is_true {
@@ -50,7 +50,7 @@ mod nested_fns {
         println!("called and covered");
         inner_not_covered(is_true);
 
-        #[no_coverage]
+        #[coverage(off)]
         fn inner_not_covered(is_true: bool) {
             if is_true {
                 println!("called but not covered");
diff --git a/tests/debuginfo/pretty-std-collections.rs b/tests/debuginfo/pretty-std-collections.rs
index 93597aa7e23..93a0dff6848 100644
--- a/tests/debuginfo/pretty-std-collections.rs
+++ b/tests/debuginfo/pretty-std-collections.rs
@@ -1,7 +1,6 @@
 // ignore-windows failing on win32 bot
 // ignore-freebsd: gdb package too new
 // ignore-android: FIXME(#10381)
-// ignore-macos: FIXME(#78665)
 // compile-flags:-g
 
 // The pretty printers being tested here require the patch from
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index 80ac92d59f3..b06666c9dd7 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -2,7 +2,14 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: impl std::future::Future<Output = ()>,
+            ty: Alias(
+                Opaque,
+                AliasTy {
+                    args: [
+                    ],
+                    def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}),
+                },
+            ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:15:9: 15:14 (#8),
                 scope: scope[0],
@@ -10,7 +17,14 @@
             ignore_for_traits: false,
         },
         _1: GeneratorSavedTy {
-            ty: impl std::future::Future<Output = ()>,
+            ty: Alias(
+                Opaque,
+                AliasTy {
+                    args: [
+                    ],
+                    def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}),
+                },
+            ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:16:9: 16:14 (#10),
                 scope: scope[0],
diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..07ac5b72e24
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff
@@ -0,0 +1,63 @@
+- // MIR for `constant` before DataflowConstProp
++ // MIR for `constant` after DataflowConstProp
+  
+  fn constant() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _3: isize;
+      scope 1 {
+          debug e => _1;
+          let _2: i32;
+          let _4: i32;
+          let _5: i32;
+          scope 2 {
+              debug x => _2;
+          }
+          scope 3 {
+              debug x => _4;
+          }
+          scope 4 {
+              debug x => _5;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const _;
+          StorageLive(_2);
+-         _3 = discriminant(_1);
+-         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _3 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = ((_1 as V2).0: i32);
+          _2 = _5;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+-         _4 = ((_1 as V1).0: i32);
+-         _2 = _4;
++         _4 = const 0_i32;
++         _2 = const 0_i32;
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          _0 = const ();
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..07ac5b72e24
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff
@@ -0,0 +1,63 @@
+- // MIR for `constant` before DataflowConstProp
++ // MIR for `constant` after DataflowConstProp
+  
+  fn constant() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _3: isize;
+      scope 1 {
+          debug e => _1;
+          let _2: i32;
+          let _4: i32;
+          let _5: i32;
+          scope 2 {
+              debug x => _2;
+          }
+          scope 3 {
+              debug x => _4;
+          }
+          scope 4 {
+              debug x => _5;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const _;
+          StorageLive(_2);
+-         _3 = discriminant(_1);
+-         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _3 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = ((_1 as V2).0: i32);
+          _2 = _5;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+-         _4 = ((_1 as V1).0: i32);
+-         _2 = _4;
++         _4 = const 0_i32;
++         _2 = const 0_i32;
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          _0 = const ();
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff
index 775325c4d06..775325c4d06 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff
diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..775325c4d06
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff
@@ -0,0 +1,82 @@
+- // MIR for `multiple` before DataflowConstProp
++ // MIR for `multiple` after DataflowConstProp
+  
+  fn multiple(_1: bool, _2: u8) -> () {
+      debug x => _1;
+      debug i => _2;
+      let mut _0: ();
+      let _3: std::option::Option<u8>;
+      let mut _4: bool;
+      let mut _5: u8;
+      let mut _7: isize;
+      scope 1 {
+          debug e => _3;
+          let _6: u8;
+          let _8: u8;
+          scope 2 {
+              debug x => _6;
+              let _9: u8;
+              scope 4 {
+                  debug y => _9;
+              }
+          }
+          scope 3 {
+              debug i => _8;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          switchInt(move _4) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = _2;
+          _3 = Option::<u8>::Some(move _5);
+          StorageDead(_5);
+          goto -> bb3;
+      }
+  
+      bb2: {
+          _3 = Option::<u8>::None;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_4);
+          StorageLive(_6);
+          _7 = discriminant(_3);
+          switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb5];
+      }
+  
+      bb4: {
+          _6 = const 0_u8;
+          goto -> bb7;
+      }
+  
+      bb5: {
+          unreachable;
+      }
+  
+      bb6: {
+          StorageLive(_8);
+          _8 = ((_3 as Some).0: u8);
+          _6 = _8;
+          StorageDead(_8);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          StorageLive(_9);
+          _9 = _6;
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_6);
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.32bit.diff
index 960e69ee916..960e69ee916 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.32bit.diff
diff --git a/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..960e69ee916
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.mutate_discriminant.DataflowConstProp.64bit.diff
@@ -0,0 +1,26 @@
+- // MIR for `mutate_discriminant` before DataflowConstProp
++ // MIR for `mutate_discriminant` after DataflowConstProp
+  
+  fn mutate_discriminant() -> u8 {
+      let mut _0: u8;
+      let mut _1: std::option::Option<NonZeroUsize>;
+      let mut _2: isize;
+  
+      bb0: {
+          discriminant(_1) = 1;
+          (((_1 as variant#1).0: NonZeroUsize).0: usize) = const 0_usize;
+          _2 = discriminant(_1);
+          switchInt(_2) -> [0: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          _0 = const 1_u8;
+          return;
+      }
+  
+      bb2: {
+          _0 = const 2_u8;
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs
index 79a20d7ef45..5a10e9e883d 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.rs
+++ b/tests/mir-opt/dataflow-const-prop/enum.rs
@@ -1,9 +1,11 @@
 // unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 #![feature(custom_mir, core_intrinsics, rustc_attrs)]
 
 use std::intrinsics::mir::*;
 
+#[derive(Copy, Clone)]
 enum E {
     V1(i32),
     V2(i32)
@@ -15,6 +17,24 @@ fn simple() {
     let x = match e { E::V1(x) => x, E::V2(x) => x };
 }
 
+// EMIT_MIR enum.constant.DataflowConstProp.diff
+fn constant() {
+    const C: E = E::V1(0);
+    let e = C;
+    let x = match e { E::V1(x) => x, E::V2(x) => x };
+}
+
+// EMIT_MIR enum.statics.DataflowConstProp.diff
+fn statics() {
+    static C: E = E::V1(0);
+    let e = C;
+    let x = match e { E::V1(x) => x, E::V2(x) => x };
+
+    static RC: &E = &E::V2(4);
+    let e = RC;
+    let x = match e { E::V1(x) => x, E::V2(x) => x };
+}
+
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
 struct NonZeroUsize(usize);
@@ -63,6 +83,8 @@ fn multiple(x: bool, i: u8) {
 
 fn main() {
     simple();
+    constant();
+    statics();
     mutate_discriminant();
     multiple(false, 5);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
index 3946e7c7d96..3946e7c7d96 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..3946e7c7d96
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
@@ -0,0 +1,63 @@
+- // MIR for `simple` before DataflowConstProp
++ // MIR for `simple` after DataflowConstProp
+  
+  fn simple() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _3: isize;
+      scope 1 {
+          debug e => _1;
+          let _2: i32;
+          let _4: i32;
+          let _5: i32;
+          scope 2 {
+              debug x => _2;
+          }
+          scope 3 {
+              debug x => _4;
+          }
+          scope 4 {
+              debug x => _5;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = E::V1(const 0_i32);
+          StorageLive(_2);
+-         _3 = discriminant(_1);
+-         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _3 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = ((_1 as V2).0: i32);
+          _2 = _5;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+-         _4 = ((_1 as V1).0: i32);
+-         _2 = _4;
++         _4 = const 0_i32;
++         _2 = const 0_i32;
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          _0 = const ();
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..ae8b44c953e
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
@@ -0,0 +1,126 @@
+- // MIR for `statics` before DataflowConstProp
++ // MIR for `statics` after DataflowConstProp
+  
+  fn statics() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _2: &E;
+      let mut _4: isize;
+      let mut _8: &&E;
+      let mut _10: isize;
+      scope 1 {
+          debug e => _1;
+          let _3: i32;
+          let _5: i32;
+          let _6: i32;
+          scope 2 {
+              debug x => _3;
+              let _7: &E;
+              scope 5 {
+                  debug e => _7;
+                  let _9: &i32;
+                  let _11: &i32;
+                  let _12: &i32;
+                  scope 6 {
+                      debug x => _9;
+                  }
+                  scope 7 {
+                      debug x => _11;
+                  }
+                  scope 8 {
+                      debug x => _12;
+                  }
+              }
+          }
+          scope 3 {
+              debug x => _5;
+          }
+          scope 4 {
+              debug x => _6;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = const {alloc1: &E};
+          _1 = (*_2);
+          StorageDead(_2);
+          StorageLive(_3);
+-         _4 = discriminant(_1);
+-         switchInt(move _4) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _4 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = ((_1 as V2).0: i32);
+          _3 = _6;
+          StorageDead(_6);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_5);
+-         _5 = ((_1 as V1).0: i32);
+-         _3 = _5;
++         _5 = const 0_i32;
++         _3 = const 0_i32;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = const {alloc2: &&E};
+          _7 = (*_8);
+          StorageDead(_8);
+          StorageLive(_9);
+          _10 = discriminant((*_7));
+          switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb2];
+      }
+  
+      bb5: {
+          StorageLive(_12);
+          _12 = &(((*_7) as V2).0: i32);
+          _9 = &(*_12);
+          StorageDead(_12);
+          goto -> bb7;
+      }
+  
+      bb6: {
+          StorageLive(_11);
+          _11 = &(((*_7) as V1).0: i32);
+          _9 = _11;
+          StorageDead(_11);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_7);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
+  alloc2 (static: RC, size: 4, align: 4) {
+      ╾─alloc14─╼                                     │ ╾──╼
+  }
+  
+  alloc14 (size: 8, align: 4) {
+      01 00 00 00 04 00 00 00                         │ ........
+  }
+  
+  alloc1 (static: statics::C, size: 8, align: 4) {
+      00 00 00 00 00 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..63799b3bac3
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
@@ -0,0 +1,126 @@
+- // MIR for `statics` before DataflowConstProp
++ // MIR for `statics` after DataflowConstProp
+  
+  fn statics() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _2: &E;
+      let mut _4: isize;
+      let mut _8: &&E;
+      let mut _10: isize;
+      scope 1 {
+          debug e => _1;
+          let _3: i32;
+          let _5: i32;
+          let _6: i32;
+          scope 2 {
+              debug x => _3;
+              let _7: &E;
+              scope 5 {
+                  debug e => _7;
+                  let _9: &i32;
+                  let _11: &i32;
+                  let _12: &i32;
+                  scope 6 {
+                      debug x => _9;
+                  }
+                  scope 7 {
+                      debug x => _11;
+                  }
+                  scope 8 {
+                      debug x => _12;
+                  }
+              }
+          }
+          scope 3 {
+              debug x => _5;
+          }
+          scope 4 {
+              debug x => _6;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = const {alloc1: &E};
+          _1 = (*_2);
+          StorageDead(_2);
+          StorageLive(_3);
+-         _4 = discriminant(_1);
+-         switchInt(move _4) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _4 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = ((_1 as V2).0: i32);
+          _3 = _6;
+          StorageDead(_6);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_5);
+-         _5 = ((_1 as V1).0: i32);
+-         _3 = _5;
++         _5 = const 0_i32;
++         _3 = const 0_i32;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = const {alloc2: &&E};
+          _7 = (*_8);
+          StorageDead(_8);
+          StorageLive(_9);
+          _10 = discriminant((*_7));
+          switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb2];
+      }
+  
+      bb5: {
+          StorageLive(_12);
+          _12 = &(((*_7) as V2).0: i32);
+          _9 = &(*_12);
+          StorageDead(_12);
+          goto -> bb7;
+      }
+  
+      bb6: {
+          StorageLive(_11);
+          _11 = &(((*_7) as V1).0: i32);
+          _9 = _11;
+          StorageDead(_11);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_7);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
+  alloc2 (static: RC, size: 8, align: 8) {
+      ╾───────alloc14───────╼                         │ ╾──────╼
+  }
+  
+  alloc14 (size: 8, align: 4) {
+      01 00 00 00 04 00 00 00                         │ ........
+  }
+  
+  alloc1 (static: statics::C, size: 8, align: 4) {
+      00 00 00 00 00 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
index be55d259dcf..e99b413f708 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
@@ -55,11 +55,12 @@
           _10 = const _;
           StorageLive(_11);
           _11 = const 1_usize;
-          _12 = Len((*_10));
+-         _12 = Len((*_10));
 -         _13 = Lt(_11, _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable];
-+         _13 = Lt(const 1_usize, _12);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
index f9a6c509ac8..759a793fbf3 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -55,11 +55,12 @@
           _10 = const _;
           StorageLive(_11);
           _11 = const 1_usize;
-          _12 = Len((*_10));
+-         _12 = Len((*_10));
 -         _13 = Lt(_11, _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue];
-+         _13 = Lt(const 1_usize, _12);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
index be55d259dcf..e99b413f708 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
@@ -55,11 +55,12 @@
           _10 = const _;
           StorageLive(_11);
           _11 = const 1_usize;
-          _12 = Len((*_10));
+-         _12 = Len((*_10));
 -         _13 = Lt(_11, _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable];
-+         _13 = Lt(const 1_usize, _12);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
index f9a6c509ac8..759a793fbf3 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -55,11 +55,12 @@
           _10 = const _;
           StorageLive(_11);
           _11 = const 1_usize;
-          _12 = Len((*_10));
+-         _12 = Len((*_10));
 -         _13 = Lt(_11, _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue];
-+         _13 = Lt(const 1_usize, _12);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..2de6ba307d5
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
@@ -0,0 +1,129 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: S;
+      let mut _3: i32;
+      let mut _5: i32;
+      let mut _6: i32;
+      let mut _11: BigStruct;
+      let mut _16: &&BigStruct;
+      let mut _17: &BigStruct;
+      let mut _18: &BigStruct;
+      let mut _19: &BigStruct;
+      let mut _20: &BigStruct;
+      let mut _21: &BigStruct;
+      scope 1 {
+          debug s => _1;
+          let _2: i32;
+          scope 2 {
+              debug a => _2;
+              let _4: i32;
+              scope 3 {
+                  debug b => _4;
+                  let _7: S;
+                  let _8: u8;
+                  let _9: f32;
+                  let _10: S;
+                  scope 4 {
+                      debug a => _7;
+                      debug b => _8;
+                      debug c => _9;
+                      debug d => _10;
+                      let _12: S;
+                      let _13: u8;
+                      let _14: f32;
+                      let _15: S;
+                      scope 5 {
+                          debug a => _12;
+                          debug b => _13;
+                          debug c => _14;
+                          debug d => _15;
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = S(const 1_i32);
+          StorageLive(_2);
+          StorageLive(_3);
+-         _3 = (_1.0: i32);
+-         _2 = Add(move _3, const 2_i32);
++         _3 = const 1_i32;
++         _2 = const 3_i32;
+          StorageDead(_3);
+          (_1.0: i32) = const 3_i32;
+          StorageLive(_4);
+          StorageLive(_5);
+-         _5 = _2;
++         _5 = const 3_i32;
+          StorageLive(_6);
+-         _6 = (_1.0: i32);
+-         _4 = Add(move _5, move _6);
++         _6 = const 3_i32;
++         _4 = const 6_i32;
+          StorageDead(_6);
+          StorageDead(_5);
+          StorageLive(_11);
+          _11 = const _;
+          StorageLive(_7);
+-         _7 = (_11.0: S);
++         _7 = const S(1_i32);
+          StorageLive(_8);
+-         _8 = (_11.1: u8);
++         _8 = const 5_u8;
+          StorageLive(_9);
+-         _9 = (_11.2: f32);
++         _9 = const 7f32;
+          StorageLive(_10);
+-         _10 = (_11.3: S);
++         _10 = const S(13_i32);
+          StorageDead(_11);
+          StorageLive(_16);
+          _16 = const {alloc1: &&BigStruct};
+          _17 = deref_copy (*_16);
+          StorageLive(_12);
+          _18 = deref_copy (*_16);
+-         _12 = ((*_18).0: S);
++         _12 = const S(1_i32);
+          StorageLive(_13);
+          _19 = deref_copy (*_16);
+-         _13 = ((*_19).1: u8);
++         _13 = const 5_u8;
+          StorageLive(_14);
+          _20 = deref_copy (*_16);
+-         _14 = ((*_20).2: f32);
++         _14 = const 7f32;
+          StorageLive(_15);
+          _21 = deref_copy (*_16);
+-         _15 = ((*_21).3: S);
++         _15 = const S(13_i32);
+          StorageDead(_16);
+          _0 = const ();
+          StorageDead(_15);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          StorageDead(_10);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
+  alloc1 (static: STAT, size: 4, align: 4) {
+      ╾─alloc15─╼                                     │ ╾──╼
+  }
+  
+  alloc15 (size: 16, align: 4) {
+      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..71a28f2165b
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
@@ -0,0 +1,129 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: S;
+      let mut _3: i32;
+      let mut _5: i32;
+      let mut _6: i32;
+      let mut _11: BigStruct;
+      let mut _16: &&BigStruct;
+      let mut _17: &BigStruct;
+      let mut _18: &BigStruct;
+      let mut _19: &BigStruct;
+      let mut _20: &BigStruct;
+      let mut _21: &BigStruct;
+      scope 1 {
+          debug s => _1;
+          let _2: i32;
+          scope 2 {
+              debug a => _2;
+              let _4: i32;
+              scope 3 {
+                  debug b => _4;
+                  let _7: S;
+                  let _8: u8;
+                  let _9: f32;
+                  let _10: S;
+                  scope 4 {
+                      debug a => _7;
+                      debug b => _8;
+                      debug c => _9;
+                      debug d => _10;
+                      let _12: S;
+                      let _13: u8;
+                      let _14: f32;
+                      let _15: S;
+                      scope 5 {
+                          debug a => _12;
+                          debug b => _13;
+                          debug c => _14;
+                          debug d => _15;
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = S(const 1_i32);
+          StorageLive(_2);
+          StorageLive(_3);
+-         _3 = (_1.0: i32);
+-         _2 = Add(move _3, const 2_i32);
++         _3 = const 1_i32;
++         _2 = const 3_i32;
+          StorageDead(_3);
+          (_1.0: i32) = const 3_i32;
+          StorageLive(_4);
+          StorageLive(_5);
+-         _5 = _2;
++         _5 = const 3_i32;
+          StorageLive(_6);
+-         _6 = (_1.0: i32);
+-         _4 = Add(move _5, move _6);
++         _6 = const 3_i32;
++         _4 = const 6_i32;
+          StorageDead(_6);
+          StorageDead(_5);
+          StorageLive(_11);
+          _11 = const _;
+          StorageLive(_7);
+-         _7 = (_11.0: S);
++         _7 = const S(1_i32);
+          StorageLive(_8);
+-         _8 = (_11.1: u8);
++         _8 = const 5_u8;
+          StorageLive(_9);
+-         _9 = (_11.2: f32);
++         _9 = const 7f32;
+          StorageLive(_10);
+-         _10 = (_11.3: S);
++         _10 = const S(13_i32);
+          StorageDead(_11);
+          StorageLive(_16);
+          _16 = const {alloc1: &&BigStruct};
+          _17 = deref_copy (*_16);
+          StorageLive(_12);
+          _18 = deref_copy (*_16);
+-         _12 = ((*_18).0: S);
++         _12 = const S(1_i32);
+          StorageLive(_13);
+          _19 = deref_copy (*_16);
+-         _13 = ((*_19).1: u8);
++         _13 = const 5_u8;
+          StorageLive(_14);
+          _20 = deref_copy (*_16);
+-         _14 = ((*_20).2: f32);
++         _14 = const 7f32;
+          StorageLive(_15);
+          _21 = deref_copy (*_16);
+-         _15 = ((*_21).3: S);
++         _15 = const S(13_i32);
+          StorageDead(_16);
+          _0 = const ();
+          StorageDead(_15);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          StorageDead(_10);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
+  alloc1 (static: STAT, size: 8, align: 8) {
+      ╾───────alloc15───────╼                         │ ╾──────╼
+  }
+  
+  alloc15 (size: 16, align: 4) {
+      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
deleted file mode 100644
index 914bc8ac47e..00000000000
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
+++ /dev/null
@@ -1,51 +0,0 @@
-- // MIR for `main` before DataflowConstProp
-+ // MIR for `main` after DataflowConstProp
-  
-  fn main() -> () {
-      let mut _0: ();
-      let mut _1: S;
-      let mut _3: i32;
-      let mut _5: i32;
-      let mut _6: i32;
-      scope 1 {
-          debug s => _1;
-          let _2: i32;
-          scope 2 {
-              debug a => _2;
-              let _4: i32;
-              scope 3 {
-                  debug b => _4;
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = S(const 1_i32);
-          StorageLive(_2);
-          StorageLive(_3);
--         _3 = (_1.0: i32);
--         _2 = Add(move _3, const 2_i32);
-+         _3 = const 1_i32;
-+         _2 = const 3_i32;
-          StorageDead(_3);
-          (_1.0: i32) = const 3_i32;
-          StorageLive(_4);
-          StorageLive(_5);
--         _5 = _2;
-+         _5 = const 3_i32;
-          StorageLive(_6);
--         _6 = (_1.0: i32);
--         _4 = Add(move _5, move _6);
-+         _6 = const 3_i32;
-+         _4 = const 6_i32;
-          StorageDead(_6);
-          StorageDead(_5);
-          _0 = const ();
-          StorageDead(_4);
-          StorageDead(_2);
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs
index 841b279e03e..e92a1676d3f 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.rs
+++ b/tests/mir-opt/dataflow-const-prop/struct.rs
@@ -1,11 +1,22 @@
 // unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
+#[derive(Copy, Clone)]
 struct S(i32);
 
+#[derive(Copy, Clone)]
+struct BigStruct(S, u8, f32, S);
+
 // EMIT_MIR struct.main.DataflowConstProp.diff
 fn main() {
     let mut s = S(1);
     let a = s.0 + 2;
     s.0 = 3;
     let b = a + s.0;
+
+    const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13));
+    let BigStruct(a, b, c, d) = VAL;
+
+    static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13));
+    let BigStruct(a, b, c, d) = *STAT;
 }
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 6b4f4c80560..79fd9457ce1 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -9,7 +9,7 @@ use core::num::flt2dec;
 use std::fmt::{Formatter, Result};
 
 // EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
-fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
+pub fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
 where
     T: flt2dec::DecodableFloat,
 {
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
index 958078b9706..acbb7904985 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: std::string::String,
+            ty: Adt(
+                std::string::String,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
index 7e050e585b1..c17d4421542 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: std::string::String,
+            ty: Adt(
+                std::string::String,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index 13d703b908c..e33f5f59de1 100644
--- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: HasDrop,
+            ty: Adt(
+                HasDrop,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_tiny.rs:20:13: 20:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index f12179a8905..b6a673b6355 100644
--- a/tests/mir-opt/issue_99325.main.built.after.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
new file mode 100644
index 00000000000..9d112cfa20a
--- /dev/null
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -0,0 +1,276 @@
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+|
+fn main() -> () {
+    let mut _0: ();
+    let _1: ();
+    let mut _2: (&&[u8], &&[u8; 4]);
+    let mut _3: &&[u8];
+    let _4: &[u8];
+    let mut _5: &&[u8; 4];
+    let _6: &[u8; 4];
+    let _7: [u8; 4];
+    let _8: &&[u8];
+    let _9: &&[u8; 4];
+    let mut _10: bool;
+    let mut _11: &&[u8];
+    let mut _12: &&[u8; 4];
+    let mut _13: !;
+    let _15: !;
+    let mut _16: core::panicking::AssertKind;
+    let mut _17: &&[u8];
+    let _18: &&[u8];
+    let mut _19: &&[u8; 4];
+    let _20: &&[u8; 4];
+    let mut _21: std::option::Option<std::fmt::Arguments<'_>>;
+    let _22: ();
+    let mut _23: (&&[u8], &&[u8; 4]);
+    let mut _24: &&[u8];
+    let _25: &[u8];
+    let mut _26: &&[u8; 4];
+    let _27: &[u8; 4];
+    let _28: &&[u8];
+    let _29: &&[u8; 4];
+    let mut _30: bool;
+    let mut _31: &&[u8];
+    let mut _32: &&[u8; 4];
+    let mut _33: !;
+    let _35: !;
+    let mut _36: core::panicking::AssertKind;
+    let mut _37: &&[u8];
+    let _38: &&[u8];
+    let mut _39: &&[u8; 4];
+    let _40: &&[u8; 4];
+    let mut _41: std::option::Option<std::fmt::Arguments<'_>>;
+    scope 1 {
+        debug left_val => _8;
+        debug right_val => _9;
+        let _14: core::panicking::AssertKind;
+        scope 2 {
+            debug kind => _14;
+        }
+    }
+    scope 3 {
+        debug left_val => _28;
+        debug right_val => _29;
+        let _34: core::panicking::AssertKind;
+        scope 4 {
+            debug kind => _34;
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);
+        StorageLive(_2);
+        StorageLive(_3);
+        StorageLive(_4);
+        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb21];
+    }
+
+    bb1: {
+        _3 = &_4;
+        StorageLive(_5);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8];
+        _6 = &_7;
+        _5 = &_6;
+        _2 = (move _3, move _5);
+        StorageDead(_5);
+        StorageDead(_3);
+        FakeRead(ForMatchedPlace(None), _2);
+        StorageLive(_8);
+        _8 = (_2.0: &&[u8]);
+        StorageLive(_9);
+        _9 = (_2.1: &&[u8; 4]);
+        StorageLive(_10);
+        StorageLive(_11);
+        _11 = &(*_8);
+        StorageLive(_12);
+        _12 = &(*_9);
+        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb2, unwind: bb21];
+    }
+
+    bb2: {
+        switchInt(move _10) -> [0: bb4, otherwise: bb3];
+    }
+
+    bb3: {
+        StorageDead(_12);
+        StorageDead(_11);
+        goto -> bb8;
+    }
+
+    bb4: {
+        goto -> bb5;
+    }
+
+    bb5: {
+        StorageDead(_12);
+        StorageDead(_11);
+        StorageLive(_14);
+        _14 = core::panicking::AssertKind::Eq;
+        FakeRead(ForLet(None), _14);
+        StorageLive(_15);
+        StorageLive(_16);
+        _16 = move _14;
+        StorageLive(_17);
+        StorageLive(_18);
+        _18 = &(*_8);
+        _17 = &(*_18);
+        StorageLive(_19);
+        StorageLive(_20);
+        _20 = &(*_9);
+        _19 = &(*_20);
+        StorageLive(_21);
+        _21 = Option::<Arguments<'_>>::None;
+        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb21;
+    }
+
+    bb6: {
+        StorageDead(_21);
+        StorageDead(_19);
+        StorageDead(_17);
+        StorageDead(_16);
+        StorageDead(_20);
+        StorageDead(_18);
+        StorageDead(_15);
+        StorageDead(_14);
+        unreachable;
+    }
+
+    bb7: {
+        goto -> bb9;
+    }
+
+    bb8: {
+        _1 = const ();
+        goto -> bb9;
+    }
+
+    bb9: {
+        StorageDead(_10);
+        StorageDead(_9);
+        StorageDead(_8);
+        goto -> bb10;
+    }
+
+    bb10: {
+        StorageDead(_7);
+        StorageDead(_6);
+        StorageDead(_4);
+        StorageDead(_2);
+        StorageDead(_1);
+        StorageLive(_22);
+        StorageLive(_23);
+        StorageLive(_24);
+        StorageLive(_25);
+        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb11, unwind: bb21];
+    }
+
+    bb11: {
+        _24 = &_25;
+        StorageLive(_26);
+        StorageLive(_27);
+        _27 = const b"AAAA";
+        _26 = &_27;
+        _23 = (move _24, move _26);
+        StorageDead(_26);
+        StorageDead(_24);
+        FakeRead(ForMatchedPlace(None), _23);
+        StorageLive(_28);
+        _28 = (_23.0: &&[u8]);
+        StorageLive(_29);
+        _29 = (_23.1: &&[u8; 4]);
+        StorageLive(_30);
+        StorageLive(_31);
+        _31 = &(*_28);
+        StorageLive(_32);
+        _32 = &(*_29);
+        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb12, unwind: bb21];
+    }
+
+    bb12: {
+        switchInt(move _30) -> [0: bb14, otherwise: bb13];
+    }
+
+    bb13: {
+        StorageDead(_32);
+        StorageDead(_31);
+        goto -> bb18;
+    }
+
+    bb14: {
+        goto -> bb15;
+    }
+
+    bb15: {
+        StorageDead(_32);
+        StorageDead(_31);
+        StorageLive(_34);
+        _34 = core::panicking::AssertKind::Eq;
+        FakeRead(ForLet(None), _34);
+        StorageLive(_35);
+        StorageLive(_36);
+        _36 = move _34;
+        StorageLive(_37);
+        StorageLive(_38);
+        _38 = &(*_28);
+        _37 = &(*_38);
+        StorageLive(_39);
+        StorageLive(_40);
+        _40 = &(*_29);
+        _39 = &(*_40);
+        StorageLive(_41);
+        _41 = Option::<Arguments<'_>>::None;
+        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb21;
+    }
+
+    bb16: {
+        StorageDead(_41);
+        StorageDead(_39);
+        StorageDead(_37);
+        StorageDead(_36);
+        StorageDead(_40);
+        StorageDead(_38);
+        StorageDead(_35);
+        StorageDead(_34);
+        unreachable;
+    }
+
+    bb17: {
+        goto -> bb19;
+    }
+
+    bb18: {
+        _22 = const ();
+        goto -> bb19;
+    }
+
+    bb19: {
+        StorageDead(_30);
+        StorageDead(_29);
+        StorageDead(_28);
+        goto -> bb20;
+    }
+
+    bb20: {
+        StorageDead(_27);
+        StorageDead(_25);
+        StorageDead(_23);
+        StorageDead(_22);
+        _0 = const ();
+        return;
+    }
+
+    bb21 (cleanup): {
+        resume;
+    }
+}
+
+alloc4 (size: 4, align: 1) {
+    41 41 41 41                                     │ AAAA
+}
diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs
index fe819cddb2c..3603228a502 100644
--- a/tests/mir-opt/issue_99325.rs
+++ b/tests/mir-opt/issue_99325.rs
@@ -1,3 +1,5 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 #![feature(adt_const_params)]
 #![allow(incomplete_features)]
 
diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp
index 7d7f682130d..fd9386be8f3 100644
--- a/tests/pretty/tests-are-sorted.pp
+++ b/tests/pretty/tests-are-sorted.pp
@@ -79,7 +79,7 @@ pub const a_test: test::TestDescAndFn =
     };
 fn a_test() {}
 #[rustc_main]
-#[no_coverage]
+#[coverage(off)]
 pub fn main() -> () {
     extern crate test;
     test::test_main_static(&[&a_test, &m_test, &z_test])
diff --git a/tests/run-coverage/closure_macro.coverage b/tests/run-coverage/closure_macro.coverage
index 1bfd2013da8..0f2c917e090 100644
--- a/tests/run-coverage/closure_macro.coverage
+++ b/tests/run-coverage/closure_macro.coverage
@@ -1,5 +1,5 @@
    LL|       |// compile-flags: --edition=2018
-   LL|       |#![feature(no_coverage)]
+   LL|       |#![feature(coverage_attribute)]
    LL|       |
    LL|       |macro_rules! bail {
    LL|       |    ($msg:literal $(,)?) => {
diff --git a/tests/run-coverage/closure_macro.rs b/tests/run-coverage/closure_macro.rs
index 5e3b00d1ef5..9b289141c2e 100644
--- a/tests/run-coverage/closure_macro.rs
+++ b/tests/run-coverage/closure_macro.rs
@@ -1,5 +1,5 @@
 // compile-flags: --edition=2018
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 
 macro_rules! bail {
     ($msg:literal $(,)?) => {
diff --git a/tests/run-coverage/closure_macro_async.coverage b/tests/run-coverage/closure_macro_async.coverage
index 018e3160e4f..74247f1bc6f 100644
--- a/tests/run-coverage/closure_macro_async.coverage
+++ b/tests/run-coverage/closure_macro_async.coverage
@@ -1,5 +1,5 @@
    LL|       |// compile-flags: --edition=2018
-   LL|       |#![feature(no_coverage)]
+   LL|       |#![feature(coverage_attribute)]
    LL|       |
    LL|       |macro_rules! bail {
    LL|       |    ($msg:literal $(,)?) => {
@@ -40,7 +40,7 @@
    LL|      1|    Ok(())
    LL|      1|}
    LL|       |
-   LL|       |#[no_coverage]
+   LL|       |#[coverage(off)]
    LL|       |fn main() {
    LL|       |    executor::block_on(test()).unwrap();
    LL|       |}
@@ -52,18 +52,18 @@
    LL|       |        task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
    LL|       |    };
    LL|       |
-   LL|       |    #[no_coverage]
+   LL|       |    #[coverage(off)]
    LL|       |    pub fn block_on<F: Future>(mut future: F) -> F::Output {
    LL|       |        let mut future = unsafe { Pin::new_unchecked(&mut future) };
    LL|       |        use std::hint::unreachable_unchecked;
    LL|       |        static VTABLE: RawWakerVTable = RawWakerVTable::new(
-   LL|       |            #[no_coverage]
+   LL|       |            #[coverage(off)]
    LL|       |            |_| unsafe { unreachable_unchecked() }, // clone
-   LL|       |            #[no_coverage]
+   LL|       |            #[coverage(off)]
    LL|       |            |_| unsafe { unreachable_unchecked() }, // wake
-   LL|       |            #[no_coverage]
+   LL|       |            #[coverage(off)]
    LL|       |            |_| unsafe { unreachable_unchecked() }, // wake_by_ref
-   LL|       |            #[no_coverage]
+   LL|       |            #[coverage(off)]
    LL|       |            |_| (),
    LL|       |        );
    LL|       |        let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
diff --git a/tests/run-coverage/closure_macro_async.rs b/tests/run-coverage/closure_macro_async.rs
index 3d6bdb38a2a..b4275599e59 100644
--- a/tests/run-coverage/closure_macro_async.rs
+++ b/tests/run-coverage/closure_macro_async.rs
@@ -1,5 +1,5 @@
 // compile-flags: --edition=2018
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 
 macro_rules! bail {
     ($msg:literal $(,)?) => {
@@ -39,7 +39,7 @@ pub async fn test() -> Result<(), String> {
     Ok(())
 }
 
-#[no_coverage]
+#[coverage(off)]
 fn main() {
     executor::block_on(test()).unwrap();
 }
@@ -51,18 +51,18 @@ mod executor {
         task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
     };
 
-    #[no_coverage]
+    #[coverage(off)]
     pub fn block_on<F: Future>(mut future: F) -> F::Output {
         let mut future = unsafe { Pin::new_unchecked(&mut future) };
         use std::hint::unreachable_unchecked;
         static VTABLE: RawWakerVTable = RawWakerVTable::new(
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // clone
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // wake
-            #[no_coverage]
+            #[coverage(off)]
             |_| unsafe { unreachable_unchecked() }, // wake_by_ref
-            #[no_coverage]
+            #[coverage(off)]
             |_| (),
         );
         let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
diff --git a/tests/run-coverage/no_cov_crate.coverage b/tests/run-coverage/no_cov_crate.coverage
index 73f6fbd0c2b..f5a0322bf3e 100644
--- a/tests/run-coverage/no_cov_crate.coverage
+++ b/tests/run-coverage/no_cov_crate.coverage
@@ -1,17 +1,17 @@
-   LL|       |// Enables `no_coverage` on the entire crate
-   LL|       |#![feature(no_coverage)]
+   LL|       |// Enables `coverage(off)` on the entire crate
+   LL|       |#![feature(coverage_attribute)]
    LL|       |
-   LL|       |#[no_coverage]
+   LL|       |#[coverage(off)]
    LL|       |fn do_not_add_coverage_1() {
    LL|       |    println!("called but not covered");
    LL|       |}
    LL|       |
    LL|       |fn do_not_add_coverage_2() {
-   LL|       |    #![no_coverage]
+   LL|       |    #![coverage(off)]
    LL|       |    println!("called but not covered");
    LL|       |}
    LL|       |
-   LL|       |#[no_coverage]
+   LL|       |#[coverage(off)]
    LL|       |#[allow(dead_code)]
    LL|       |fn do_not_add_coverage_not_called() {
    LL|       |    println!("not called and not covered");
@@ -33,7 +33,7 @@
    LL|       |// FIXME: These test-cases illustrate confusing results of nested functions.
    LL|       |// See https://github.com/rust-lang/rust/issues/93319
    LL|       |mod nested_fns {
-   LL|       |    #[no_coverage]
+   LL|       |    #[coverage(off)]
    LL|       |    pub fn outer_not_covered(is_true: bool) {
    LL|      1|        fn inner(is_true: bool) {
    LL|      1|            if is_true {
@@ -50,7 +50,7 @@
    LL|      1|        println!("called and covered");
    LL|      1|        inner_not_covered(is_true);
    LL|      1|
-   LL|      1|        #[no_coverage]
+   LL|      1|        #[coverage(off)]
    LL|      1|        fn inner_not_covered(is_true: bool) {
    LL|      1|            if is_true {
    LL|      1|                println!("called but not covered");
diff --git a/tests/run-coverage/no_cov_crate.rs b/tests/run-coverage/no_cov_crate.rs
index 5b748aeefb7..e12e4bc55e3 100644
--- a/tests/run-coverage/no_cov_crate.rs
+++ b/tests/run-coverage/no_cov_crate.rs
@@ -1,17 +1,17 @@
-// Enables `no_coverage` on the entire crate
-#![feature(no_coverage)]
+// Enables `coverage(off)` on the entire crate
+#![feature(coverage_attribute)]
 
-#[no_coverage]
+#[coverage(off)]
 fn do_not_add_coverage_1() {
     println!("called but not covered");
 }
 
 fn do_not_add_coverage_2() {
-    #![no_coverage]
+    #![coverage(off)]
     println!("called but not covered");
 }
 
-#[no_coverage]
+#[coverage(off)]
 #[allow(dead_code)]
 fn do_not_add_coverage_not_called() {
     println!("not called and not covered");
@@ -33,7 +33,7 @@ fn add_coverage_not_called() {
 // FIXME: These test-cases illustrate confusing results of nested functions.
 // See https://github.com/rust-lang/rust/issues/93319
 mod nested_fns {
-    #[no_coverage]
+    #[coverage(off)]
     pub fn outer_not_covered(is_true: bool) {
         fn inner(is_true: bool) {
             if is_true {
@@ -50,7 +50,7 @@ mod nested_fns {
         println!("called and covered");
         inner_not_covered(is_true);
 
-        #[no_coverage]
+        #[coverage(off)]
         fn inner_not_covered(is_true: bool) {
             if is_true {
                 println!("called but not covered");
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 04c551cf4bb..b59a65a713f 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries};
 use rustc_middle::query::queries::mir_borrowck::ProvidedValue;
 use rustc_middle::query::{ExternProviders, Providers};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::{Session, EarlyErrorHandler};
+use rustc_session::Session;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::thread_local;
@@ -58,7 +58,6 @@ impl rustc_driver::Callbacks for CompilerCalls {
     // the result.
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         compiler: &Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/tests/run-make/compressed-debuginfo/Makefile b/tests/run-make/compressed-debuginfo/Makefile
new file mode 100644
index 00000000000..f9e4927d008
--- /dev/null
+++ b/tests/run-make/compressed-debuginfo/Makefile
@@ -0,0 +1,15 @@
+# ignore-cross-compile
+include ../tools.mk
+
+# only-linux
+# min-llvm-version: 16.0
+#
+# This tests debuginfo-compression.
+
+all: zlib zstandard
+
+zlib:
+	test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zlib foo.rs 2>&1 | sed 's/.*unknown.*zlib.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZLIB
+
+zstandard:
+	test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zstd foo.rs 2>&1 | sed 's/.*unknown.*zstd.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZST
diff --git a/tests/run-make/compressed-debuginfo/foo.rs b/tests/run-make/compressed-debuginfo/foo.rs
new file mode 100644
index 00000000000..185ce22450c
--- /dev/null
+++ b/tests/run-make/compressed-debuginfo/foo.rs
@@ -0,0 +1,3 @@
+pub fn foo() -> i32 {
+    42
+}
diff --git a/tests/run-make/emit-path-unhashed/Makefile b/tests/run-make/emit-path-unhashed/Makefile
index 74047fe5f86..611f8578140 100644
--- a/tests/run-make/emit-path-unhashed/Makefile
+++ b/tests/run-make/emit-path-unhashed/Makefile
@@ -5,10 +5,10 @@ OUT=$(TMPDIR)/emit
 # --emit KIND=PATH should not affect crate hash vs --emit KIND
 all: $(OUT)/a/libfoo.rlib $(OUT)/b/libfoo.rlib $(OUT)/c/libfoo.rlib \
 		$(TMPDIR)/libfoo.rlib
-	$(RUSTC) -Zls $(TMPDIR)/libfoo.rlib > $(TMPDIR)/base.txt
-	$(RUSTC) -Zls $(OUT)/a/libfoo.rlib > $(TMPDIR)/a.txt
-	$(RUSTC) -Zls $(OUT)/b/libfoo.rlib > $(TMPDIR)/b.txt
-	$(RUSTC) -Zls $(OUT)/c/libfoo.rlib > $(TMPDIR)/c.txt
+	$(RUSTC) -Zls=root $(TMPDIR)/libfoo.rlib > $(TMPDIR)/base.txt
+	$(RUSTC) -Zls=root $(OUT)/a/libfoo.rlib > $(TMPDIR)/a.txt
+	$(RUSTC) -Zls=root $(OUT)/b/libfoo.rlib > $(TMPDIR)/b.txt
+	$(RUSTC) -Zls=root $(OUT)/c/libfoo.rlib > $(TMPDIR)/c.txt
 
 	diff $(TMPDIR)/base.txt $(TMPDIR)/a.txt
 	diff $(TMPDIR)/base.txt $(TMPDIR)/b.txt
diff --git a/tests/run-make/ls-metadata/Makefile b/tests/run-make/ls-metadata/Makefile
index 123dd64e15c..f03569baef7 100644
--- a/tests/run-make/ls-metadata/Makefile
+++ b/tests/run-make/ls-metadata/Makefile
@@ -3,6 +3,6 @@ include ../tools.mk
 
 all:
 	$(RUSTC) foo.rs
-	$(RUSTC) -Z ls $(TMPDIR)/foo
+	$(RUSTC) -Z ls=root $(TMPDIR)/foo
 	touch $(TMPDIR)/bar
-	$(RUSTC) -Z ls $(TMPDIR)/bar
+	$(RUSTC) -Z ls=root $(TMPDIR)/bar
diff --git a/tests/run-make/lto-linkage-used-attr/Makefile b/tests/run-make/lto-linkage-used-attr/Makefile
new file mode 100644
index 00000000000..e78b83890ed
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/Makefile
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+# Verify that the impl_* symbols are preserved. #108030
+# only-x86_64-unknown-linux-gnu
+# min-llvm-version: 17
+
+all:
+	$(RUSTC) -Cdebuginfo=0 -Copt-level=3 lib.rs
+	$(RUSTC) -Clto=fat -Cdebuginfo=0 -Copt-level=3 main.rs
diff --git a/tests/run-make/lto-linkage-used-attr/lib.rs b/tests/run-make/lto-linkage-used-attr/lib.rs
new file mode 100644
index 00000000000..0a92ea9cd22
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/lib.rs
@@ -0,0 +1,50 @@
+#![crate_type = "rlib"]
+#![crate_type = "cdylib"]
+
+#[macro_export]
+macro_rules! asm_func {
+    ($name:expr, $body:expr $(, $($args:tt)*)?) => {
+        core::arch::global_asm!(
+            concat!(
+                ".p2align 4\n",
+                ".hidden ", $name, "\n",
+                ".global ", $name, "\n",
+                ".type ", $name, ",@function\n",
+                $name, ":\n",
+                $body,
+                ".size ", $name, ",.-", $name,
+            )
+            $(, $($args)*)?
+        );
+    };
+}
+
+macro_rules! libcall_trampoline {
+    ($libcall:ident ; $libcall_impl:ident) => {
+        asm_func!(
+            stringify!($libcall),
+            concat!(
+                "
+                   .cfi_startproc simple
+                   .cfi_def_cfa_offset 0
+                    jmp {}
+                    .cfi_endproc
+                ",
+            ),
+            sym $libcall_impl
+        );
+    };
+}
+
+pub mod trampolines {
+    extern "C" {
+        pub fn table_fill_funcref();
+        pub fn table_fill_externref();
+    }
+
+    unsafe extern "C" fn impl_table_fill_funcref() {}
+    unsafe extern "C" fn impl_table_fill_externref() {}
+
+    libcall_trampoline!(table_fill_funcref ; impl_table_fill_funcref);
+    libcall_trampoline!(table_fill_externref ; impl_table_fill_externref);
+}
diff --git a/tests/run-make/lto-linkage-used-attr/main.rs b/tests/run-make/lto-linkage-used-attr/main.rs
new file mode 100644
index 00000000000..256b02e5b0b
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/main.rs
@@ -0,0 +1,10 @@
+extern crate lib;
+
+use lib::trampolines::*;
+
+fn main() {
+    unsafe {
+        table_fill_externref();
+        table_fill_funcref();
+    }
+}
diff --git a/tests/run-make/output-filename-overwrites-input/Makefile b/tests/run-make/output-filename-overwrites-input/Makefile
index 605b86b253e..fe5d231382d 100644
--- a/tests/run-make/output-filename-overwrites-input/Makefile
+++ b/tests/run-make/output-filename-overwrites-input/Makefile
@@ -8,7 +8,7 @@ all:
 	cp bar.rs $(TMPDIR)/bar.rlib
 	$(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \
 		| $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable"
-	$(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls $(TMPDIR)/foo 2>&1
+	$(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls=root $(TMPDIR)/foo 2>&1
 	cp foo.rs $(TMPDIR)/foo.rs
 	$(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \
 		| $(CGREP) -e "the input file \".*foo.rs\" would be overwritten by the generated executable"
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 6e880302f28..84c20355500 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -33,21 +33,21 @@ define-function: (
 
 call-function: ("check-colors", {
     "theme": "ayu",
-    "color": "rgb(197, 197, 197)",
-    "background": "rgb(49, 69, 89)",
-    "box_shadow": "rgb(92, 103, 115)",
+    "color": "#c5c5c5",
+    "background": "#314559",
+    "box_shadow": "#5c6773",
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "color": "rgb(0, 0, 0)",
-    "background": "rgb(250, 251, 252)",
-    "box_shadow": "rgb(198, 203, 209)",
+    "color": "#000",
+    "background": "#fafbfc",
+    "box_shadow": "#c6cbd1",
 })
 call-function: ("check-colors", {
     "theme": "light",
-    "color": "rgb(0, 0, 0)",
-    "background": "rgb(250, 251, 252)",
-    "box_shadow": "rgb(198, 203, 209)",
+    "color": "#000",
+    "background": "#fafbfc",
+    "box_shadow": "#c6cbd1",
 })
 
 // This test ensures that opening the help popover without switching pages works.
diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml
index 46d1856b4d6..e7c64791256 100644
--- a/tests/rustdoc-gui/search-no-result.goml
+++ b/tests/rustdoc-gui/search-no-result.goml
@@ -21,16 +21,16 @@ define-function: (
 
 call-function: ("check-no-result", {
     "theme": "ayu",
-    "link": "rgb(57, 175, 215)",
-    "link_hover": "rgb(57, 175, 215)",
+    "link": "#39afd7",
+    "link_hover": "#39afd7",
 })
 call-function: ("check-no-result", {
     "theme": "dark",
-    "link": "rgb(210, 153, 29)",
-    "link_hover": "rgb(210, 153, 29)",
+    "link": "#d2991d",
+    "link_hover": "#d2991d",
 })
 call-function: ("check-no-result", {
     "theme": "light",
-    "link": "rgb(56, 115, 173)",
-    "link_hover": "rgb(56, 115, 173)",
+    "link": "#3873ad",
+    "link_hover": "#3873ad",
 })
diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs
index 555d0579bee..ac486c36ad0 100644
--- a/tests/rustdoc/issue-32077-type-alias-impls.rs
+++ b/tests/rustdoc/issue-32077-type-alias-impls.rs
@@ -19,6 +19,8 @@ impl<T> Foo for GenericStruct<T> {}
 impl Bar for GenericStruct<u32> {}
 
 // @has 'foo/type.TypedefStruct.html'
+// We check that "Aliased type" is also present as a title in the sidebar.
+// @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type'
 // We check that we have the implementation of the type alias itself.
 // @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct'
 // @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'
@@ -29,6 +31,11 @@ impl Bar for GenericStruct<u32> {}
 // @!has - '//h3' 'impl Bar for GenericStruct<u32> {}'
 // Same goes for the `Deref` impl.
 // @!has - '//h2' 'Methods from Deref<Target = u32>'
+// @count - '//nav[@class="sidebar"]//a' 'on_alias' 1
+// @count - '//nav[@class="sidebar"]//a' 'on_gen' 1
+// @count - '//nav[@class="sidebar"]//a' 'Foo' 1
+// @!has - '//nav[@class="sidebar"]//a' 'Bar'
+// @!has - '//nav[@class="sidebar"]//a' 'on_u32'
 pub type TypedefStruct = GenericStruct<u8>;
 
 impl TypedefStruct {
diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
index b060e3a3e38..0e661795999 100644
--- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
+++ b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
@@ -1,9 +1,12 @@
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
 
 warning: item is named 'lintme'
@@ -22,8 +25,9 @@ LL | #![plugin(lint_tool_test)]
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
 
 warning: 5 warnings emitted
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index d55eae86f07..a11720c4b55 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -154,6 +154,10 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> {
         }
     }
 
+    let foo_const = get_item(tcx, &items, (DefKind::Const, "FOO")).unwrap();
+    // Ensure we don't panic trying to get the body of a constant.
+    foo_const.body();
+
     ControlFlow::Continue(())
 }
 
@@ -191,6 +195,8 @@ fn generate_input(path: &str) -> std::io::Result<()> {
     write!(
         file,
         r#"
+    pub const FOO: u32 = 1 + 2;
+
     fn generic<T, const U: usize>(t: T) -> [(); U] {{
         _ = t;
         [(); U]
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 0bbcba200c7..b3e75bb8233 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -1,14 +1,24 @@
 // check-pass
-#![feature(rustc_attrs, transparent_unions)]
-#![allow(unused, improper_ctypes_definitions)]
+#![feature(rustc_attrs, unsized_fn_params, transparent_unions)]
+#![allow(unused, improper_ctypes_definitions, internal_features)]
 use std::marker::PhantomData;
+use std::mem::ManuallyDrop;
 use std::num::NonZeroI32;
 use std::ptr::NonNull;
 
+// FIXME: a bunch of targets are broken in various ways.
+// Hence there are `cfg` throughout this test to disable parts of it on those targets.
+// sparc64: https://github.com/rust-lang/rust/issues/115336
+// mips64: https://github.com/rust-lang/rust/issues/115404
+// riscv64: https://github.com/rust-lang/rust/issues/115481
+// loongarch64: https://github.com/rust-lang/rust/issues/115509
+
 macro_rules! assert_abi_compatible {
     ($name:ident, $t1:ty, $t2:ty) => {
         mod $name {
             use super::*;
+            // Declaring a `type` doesn't even check well-formedness, so we also declare a function.
+            fn check_wf(_x: $t1, _y: $t2) {}
             // Test argument and return value, `Rust` and `C` ABIs.
             #[rustc_abi(assert_eq)]
             type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2);
@@ -22,7 +32,7 @@ macro_rules! assert_abi_compatible {
 struct Zst;
 
 #[repr(C)]
-struct ReprC1<T>(T);
+struct ReprC1<T: ?Sized>(T);
 #[repr(C)]
 struct ReprC2Int<T>(i32, T);
 #[repr(C)]
@@ -37,9 +47,9 @@ enum ReprCEnum<T> {
     Variant2(T),
 }
 #[repr(C)]
-union ReprCUnion<T: Copy> {
+union ReprCUnion<T> {
     nothing: (),
-    something: T,
+    something: ManuallyDrop<T>,
 }
 
 macro_rules! test_abi_compatible {
@@ -71,20 +81,26 @@ test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32);
 
 // Some further guarantees we will likely (have to) make.
 test_abi_compatible!(zst_unit, Zst, ());
+#[cfg(not(any(target_arch = "sparc64")))]
 test_abi_compatible!(zst_array, Zst, [u8; 0]);
 test_abi_compatible!(nonzero_int, NonZeroI32, i32);
 
+// `DispatchFromDyn` relies on ABI compatibility.
+// This is interesting since these types are not `repr(transparent)`.
+test_abi_compatible!(rc, std::rc::Rc<i32>, *mut i32);
+test_abi_compatible!(arc, std::sync::Arc<i32>, *mut i32);
+
 // `repr(transparent)` compatibility.
 #[repr(transparent)]
-struct Wrapper1<T>(T);
+struct Wrapper1<T: ?Sized>(T);
 #[repr(transparent)]
-struct Wrapper2<T>((), Zst, T);
+struct Wrapper2<T: ?Sized>((), Zst, T);
 #[repr(transparent)]
 struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
 #[repr(transparent)]
-union WrapperUnion<T: Copy> {
+union WrapperUnion<T> {
     nothing: (),
-    something: T,
+    something: ManuallyDrop<T>,
 }
 
 macro_rules! test_transparent {
@@ -94,6 +110,7 @@ macro_rules! test_transparent {
             test_abi_compatible!(wrap1, $t, Wrapper1<$t>);
             test_abi_compatible!(wrap2, $t, Wrapper2<$t>);
             test_abi_compatible!(wrap3, $t, Wrapper3<$t>);
+            #[cfg(not(any(target_arch = "riscv64", target_arch = "loongarch64")))]
             test_abi_compatible!(wrap4, $t, WrapperUnion<$t>);
         }
     };
@@ -103,22 +120,50 @@ test_transparent!(simple, i32);
 test_transparent!(reference, &'static i32);
 test_transparent!(zst, Zst);
 test_transparent!(unit, ());
-test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment
-test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit
-test_transparent!(tuple, (i32, f32, i64, f64));
-test_transparent!(empty_array, [u32; 0]);
-test_transparent!(empty_1zst_array, [u8; 0]);
-test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
-test_transparent!(large_array, [i32; 16]);
 test_transparent!(enum_, Option<i32>);
 test_transparent!(enum_niched, Option<&'static i32>);
-// Pure-float types that are not ScalarPair seem to be tricky.
-// FIXME: <https://github.com/rust-lang/rust/issues/115664>
-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
-mod tricky {
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod tuples {
     use super::*;
+    // mixing in some floats since they often get special treatment
+    test_transparent!(pair, (i32, f32));
+    // chosen to fit into 64bit
+    test_transparent!(triple, (i8, i16, f32));
+    // Pure-float types that are not ScalarPair seem to be tricky.
     test_transparent!(triple_f32, (f32, f32, f32));
     test_transparent!(triple_f64, (f64, f64, f64));
+    // and also something that's larger than 2 pointers
+    test_transparent!(tuple, (i32, f32, i64, f64));
+}
+// Some targets have special rules for arrays.
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod arrays {
+    use super::*;
+    test_transparent!(empty_array, [u32; 0]);
+    test_transparent!(empty_1zst_array, [u8; 0]);
+    test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
+    test_transparent!(large_array, [i32; 16]);
+}
+
+// Some tests with unsized types (not all wrappers are compatible with that).
+macro_rules! test_transparent_unsized {
+    ($name:ident, $t:ty) => {
+        mod $name {
+            use super::*;
+            assert_abi_compatible!(wrap1, $t, Wrapper1<$t>);
+            assert_abi_compatible!(wrap1_reprc, ReprC1<$t>, ReprC1<Wrapper1<$t>>);
+            assert_abi_compatible!(wrap2, $t, Wrapper2<$t>);
+            assert_abi_compatible!(wrap2_reprc, ReprC1<$t>, ReprC1<Wrapper2<$t>>);
+        }
+    };
+}
+
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod unsized_ {
+    use super::*;
+    test_transparent_unsized!(str_, str);
+    test_transparent_unsized!(slice, [u8]);
+    test_transparent_unsized!(dyn_trait, dyn std::any::Any);
 }
 
 // RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index 9decb41d565..ac37d7b6bff 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -4,6 +4,7 @@
 // normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
 // This pattern is prepared for when we account for alignment in the niche.
 // normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL"
+// normalize-stderr-test "Leaf\(0x0*20\)" -> "Leaf(0x0...20)"
 // Some attributes are only computed for release builds:
 // compile-flags: -O
 #![feature(rustc_attrs)]
@@ -48,3 +49,6 @@ type TestAbiNeFloat = (fn(f32), fn(u32)); //~ ERROR: ABIs are not compatible
 // Sign matters on some targets (such as s390x), so let's make sure we never accept this.
 #[rustc_abi(assert_eq)]
 type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 0feaf0971d8..f56f5c525ab 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -87,7 +87,7 @@ error: fn_abi_of(test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:15:1
+  --> $DIR/debug.rs:16:1
    |
 LL | fn test(_x: u8) -> bool { true }
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:18:1
+  --> $DIR/debug.rs:19:1
    |
 LL | type TestFnPtr = fn(bool) -> u8;
    | ^^^^^^^^^^^^^^
@@ -190,7 +190,7 @@ error: fn_abi_of(test_generic) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: *const T,
+                       ty: *const T/#0,
                        layout: Layout {
                            size: $SOME_SIZE,
                            align: AbiAndPrefAlign {
@@ -257,111 +257,17 @@ error: fn_abi_of(test_generic) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:21:1
+  --> $DIR/debug.rs:22:1
    |
 LL | fn test_generic<T>(_x: *const T) { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:24:1
+  --> $DIR/debug.rs:25:1
    |
 LL | const C: () = ();
    | ^^^^^^^^^^^
 
-error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:28:5
-   |
-LL |     const C: () = ();
-   |     ^^^^^^^^^^^
-
-error: fn_abi_of(assoc_test) = FnAbi {
-           args: [
-               ArgAbi {
-                   layout: TyAndLayout {
-                       ty: &S,
-                       layout: Layout {
-                           size: $SOME_SIZE,
-                           align: AbiAndPrefAlign {
-                               abi: $SOME_ALIGN,
-                               pref: $SOME_ALIGN,
-                           },
-                           abi: Scalar(
-                               Initialized {
-                                   value: Pointer(
-                                       AddressSpace(
-                                           0,
-                                       ),
-                                   ),
-                                   valid_range: $NON_NULL,
-                               },
-                           ),
-                           fields: Primitive,
-                           largest_niche: Some(
-                               Niche {
-                                   offset: Size(0 bytes),
-                                   value: Pointer(
-                                       AddressSpace(
-                                           0,
-                                       ),
-                                   ),
-                                   valid_range: $NON_NULL,
-                               },
-                           ),
-                           variants: Single {
-                               index: 0,
-                           },
-                           max_repr_align: None,
-                           unadjusted_abi_align: $SOME_ALIGN,
-                       },
-                   },
-                   mode: Direct(
-                       ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef,
-                           arg_ext: None,
-                           pointee_size: Size(2 bytes),
-                           pointee_align: Some(
-                               Align(2 bytes),
-                           ),
-                       },
-                   ),
-               },
-           ],
-           ret: ArgAbi {
-               layout: TyAndLayout {
-                   ty: (),
-                   layout: Layout {
-                       size: Size(0 bytes),
-                       align: AbiAndPrefAlign {
-                           abi: $SOME_ALIGN,
-                           pref: $SOME_ALIGN,
-                       },
-                       abi: Aggregate {
-                           sized: true,
-                       },
-                       fields: Arbitrary {
-                           offsets: [],
-                           memory_index: [],
-                       },
-                       largest_niche: None,
-                       variants: Single {
-                           index: 0,
-                       },
-                       max_repr_align: None,
-                       unadjusted_abi_align: $SOME_ALIGN,
-                   },
-               },
-               mode: Ignore,
-           },
-           c_variadic: false,
-           fixed_count: 1,
-           conv: Rust,
-           can_unwind: $SOME_BOOL,
-       }
-  --> $DIR/debug.rs:33:5
-   |
-LL |     fn assoc_test(&self) { }
-   |     ^^^^^^^^^^^^^^^^^^^^
-
 error: ABIs are not compatible
        left ABI = FnAbi {
            args: [
@@ -503,7 +409,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:40:1
+  --> $DIR/debug.rs:41:1
    |
 LL | type TestAbiNe = (fn(u8), fn(u32));
    | ^^^^^^^^^^^^^^
@@ -513,7 +419,7 @@ error: ABIs are not compatible
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: [u8; 32],
+                       ty: [u8; Const { ty: usize, kind: Leaf(0x0...20) }],
                        layout: Layout {
                            size: Size(32 bytes),
                            align: AbiAndPrefAlign {
@@ -584,7 +490,7 @@ error: ABIs are not compatible
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: [u32; 32],
+                       ty: [u32; Const { ty: usize, kind: Leaf(0x0...20) }],
                        layout: Layout {
                            size: Size(128 bytes),
                            align: AbiAndPrefAlign {
@@ -651,7 +557,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:43:1
+  --> $DIR/debug.rs:44:1
    |
 LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
    | ^^^^^^^^^^^^^^^^^^^^
@@ -794,7 +700,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:46:1
+  --> $DIR/debug.rs:47:1
    |
 LL | type TestAbiNeFloat = (fn(f32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^^
@@ -940,10 +846,114 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:50:1
+  --> $DIR/debug.rs:51:1
    |
 LL | type TestAbiNeSign = (fn(i32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/debug.rs:54:46
+   |
+LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
+   |                                              ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+  --> $DIR/debug.rs:29:5
+   |
+LL |     const C: () = ();
+   |     ^^^^^^^^^^^
+
+error: fn_abi_of(assoc_test) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: &ReErased Adt(S, []),
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Pointer(
+                                       AddressSpace(
+                                           0,
+                                       ),
+                                   ),
+                                   valid_range: $NON_NULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: Some(
+                               Niche {
+                                   offset: Size(0 bytes),
+                                   value: Pointer(
+                                       AddressSpace(
+                                           0,
+                                       ),
+                                   ),
+                                   valid_range: $NON_NULL,
+                               },
+                           ),
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoAlias | NonNull | ReadOnly | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(2 bytes),
+                           pointee_align: Some(
+                               Align(2 bytes),
+                           ),
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:34:5
+   |
+LL |     fn assoc_test(&self) { }
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-consts/associated-const-array-len.stderr b/tests/ui/associated-consts/associated-const-array-len.stderr
index 0e0dec35b53..e3db45810fd 100644
--- a/tests/ui/associated-consts/associated-const-array-len.stderr
+++ b/tests/ui/associated-consts/associated-const-array-len.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied
    |
 LL | const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
    |                 ^^^ the trait `Foo` is not implemented for `i32`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-const-array-len.rs:1:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index e9fe3a5e514..927422fa8dc 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -51,6 +51,11 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
 LL |     foo::<Demo>()();
    |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-105330.rs:1:1
+   |
+LL | pub trait TraitWAssocConst {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:11
    |
@@ -87,6 +92,11 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
 LL |     foo::<Demo>();
    |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-105330.rs:1:1
+   |
+LL | pub trait TraitWAssocConst {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:11
    |
diff --git a/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr b/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
index 8c3463a2832..fbc4ccd4cf4 100644
--- a/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
+++ b/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Add<A>` is not satisfied
    |
 LL |     r = r + a;
    |           ^ the trait `Add<A>` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-types-ICE-when-projecting-out-of-err.rs:15:1
+   |
+LL | trait Add<RHS=Self> {
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index bd3ee2abd2c..b3f2e16ba0d 100644
--- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(T, U): Get` is not satisfied
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
    |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-types-no-suitable-supertrait.rs:12:1
+   |
+LL | trait Get {
+   | ^^^^^^^^^
 
 error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:17:40
diff --git a/tests/ui/associated-types/defaults-suitability.stderr b/tests/ui/associated-types/defaults-suitability.stderr
index 4b2094691f8..0a8ad0f89e2 100644
--- a/tests/ui/associated-types/defaults-suitability.stderr
+++ b/tests/ui/associated-types/defaults-suitability.stderr
@@ -58,6 +58,11 @@ error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
 LL |     type Assoc: Foo<Self> = ();
    |                             ^^ the trait `Foo<Self>` is not implemented for `()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/defaults-suitability.rs:27:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
 note: required by a bound in `Bar::Assoc`
   --> $DIR/defaults-suitability.rs:34:17
    |
diff --git a/tests/ui/associated-types/issue-23595-2.stderr b/tests/ui/associated-types/issue-23595-2.stderr
index dded673f6ee..73effa9f955 100644
--- a/tests/ui/associated-types/issue-23595-2.stderr
+++ b/tests/ui/associated-types/issue-23595-2.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `anything_here_kills_it` not found for `Self`
   --> $DIR/issue-23595-2.rs:6:22
    |
 LL |     type B = C<Self::anything_here_kills_it>;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: `Self` has the following associated type: `B`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr
index a84b599b52b..266e22d4726 100644
--- a/tests/ui/associated-types/issue-59324.stderr
+++ b/tests/ui/associated-types/issue-59324.stderr
@@ -48,6 +48,12 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
    |
 LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-59324.rs:3:1
+   |
+LL | pub trait Foo: NotFoo {
+   | ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
   --> $DIR/issue-59324.rs:19:10
diff --git a/tests/ui/associated-types/issue-64855.stderr b/tests/ui/associated-types/issue-64855.stderr
index 6ad795c1117..f1016f0e3a1 100644
--- a/tests/ui/associated-types/issue-64855.stderr
+++ b/tests/ui/associated-types/issue-64855.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied
    |
 LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
    |                   ^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<T>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-64855.rs:1:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs
new file mode 100644
index 00000000000..77c9876ffa5
--- /dev/null
+++ b/tests/ui/associated-types/issue-85103-layout-debug.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ the trait bound `[E]: ToOwned` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.stderr b/tests/ui/associated-types/issue-85103-layout-debug.stderr
new file mode 100644
index 00000000000..0bdea10ba47
--- /dev/null
+++ b/tests/ui/associated-types/issue-85103-layout-debug.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `[E]: ToOwned` is not satisfied
+  --> $DIR/issue-85103-layout-debug.rs:6:21
+   |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+   |                     ^^^^^^^^^^^^ the trait `ToOwned` is not implemented for `[E]`
+   |
+note: required by a bound in `Cow`
+  --> $SRC_DIR/alloc/src/borrow.rs:LL:COL
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | type Edges<'a, E> where [E]: ToOwned = Cow<'a, [E]>;
+   |                   ++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/issue-85103.rs b/tests/ui/associated-types/issue-85103.rs
deleted file mode 100644
index 9c6a419e9f7..00000000000
--- a/tests/ui/associated-types/issue-85103.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(rustc_attrs)]
-
-use std::borrow::Cow;
-
-#[rustc_layout(debug)]
-type Edges<'a, E> = Cow<'a, [E]>;
-//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
-
-fn main() {}
diff --git a/tests/ui/associated-types/issue-85103.stderr b/tests/ui/associated-types/issue-85103.stderr
deleted file mode 100644
index 17f7148074c..00000000000
--- a/tests/ui/associated-types/issue-85103.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
-  --> $DIR/issue-85103.rs:6:1
-   |
-LL | type Edges<'a, E> = Cow<'a, [E]>;
-   | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
index 3b4689e08cc..056d9201b4a 100644
--- a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
+++ b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Foo::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:4:17
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Baz::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:13:18
    |
@@ -31,6 +41,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Bat::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:24:27
    |
diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr
index 5d29325c827..c855e902ba9 100644
--- a/tests/ui/async-await/async-is-unwindsafe.stderr
+++ b/tests/ui/async-await/async-is-unwindsafe.stderr
@@ -15,7 +15,7 @@ LL | |     });
    |       within this `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`
    |
    = help: within `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`
-   = note: `UnwindSafe` is implemented for `&std::task::Context<'_>`, but not for `&mut std::task::Context<'_>`
+   = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
 note: future does not implement `UnwindSafe` as this value is used across an await
   --> $DIR/async-is-unwindsafe.rs:25:18
    |
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
new file mode 100644
index 00000000000..4653fe7375d
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+pub trait Layer {
+    fn process(&mut self) -> u32;
+}
+
+pub struct State {
+    layers: Vec<Box<dyn Layer>>,
+}
+
+impl State {
+    pub fn process(&mut self) -> u32 {
+        self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
+        //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
new file mode 100644
index 00000000000..e0f6ab1321f
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+pub trait Layer {
+    fn process(&mut self) -> u32;
+}
+
+pub struct State {
+    layers: Vec<Box<dyn Layer>>,
+}
+
+impl State {
+    pub fn process(&mut self) -> u32 {
+        self.layers.iter().fold(0, |result, mut layer| result + layer.process())
+        //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
new file mode 100644
index 00000000000..7e0fc2cf298
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
@@ -0,0 +1,16 @@
+error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-115259-suggest-iter-mut.rs:15:65
+   |
+LL |         self.layers.iter().fold(0, |result, mut layer| result + layer.process())
+   |                                             ---------           ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                             |
+   |                                             consider changing this binding's type to be: `&mut Box<dyn Layer>`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |         self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
+   |                     ~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
new file mode 100644
index 00000000000..f02374d8e11
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+use std::path::PathBuf;
+
+#[derive(Clone)]
+struct Container {
+    things: Vec<PathBuf>,
+}
+
+impl Container {
+    fn things(&mut self) -> &[PathBuf] {
+        &self.things
+    }
+}
+
+// contains containers
+struct ContainerContainer {
+    contained: Vec<Container>,
+}
+
+impl ContainerContainer {
+    fn contained(&self) -> &[Container] {
+        &self.contained
+    }
+
+    fn all_the_things(&mut self) -> &[PathBuf] {
+        let mut vec = self.contained.clone();
+        let _a =
+            vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+        //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
new file mode 100644
index 00000000000..2d0b837a946
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+use std::path::PathBuf;
+
+#[derive(Clone)]
+struct Container {
+    things: Vec<PathBuf>,
+}
+
+impl Container {
+    fn things(&mut self) -> &[PathBuf] {
+        &self.things
+    }
+}
+
+// contains containers
+struct ContainerContainer {
+    contained: Vec<Container>,
+}
+
+impl ContainerContainer {
+    fn contained(&self) -> &[Container] {
+        &self.contained
+    }
+
+    fn all_the_things(&mut self) -> &[PathBuf] {
+        let mut vec = self.contained.clone();
+        let _a =
+            vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+        //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
new file mode 100644
index 00000000000..19f194100a1
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
@@ -0,0 +1,16 @@
+error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45
+   |
+LL |             vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+   |                                  ---------  ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                  |
+   |                                  consider changing this binding's type to be: `&mut Container`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |             vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+   |                 ~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
new file mode 100644
index 00000000000..8bf2625de6d
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct A {
+    a: i32,
+}
+
+impl A {
+    fn double(&mut self) {
+        self.a += self.a
+    }
+}
+
+fn baz() {
+    let mut v = [A { a: 4 }];
+    v.iter_mut().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn bar() {
+    let mut v = [A { a: 4 }];
+    v.iter_mut().rev().rev().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
new file mode 100644
index 00000000000..39bc30bf294
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct A {
+    a: i32,
+}
+
+impl A {
+    fn double(&mut self) {
+        self.a += self.a
+    }
+}
+
+fn baz() {
+    let mut v = [A { a: 4 }];
+    v.iter().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn bar() {
+    let mut v = [A { a: 4 }];
+    v.iter().rev().rev().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
new file mode 100644
index 00000000000..fd58e433020
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
@@ -0,0 +1,29 @@
+error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut.rs:18:27
+   |
+LL |     v.iter().for_each(|a| a.double());
+   |                        -  ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                        |
+   |                        consider changing this binding's type to be: `&mut A`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |     v.iter_mut().for_each(|a| a.double());
+   |       ~~~~~~~~
+
+error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut.rs:25:39
+   |
+LL |     v.iter().rev().rev().for_each(|a| a.double());
+   |                                    -  ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                    |
+   |                                    consider changing this binding's type to be: `&mut A`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |     v.iter_mut().rev().rev().for_each(|a| a.double());
+   |       ~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs
index fbebc80d91c..750a88f97eb 100644
--- a/tests/ui/cast/cast-as-bool.rs
+++ b/tests/ui/cast/cast-as-bool.rs
@@ -1,12 +1,48 @@
 fn main() {
-    let u = 5 as bool; //~ ERROR cannot cast as `bool`
+    let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool`
                        //~| HELP compare with zero instead
                        //~| SUGGESTION 5 != 0
 
-    let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
+    let t = (1 + 2) as bool; //~ ERROR cannot cast `i32` as `bool`
                              //~| HELP compare with zero instead
                              //~| SUGGESTION (1 + 2) != 0
 
+    let _ = 5_u32 as bool; //~ ERROR cannot cast `u32` as `bool`
+                           //~| HELP compare with zero instead
+
+    let _ = 64.0_f64 as bool; //~ ERROR cannot cast `f64` as `bool`
+                              //~| HELP compare with zero instead
+
+    // Enums that can normally be cast to integers can't be cast to `bool`, just like integers.
+    // Note that enums that cannot be cast to integers can't be cast to anything at *all*
+    // so that's not tested here.
+    enum IntEnum {
+        Zero,
+        One,
+        Two
+    }
+    let _ = IntEnum::One as bool; //~ ERROR cannot cast `IntEnum` as `bool`
+
+    fn uwu(_: u8) -> String {
+        todo!()
+    }
+
+    unsafe fn owo() {}
+
+    // fn item to bool
+    let _ = uwu as bool; //~ ERROR cannot cast `fn(u8) -> String {uwu}` as `bool`
+    // unsafe fn item
+    let _ = owo as bool; //~ ERROR cannot cast `unsafe fn() {owo}` as `bool`
+
+    // fn ptr to bool
+    let _ = uwu as fn(u8) -> String as bool; //~ ERROR cannot cast `fn(u8) -> String` as `bool`
+
+    let _ = 'x' as bool; //~ ERROR cannot cast `char` as `bool`
+
+    let ptr = 1 as *const ();
+
+    let _ = ptr as bool; //~ ERROR cannot cast `*const ()` as `bool`
+
     let v = "hello" as bool;
     //~^ ERROR casting `&'static str` as `bool` is invalid
     //~| HELP consider using the `is_empty` method on `&'static str` to determine if it contains anything
diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr
index 19ac8f10fec..852fb30cc20 100644
--- a/tests/ui/cast/cast-as-bool.stderr
+++ b/tests/ui/cast/cast-as-bool.stderr
@@ -1,18 +1,66 @@
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:2:13
    |
 LL |     let u = 5 as bool;
    |             ^^^^^^^^^ help: compare with zero instead: `5 != 0`
 
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:6:13
    |
 LL |     let t = (1 + 2) as bool;
    |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
 
-error[E0606]: casting `&'static str` as `bool` is invalid
+error[E0054]: cannot cast `u32` as `bool`
   --> $DIR/cast-as-bool.rs:10:13
    |
+LL |     let _ = 5_u32 as bool;
+   |             ^^^^^^^^^^^^^ help: compare with zero instead: `5_u32 != 0`
+
+error[E0054]: cannot cast `f64` as `bool`
+  --> $DIR/cast-as-bool.rs:13:13
+   |
+LL |     let _ = 64.0_f64 as bool;
+   |             ^^^^^^^^^^^^^^^^ help: compare with zero instead: `64.0_f64 != 0`
+
+error[E0054]: cannot cast `IntEnum` as `bool`
+  --> $DIR/cast-as-bool.rs:24:13
+   |
+LL |     let _ = IntEnum::One as bool;
+   |             ^^^^^^^^^^^^^^^^^^^^ unsupported cast
+
+error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool`
+  --> $DIR/cast-as-bool.rs:33:13
+   |
+LL |     let _ = uwu as bool;
+   |             ^^^^^^^^^^^ unsupported cast
+
+error[E0054]: cannot cast `unsafe fn() {owo}` as `bool`
+  --> $DIR/cast-as-bool.rs:35:13
+   |
+LL |     let _ = owo as bool;
+   |             ^^^^^^^^^^^ unsupported cast
+
+error[E0054]: cannot cast `fn(u8) -> String` as `bool`
+  --> $DIR/cast-as-bool.rs:38:13
+   |
+LL |     let _ = uwu as fn(u8) -> String as bool;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast
+
+error[E0054]: cannot cast `char` as `bool`
+  --> $DIR/cast-as-bool.rs:40:13
+   |
+LL |     let _ = 'x' as bool;
+   |             ^^^^^^^^^^^ unsupported cast
+
+error[E0054]: cannot cast `*const ()` as `bool`
+  --> $DIR/cast-as-bool.rs:44:13
+   |
+LL |     let _ = ptr as bool;
+   |             ^^^^^^^^^^^ unsupported cast
+
+error[E0606]: casting `&'static str` as `bool` is invalid
+  --> $DIR/cast-as-bool.rs:46:13
+   |
 LL |     let v = "hello" as bool;
    |             ^^^^^^^^^^^^^^^
    |
@@ -21,7 +69,7 @@ help: consider using the `is_empty` method on `&'static str` to determine if it
 LL |     let v = !"hello".is_empty();
    |             +       ~~~~~~~~~~~
 
-error: aborting due to 3 previous errors
+error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0054, E0606.
 For more information about an error, try `rustc --explain E0054`.
diff --git a/tests/ui/cast/cast-rfc0401-2.rs b/tests/ui/cast/cast-rfc0401-2.rs
index 7709aa34104..70604a587ea 100644
--- a/tests/ui/cast/cast-rfc0401-2.rs
+++ b/tests/ui/cast/cast-rfc0401-2.rs
@@ -4,5 +4,5 @@
 
 fn main() {
     let _ = 3 as bool;
-    //~^ ERROR cannot cast as `bool`
+    //~^ ERROR cannot cast `i32` as `bool`
 }
diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr
index 52f6af78a9b..5dc21ca847c 100644
--- a/tests/ui/cast/cast-rfc0401-2.stderr
+++ b/tests/ui/cast/cast-rfc0401-2.stderr
@@ -1,4 +1,4 @@
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401-2.rs:6:13
    |
 LL |     let _ = 3 as bool;
diff --git a/tests/ui/codegen/subtyping-enforces-type-equality.rs b/tests/ui/codegen/subtyping-enforces-type-equality.rs
new file mode 100644
index 00000000000..a5ffcb3f854
--- /dev/null
+++ b/tests/ui/codegen/subtyping-enforces-type-equality.rs
@@ -0,0 +1,48 @@
+// ignore-pass
+// build-pass
+// edition:2021
+use std::future::Future;
+use std::pin::Pin;
+
+type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
+
+fn main() {
+    let _ = wrapper_call(handler);
+}
+
+async fn wrapper_call(handler: impl Handler) {
+    handler.call().await;
+}
+async fn handler() {
+    f(&()).await;
+}
+async fn f<'a>(db: impl Acquire<'a>) {
+    db.acquire().await;
+}
+
+trait Handler {
+    type Future: Future;
+    fn call(self) -> Self::Future;
+}
+
+impl<Fut, F> Handler for F
+where
+    F: Fn() -> Fut,
+    Fut: Future,
+{
+    type Future = Fut;
+    fn call(self) -> Self::Future {
+        loop {}
+    }
+}
+
+trait Acquire<'a> {
+    type Connection;
+    fn acquire(self) -> BoxFuture<Self::Connection>;
+}
+impl<'a> Acquire<'a> for &'a () {
+    type Connection = Self;
+    fn acquire(self) -> BoxFuture<Self> {
+        loop {}
+    }
+}
diff --git a/tests/ui/codegen/subtyping-enforces-type-equality.stderr b/tests/ui/codegen/subtyping-enforces-type-equality.stderr
new file mode 100644
index 00000000000..870ca0f839f
--- /dev/null
+++ b/tests/ui/codegen/subtyping-enforces-type-equality.stderr
@@ -0,0 +1 @@
+WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type. See the issues/114858
diff --git a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
index 2e2dac288a1..a3a37fd2775 100644
--- a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
+++ b/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
@@ -6,6 +6,11 @@ LL |     takes_t(t);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/coherence-unsafe-trait-object-impl.rs:6:1
+   |
+LL | trait Trait: Sized {
+   | ^^^^^^^^^^^^^^^^^^
 note: required by a bound in `takes_t`
   --> $DIR/coherence-unsafe-trait-object-impl.rs:10:15
    |
diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
index cb51d9b1ea5..b3a27566026 100644
--- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
+++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `[Adt; std::mem::size_of::<Self::Assoc>()]: Foo` i
    |
 LL |         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; std::mem::size_of::<Self::Assoc>()]`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-evaluate-array-len-on-err-1.rs:9:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/early/const-param-from-outer-fn.rs b/tests/ui/const-generics/early/const-param-from-outer-fn.rs
index c3b418ee3f8..ee57f3c4fc3 100644
--- a/tests/ui/const-generics/early/const-param-from-outer-fn.rs
+++ b/tests/ui/const-generics/early/const-param-from-outer-fn.rs
@@ -1,6 +1,6 @@
 fn foo<const X: u32>() {
     fn bar() -> u32 {
-        X //~ ERROR can't use generic parameters from outer function
+        X //~ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/const-generics/early/const-param-from-outer-fn.stderr b/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
index e3bf38b702e..826f2657905 100644
--- a/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
+++ b/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/const-param-from-outer-fn.rs:3:9
    |
 LL | fn foo<const X: u32>() {
-   |              - const parameter from outer function
+   |              - const parameter from outer item
 LL |     fn bar() -> u32 {
-   |           - help: try using a local generic parameter instead: `<X>`
+   |           - help: try introducing a local generic parameter here: `<X>`
 LL |         X
-   |         ^ use of generic parameter from outer function
+   |         ^ use of generic parameter from outer item
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
index e50ac671eca..9391b1c1a17 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
@@ -6,7 +6,11 @@ LL |     writes_to_specific_path(&cap);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Delegates<U>` is implemented for `T`
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-85848.rs:4:1
+   |
+LL | trait _Contains<T> {
+   | ^^^^^^^^^^^^^^^^^^
 note: required for `&C` to implement `Contains<(), true>`
   --> $DIR/issue-85848.rs:21:12
    |
diff --git a/tests/ui/const-generics/issues/issue-86530.stderr b/tests/ui/const-generics/issues/issue-86530.stderr
index 620ed4f0fb2..d02808f7c56 100644
--- a/tests/ui/const-generics/issues/issue-86530.stderr
+++ b/tests/ui/const-generics/issues/issue-86530.stderr
@@ -6,6 +6,11 @@ LL |     z(" ");
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-86530.rs:4:1
+   |
+LL | pub trait X {
+   | ^^^^^^^^^^^
 note: required by a bound in `z`
   --> $DIR/issue-86530.rs:10:8
    |
diff --git a/tests/ui/cross/cross-fn-cache-hole.stderr b/tests/ui/cross/cross-fn-cache-hole.stderr
index 7e15562b081..79d1713934b 100644
--- a/tests/ui/cross/cross-fn-cache-hole.stderr
+++ b/tests/ui/cross/cross-fn-cache-hole.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `i32: Bar<u32>` is not satisfied
 LL |     where i32: Foo<u32, A>
    |           ^^^^^^^^^^^^^^^^ the trait `Bar<u32>` is not implemented for `i32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/cross-fn-cache-hole.rs:11:1
+   |
+LL | trait Bar<X> { }
+   | ^^^^^^^^^^^^
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 6bfc859bfe8..3d9f8129d93 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -60,7 +60,7 @@ impl ::core::marker::StructuralEq for Empty { }
 impl ::core::cmp::Eq for Empty {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
@@ -135,7 +135,7 @@ impl ::core::marker::StructuralEq for Point { }
 impl ::core::cmp::Eq for Point {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
     }
@@ -221,7 +221,7 @@ impl ::core::marker::StructuralEq for PackedPoint { }
 impl ::core::cmp::Eq for PackedPoint {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
     }
@@ -334,7 +334,7 @@ impl ::core::marker::StructuralEq for Big { }
 impl ::core::cmp::Eq for Big {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
     }
@@ -500,7 +500,7 @@ impl ::core::marker::StructuralEq for Unsized { }
 impl ::core::cmp::Eq for Unsized {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<[u32]>;
     }
@@ -615,7 +615,7 @@ impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for
     Generic<T, U> where T::A: ::core::cmp::Eq {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<T>;
         let _: ::core::cmp::AssertParamIsEq<T::A>;
@@ -738,7 +738,7 @@ impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq +
     T::A: ::core::cmp::Eq + ::core::marker::Copy {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<T>;
         let _: ::core::cmp::AssertParamIsEq<T::A>;
@@ -821,7 +821,7 @@ impl ::core::marker::StructuralEq for Enum0 { }
 impl ::core::cmp::Eq for Enum0 {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
@@ -892,7 +892,7 @@ impl ::core::marker::StructuralEq for Enum1 { }
 impl ::core::cmp::Eq for Enum1 {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
     }
@@ -959,7 +959,7 @@ impl ::core::marker::StructuralEq for Fieldless1 { }
 impl ::core::cmp::Eq for Fieldless1 {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
@@ -1034,7 +1034,7 @@ impl ::core::marker::StructuralEq for Fieldless { }
 impl ::core::cmp::Eq for Fieldless {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
@@ -1142,7 +1142,7 @@ impl ::core::marker::StructuralEq for Mixed { }
 impl ::core::cmp::Eq for Mixed {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
         let _: ::core::cmp::AssertParamIsEq<Option<u32>>;
@@ -1270,7 +1270,7 @@ impl ::core::marker::StructuralEq for Fielded { }
 impl ::core::cmp::Eq for Fielded {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
         let _: ::core::cmp::AssertParamIsEq<bool>;
@@ -1393,7 +1393,7 @@ impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for
     EnumGeneric<T, U> {
     #[inline]
     #[doc(hidden)]
-    #[no_coverage]
+    #[coverage(off)]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<T>;
         let _: ::core::cmp::AssertParamIsEq<U>;
diff --git a/tests/ui/dst/dst-bad-coerce1.stderr b/tests/ui/dst/dst-bad-coerce1.stderr
index 2c75518c298..455d15e935f 100644
--- a/tests/ui/dst/dst-bad-coerce1.stderr
+++ b/tests/ui/dst/dst-bad-coerce1.stderr
@@ -15,6 +15,11 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
 LL |     let f3: &Fat<dyn Bar> = f2;
    |                             ^^ the trait `Bar` is not implemented for `Foo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dst-bad-coerce1.rs:10:1
+   |
+LL | trait Bar { fn bar(&self) {} }
+   | ^^^^^^^^^
    = note: required for the cast from `&Fat<Foo>` to `&Fat<dyn Bar>`
 
 error[E0308]: mismatched types
@@ -34,6 +39,11 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
 LL |     let f3: &(dyn Bar,) = f2;
    |                           ^^ the trait `Bar` is not implemented for `Foo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dst-bad-coerce1.rs:10:1
+   |
+LL | trait Bar { fn bar(&self) {} }
+   | ^^^^^^^^^
    = note: required for the cast from `&(Foo,)` to `&(dyn Bar,)`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr
index ae54b9ca707..e039bb6f1c8 100644
--- a/tests/ui/dyn-star/error.stderr
+++ b/tests/ui/dyn-star/error.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied
    |
 LL |     let dyn_i: dyn* Foo = i;
    |                           ^ the trait `Foo` is not implemented for `{integer}`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/error.rs:6:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0054.stderr b/tests/ui/error-codes/E0054.stderr
index 6b1092760fb..ea81f4476a7 100644
--- a/tests/ui/error-codes/E0054.stderr
+++ b/tests/ui/error-codes/E0054.stderr
@@ -1,4 +1,4 @@
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/E0054.rs:3:24
    |
 LL |     let x_is_nonzero = x as bool;
diff --git a/tests/ui/error-codes/E0220.stderr b/tests/ui/error-codes/E0220.stderr
index 11763ce788d..e03eadacae4 100644
--- a/tests/ui/error-codes/E0220.stderr
+++ b/tests/ui/error-codes/E0220.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `F` not found for `Trait`
   --> $DIR/E0220.rs:5:22
    |
 LL | type Foo = dyn Trait<F=i32>;
-   |                      ^ associated type `F` not found
+   |                      ^ help: `Trait` has the following associated type: `Bar`
 
 error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified
   --> $DIR/E0220.rs:5:16
diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr
index 440e43dff81..0b0d2b09720 100644
--- a/tests/ui/error-codes/E0277.stderr
+++ b/tests/ui/error-codes/E0277.stderr
@@ -21,6 +21,11 @@ LL |     some_func(5i32);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/E0277.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `some_func`
   --> $DIR/E0277.rs:7:17
    |
diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr
index fa4b91cacef..928c8d11d20 100644
--- a/tests/ui/error-codes/E0401.stderr
+++ b/tests/ui/error-codes/E0401.stderr
@@ -1,26 +1,26 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:4:39
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |             -                         ^ use of generic parameter from outer function
+   |             -                         ^ use of generic parameter from outer item
    |             |
-   |             help: try using a local generic parameter instead: `T,`
+   |             help: try introducing a local generic parameter here: `T,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:9:16
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 ...
 LL |     fn baz<U,
-   |            - help: try using a local generic parameter instead: `T,`
+   |            - help: try introducing a local generic parameter here: `T,`
 ...
 LL |            (y: T) {
-   |                ^ use of generic parameter from outer function
+   |                ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
@@ -29,8 +29,8 @@ LL | impl<T> Iterator for A<T> {
 LL |         fn helper(sel: &Self) -> u8 {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer function
-   |                         use a type here instead
+   |                         use of generic parameter from outer item
+   |                         refer to the type directly here instead
 
 error[E0282]: type annotations needed
   --> $DIR/E0401.rs:11:5
diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs
index 8fadce526d9..77d28838a10 100644
--- a/tests/ui/error-codes/E0602.rs
+++ b/tests/ui/error-codes/E0602.rs
@@ -1,6 +1,8 @@
 // compile-flags:-D bogus
+// check-pass
 
 // error-pattern:E0602
 // error-pattern:requested on the command line with `-D bogus`
+// error-pattern:`#[warn(unknown_lints)]` on by default
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0602.stderr b/tests/ui/error-codes/E0602.stderr
index 2b372263345..60ecec7cdd7 100644
--- a/tests/ui/error-codes/E0602.stderr
+++ b/tests/ui/error-codes/E0602.stderr
@@ -1,11 +1,16 @@
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error: aborting due to 2 previous errors
+warning[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+warning: 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr
index e8ee1d96942..74a2bc8d768 100644
--- a/tests/ui/error-festival.stderr
+++ b/tests/ui/error-festival.stderr
@@ -59,7 +59,7 @@ error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
 LL |     x as Vec<u8>;
    |     ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `{integer}` as `bool`
   --> $DIR/error-festival.rs:33:24
    |
 LL |     let x_is_nonzero = x as bool;
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
new file mode 100644
index 00000000000..0a463755f13
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+#![feature(no_coverage)] //~ ERROR feature has been removed [E0557]
+
+#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(coverage)`
+struct Foo {
+    a: u8,
+    b: u32,
+}
+
+#[coverage(off)] //~ ERROR the `#[coverage]` attribute is an experimental feature
+fn requires_feature_coverage() -> bool {
+    let bar = Foo { a: 0, b: 0 };
+    bar == Foo { a: 0, b: 0 }
+}
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
new file mode 100644
index 00000000000..3912b9834fe
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
@@ -0,0 +1,21 @@
+error[E0557]: feature has been removed
+  --> $DIR/feature-gate-coverage-attribute.rs:2:12
+   |
+LL | #![feature(no_coverage)]
+   |            ^^^^^^^^^^^ feature has been removed
+   |
+   = note: renamed to `coverage`
+
+error[E0658]: the `#[coverage]` attribute is an experimental feature
+  --> $DIR/feature-gate-coverage-attribute.rs:10:1
+   |
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
+   = help: add `#![feature(coverage_attribute)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0557, E0658.
+For more information about an error, try `rustc --explain E0557`.
diff --git a/tests/ui/feature-gates/feature-gate-no_coverage.rs b/tests/ui/feature-gates/feature-gate-no_coverage.rs
deleted file mode 100644
index fd4c6f76059..00000000000
--- a/tests/ui/feature-gates/feature-gate-no_coverage.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![crate_type = "lib"]
-
-#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(no_coverage)`
-struct Foo {
-    a: u8,
-    b: u32,
-}
-
-#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
-fn requires_feature_no_coverage() -> bool {
-    let bar = Foo { a: 0, b: 0 };
-    bar == Foo { a: 0, b: 0 }
-}
diff --git a/tests/ui/feature-gates/feature-gate-no_coverage.stderr b/tests/ui/feature-gates/feature-gate-no_coverage.stderr
deleted file mode 100644
index f7167e0b771..00000000000
--- a/tests/ui/feature-gates/feature-gate-no_coverage.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[no_coverage]` attribute is an experimental feature
-  --> $DIR/feature-gate-no_coverage.rs:9:1
-   |
-LL | #[no_coverage]
-   | ^^^^^^^^^^^^^^
-   |
-   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
-   = help: add `#![feature(no_coverage)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/generic-associated-types/issue-101020.stderr b/tests/ui/generic-associated-types/issue-101020.stderr
index 5c8db617c17..91967fb8509 100644
--- a/tests/ui/generic-associated-types/issue-101020.stderr
+++ b/tests/ui/generic-associated-types/issue-101020.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satis
 LL |     (&mut EmptyIter).consume(());
    |                      ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-101020.rs:28:1
+   |
+LL | trait Foo<T> {}
+   | ^^^^^^^^^^^^
 note: required for `&'a mut ()` to implement `for<'a> FuncInput<'a, &'a mut ()>`
   --> $DIR/issue-101020.rs:27:20
    |
diff --git a/tests/ui/generics/issue-94432-garbage-ice.rs b/tests/ui/generics/issue-94432-garbage-ice.rs
index d0709e2d2a4..4ddb3a7e9f8 100644
--- a/tests/ui/generics/issue-94432-garbage-ice.rs
+++ b/tests/ui/generics/issue-94432-garbage-ice.rs
@@ -4,7 +4,7 @@
 
 fn�a<e>(){fn�p(){e}} //~ ERROR unknown start of token: \u{fffd}
 //~^ ERROR unknown start of token: \u{fffd}
-//~^^ ERROR can't use generic parameters from outer function [E0401]
+//~^^ ERROR can't use generic parameters from outer item [E0401]
 //~^^^ WARN type parameter `e` should have an upper camel case name
 
 fn main(){}
diff --git a/tests/ui/generics/issue-98432.rs b/tests/ui/generics/issue-98432.rs
index 780c50d6ffa..c31dea76c09 100644
--- a/tests/ui/generics/issue-98432.rs
+++ b/tests/ui/generics/issue-98432.rs
@@ -2,7 +2,7 @@ struct Struct<T>(T);
 
 impl<T> Struct<T> {
     const CONST: fn() = || {
-        struct _Obligation where T:; //~ ERROR can't use generic parameters from outer function
+        struct _Obligation where T:; //~ ERROR can't use generic parameters from outer item
     };
 }
 
diff --git a/tests/ui/generics/issue-98432.stderr b/tests/ui/generics/issue-98432.stderr
index c7b5c33618d..0736d94106e 100644
--- a/tests/ui/generics/issue-98432.stderr
+++ b/tests/ui/generics/issue-98432.stderr
@@ -1,13 +1,13 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-98432.rs:5:34
    |
 LL | impl<T> Struct<T> {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     const CONST: fn() = || {
 LL |         struct _Obligation where T:;
-   |                           -      ^ use of generic parameter from outer function
+   |                           -      ^ use of generic parameter from outer item
    |                           |
-   |                           help: try using a local generic parameter instead: `<T>`
+   |                           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
index edef6ccd34e..7fe803550bd 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL |     C: StackContext,
    |        ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
@@ -26,6 +31,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL | impl<C> EthernetWorker<C> {}
    |         ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
@@ -48,6 +58,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL |     type Handler = Ctx<C::Dispatcher>;
    |                    ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
diff --git a/tests/ui/impl-trait/async_scope_creep.rs b/tests/ui/impl-trait/async_scope_creep.rs
index 7a9d64d339f..9a8831a299e 100644
--- a/tests/ui/impl-trait/async_scope_creep.rs
+++ b/tests/ui/impl-trait/async_scope_creep.rs
@@ -1,6 +1,7 @@
 #![feature(type_alias_impl_trait)]
 // edition:2021
-// check-pass
+//[rpit] check-pass
+// revisions: tait rpit
 
 struct Pending {}
 
@@ -12,15 +13,23 @@ impl AsyncRead for i32 {}
 
 type PendingReader<'a> = impl AsyncRead + 'a;
 
-type OpeningReadFuture<'a> =
-    impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
+#[cfg(tait)]
+type OpeningReadFuture<'a> = impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
 
 impl Pending {
     async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
         Ok(42)
     }
 
+    #[cfg(tait)]
     fn read_fut(&mut self) -> OpeningReadFuture<'_> {
+        self.read() //[tait]~ ERROR: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+    }
+
+    #[cfg(rpit)]
+    fn read_fut(
+        &mut self,
+    ) -> impl std::future::Future<Output = Result<PendingReader<'_>, CantOpen>> {
         self.read()
     }
 }
diff --git a/tests/ui/impl-trait/async_scope_creep.tait.stderr b/tests/ui/impl-trait/async_scope_creep.tait.stderr
new file mode 100644
index 00000000000..165096a0574
--- /dev/null
+++ b/tests/ui/impl-trait/async_scope_creep.tait.stderr
@@ -0,0 +1,9 @@
+error[E0284]: type annotations needed: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+  --> $DIR/async_scope_creep.rs:26:9
+   |
+LL |         self.read()
+   |         ^^^^^^^^^^^ cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/imports/import-after-macro-expand-10.rs b/tests/ui/imports/import-after-macro-expand-10.rs
new file mode 100644
index 00000000000..b3520c42dfc
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-10.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+mod b {
+    pub mod http {
+        pub struct HeaderMap;
+    }
+
+    pub use self::http::*;
+    #[derive(Debug)]
+    pub struct HeaderMap;
+}
+
+use crate::b::*;
+
+fn main() {
+    let h: crate::b::HeaderMap = HeaderMap;
+}
diff --git a/tests/ui/imports/import-after-macro-expand-11.rs b/tests/ui/imports/import-after-macro-expand-11.rs
new file mode 100644
index 00000000000..2b81dfc236a
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-11.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+#[derive(Debug)]
+struct H;
+
+mod p {
+    use super::*;
+
+    #[derive(Clone)]
+    struct H;
+
+    mod t {
+        use super::*;
+
+        fn f() {
+           let h: crate::p::H = H;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/imports/import-after-macro-expand-12.rs b/tests/ui/imports/import-after-macro-expand-12.rs
new file mode 100644
index 00000000000..f92e8c12fca
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-12.rs
@@ -0,0 +1,34 @@
+// check-pass
+// https://github.com/rust-lang/rust/issues/115377
+
+use module::*;
+
+mod module {
+    pub enum B {}
+    impl B {
+        pub const ASSOC: u8 = 0;
+    }
+}
+
+#[derive()]
+pub enum B {}
+impl B {
+    pub const ASSOC: u16 = 0;
+}
+
+macro_rules! m {
+    ($right:expr) => {
+        $right
+    };
+}
+
+fn main() {
+    let a: u16 = {
+        use self::*;
+        B::ASSOC
+    };
+    let b: u16 = m!({
+        use self::*;
+        B::ASSOC
+    });
+}
diff --git a/tests/ui/imports/import-after-macro-expand-13.rs b/tests/ui/imports/import-after-macro-expand-13.rs
new file mode 100644
index 00000000000..fd640002c3e
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-13.rs
@@ -0,0 +1,22 @@
+// check-pass
+// similar as `import-after-macro-expand-6.rs`
+
+use crate::a::HeaderMap;
+
+mod b {
+    pub mod http {
+        pub struct HeaderMap;
+    }
+
+    pub use self::http::*;
+    #[derive(Debug)]
+    pub struct HeaderMap;
+}
+
+mod a {
+    pub use crate::b::*;
+}
+
+fn main() {
+    let h: crate::b::HeaderMap = HeaderMap;
+}
diff --git a/tests/ui/imports/import-after-macro-expand-14.rs b/tests/ui/imports/import-after-macro-expand-14.rs
new file mode 100644
index 00000000000..4d461a0e20c
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-14.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+use crate::a::HeaderMap;
+
+mod b {
+    pub mod http {
+        #[derive(Clone)]
+        pub struct HeaderMap;
+    }
+
+    pub use self::http::*;
+    #[derive(Debug)]
+    pub struct HeaderMap;
+}
+
+mod a {
+    pub use crate::b::*;
+}
+
+fn main() {
+    let h: crate::b::HeaderMap = HeaderMap;
+}
diff --git a/tests/ui/imports/import-after-macro-expand-2.rs b/tests/ui/imports/import-after-macro-expand-2.rs
index b3996d48840..ff773fc8272 100644
--- a/tests/ui/imports/import-after-macro-expand-2.rs
+++ b/tests/ui/imports/import-after-macro-expand-2.rs
@@ -12,9 +12,7 @@ mod tests {
     use super::*;
 
     fn test_thing() {
-        let thing: crate::thing::Thing = Thing::Bar;
-        // FIXME: `thing` should refer to `crate::Thing`,
-        // FIXME: but doesn't currently refer to it due to backward compatibility
+        let thing: crate::Thing = Thing::Foo;
     }
 }
 
diff --git a/tests/ui/imports/import-after-macro-expand-4.rs b/tests/ui/imports/import-after-macro-expand-4.rs
index 02cc3f01af9..fc0a232a93c 100644
--- a/tests/ui/imports/import-after-macro-expand-4.rs
+++ b/tests/ui/imports/import-after-macro-expand-4.rs
@@ -1,3 +1,4 @@
+// check-pass
 // https://github.com/rust-lang/rust/pull/113242#issuecomment-1616034904
 // similar with `import-after-macro-expand-2.rs`
 
@@ -10,16 +11,6 @@ pub use a::*;
 mod c {
     use crate::*;
     pub struct S(Vec<P>);
-    //~^ ERROR the size for values of type
-    //~| WARNING trait objects without an explicit
-    //~| WARNING this is accepted in the current edition
-    //~| WARNING trait objects without an explicit
-    //~| WARNING this is accepted in the current edition
-    //~| WARNING trait objects without an explicit
-    //~| WARNING this is accepted in the current edition
-
-    // FIXME: should works, but doesn't currently refer
-    // to it due to backward compatibility
 }
 
 #[derive(Clone)]
diff --git a/tests/ui/imports/import-after-macro-expand-4.stderr b/tests/ui/imports/import-after-macro-expand-4.stderr
deleted file mode 100644
index 01f70cfc5bf..00000000000
--- a/tests/ui/imports/import-after-macro-expand-4.stderr
+++ /dev/null
@@ -1,53 +0,0 @@
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/import-after-macro-expand-4.rs:12:22
-   |
-LL |     pub struct S(Vec<P>);
-   |                      ^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
-   |
-LL |     pub struct S(Vec<dyn P>);
-   |                      +++
-
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/import-after-macro-expand-4.rs:12:22
-   |
-LL |     pub struct S(Vec<P>);
-   |                      ^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
-   |
-LL |     pub struct S(Vec<dyn P>);
-   |                      +++
-
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/import-after-macro-expand-4.rs:12:22
-   |
-LL |     pub struct S(Vec<P>);
-   |                      ^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
-   |
-LL |     pub struct S(Vec<dyn P>);
-   |                      +++
-
-error[E0277]: the size for values of type `(dyn a::P + 'static)` cannot be known at compilation time
-  --> $DIR/import-after-macro-expand-4.rs:12:18
-   |
-LL |     pub struct S(Vec<P>);
-   |                  ^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `(dyn a::P + 'static)`
-note: required by a bound in `Vec`
-  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-
-error: aborting due to previous error; 3 warnings emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/imports/import-after-macro-expand-6.rs b/tests/ui/imports/import-after-macro-expand-6.rs
index ab5bb37a175..bff8efebca6 100644
--- a/tests/ui/imports/import-after-macro-expand-6.rs
+++ b/tests/ui/imports/import-after-macro-expand-6.rs
@@ -18,7 +18,5 @@ mod b {
 use crate::a::HeaderMap;
 
 fn main() {
-    let h: crate::b::http::HeaderMap = HeaderMap;
-    // FIXME: should refer to `crate::b::HeaderMap`,
-    // FIXME: but doesn't currently refer to it due to backward compatibility
+    let h: crate::b::HeaderMap = HeaderMap;
 }
diff --git a/tests/ui/imports/import-after-macro-expand-9.rs b/tests/ui/imports/import-after-macro-expand-9.rs
new file mode 100644
index 00000000000..deee42c3b84
--- /dev/null
+++ b/tests/ui/imports/import-after-macro-expand-9.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+use crate::b::*;
+
+mod b {
+    pub mod http {
+        pub struct HeaderMap;
+    }
+
+    pub use self::http::*;
+    #[derive(Debug)]
+    pub struct HeaderMap;
+}
+
+fn main() {
+    let h: crate::b::HeaderMap = HeaderMap;
+}
diff --git a/tests/ui/inner-static-type-parameter.rs b/tests/ui/inner-static-type-parameter.rs
index c08ccd29d80..a1994e7529c 100644
--- a/tests/ui/inner-static-type-parameter.rs
+++ b/tests/ui/inner-static-type-parameter.rs
@@ -4,7 +4,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
 
 fn foo<T>() {
     static a: Bar<T> = Bar::What;
-//~^ ERROR can't use generic parameters from outer function
+//~^ ERROR can't use generic parameters from outer item
 }
 
 fn main() {
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr
index e4e449e4159..ff6558e494b 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/inner-static-type-parameter.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/inner-static-type-parameter.rs:6:19
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     static a: Bar<T> = Bar::What;
-   |                   ^ use of generic parameter from outer function
+   |                   ^ use of generic parameter from outer item
 
 error[E0392]: parameter `T` is never used
   --> $DIR/inner-static-type-parameter.rs:3:10
diff --git a/tests/ui/issues/issue-18611.stderr b/tests/ui/issues/issue-18611.stderr
index bd18d46223e..784b9b984e9 100644
--- a/tests/ui/issues/issue-18611.stderr
+++ b/tests/ui/issues/issue-18611.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied
    |
 LL | fn add_state(op: <isize as HasState>::State) {
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-18611.rs:5:1
+   |
+LL | trait HasState {
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-25076.stderr b/tests/ui/issues/issue-25076.stderr
index 159cc484c5d..065bf7def42 100644
--- a/tests/ui/issues/issue-25076.stderr
+++ b/tests/ui/issues/issue-25076.stderr
@@ -6,6 +6,11 @@ LL |     do_fold(bot(), ());
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-25076.rs:3:1
+   |
+LL | trait InOut<T> { type Out; }
+   | ^^^^^^^^^^^^^^
 note: required by a bound in `do_fold`
   --> $DIR/issue-25076.rs:5:18
    |
diff --git a/tests/ui/issues/issue-3214.rs b/tests/ui/issues/issue-3214.rs
index e3c07bb3f72..b2c27f5be95 100644
--- a/tests/ui/issues/issue-3214.rs
+++ b/tests/ui/issues/issue-3214.rs
@@ -1,6 +1,6 @@
 fn foo<T>() {
     struct Foo {
-        x: T, //~ ERROR can't use generic parameters from outer function
+        x: T, //~ ERROR can't use generic parameters from outer item
     }
 
     impl<T> Drop for Foo<T> {
diff --git a/tests/ui/issues/issue-3214.stderr b/tests/ui/issues/issue-3214.stderr
index 7a2d772f0a1..5b57c1baf90 100644
--- a/tests/ui/issues/issue-3214.stderr
+++ b/tests/ui/issues/issue-3214.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3214.rs:3:12
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     struct Foo {
-   |               - help: try using a local generic parameter instead: `<T>`
+   |               - help: try introducing a local generic parameter here: `<T>`
 LL |         x: T,
-   |            ^ use of generic parameter from outer function
+   |            ^ use of generic parameter from outer item
 
 error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-3214.rs:6:22
diff --git a/tests/ui/issues/issue-35570.stderr b/tests/ui/issues/issue-35570.stderr
index 2697d46bdb2..197e80ac097 100644
--- a/tests/ui/issues/issue-35570.stderr
+++ b/tests/ui/issues/issue-35570.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
    |
 LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-35570.rs:4:1
+   |
+LL | trait Trait2<'a> {
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-5997-enum.rs b/tests/ui/issues/issue-5997-enum.rs
index 3ff4e036c60..0b1857ae3df 100644
--- a/tests/ui/issues/issue-5997-enum.rs
+++ b/tests/ui/issues/issue-5997-enum.rs
@@ -1,6 +1,6 @@
 fn f<Z>() -> bool {
     enum E { V(Z) }
-    //~^ ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
     true
 }
 
diff --git a/tests/ui/issues/issue-5997-enum.stderr b/tests/ui/issues/issue-5997-enum.stderr
index 3a79215d3ae..d07258ea7a2 100644
--- a/tests/ui/issues/issue-5997-enum.stderr
+++ b/tests/ui/issues/issue-5997-enum.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-5997-enum.rs:2:16
    |
 LL | fn f<Z>() -> bool {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     enum E { V(Z) }
-   |           -    ^ use of generic parameter from outer function
+   |           -    ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<Z>`
+   |           help: try introducing a local generic parameter here: `<Z>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-5997-struct.rs b/tests/ui/issues/issue-5997-struct.rs
index 6cf510b0a9d..19d994b0dfb 100644
--- a/tests/ui/issues/issue-5997-struct.rs
+++ b/tests/ui/issues/issue-5997-struct.rs
@@ -1,5 +1,5 @@
 fn f<T>() -> bool {
-    struct S(T); //~ ERROR can't use generic parameters from outer function
+    struct S(T); //~ ERROR can't use generic parameters from outer item
 
     true
 }
diff --git a/tests/ui/issues/issue-5997-struct.stderr b/tests/ui/issues/issue-5997-struct.stderr
index d2e97f76771..83229e02c6c 100644
--- a/tests/ui/issues/issue-5997-struct.stderr
+++ b/tests/ui/issues/issue-5997-struct.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-5997-struct.rs:2:14
    |
 LL | fn f<T>() -> bool {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     struct S(T);
-   |             -^ use of generic parameter from outer function
+   |             -^ use of generic parameter from outer item
    |             |
-   |             help: try using a local generic parameter instead: `<T>`
+   |             help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-60218.stderr b/tests/ui/issues/issue-60218.stderr
index 563690c9a5d..ae3c4d12025 100644
--- a/tests/ui/issues/issue-60218.stderr
+++ b/tests/ui/issues/issue-60218.stderr
@@ -6,6 +6,11 @@ LL |     trigger_error(vec![], |x: &u32| x)
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-60218.rs:7:1
+   |
+LL | pub trait Foo {}
+   | ^^^^^^^^^^^^^
 note: required by a bound in `trigger_error`
   --> $DIR/issue-60218.rs:13:72
    |
diff --git a/tests/ui/issues/issue-66353.stderr b/tests/ui/issues/issue-66353.stderr
index 71530f58220..7ab7547b42d 100644
--- a/tests/ui/issues/issue-66353.stderr
+++ b/tests/ui/issues/issue-66353.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): _A` is not satisfied
    |
 LL |     _Func::< <() as _A>::AssocT >::func(());
    |               ^^ the trait `_A` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-66353.rs:7:1
+   |
+LL | trait _A {
+   | ^^^^^^^^
 
 error[E0277]: the trait bound `(): _Func<_>` is not satisfied
   --> $DIR/issue-66353.rs:12:41
@@ -11,6 +17,12 @@ LL |     _Func::< <() as _A>::AssocT >::func(());
    |     ----------------------------------- ^^ the trait `_Func<_>` is not implemented for `()`
    |     |
    |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-66353.rs:3:1
+   |
+LL | trait _Func<T> {
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 97dc73d3aa7..65f2f3b89af 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -73,3 +73,6 @@ impl S {
     #[rustc_layout(debug)]
     const C: () = (); //~ ERROR: can only be applied to
 }
+
+#[rustc_layout(debug)]
+type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index 0973043c678..5162a771b4d 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -162,7 +162,7 @@ error: layout_of(U) = Layout {
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^
 
-error: layout_of(std::result::Result<i32, i32>) = Layout {
+error: layout_of(Result<i32, i32>) = Layout {
            size: Size(8 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -522,7 +522,7 @@ error: layout_of(P5) = Layout {
 LL | union P5 { zst: [u16; 0], byte: u8 }
    | ^^^^^^^^
 
-error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
+error: layout_of(MaybeUninit<u8>) = Layout {
            size: Size(1 bytes),
            align: AbiAndPrefAlign {
                abi: Align(1 bytes),
@@ -557,11 +557,21 @@ error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarat
 LL | const C: () = ();
    | ^^^^^^^^^^^
 
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/debug.rs:78:19
+   |
+LL | type Impossible = (str, str);
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last element of a tuple may have a dynamically sized type
+
 error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
   --> $DIR/debug.rs:74:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
 
-error: aborting due to 16 previous errors
+error: aborting due to 17 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs
new file mode 100644
index 00000000000..9703d2bf294
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.rs
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+#![feature(transparent_unions)]
+use std::marker::PhantomData;
+
+// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect
+// the result of `homogeneous_aggregate`.
+
+type Tuple = (f32, f32, f32);
+
+struct Zst;
+
+#[repr(transparent)]
+struct Wrapper1<T>(T);
+#[repr(transparent)]
+struct Wrapper2<T>((), Zst, T);
+#[repr(transparent)]
+struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
+#[repr(transparent)]
+union WrapperUnion<T: Copy> {
+    nothing: (),
+    something: T,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test0 = Tuple;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test1 = Wrapper1<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test2 = Wrapper2<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test3 = Wrapper3<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test4 = WrapperUnion<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+fn main() {}
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.stderr b/tests/ui/layout/homogeneous-aggr-transparent.stderr
new file mode 100644
index 00000000000..99eb703ac82
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.stderr
@@ -0,0 +1,32 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:25:1
+   |
+LL | pub type Test0 = Tuple;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:29:1
+   |
+LL | pub type Test1 = Wrapper1<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:33:1
+   |
+LL | pub type Test2 = Wrapper2<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:37:1
+   |
+LL | pub type Test3 = Wrapper3<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:41:1
+   |
+LL | pub type Test4 = WrapperUnion<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr
index df9f1cc8d10..8161f97dde0 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.stderr
+++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr
@@ -1,4 +1,4 @@
-error: layout_of(std::result::Result<[u32; 0], bool>) = Layout {
+error: layout_of(Result<[u32; 0], bool>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -232,7 +232,7 @@ error: layout_of(MultipleAlignments) = Layout {
 LL | enum MultipleAlignments {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) = Layout {
+error: layout_of(Result<[u32; 0], Packed<NonZeroU16>>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -337,7 +337,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) =
 LL | type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZeroU16>>;
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
+error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr
index 5b93eff8614..6361d8ad30b 100644
--- a/tests/ui/lifetimes/issue-95023.stderr
+++ b/tests/ui/lifetimes/issue-95023.stderr
@@ -36,7 +36,7 @@ error[E0220]: associated type `B` not found for `Self`
   --> $DIR/issue-95023.rs:6:44
    |
 LL |     fn foo<const N: usize>(&self) -> Self::B<{N}>;
-   |                                            ^ associated type `B` not found
+   |                                            ^ help: `Self` has the following associated type: `Output`
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index ef1127c59ac..421ab3fcf4e 100644
--- a/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
    |
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/lifetime-elision-return-type-trait.rs:1:1
+   |
+LL | trait Future {
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr
index 510b36edd8f..f0c7210dde7 100644
--- a/tests/ui/limits/issue-55878.stderr
+++ b/tests/ui/limits/issue-55878.stderr
@@ -1,6 +1,8 @@
-error[E0080]: values of the type `[u8; usize::MAX]` are too big for the current architecture
+error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
+   = note: values of the type `[u8; usize::MAX]` are too big for the current architecture
+   |
 note: inside `std::mem::size_of::<[u8; usize::MAX]>`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 note: inside `main`
diff --git a/tests/ui/limits/issue-56762.rs b/tests/ui/limits/issue-56762.rs
index ed7ee4da85d..1c7facb045d 100644
--- a/tests/ui/limits/issue-56762.rs
+++ b/tests/ui/limits/issue-56762.rs
@@ -14,8 +14,10 @@ impl TooBigArray {
 }
 
 static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new();
-//~^ ERROR values of the type `[u8; 2305843009213693951]` are too big
+//~^ ERROR could not evaluate static initializer
+//~| too big
 static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE];
-//~^ ERROR values of the type `[u8; 2305843009213693951]` are too big
+//~^ ERROR could not evaluate static initializer
+//~| too big
 
 fn main() { }
diff --git a/tests/ui/limits/issue-56762.stderr b/tests/ui/limits/issue-56762.stderr
index 29f2a8859ee..3a6c3559ac1 100644
--- a/tests/ui/limits/issue-56762.stderr
+++ b/tests/ui/limits/issue-56762.stderr
@@ -1,14 +1,14 @@
-error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture
+error[E0080]: could not evaluate static initializer
   --> $DIR/issue-56762.rs:16:1
    |
 LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693951]` are too big for the current architecture
 
-error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture
-  --> $DIR/issue-56762.rs:18:1
+error[E0080]: could not evaluate static initializer
+  --> $DIR/issue-56762.rs:19:1
    |
 LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693951]` are too big for the current architecture
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs
new file mode 100644
index 00000000000..ce8d9848e42
--- /dev/null
+++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs
@@ -0,0 +1,14 @@
+// build-fail
+// failure-status: 101
+// known-bug: #109681
+
+// This test verifies that we continue to hit the LLVM error for common linkage with non-zero
+// initializers, since it generates invalid LLVM IR.
+// Linkages are internal features marked as perma-unstable, so we don't need to fix the issue
+// for now.
+#![crate_type="lib"]
+#![feature(linkage)]
+
+#[linkage = "common"]
+#[no_mangle]
+pub static TEST: bool = true;
diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr
new file mode 100644
index 00000000000..667bb3ec130
--- /dev/null
+++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr
@@ -0,0 +1,3 @@
+'common' global must have a zero initializer!
+ptr @TEST
+LLVM ERROR: Broken module found, compilation aborted!
diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs
index f3dea87a6b6..a9e4e4a6017 100644
--- a/tests/ui/lint/cli-unknown-force-warn.rs
+++ b/tests/ui/lint/cli-unknown-force-warn.rs
@@ -1,7 +1,11 @@
 // Checks that rustc correctly errors when passed an invalid lint with
 // `--force-warn`. This is a regression test for issue #86958.
-//
+
+// check-pass
 // compile-flags: --force-warn foo-qux
+
 // error-pattern: unknown lint: `foo_qux`
+// error-pattern: requested on the command line with `--force-warn foo_qux`
+// error-pattern: `#[warn(unknown_lints)]` on by default
 
 fn main() {}
diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/cli-unknown-force-warn.stderr
index 9ce9f405aee..2ee718a8c8e 100644
--- a/tests/ui/lint/cli-unknown-force-warn.stderr
+++ b/tests/ui/lint/cli-unknown-force-warn.stderr
@@ -1,11 +1,16 @@
-error[E0602]: unknown lint: `foo_qux`
+warning[E0602]: unknown lint: `foo_qux`
    |
    = note: requested on the command line with `--force-warn foo_qux`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `foo_qux`
+warning[E0602]: unknown lint: `foo_qux`
    |
    = note: requested on the command line with `--force-warn foo_qux`
 
-error: aborting due to 2 previous errors
+warning[E0602]: unknown lint: `foo_qux`
+   |
+   = note: requested on the command line with `--force-warn foo_qux`
+
+warning: 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs
index 70dd2a71f26..ac24f61b0ac 100644
--- a/tests/ui/lint/lint-ctypes-94223.rs
+++ b/tests/ui/lint/lint-ctypes-94223.rs
@@ -24,6 +24,13 @@ enum BadUnion {
 type Foo = extern "C" fn([u8]);
 //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe
 
+pub trait FooTrait {
+    type FooType;
+}
+
+pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
+//~^ ERROR `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
+
 pub struct FfiUnsafe;
 
 #[allow(improper_ctypes_definitions)]
diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr
index 49e64ed5140..bd127cf6004 100644
--- a/tests/ui/lint/lint-ctypes-94223.stderr
+++ b/tests/ui/lint/lint-ctypes-94223.stderr
@@ -66,8 +66,17 @@ LL | type Foo = extern "C" fn([u8]);
    = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
+error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-94223.rs:31:20
+   |
+LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:34:17
+  --> $DIR/lint-ctypes-94223.rs:41:17
    |
 LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -75,13 +84,13 @@ LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:37:30
+  --> $DIR/lint-ctypes-94223.rs:44:30
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -89,13 +98,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:37:56
+  --> $DIR/lint-ctypes-94223.rs:44:56
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -103,13 +112,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:41:22
+  --> $DIR/lint-ctypes-94223.rs:48:22
    |
 LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -117,10 +126,10 @@ LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
new file mode 100644
index 00000000000..ca08eb23a57
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
@@ -0,0 +1,8 @@
+#![deny(improper_ctypes_definitions)]
+
+extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+    //~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe
+    None
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
new file mode 100644
index 00000000000..f59fb3cc750
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
@@ -0,0 +1,16 @@
+error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
+   |
+LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+   |                                             ^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs
new file mode 100644
index 00000000000..8cf91cf60eb
--- /dev/null
+++ b/tests/ui/lint/lint-removed-cmdline-deny.rs
@@ -0,0 +1,13 @@
+// The raw_pointer_derived lint warns about its removal
+// cc #30346
+
+// compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive
+
+// error-pattern:lint `raw_pointer_derive` has been removed
+// error-pattern:requested on the command line with `-D raw_pointer_derive`
+// error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+
+#![warn(unused)]
+
+#[deny(warnings)]
+fn main() { let unused = (); }
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr
new file mode 100644
index 00000000000..80c85d01e53
--- /dev/null
+++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr
@@ -0,0 +1,28 @@
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+   = note: requested on the command line with `-D renamed-and-removed-lints`
+
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+error: unused variable: `unused`
+  --> $DIR/lint-removed-cmdline-deny.rs:13:17
+   |
+LL | fn main() { let unused = (); }
+   |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-removed-cmdline-deny.rs:12:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs
index 462beabb945..34373df3a9c 100644
--- a/tests/ui/lint/lint-removed-cmdline.rs
+++ b/tests/ui/lint/lint-removed-cmdline.rs
@@ -4,6 +4,7 @@
 // compile-flags:-D raw_pointer_derive
 
 // error-pattern:lint `raw_pointer_derive` has been removed
+// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
 // error-pattern:requested on the command line with `-D raw_pointer_derive`
 
 #![warn(unused)]
diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr
index 9be532ef234..ebfae34ade9 100644
--- a/tests/ui/lint/lint-removed-cmdline.stderr
+++ b/tests/ui/lint/lint-removed-cmdline.stderr
@@ -1,6 +1,7 @@
 warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
    |
    = note: requested on the command line with `-D raw_pointer_derive`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
    |
@@ -11,13 +12,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point
    = note: requested on the command line with `-D raw_pointer_derive`
 
 error: unused variable: `unused`
-  --> $DIR/lint-removed-cmdline.rs:12:17
+  --> $DIR/lint-removed-cmdline.rs:13:17
    |
 LL | fn main() { let unused = (); }
    |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
    |
 note: the lint level is defined here
-  --> $DIR/lint-removed-cmdline.rs:11:8
+  --> $DIR/lint-removed-cmdline.rs:12:8
    |
 LL | #[deny(warnings)]
    |        ^^^^^^^^
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs
new file mode 100644
index 00000000000..01629aaca80
--- /dev/null
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs
@@ -0,0 +1,10 @@
+// compile-flags:-D renamed-and-removed-lints -D bare_trait_object
+
+// error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects`
+// error-pattern:use the new name `bare_trait_objects`
+// error-pattern:requested on the command line with `-D bare_trait_object`
+// error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+// error-pattern:unused
+
+#[deny(unused)]
+fn main() { let unused = (); }
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
new file mode 100644
index 00000000000..df22ef60daf
--- /dev/null
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
@@ -0,0 +1,31 @@
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+   = note: requested on the command line with `-D renamed-and-removed-lints`
+
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+
+error: unused variable: `unused`
+  --> $DIR/lint-renamed-cmdline-deny.rs:10:17
+   |
+LL | fn main() { let unused = (); }
+   |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-renamed-cmdline-deny.rs:9:8
+   |
+LL | #[deny(unused)]
+   |        ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs
index c873771e308..fba7c33311d 100644
--- a/tests/ui/lint/lint-renamed-cmdline.rs
+++ b/tests/ui/lint/lint-renamed-cmdline.rs
@@ -2,6 +2,7 @@
 
 // error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects`
 // error-pattern:requested on the command line with `-D bare_trait_object`
+// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
 // error-pattern:unused
 
 #[deny(unused)]
diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr
index 8dfd61ac927..a41284003ed 100644
--- a/tests/ui/lint/lint-renamed-cmdline.stderr
+++ b/tests/ui/lint/lint-renamed-cmdline.stderr
@@ -1,23 +1,27 @@
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
 
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
 
 error: unused variable: `unused`
-  --> $DIR/lint-renamed-cmdline.rs:8:17
+  --> $DIR/lint-renamed-cmdline.rs:9:17
    |
 LL | fn main() { let unused = (); }
    |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
    |
 note: the lint level is defined here
-  --> $DIR/lint-renamed-cmdline.rs:7:8
+  --> $DIR/lint-renamed-cmdline.rs:8:8
    |
 LL | #[deny(unused)]
    |        ^^^^^^
diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr
index a11ee769c7c..85852782222 100644
--- a/tests/ui/lint/lint-unexported-no-mangle.stderr
+++ b/tests/ui/lint/lint-unexported-no-mangle.stderr
@@ -1,6 +1,7 @@
 warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
    |
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs
new file mode 100644
index 00000000000..c7f8d434c04
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags:-A unknown-lints -D bogus -D dead_cod
+
+fn main() { }
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
new file mode 100644
index 00000000000..31bc2047356
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
@@ -0,0 +1,9 @@
+// compile-flags:-D unknown-lints -D bogus -D dead_cod
+
+// error-pattern:unknown lint: `bogus`
+// error-pattern:requested on the command line with `-D bogus`
+// error-pattern:requested on the command line with `-D dead_cod`
+// error-pattern:requested on the command line with `-D unknown-lints`
+// error-pattern:did you mean: `dead_code`
+
+fn main() { }
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr
new file mode 100644
index 00000000000..677b5edc894
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr
@@ -0,0 +1,31 @@
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+   = note: requested on the command line with `-D unknown-lints`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs
index 7f3f55fbad0..81539cb6dc1 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline.rs
+++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs
@@ -1,7 +1,9 @@
+// check-pass
 // compile-flags:-D bogus -D dead_cod
 
 // error-pattern:unknown lint: `bogus`
 // error-pattern:requested on the command line with `-D bogus`
+// error-pattern:`#[warn(unknown_lints)]` on by default
 // error-pattern:unknown lint: `dead_cod`
 // error-pattern:requested on the command line with `-D dead_cod`
 // error-pattern:did you mean: `dead_code`
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr
index 3855d552792..10db76ac4f1 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr
+++ b/tests/ui/lint/lint-unknown-lint-cmdline.stderr
@@ -1,21 +1,31 @@
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `dead_cod`
+warning[E0602]: unknown lint: `dead_cod`
    |
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error[E0602]: unknown lint: `dead_cod`
+warning[E0602]: unknown lint: `dead_cod`
    |
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error: aborting due to 4 previous errors
+warning[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+warning[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+warning: 6 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/no-coverage.rs b/tests/ui/lint/no-coverage.rs
index 07906a43472..907d25d333e 100644
--- a/tests/ui/lint/no-coverage.rs
+++ b/tests/ui/lint/no-coverage.rs
@@ -1,55 +1,55 @@
 #![feature(extern_types)]
-#![feature(no_coverage)]
+#![feature(coverage_attribute)]
 #![feature(impl_trait_in_assoc_type)]
 #![warn(unused_attributes)]
-#![no_coverage]
-//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+#![coverage(off)]
+//~^ WARN: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
 
-#[no_coverage]
-//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+#[coverage(off)]
+//~^ WARN: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
 trait Trait {
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     const X: u32;
 
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     type T;
 
     type U;
 }
 
-#[no_coverage]
-//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+#[coverage(off)]
+//~^ WARN: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
 impl Trait for () {
     const X: u32 = 0;
 
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     type T = Self;
 
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     type U = impl Trait; //~ ERROR unconstrained opaque type
 }
 
 extern "C" {
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     static X: u32;
 
-    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    #[coverage(off)] //~ ERROR `#[coverage]` must be applied to coverable code
     type T;
 }
 
-#[no_coverage]
+#[coverage(off)]
 fn main() {
-    #[no_coverage]
-    //~^ WARN `#[no_coverage]` may only be applied to function definitions
+    #[coverage(off)]
+    //~^ WARN `#[coverage]` may only be applied to function definitions
     let _ = ();
 
     match () {
-        #[no_coverage]
-        //~^ WARN `#[no_coverage]` may only be applied to function definitions
+        #[coverage(off)]
+        //~^ WARN `#[coverage]` may only be applied to function definitions
         () => (),
     }
 
-    #[no_coverage]
-    //~^ WARN `#[no_coverage]` may only be applied to function definitions
+    #[coverage(off)]
+    //~^ WARN `#[coverage]` may only be applied to function definitions
     return ();
 }
diff --git a/tests/ui/lint/no-coverage.stderr b/tests/ui/lint/no-coverage.stderr
index 404efbeac1e..a87b0fb49f0 100644
--- a/tests/ui/lint/no-coverage.stderr
+++ b/tests/ui/lint/no-coverage.stderr
@@ -1,8 +1,8 @@
-warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+warning: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
   --> $DIR/no-coverage.rs:8:1
    |
-LL | #[no_coverage]
-   | ^^^^^^^^^^^^^^
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/no-coverage.rs:4:9
@@ -10,83 +10,83 @@ note: the lint level is defined here
 LL | #![warn(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+warning: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
   --> $DIR/no-coverage.rs:20:1
    |
-LL | #[no_coverage]
-   | ^^^^^^^^^^^^^^
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` may only be applied to function definitions
+warning: `#[coverage]` may only be applied to function definitions
   --> $DIR/no-coverage.rs:42:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` may only be applied to function definitions
+warning: `#[coverage]` may only be applied to function definitions
   --> $DIR/no-coverage.rs:47:9
    |
-LL |         #[no_coverage]
-   |         ^^^^^^^^^^^^^^
+LL |         #[coverage(off)]
+   |         ^^^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` may only be applied to function definitions
+warning: `#[coverage]` may only be applied to function definitions
   --> $DIR/no-coverage.rs:52:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:11:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     const X: u32;
    |     ------------- not coverable code
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:14:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     type T;
    |     ------- not coverable code
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:25:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     type T = Self;
    |     -------------- not coverable code
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:28:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     type U = impl Trait;
    |     -------------------- not coverable code
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:33:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     static X: u32;
    |     -------------- not coverable code
 
-error[E0788]: `#[no_coverage]` must be applied to coverable code
+error[E0788]: `#[coverage]` must be applied to coverable code
   --> $DIR/no-coverage.rs:36:5
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL |     #[coverage(off)]
+   |     ^^^^^^^^^^^^^^^^
 LL |     type T;
    |     ------- not coverable code
 
-warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+warning: `#[coverage]` does not propagate into items and must be applied to the contained functions directly
   --> $DIR/no-coverage.rs:5:1
    |
-LL | #![no_coverage]
-   | ^^^^^^^^^^^^^^^
+LL | #![coverage(off)]
+   | ^^^^^^^^^^^^^^^^^
 
 error: unconstrained opaque type
   --> $DIR/no-coverage.rs:29:14
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 6b9ac3c5852..0cea60746bf 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -82,13 +82,13 @@ error[E0606]: casting `f32` as `*const u8` is invalid
 LL |     let _ = f as *const u8;
    |             ^^^^^^^^^^^^^^
 
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401.rs:39:13
    |
 LL |     let _ = 3_i32 as bool;
    |             ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0`
 
-error[E0054]: cannot cast as `bool`
+error[E0054]: cannot cast `E` as `bool`
   --> $DIR/cast-rfc0401.rs:40:13
    |
 LL |     let _ = E::A as bool;
diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr
index 3ac5e96c574..4eff08ead42 100644
--- a/tests/ui/namespace/namespace-mix.stderr
+++ b/tests/ui/namespace/namespace-mix.stderr
@@ -114,6 +114,11 @@ LL |     check(m1::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -128,6 +133,11 @@ LL |     check(m2::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -142,6 +152,11 @@ LL |     check(m2::S);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -156,6 +171,11 @@ LL |     check(xm1::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -170,6 +190,11 @@ LL |     check(xm2::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -184,6 +209,11 @@ LL |     check(xm2::S);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -198,6 +228,11 @@ LL |     check(m3::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -212,6 +247,11 @@ LL |     check(m3::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -226,6 +266,11 @@ LL |     check(m4::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -240,6 +285,11 @@ LL |     check(m4::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -254,6 +304,11 @@ LL |     check(xm3::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -268,6 +323,11 @@ LL |     check(xm3::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -282,6 +342,11 @@ LL |     check(xm4::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -296,6 +361,11 @@ LL |     check(xm4::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -310,6 +380,11 @@ LL |     check(m5::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -324,6 +399,11 @@ LL |     check(m5::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -338,6 +418,11 @@ LL |     check(m6::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -352,6 +437,11 @@ LL |     check(m6::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -366,6 +456,11 @@ LL |     check(xm5::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -380,6 +475,11 @@ LL |     check(xm5::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -394,6 +494,11 @@ LL |     check(xm6::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -408,6 +513,11 @@ LL |     check(xm6::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -422,6 +532,11 @@ LL |     check(m7::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -436,6 +551,11 @@ LL |     check(m8::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -450,6 +570,11 @@ LL |     check(m8::V);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -464,6 +589,11 @@ LL |     check(xm7::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -478,6 +608,11 @@ LL |     check(xm8::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -492,6 +627,11 @@ LL |     check(xm8::V);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -506,6 +646,11 @@ LL |     check(m9::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -520,6 +665,11 @@ LL |     check(m9::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -534,6 +684,11 @@ LL |     check(mA::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -548,6 +703,11 @@ LL |     check(mA::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -562,6 +722,11 @@ LL |     check(xm9::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -576,6 +741,11 @@ LL |     check(xm9::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -590,6 +760,11 @@ LL |     check(xmA::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -604,6 +779,11 @@ LL |     check(xmA::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -618,6 +798,11 @@ LL |     check(mB::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -632,6 +817,11 @@ LL |     check(mB::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -646,6 +836,11 @@ LL |     check(mC::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -660,6 +855,11 @@ LL |     check(mC::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -674,6 +874,11 @@ LL |     check(xmB::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -688,6 +893,11 @@ LL |     check(xmB::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -702,6 +912,11 @@ LL |     check(xmC::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -716,6 +931,11 @@ LL |     check(xmC::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs
index 85413acdb14..25bac1ba24b 100644
--- a/tests/ui/nested-ty-params.rs
+++ b/tests/ui/nested-ty-params.rs
@@ -1,4 +1,4 @@
-// error-pattern:can't use generic parameters from outer function
+// error-pattern:can't use generic parameters from outer item
 fn hd<U>(v: Vec<U> ) -> U {
     fn hd1(w: [U]) -> U { return w[0]; }
 
diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/nested-ty-params.stderr
index 8f4746f5ec3..a9cdec66719 100644
--- a/tests/ui/nested-ty-params.stderr
+++ b/tests/ui/nested-ty-params.stderr
@@ -1,22 +1,22 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/nested-ty-params.rs:3:16
    |
 LL | fn hd<U>(v: Vec<U> ) -> U {
-   |       - type parameter from outer function
+   |       - type parameter from outer item
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |           -    ^ use of generic parameter from outer function
+   |           -    ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<U>`
+   |           help: try introducing a local generic parameter here: `<U>`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/nested-ty-params.rs:3:23
    |
 LL | fn hd<U>(v: Vec<U> ) -> U {
-   |       - type parameter from outer function
+   |       - type parameter from outer item
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |           -           ^ use of generic parameter from outer function
+   |           -           ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<U>`
+   |           help: try introducing a local generic parameter here: `<U>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/never_type/feature-gate-never_type_fallback.stderr b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
index 2db1cc4b776..56aafbb4ce8 100644
--- a/tests/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -8,6 +8,11 @@ LL |     foo(panic!())
    |     |   this tail expression is of type `()`
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/feature-gate-never_type_fallback.rs:7:1
+   |
+LL | trait T {}
+   | ^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/feature-gate-never_type_fallback.rs:13:16
    |
diff --git a/tests/ui/never_type/impl_trait_fallback3.stderr b/tests/ui/never_type/impl_trait_fallback3.stderr
index 5d5d216fb9b..821d141569e 100644
--- a/tests/ui/never_type/impl_trait_fallback3.stderr
+++ b/tests/ui/never_type/impl_trait_fallback3.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn a() -> Foo {
    |           ^^^ the trait `T` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl_trait_fallback3.rs:5:1
+   |
+LL | trait T {
+   | ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/never_type/impl_trait_fallback4.stderr b/tests/ui/never_type/impl_trait_fallback4.stderr
index f2e216e9044..67421ba8da7 100644
--- a/tests/ui/never_type/impl_trait_fallback4.stderr
+++ b/tests/ui/never_type/impl_trait_fallback4.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn foo() -> impl T {
    |             ^^^^^^ the trait `T` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl_trait_fallback4.rs:3:1
+   |
+LL | trait T {
+   | ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/on-unimplemented/on-trait.stderr b/tests/ui/on-unimplemented/on-trait.stderr
index 4b040f1ac5a..4847a1a5a61 100644
--- a/tests/ui/on-unimplemented/on-trait.stderr
+++ b/tests/ui/on-unimplemented/on-trait.stderr
@@ -5,6 +5,11 @@ LL |     let y: Option<Vec<u8>> = collect(x.iter()); // this should give approxi
    |                              ^^^^^^^ a collection of type `Option<Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
    |
    = help: the trait `MyFromIterator<&u8>` is not implemented for `Option<Vec<u8>>`
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-trait.rs:17:1
+   |
+LL | trait MyFromIterator<A> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `collect`
   --> $DIR/on-trait.rs:22:39
    |
@@ -18,6 +23,11 @@ LL |     let x: String = foobar();
    |                     ^^^^^^ test error `String` with `u8` `_` `u32` in `Foo`
    |
    = help: the trait `Foo<u8, _, u32>` is not implemented for `String`
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-trait.rs:7:3
+   |
+LL |   pub trait Foo<Bar, Baz, Quux> {}
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foobar`
   --> $DIR/on-trait.rs:12:24
    |
diff --git a/tests/ui/on-unimplemented/parent-label.stderr b/tests/ui/on-unimplemented/parent-label.stderr
index 8cd7412fd9d..101a41512d2 100644
--- a/tests/ui/on-unimplemented/parent-label.stderr
+++ b/tests/ui/on-unimplemented/parent-label.stderr
@@ -8,6 +8,11 @@ LL |         f(Foo {});
    |         |
    |         required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -24,6 +29,11 @@ LL |             f(Foo {});
    |             |
    |             required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -41,6 +51,11 @@ LL |             f(Foo {});
    |             |
    |             required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -58,6 +73,11 @@ LL |     f(Foo {});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
diff --git a/tests/ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs b/tests/ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs
new file mode 100644
index 00000000000..3421333b8a0
--- /dev/null
+++ b/tests/ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs
@@ -0,0 +1,21 @@
+// Regression test for issue #115780.
+// Ensure that we don't emit a parse error for the token sequence `Ident "<" Ty` in pattern position
+// if we are inside a macro call since it can be valid input for a subsequent macro rule.
+// See also #103534.
+
+// check-pass
+
+macro_rules! mdo {
+    ($p: pat =<< $e: expr ; $( $t: tt )*) => {
+        $e.and_then(|$p| mdo! { $( $t )* })
+    };
+    (ret<$ty: ty> $e: expr;) => { Some::<$ty>($e) };
+}
+
+fn main() {
+    mdo! {
+        x_val =<< Some(0);
+        y_val =<< Some(1);
+        ret<(i32, i32)> (x_val, y_val);
+    };
+}
diff --git a/tests/ui/pattern/issue-114896.rs b/tests/ui/pattern/issue-114896.rs
new file mode 100644
index 00000000000..cde37f658d6
--- /dev/null
+++ b/tests/ui/pattern/issue-114896.rs
@@ -0,0 +1,7 @@
+fn main() {
+    fn x(a: &char) {
+        let &b = a;
+        b.make_ascii_uppercase();
+//~^ cannot borrow `b` as mutable, as it is not declared as mutable
+    }
+}
diff --git a/tests/ui/pattern/issue-114896.stderr b/tests/ui/pattern/issue-114896.stderr
new file mode 100644
index 00000000000..ffeb7bc1365
--- /dev/null
+++ b/tests/ui/pattern/issue-114896.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/issue-114896.rs:4:9
+   |
+LL |         let &b = a;
+   |             -- help: consider changing this to be mutable: `&(mut b)`
+LL |         b.make_ascii_uppercase();
+   |         ^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index 8a8246376fe..8716defa17a 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Project` is not satisfied
    |
 LL | pub fn uwu() -> <() as Project>::Assoc {}
    |                 ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/bad-type-env-capture.stderr b/tests/ui/resolve/bad-type-env-capture.stderr
index b6282c2d070..941b6b7a68c 100644
--- a/tests/ui/resolve/bad-type-env-capture.stderr
+++ b/tests/ui/resolve/bad-type-env-capture.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/bad-type-env-capture.rs:2:15
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(b: T) { }
-   |           -   ^ use of generic parameter from outer function
+   |           -   ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
new file mode 100644
index 00000000000..4f853829279
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -0,0 +1,28 @@
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:12:20
+   |
+LL | fn outer<T: Tr>() { // outer function
+   |          - type parameter from outer item
+LL |     const K: u32 = T::C;
+   |                    ^^^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
+   |
+LL | impl<T> Tr for T { // outer impl block
+   |      - type parameter from outer item
+LL |     const C: u32 = {
+LL |         const I: u32 = T::C;
+   |                        ^^^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
+   |
+LL | struct S<T: Tr>(U32<{ // outer struct
+   |          - type parameter from outer item
+LL |     const _: u32 = T::C;
+   |                    ^^^^ use of generic parameter from outer item
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
new file mode 100644
index 00000000000..1cb55842bc6
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -0,0 +1,34 @@
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:12:20
+   |
+LL | fn outer<T: Tr>() { // outer function
+   |          - type parameter from outer item
+LL |     const K: u32 = T::C;
+   |            -       ^^^^ use of generic parameter from outer item
+   |            |
+   |            help: try introducing a local generic parameter here: `<T>`
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
+   |
+LL | impl<T> Tr for T { // outer impl block
+   |      - type parameter from outer item
+LL |     const C: u32 = {
+LL |         const I: u32 = T::C;
+   |                -       ^^^^ use of generic parameter from outer item
+   |                |
+   |                help: try introducing a local generic parameter here: `<T>`
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
+   |
+LL | struct S<T: Tr>(U32<{ // outer struct
+   |          - type parameter from outer item
+LL |     const _: u32 = T::C;
+   |            -       ^^^^ use of generic parameter from outer item
+   |            |
+   |            help: try introducing a local generic parameter here: `<T>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs
new file mode 100644
index 00000000000..e5647d72cba
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs
@@ -0,0 +1,39 @@
+// Regression test for issue #115720.
+// If a const item contains generic params from an outer items, only suggest
+// turning the const item generic if the feature `generic_const_items` is enabled.
+
+// revisions: default generic_const_items
+
+#![cfg_attr(generic_const_items, feature(generic_const_items))]
+#![feature(generic_const_exprs)] // only used for the test case "outer struct"
+#![allow(incomplete_features)]
+
+fn outer<T: Tr>() { // outer function
+    const K: u32 = T::C;
+    //~^ ERROR can't use generic parameters from outer item
+    //[generic_const_items]~| HELP try introducing a local generic parameter here
+}
+
+impl<T> Tr for T { // outer impl block
+    const C: u32 = {
+        const I: u32 = T::C;
+        //~^ ERROR can't use generic parameters from outer item
+        //[generic_const_items]~| HELP try introducing a local generic parameter here
+        I
+    };
+}
+
+struct S<T: Tr>(U32<{ // outer struct
+    const _: u32 = T::C;
+    //~^ ERROR can't use generic parameters from outer item
+    //[generic_const_items]~| HELP try introducing a local generic parameter here
+    0
+}>);
+
+trait Tr {
+    const C: u32;
+}
+
+struct U32<const N: u32>;
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs
index 942d6b9a568..de3e73437f0 100644
--- a/tests/ui/resolve/issue-12796.rs
+++ b/tests/ui/resolve/issue-12796.rs
@@ -1,7 +1,7 @@
 trait Trait {
     fn outer(&self) {
         fn inner(_: &Self) {
-            //~^ ERROR can't use generic parameters from outer function
+            //~^ ERROR can't use generic parameters from outer item
         }
     }
 }
diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr
index a01fd2d6542..ef59d00360b 100644
--- a/tests/ui/resolve/issue-12796.stderr
+++ b/tests/ui/resolve/issue-12796.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-12796.rs:3:22
    |
 LL |         fn inner(_: &Self) {
    |                      ^^^^
    |                      |
-   |                      use of generic parameter from outer function
+   |                      use of generic parameter from outer item
    |                      can't use `Self` here
 
 error: aborting due to previous error
diff --git a/tests/ui/resolve/issue-3021-c.rs b/tests/ui/resolve/issue-3021-c.rs
index 94ed1fdf781..bd21d124423 100644
--- a/tests/ui/resolve/issue-3021-c.rs
+++ b/tests/ui/resolve/issue-3021-c.rs
@@ -1,8 +1,8 @@
 fn siphash<T>() {
 
     trait U {
-        fn g(&self, x: T) -> T;  //~ ERROR can't use generic parameters from outer function
-        //~^ ERROR can't use generic parameters from outer function
+        fn g(&self, x: T) -> T;  //~ ERROR can't use generic parameters from outer item
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/resolve/issue-3021-c.stderr b/tests/ui/resolve/issue-3021-c.stderr
index 5176efc3a6b..537bbaf7b6a 100644
--- a/tests/ui/resolve/issue-3021-c.stderr
+++ b/tests/ui/resolve/issue-3021-c.stderr
@@ -1,24 +1,24 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3021-c.rs:4:24
    |
 LL | fn siphash<T>() {
-   |            - type parameter from outer function
+   |            - type parameter from outer item
 LL |
 LL |     trait U {
-   |            - help: try using a local generic parameter instead: `<T>`
+   |            - help: try introducing a local generic parameter here: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |                        ^ use of generic parameter from outer function
+   |                        ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3021-c.rs:4:30
    |
 LL | fn siphash<T>() {
-   |            - type parameter from outer function
+   |            - type parameter from outer item
 LL |
 LL |     trait U {
-   |            - help: try using a local generic parameter instead: `<T>`
+   |            - help: try introducing a local generic parameter here: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |                              ^ use of generic parameter from outer function
+   |                              ^ use of generic parameter from outer item
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs b/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
index ce45f630e48..4fa3f12d024 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
@@ -1,7 +1,7 @@
 unsafe fn foo<A>() {
     extern "C" {
         static baz: *const A;
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 
     let bar: *const u64 = core::mem::transmute(&baz);
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
index 6bbf76dd1fb..3e9c3fd11b7 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
@@ -1,11 +1,11 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65025-extern-static-parent-generics.rs:3:28
    |
 LL | unsafe fn foo<A>() {
-   |               - type parameter from outer function
+   |               - type parameter from outer item
 LL |     extern "C" {
 LL |         static baz: *const A;
-   |                            ^ use of generic parameter from outer function
+   |                            ^ use of generic parameter from outer item
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.rs b/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
index f96c04841dd..bc99584a8d2 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
@@ -1,26 +1,26 @@
 fn f<T>() {
     extern "C" {
         static a: *const T;
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 fn g<T: Default>() {
     static a: *const T = Default::default();
-    //~^ ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
 }
 
 fn h<const N: usize>() {
     extern "C" {
         static a: [u8; N];
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 fn i<const N: usize>() {
     static a: [u8; N] = [0; N];
-    //~^ ERROR can't use generic parameters from outer function
-    //~| ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
+    //~| ERROR can't use generic parameters from outer item
 }
 
 fn main() {}
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
index 7ed572f80b8..f1fe1a6002c 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -1,44 +1,44 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:3:26
    |
 LL | fn f<T>() {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     extern "C" {
 LL |         static a: *const T;
-   |                          ^ use of generic parameter from outer function
+   |                          ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:9:22
    |
 LL | fn g<T: Default>() {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     static a: *const T = Default::default();
-   |                      ^ use of generic parameter from outer function
+   |                      ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:15:24
    |
 LL | fn h<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     extern "C" {
 LL |         static a: [u8; N];
-   |                        ^ use of generic parameter from outer function
+   |                        ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:20
    |
 LL | fn i<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
-   |                    ^ use of generic parameter from outer function
+   |                    ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:29
    |
 LL | fn i<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
-   |                             ^ use of generic parameter from outer function
+   |                             ^ use of generic parameter from outer item
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs b/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
index c77a66524f7..2d5f34c62a6 100644
--- a/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
+++ b/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
@@ -6,7 +6,7 @@ trait TraitA<A> {
     fn outer(&self) {
         enum Foo<B> {
             Variance(A)
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
         }
     }
 }
@@ -14,21 +14,21 @@ trait TraitA<A> {
 trait TraitB<A> {
     fn outer(&self) {
         struct Foo<B>(A);
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 trait TraitC<A> {
     fn outer(&self) {
         struct Foo<B> { a: A }
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 trait TraitD<A> {
     fn outer(&self) {
         fn foo<B>(a: A) { }
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
index 0a6d1cc3bcd..1ab56fdc504 100644
--- a/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
+++ b/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
@@ -1,46 +1,46 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:8:22
    |
 LL | trait TraitA<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         enum Foo<B> {
-   |                  - help: try using a local generic parameter instead: `A,`
+   |                  - help: try introducing a local generic parameter here: `A,`
 LL |             Variance(A)
-   |                      ^ use of generic parameter from outer function
+   |                      ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:16:23
    |
 LL | trait TraitB<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         struct Foo<B>(A);
-   |                    -  ^ use of generic parameter from outer function
+   |                    -  ^ use of generic parameter from outer item
    |                    |
-   |                    help: try using a local generic parameter instead: `A,`
+   |                    help: try introducing a local generic parameter here: `A,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
    |
 LL | trait TraitC<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         struct Foo<B> { a: A }
-   |                    -       ^ use of generic parameter from outer function
+   |                    -       ^ use of generic parameter from outer item
    |                    |
-   |                    help: try using a local generic parameter instead: `A,`
+   |                    help: try introducing a local generic parameter here: `A,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
    |
 LL | trait TraitD<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         fn foo<B>(a: A) { }
-   |                -     ^ use of generic parameter from outer function
+   |                -     ^ use of generic parameter from outer item
    |                |
-   |                help: try using a local generic parameter instead: `A,`
+   |                help: try introducing a local generic parameter here: `A,`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed
new file mode 100644
index 00000000000..fc68884fe9c
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+// compile-flags: --cfg=whatever -Aunused
+
+use y::z;
+#[cfg(whatever)]
+use y::Whatever;
+
+mod y {
+    pub(crate) fn z() {}
+    pub(crate) struct Whatever;
+}
+
+fn main() {
+    z();
+    //~^ ERROR cannot find function `z` in this scope
+}
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs
new file mode 100644
index 00000000000..38a1095703b
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+// compile-flags: --cfg=whatever -Aunused
+
+#[cfg(whatever)]
+use y::Whatever;
+
+mod y {
+    pub(crate) fn z() {}
+    pub(crate) struct Whatever;
+}
+
+fn main() {
+    z();
+    //~^ ERROR cannot find function `z` in this scope
+}
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr
new file mode 100644
index 00000000000..d3574851d5c
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr
@@ -0,0 +1,14 @@
+error[E0425]: cannot find function `z` in this scope
+  --> $DIR/suggest-import-without-clobbering-attrs.rs:13:5
+   |
+LL |     z();
+   |     ^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use y::z;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs
index eccb315feb1..f4dfa4c40ab 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.rs
+++ b/tests/ui/resolve/use-self-in-inner-fn.rs
@@ -4,9 +4,9 @@ impl A {
 //~^ NOTE `Self` type implicitly declared here, by this `impl`
     fn banana(&mut self) {
         fn peach(this: &Self) {
-        //~^ ERROR can't use generic parameters from outer function
-        //~| NOTE use of generic parameter from outer function
-        //~| NOTE use a type here instead
+        //~^ ERROR can't use generic parameters from outer item
+        //~| NOTE use of generic parameter from outer item
+        //~| NOTE refer to the type directly here instead
         }
     }
 }
diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr
index 96609349924..832aaacaf49 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.stderr
+++ b/tests/ui/resolve/use-self-in-inner-fn.stderr
@@ -1,4 +1,4 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/use-self-in-inner-fn.rs:6:25
    |
 LL | impl A {
@@ -7,8 +7,8 @@ LL | impl A {
 LL |         fn peach(this: &Self) {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer function
-   |                         use a type here instead
+   |                         use of generic parameter from outer item
+   |                         refer to the type directly here instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs
new file mode 100644
index 00000000000..855bbb2e992
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(const_trait_impl, effects)]
+
+pub const fn owo() {}
+
+fn main() {
+    let _ = owo;
+}
diff --git a/tests/ui/sanitize/cfg.rs b/tests/ui/sanitize/cfg.rs
index c0f08a6d1e5..523de1ceaee 100644
--- a/tests/ui/sanitize/cfg.rs
+++ b/tests/ui/sanitize/cfg.rs
@@ -2,19 +2,19 @@
 // the `#[cfg(sanitize = "option")]` attribute is configured.
 
 // needs-sanitizer-support
-// needs-sanitizer-address
-// needs-sanitizer-cfi
-// needs-sanitizer-kcfi
-// needs-sanitizer-leak
-// needs-sanitizer-memory
-// needs-sanitizer-thread
 // check-pass
-// revisions: address leak memory thread
+// revisions: address cfi kcfi leak memory thread
+//[address]needs-sanitizer-address
 //[address]compile-flags: -Zsanitizer=address --cfg address
-//[cfi]compile-flags:     -Zsanitizer=cfi     --cfg cfi
+//[cfi]needs-sanitizer-cfi
+//[cfi]compile-flags:     -Zsanitizer=cfi     --cfg cfi -Clto
+//[kcfi]needs-sanitizer-kcfi
 //[kcfi]compile-flags:    -Zsanitizer=kcfi    --cfg kcfi
+//[leak]needs-sanitizer-leak
 //[leak]compile-flags:    -Zsanitizer=leak    --cfg leak
+//[memory]needs-sanitizer-memory
 //[memory]compile-flags:  -Zsanitizer=memory  --cfg memory
+//[thread]needs-sanitizer-thread
 //[thread]compile-flags:  -Zsanitizer=thread  --cfg thread
 
 #![feature(cfg_sanitize)]
diff --git a/tests/ui/span/issue-29595.stderr b/tests/ui/span/issue-29595.stderr
index 92445e40731..7d603cdbfe5 100644
--- a/tests/ui/span/issue-29595.stderr
+++ b/tests/ui/span/issue-29595.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied
    |
 LL |     let a: u8 = Tr::C;
    |                 ^^^^^ the trait `Tr` is not implemented for `u8`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-29595.rs:1:1
+   |
+LL | trait Tr {
+   | ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/specialization/issue-38091.stderr b/tests/ui/specialization/issue-38091.stderr
index f2210a40719..4d840482b46 100644
--- a/tests/ui/specialization/issue-38091.stderr
+++ b/tests/ui/specialization/issue-38091.stderr
@@ -14,6 +14,11 @@ error[E0277]: the trait bound `(): Valid` is not satisfied
 LL |     default type Ty = ();
    |                       ^^ the trait `Valid` is not implemented for `()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-38091.rs:20:1
+   |
+LL | trait Valid {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Iterate::Ty`
   --> $DIR/issue-38091.rs:5:14
    |
diff --git a/tests/ui/suggestions/issue-89333.stderr b/tests/ui/suggestions/issue-89333.stderr
index f73f1147d5d..4739f11ddad 100644
--- a/tests/ui/suggestions/issue-89333.stderr
+++ b/tests/ui/suggestions/issue-89333.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a _: Trait` is not satisfied
 LL |     test(&|| 0);
    |     ^^^^ the trait `for<'a> Trait` is not implemented for `&'a _`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89333.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `test`
   --> $DIR/issue-89333.rs:11:55
    |
diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout
index 7bddc925996..af7f2b67152 100644
--- a/tests/ui/thir-print/thir-flat-const-variant.stdout
+++ b/tests/ui/thir-print/thir-flat-const-variant.stdout
@@ -1,7 +1,11 @@
 DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -46,7 +50,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -60,7 +68,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -72,7 +84,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -86,7 +102,11 @@ Thir {
 DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -131,7 +151,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -145,7 +169,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -157,7 +185,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -171,7 +203,11 @@ Thir {
 DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -216,7 +252,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -230,7 +270,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -242,7 +286,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -256,7 +304,11 @@ Thir {
 DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -301,7 +353,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -315,7 +371,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -327,7 +387,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 3fc130f0176..0e21b98307b 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -1,13 +1,13 @@
 DefId(0:16 ~ thir_tree_match[fcf8]::has_match):
 params: [
     Param {
-        ty: Foo
+        ty: Adt(Foo, [])
         ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
         self_kind: None
         hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1))
         param: Some( 
             Pat: {
-                ty: Foo
+                ty: Adt(Foo, [])
                 span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
                 kind: PatKind {
                     Binding {
@@ -15,7 +15,7 @@ params: [
                         name: "foo"
                         mode: ByValue
                         var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
-                        ty: Foo
+                        ty: Adt(Foo, [])
                         is_primary: true
                         subpattern: None
                     }
@@ -73,7 +73,7 @@ body:
                                                                             Match {
                                                                                 scrutinee:
                                                                                     Expr {
-                                                                                        ty: Foo
+                                                                                        ty: Adt(Foo, [])
                                                                                         temp_lifetime: Some(Node(26))
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
@@ -82,7 +82,7 @@ body:
                                                                                                 lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
                                                                                                 value:
                                                                                                     Expr {
-                                                                                                        ty: Foo
+                                                                                                        ty: Adt(Foo, [])
                                                                                                         temp_lifetime: Some(Node(26))
                                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                                         kind: 
@@ -96,7 +96,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -110,7 +110,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Bar
+                                                                                                                ty: Adt(Bar, [])
                                                                                                                 span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Variant {
@@ -169,7 +169,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -183,7 +183,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Bar
+                                                                                                                ty: Adt(Bar, [])
                                                                                                                 span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Wild
@@ -232,7 +232,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
diff --git a/tests/ui/trait-bounds/issue-82038.stderr b/tests/ui/trait-bounds/issue-82038.stderr
index f37e3286f4b..30bb4a0a850 100644
--- a/tests/ui/trait-bounds/issue-82038.stderr
+++ b/tests/ui/trait-bounds/issue-82038.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `bool: Foo` is not satisfied
    |
 LL |     <bool as Foo>::my_method();
    |      ^^^^ the trait `Foo` is not implemented for `bool`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-82038.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr b/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
index 61237a63e32..530264b344a 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u32: Trait` is not satisfied
 LL | fn explode(x: Foo<u32>) {}
    |               ^^^^^^^^ the trait `Trait` is not implemented for `u32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-fns.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-in-fns.rs:3:14
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `f32: Trait` is not satisfied
 LL | fn kaboom(y: Bar<f32>) {}
    |              ^^^^^^^^ the trait `Trait` is not implemented for `f32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-fns.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums-in-fns.rs:7:12
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr b/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
index 8a43742260b..372bbabbd86 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u16: Trait` is not satisfied
 LL | impl PolyTrait<Foo<u16>> for Struct {
    |      ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u16`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-impls.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-in-impls.rs:3:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
index 20bbe69c059..01cf76c62d5 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL |     let baz: Foo<usize> = loop { };
    |              ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-locals.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-locals.rs:5:14
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `{integer}: Trait` is not satisfied
 LL |         x: 3
    |            ^ the trait `Trait` is not implemented for `{integer}`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-locals.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-locals.rs:5:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
index fda734e8571..fa14aff684d 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL | static X: Foo<usize> = Foo {
    |           ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-static.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-static.rs:5:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums.stderr b/tests/ui/traits/bound/on-structs-and-enums.stderr
index fe05b86344b..606f764852f 100644
--- a/tests/ui/traits/bound/on-structs-and-enums.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums.stderr
@@ -20,6 +20,11 @@ error[E0277]: the trait bound `isize: Trait` is not satisfied
 LL |     a: Foo<isize>,
    |        ^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums.rs:3:14
    |
@@ -32,6 +37,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL |     Quux(Bar<usize>),
    |          ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums.rs:7:12
    |
@@ -76,6 +86,11 @@ error[E0277]: the trait bound `i32: Trait` is not satisfied
 LL |     Foo<i32>,
    |     ^^^^^^^^ the trait `Trait` is not implemented for `i32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums.rs:3:14
    |
@@ -88,6 +103,11 @@ error[E0277]: the trait bound `u8: Trait` is not satisfied
 LL |     DictionaryLike { field: Bar<u8> },
    |                             ^^^^^^^ the trait `Trait` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums.rs:7:12
    |
diff --git a/tests/ui/traits/deny-builtin-object-impl.current.stderr b/tests/ui/traits/deny-builtin-object-impl.current.stderr
index 5c1987426f7..8ca3d3a057f 100644
--- a/tests/ui/traits/deny-builtin-object-impl.current.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.current.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
 LL |     test_not_object::<dyn NotObject>();
    |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/deny-builtin-object-impl.rs:10:1
+   |
+LL | trait NotObject {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `test_not_object`
   --> $DIR/deny-builtin-object-impl.rs:14:23
    |
diff --git a/tests/ui/traits/deny-builtin-object-impl.next.stderr b/tests/ui/traits/deny-builtin-object-impl.next.stderr
index 5c1987426f7..8ca3d3a057f 100644
--- a/tests/ui/traits/deny-builtin-object-impl.next.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
 LL |     test_not_object::<dyn NotObject>();
    |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/deny-builtin-object-impl.rs:10:1
+   |
+LL | trait NotObject {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `test_not_object`
   --> $DIR/deny-builtin-object-impl.rs:14:23
    |
diff --git a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
index 263c59ee327..a5d0e6ab095 100644
--- a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
+++ b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
@@ -10,6 +10,11 @@ error[E0277]: the trait bound `for<'a> &'a mut Vec<&'a u32>: Foo<'static, i32>`
 LL |     <i32 as RefFoo<i32>>::ref_foo(unknown);
    |      ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-autoderef-ty-with-escaping-var.rs:3:1
+   |
+LL | trait Foo<'x, T> {}
+   | ^^^^^^^^^^^^^^^^
 note: required for `i32` to implement `RefFoo<i32>`
   --> $DIR/dont-autoderef-ty-with-escaping-var.rs:9:9
    |
diff --git a/tests/ui/traits/impl-bounds-checking.stderr b/tests/ui/traits/impl-bounds-checking.stderr
index 1f969efe114..bfa8213abe7 100644
--- a/tests/ui/traits/impl-bounds-checking.stderr
+++ b/tests/ui/traits/impl-bounds-checking.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `isize: Clone2` is not satisfied
 LL | impl Getter<isize> for isize {
    |                        ^^^^^ the trait `Clone2` is not implemented for `isize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl-bounds-checking.rs:1:1
+   |
+LL | pub trait Clone2 {
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `Getter`
   --> $DIR/impl-bounds-checking.rs:6:17
    |
diff --git a/tests/ui/traits/new-solver/projection-discr-kind.stderr b/tests/ui/traits/new-solver/projection-discr-kind.stderr
index 03e28f993e2..e14953f19ff 100644
--- a/tests/ui/traits/new-solver/projection-discr-kind.stderr
+++ b/tests/ui/traits/new-solver/projection-discr-kind.stderr
@@ -6,6 +6,11 @@ LL |     needs_bar(std::mem::discriminant(&x));
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-discr-kind.rs:10:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `needs_bar`
   --> $DIR/projection-discr-kind.rs:11:22
    |
diff --git a/tests/ui/traits/non_lifetime_binders/fail.stderr b/tests/ui/traits/non_lifetime_binders/fail.stderr
index 7bd02550fb3..240bcef7df5 100644
--- a/tests/ui/traits/non_lifetime_binders/fail.stderr
+++ b/tests/ui/traits/non_lifetime_binders/fail.stderr
@@ -13,6 +13,11 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
 LL |     fail();
    |     ^^^^ the trait `Trait` is not implemented for `T`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/fail.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `fail`
   --> $DIR/fail.rs:10:15
    |
diff --git a/tests/ui/traits/object-does-not-impl-trait.stderr b/tests/ui/traits/object-does-not-impl-trait.stderr
index f1dd508a467..81d67255a0b 100644
--- a/tests/ui/traits/object-does-not-impl-trait.stderr
+++ b/tests/ui/traits/object-does-not-impl-trait.stderr
@@ -6,6 +6,11 @@ LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
    |                                   |
    |                                   required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-does-not-impl-trait.rs:4:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
 note: required by a bound in `take_foo`
   --> $DIR/object-does-not-impl-trait.rs:5:15
    |
diff --git a/tests/ui/traits/vtable-res-trait-param.stderr b/tests/ui/traits/vtable-res-trait-param.stderr
index 2b3e3de9b1a..4cfceefb24c 100644
--- a/tests/ui/traits/vtable-res-trait-param.stderr
+++ b/tests/ui/traits/vtable-res-trait-param.stderr
@@ -6,6 +6,11 @@ LL |     b.gimme_an_a(y)
    |       |
    |       required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/vtable-res-trait-param.rs:1:1
+   |
+LL | trait TraitA {
+   | ^^^^^^^^^^^^
 note: required by a bound in `TraitB::gimme_an_a`
   --> $DIR/vtable-res-trait-param.rs:6:21
    |
diff --git a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
index 02c5d5d2484..be472a50769 100644
--- a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
+++ b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
@@ -27,6 +27,12 @@ LL |     Foo::test(&4i32);
    |     --------- ^^^^^ the trait `Foo` is not implemented for `i32`
    |     |
    |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/trivial-bounds-leak.rs:4:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
   --> $DIR/trivial-bounds-leak.rs:26:22
@@ -36,6 +42,11 @@ LL |     generic_function(5i32);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/trivial-bounds-leak.rs:4:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 note: required by a bound in `generic_function`
   --> $DIR/trivial-bounds-leak.rs:29:24
    |
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
new file mode 100644
index 00000000000..eefe333da45
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
@@ -0,0 +1,25 @@
+//! This tries to prove the APIT's bounds in a canonical query,
+//! which doesn't know anything about the defining scope of either
+//! opaque type and thus makes a random choice as to which opaque type
+//! becomes the hidden type of the other. When we leave the canonical
+//! query, we attempt to actually check the defining anchor, but now we
+//! have a situation where the RPIT gets constrained outside its anchor.
+
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+type Opaque = impl Sized;
+
+fn get_rpit() -> impl Clone {}
+
+fn query(_: impl FnOnce() -> Opaque) {}
+
+fn test() -> Opaque {
+    query(get_rpit);
+    get_rpit()
+}
+
+fn main() {}
diff --git a/tests/ui/type/type-arg-out-of-scope.rs b/tests/ui/type/type-arg-out-of-scope.rs
index 02aad007707..c36f9904e5d 100644
--- a/tests/ui/type/type-arg-out-of-scope.rs
+++ b/tests/ui/type/type-arg-out-of-scope.rs
@@ -1,4 +1,4 @@
-// error-pattern:can't use generic parameters from outer function
+// error-pattern:can't use generic parameters from outer item
 fn foo<T>(x: T) {
     fn bar(f: Box<dyn FnMut(T) -> T>) { }
 }
diff --git a/tests/ui/type/type-arg-out-of-scope.stderr b/tests/ui/type/type-arg-out-of-scope.stderr
index 7f18b4510f4..8665001e243 100644
--- a/tests/ui/type/type-arg-out-of-scope.stderr
+++ b/tests/ui/type/type-arg-out-of-scope.stderr
@@ -1,22 +1,22 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/type-arg-out-of-scope.rs:3:29
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |           -                 ^ use of generic parameter from outer function
+   |           -                 ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/type-arg-out-of-scope.rs:3:35
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |           -                       ^ use of generic parameter from outer function
+   |           -                       ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/union/projection-as-union-type-error-2.stderr b/tests/ui/union/projection-as-union-type-error-2.stderr
index bab226f271d..21f4ea103ad 100644
--- a/tests/ui/union/projection-as-union-type-error-2.stderr
+++ b/tests/ui/union/projection-as-union-type-error-2.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u8: NotImplemented` is not satisfied
 LL |     a: <Foo as Identity>::Identity,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-as-union-type-error-2.rs:9:1
+   |
+LL | trait NotImplemented {}
+   | ^^^^^^^^^^^^^^^^^^^^
 note: required for `u8` to implement `Identity`
   --> $DIR/projection-as-union-type-error-2.rs:11:25
    |
diff --git a/tests/ui/union/projection-as-union-type-error.stderr b/tests/ui/union/projection-as-union-type-error.stderr
index e4fbe9603ad..2b0241caf98 100644
--- a/tests/ui/union/projection-as-union-type-error.stderr
+++ b/tests/ui/union/projection-as-union-type-error.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `u8: Identity` is not satisfied
    |
 LL |     a:  <Foo as Identity>::Identity,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identity` is not implemented for `u8`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-as-union-type-error.rs:6:1
+   |
+LL | pub trait Identity {
+   | ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/unsized/issue-115809.rs b/tests/ui/unsized/issue-115809.rs
new file mode 100644
index 00000000000..ff25365ea50
--- /dev/null
+++ b/tests/ui/unsized/issue-115809.rs
@@ -0,0 +1,13 @@
+// compile-flags: --emit=link -Zmir-opt-level=2 -Zpolymorphize=on
+
+fn foo<T>() {
+    let a: [i32; 0] = [];
+    match [a[..]] {
+        //~^ ERROR cannot move a value of type `[i32]
+        //~| ERROR cannot move out of type `[i32]`, a non-copy slice
+        [[x]] => {}
+        _ => (),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/unsized/issue-115809.stderr b/tests/ui/unsized/issue-115809.stderr
new file mode 100644
index 00000000000..a92554b79b9
--- /dev/null
+++ b/tests/ui/unsized/issue-115809.stderr
@@ -0,0 +1,19 @@
+error[E0161]: cannot move a value of type `[i32]`
+  --> $DIR/issue-115809.rs:5:12
+   |
+LL |     match [a[..]] {
+   |            ^^^^^ the size of `[i32]` cannot be statically determined
+
+error[E0508]: cannot move out of type `[i32]`, a non-copy slice
+  --> $DIR/issue-115809.rs:5:12
+   |
+LL |     match [a[..]] {
+   |            ^^^^^
+   |            |
+   |            cannot move out of here
+   |            move occurs because value has type `[i32]`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0161, E0508.
+For more information about an error, try `rustc --explain E0161`.
diff --git a/tests/ui/unsized/issue-75707.stderr b/tests/ui/unsized/issue-75707.stderr
index 97618ed05ed..aa7f9c78fa8 100644
--- a/tests/ui/unsized/issue-75707.stderr
+++ b/tests/ui/unsized/issue-75707.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `MyCall: Callback` is not satisfied
 LL |     f::<dyn Processing<Call = MyCall>>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Callback` is not implemented for `MyCall`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-75707.rs:1:1
+   |
+LL | pub trait Callback {
+   | ^^^^^^^^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/issue-75707.rs:9:9
    |
diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr
index 9fd0f9c81eb..21122e37da5 100644
--- a/tests/ui/wf/hir-wf-canonicalized.stderr
+++ b/tests/ui/wf/hir-wf-canonicalized.stderr
@@ -3,12 +3,24 @@ error[E0277]: the trait bound `Bar<'a, T>: Foo` is not satisfied
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<'a, T>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/hir-wf-canonicalized.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
   --> $DIR/hir-wf-canonicalized.rs:10:15
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/hir-wf-canonicalized.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
   --> $DIR/hir-wf-canonicalized.rs:10:15
diff --git a/tests/ui/wf/issue-95665.stderr b/tests/ui/wf/issue-95665.stderr
index b1cda59a916..f80cd41a4c2 100644
--- a/tests/ui/wf/issue-95665.stderr
+++ b/tests/ui/wf/issue-95665.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u8: Trait` is not satisfied
 LL |     static VAR: Struct<u8>;
    |                 ^^^^^^^^^^ the trait `Trait` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-95665.rs:4:1
+   |
+LL | pub trait Trait: {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `Struct`
   --> $DIR/issue-95665.rs:6:22
    |
diff --git a/tests/ui/wf/wf-complex-assoc-type.stderr b/tests/ui/wf/wf-complex-assoc-type.stderr
index ef613e3132d..6a623bec815 100644
--- a/tests/ui/wf/wf-complex-assoc-type.stderr
+++ b/tests/ui/wf/wf-complex-assoc-type.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `bool: MyTrait` is not satisfied
 LL |     type MyItem = Option<((AssertMyTrait<bool>, u8))>;
    |                            ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-complex-assoc-type.rs:1:1
+   |
+LL | trait MyTrait {}
+   | ^^^^^^^^^^^^^
 note: required by a bound in `AssertMyTrait`
   --> $DIR/wf-complex-assoc-type.rs:2:25
    |
diff --git a/tests/ui/wf/wf-foreign-fn-decl-ret.stderr b/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
index b03023b5fd1..0e93601043a 100644
--- a/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
+++ b/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
    |
 LL |     pub fn lint_me() -> <() as Foo>::Assoc;
    |                         ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-foreign-fn-decl-ret.rs:6:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
   --> $DIR/wf-foreign-fn-decl-ret.rs:14:32
@@ -10,6 +16,11 @@ error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
 LL |     pub fn lint_me_aswell() -> Bar<u32>;
    |                                ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-foreign-fn-decl-ret.rs:1:1
+   |
+LL | pub trait Unsatisfied {}
+   | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/wf-foreign-fn-decl-ret.rs:4:19
    |
diff --git a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
index e460cdcd3f3..52f46562c37 100644
--- a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
+++ b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `DefaultAllocator: Allocator` is not satisfied
    |
 LL | struct Foo(Matrix<<DefaultAllocator as Allocator>::Buffer>);
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `DefaultAllocator`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:23:1
+   |
+LL | pub trait Allocator { type Buffer; }
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
index 191a8ca8ebc..29b36f44a4d 100644
--- a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
+++ b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied
 LL |     called()
    |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&'b ())`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/higher-ranked-fn-type.rs:6:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
    |
diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
index ce409f627be..54afeaa7eda 100644
--- a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
+++ b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_t
 LL |     called()
    |     ^^^^^^ the trait `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b))> Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ())`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/higher-ranked-fn-type.rs:6:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
    |
diff --git a/tests/ui/where-clauses/where-clause-method-substituion.stderr b/tests/ui/where-clauses/where-clause-method-substituion.stderr
index 8c47ed6d431..2f3b615a13b 100644
--- a/tests/ui/where-clauses/where-clause-method-substituion.stderr
+++ b/tests/ui/where-clauses/where-clause-method-substituion.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `X: Foo<X>` is not satisfied
 LL |     1.method::<X>();
    |                ^ the trait `Foo<X>` is not implemented for `X`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/where-clause-method-substituion.rs:1:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
 note: required by a bound in `Bar::method`
   --> $DIR/where-clause-method-substituion.rs:6:34
    |
diff --git a/triagebot.toml b/triagebot.toml
index 39c18a55697..7492c0d67fd 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -585,7 +585,7 @@ cc = ["@nnethercote"]
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
-users_on_vacation = ["jyn514", "clubby789", "spastorino"]
+users_on_vacation = ["jyn514", "clubby789"]
 
 [assign.adhoc_groups]
 compiler-team = [