about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs4
-rw-r--r--Cargo.lock44
-rw-r--r--compiler/rustc_ast/src/ast.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/visit.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs3
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs148
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs22
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs1
-rw-r--r--compiler/rustc_const_eval/src/lib.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs20
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs10
-rw-r--r--compiler/rustc_data_structures/src/steal.rs5
-rw-r--r--compiler/rustc_driver/src/lib.rs25
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl11
-rw-r--r--compiler/rustc_error_messages/locales/en-US/infer.ftl1
-rw-r--r--compiler/rustc_error_messages/locales/en-US/interface.ftl3
-rw-r--r--compiler/rustc_error_messages/locales/en-US/lint.ftl61
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl3
-rw-r--r--compiler/rustc_expand/src/build.rs1
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs1
-rw-r--r--compiler/rustc_hir/src/intravisit.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs174
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs160
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs46
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs133
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs33
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs35
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs25
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs4
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/errors.rs4
-rw-r--r--compiler/rustc_interface/src/passes.rs23
-rw-r--r--compiler/rustc_interface/src/queries.rs108
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs50
-rw-r--r--compiler/rustc_lint/src/builtin.rs727
-rw-r--r--compiler/rustc_lint/src/context.rs3
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs30
-rw-r--r--compiler/rustc_lint/src/early.rs1
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs17
-rw-r--r--compiler/rustc_lint/src/errors.rs5
-rw-r--r--compiler/rustc_lint/src/expect.rs42
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs73
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs67
-rw-r--r--compiler/rustc_lint/src/internal.rs109
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs47
-rw-r--r--compiler/rustc_lint/src/levels.rs187
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs1479
-rw-r--r--compiler/rustc_lint/src/methods.rs12
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs56
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs47
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs129
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs13
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs17
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs15
-rw-r--r--compiler/rustc_lint/src/traits.rs25
-rw-r--r--compiler/rustc_lint/src/types.rs333
-rw-r--r--compiler/rustc_lint/src/unused.rs169
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs4
-rw-r--r--compiler/rustc_log/Cargo.toml1
-rw-r--r--compiler/rustc_log/src/lib.rs58
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs24
-rw-r--r--compiler/rustc_macros/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs7
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs34
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs10
-rw-r--r--compiler/rustc_passes/src/check_attr.rs11
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs14
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs16
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs17
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/Cargo.toml2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/abi.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs27
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs (renamed from library/alloc/src/collections/binary_heap.rs)0
-rw-r--r--library/core/src/cmp.rs26
-rw-r--r--library/core/src/fmt/mod.rs5
-rw-r--r--library/core/src/iter/traits/iterator.rs5
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/option.rs13
-rw-r--r--library/core/src/sync/atomic.rs40
-rw-r--r--library/std/src/personality/dwarf/eh.rs31
-rw-r--r--library/std/src/sync/mpmc/array.rs14
-rw-r--r--library/std/src/sync/mpmc/list.rs16
-rw-r--r--library/std/src/sync/mpmc/mod.rs2
-rw-r--r--library/std/src/sync/mpmc/utils.rs31
-rw-r--r--library/std/src/sync/mpmc/zero.rs2
-rw-r--r--library/std/src/sync/mpsc/mod.rs9
-rw-r--r--library/std/src/sync/mpsc/sync_tests.rs8
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile1
-rw-r--r--src/doc/rustdoc/src/lints.md2
-rw-r--r--src/doc/unstable-book/src/language-features/abi-efiapi.md23
-rw-r--r--src/librustdoc/clean/types.rs12
-rw-r--r--src/librustdoc/doctest.rs10
-rw-r--r--src/librustdoc/html/render/mod.rs8
-rw-r--r--src/librustdoc/html/render/print_item.rs6
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css72
-rw-r--r--src/librustdoc/html/static/css/settings.css14
-rw-r--r--src/librustdoc/html/static/js/main.js8
-rw-r--r--src/librustdoc/html/static/js/settings.js4
-rw-r--r--src/librustdoc/lib.rs8
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs22
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs3
-rw-r--r--src/librustdoc/passes/strip_private.rs3
-rw-r--r--src/librustdoc/passes/stripper.rs27
-rw-r--r--src/tools/clippy/.github/driver.sh7
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/book/src/installation.md2
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs161
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs174
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs37
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs270
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs11
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs5
-rw-r--r--src/tools/clippy/tests/integration.rs9
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr36
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs225
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr480
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed18
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs10
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr16
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed67
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs13
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr66
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr9
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro.stderr52
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs2
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.fixed8
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr16
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.fixed21
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.rs23
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.stderr23
-rw-r--r--src/tools/clippy/tests/ui/derive.rs11
-rw-r--r--src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr59
-rw-r--r--src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs (renamed from src/tools/clippy/tests/ui/derive_hash_xor_eq.rs)21
-rw-r--r--src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr29
-rw-r--r--src/tools/clippy/tests/ui/drop_ref.rs23
-rw-r--r--src/tools/clippy/tests/ui/drop_ref.stderr38
-rw-r--r--src/tools/clippy/tests/ui/field_reassign_with_default.rs21
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.fixed35
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.rs39
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.stderr114
-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_borrow.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed10
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs10
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr18
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr14
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed2
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr90
-rw-r--r--src/tools/clippy/tests/ui/single_element_loop.fixed27
-rw-r--r--src/tools/clippy/tests/ui/single_element_loop.rs26
-rw-r--r--src/tools/clippy/tests/ui/single_element_loop.stderr29
-rw-r--r--src/tools/clippy/tests/ui/suspicious_to_owned.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unused_self.rs10
-rw-r--r--src/tools/clippy/tests/ui/unused_self.stderr18
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/rustfmt/src/closures.rs19
-rw-r--r--src/tools/rustfmt/src/expr.rs1
-rw-r--r--src/tools/tidy/src/deps.rs2
-rw-r--r--src/tools/tidy/src/error_codes.rs6
-rw-r--r--tests/codegen/abi-efiapi.rs2
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs2
-rw-r--r--tests/run-make-fulldeps/target-specs/foo.rs2
-rw-r--r--tests/rustdoc-gui/method-margins.goml10
-rw-r--r--tests/rustdoc-gui/settings.goml4
-rw-r--r--tests/rustdoc-gui/toggle-click-deadspace.goml8
-rw-r--r--tests/rustdoc-gui/toggle-docs.goml18
-rw-r--r--tests/rustdoc-gui/toggled-open-implementations.goml2
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/rustdoc/const-intrinsic.rs25
-rw-r--r--tests/rustdoc/issue-41783.rs2
-rw-r--r--tests/rustdoc/local-reexport-doc.rs2
-rw-r--r--tests/rustdoc/mixing-doc-comments-and-attrs.rs6
-rw-r--r--tests/rustdoc/multiple-import-levels.rs6
-rw-r--r--tests/rustdoc/reexport-doc-hidden.rs26
-rw-r--r--tests/rustdoc/strip-block-doc-comments-stars.rs2
-rw-r--r--tests/rustdoc/toggle-item-contents.rs40
-rw-r--r--tests/rustdoc/toggle-method.rs6
-rw-r--r--tests/rustdoc/toggle-trait-fn.rs16
-rw-r--r--tests/ui-fulldeps/pprust-expr-roundtrip.rs1
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs2
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr32
-rw-r--r--tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed14
-rw-r--r--tests/ui/associated-item/ambiguous-associated-type-with-generics.rs14
-rw-r--r--tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr9
-rw-r--r--tests/ui/associated-item/associated-item-duplicate-names-3.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-in-ambiguous-context.stderr25
-rw-r--r--tests/ui/async-await/in-trait/nested-rpit.rs4
-rw-r--r--tests/ui/attributes/log-backtrace.rs9
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr8
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr4
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr4
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr4
-rw-r--r--tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs2
-rw-r--r--tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr12
-rw-r--r--tests/ui/c-variadic/variadic-ffi-2.rs1
-rw-r--r--tests/ui/c-variadic/variadic-ffi-2.stderr2
-rw-r--r--tests/ui/chalkify/bugs/async.rs17
-rw-r--r--tests/ui/chalkify/bugs/async.stderr66
-rw-r--r--tests/ui/chalkify/impl_wf.stderr8
-rw-r--r--tests/ui/check-static-values-constraints.stderr1
-rw-r--r--tests/ui/coherence/coherence-overlap-trait-alias.stderr4
-rw-r--r--tests/ui/const-generics/issue-93647.stderr1
-rw-r--r--tests/ui/consts/const-fn-error.stderr2
-rw-r--r--tests/ui/consts/const-for.stderr2
-rw-r--r--tests/ui/consts/ct-var-in-collect_all_mismatches.rs20
-rw-r--r--tests/ui/consts/ct-var-in-collect_all_mismatches.stderr22
-rw-r--r--tests/ui/consts/invalid-inline-const-in-match-arm.stderr1
-rw-r--r--tests/ui/consts/issue-28113.stderr1
-rw-r--r--tests/ui/consts/issue-56164.stderr1
-rw-r--r--tests/ui/consts/issue-68542-closure-in-array-len.stderr1
-rw-r--r--tests/ui/consts/issue-90870.fixed3
-rw-r--r--tests/ui/consts/issue-90870.rs3
-rw-r--r--tests/ui/consts/issue-90870.stderr7
-rw-r--r--tests/ui/did_you_mean/bad-assoc-ty.stderr57
-rw-r--r--tests/ui/dst/dst-sized-trait-param.stderr4
-rw-r--r--tests/ui/error-codes/E0223.rs4
-rw-r--r--tests/ui/error-codes/E0223.stderr4
-rw-r--r--tests/ui/error-codes/E0308-2.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-efiapi.rs33
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-efiapi.stderr66
-rw-r--r--tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr9
-rw-r--r--tests/ui/impl-trait/impl_trait_projections.rs2
-rw-r--r--tests/ui/impl-trait/impl_trait_projections.stderr9
-rw-r--r--tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr19
-rw-r--r--tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr19
-rw-r--r--tests/ui/issues/issue-23073.stderr7
-rw-r--r--tests/ui/issues/issue-58712.stderr9
-rw-r--r--tests/ui/issues/issue-65230.stderr4
-rw-r--r--tests/ui/issues/issue-77919.stderr9
-rw-r--r--tests/ui/issues/issue-78622.stderr7
-rw-r--r--tests/ui/issues/issue-86756.stderr2
-rw-r--r--tests/ui/iterators/float_iterator_hint.rs15
-rw-r--r--tests/ui/iterators/float_iterator_hint.stderr13
-rw-r--r--tests/ui/iterators/integral.stderr1
-rw-r--r--tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs4
-rw-r--r--tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr24
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argc.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_args.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ret.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ty.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr11
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr11
-rw-r--r--tests/ui/lang-items/start_lang_item_args.rs101
-rw-r--r--tests/ui/lang-items/start_lang_item_args.sigpipe.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.start_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.too_many_args.stderr17
-rw-r--r--tests/ui/lint/bare-trait-objects-path.stderr2
-rw-r--r--tests/ui/lint/lint-ffi-safety-all-phantom.rs22
-rw-r--r--tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr8
-rw-r--r--tests/ui/marker_trait_attr/region-overlap.stderr8
-rw-r--r--tests/ui/never_type/issue-52443.stderr2
-rw-r--r--tests/ui/parser/dyn-trait-compatibility.stderr12
-rw-r--r--tests/ui/parser/recover-quantified-closure.rs2
-rw-r--r--tests/ui/parser/recover-quantified-closure.stderr4
-rw-r--r--tests/ui/privacy/issue-75906.stderr4
-rw-r--r--tests/ui/privacy/issue-75907.rs2
-rw-r--r--tests/ui/privacy/issue-75907.stderr8
-rw-r--r--tests/ui/privacy/privacy5.stderr96
-rw-r--r--tests/ui/privacy/suggest-making-field-public.fixed15
-rw-r--r--tests/ui/privacy/suggest-making-field-public.rs15
-rw-r--r--tests/ui/privacy/suggest-making-field-public.stderr39
-rw-r--r--tests/ui/proc-macro/panic-abort.rs4
-rw-r--r--tests/ui/proc-macro/panic-abort.stderr4
-rw-r--r--tests/ui/qualified/qualified-path-params-2.stderr7
-rw-r--r--tests/ui/resolve/issue-103202.stderr7
-rw-r--r--tests/ui/resolve/issue-39559-2.stderr2
-rw-r--r--tests/ui/resolve/issue-42944.rs2
-rw-r--r--tests/ui/resolve/issue-42944.stderr12
-rw-r--r--tests/ui/resolve/privacy-struct-ctor.stderr16
-rw-r--r--tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs45
-rw-r--r--tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr50
-rw-r--r--tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs5
-rw-r--r--tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr2
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/call.rs10
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr1
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr1
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/gate.rs5
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/gate.stderr12
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs15
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr11
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr1
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr1
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr8
-rw-r--r--tests/ui/self/self-impl.stderr4
-rw-r--r--tests/ui/span/issue-71363.stderr8
-rw-r--r--tests/ui/specialization/min_specialization/issue-79224.stderr4
-rw-r--r--tests/ui/structs/struct-path-associated-type.stderr6
-rw-r--r--tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed28
-rw-r--r--tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs28
-rw-r--r--tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr49
-rw-r--r--tests/ui/suggestions/let-binding-init-expr-as-ty.stderr7
-rw-r--r--tests/ui/suggestions/type-not-found-in-adt-field.stderr7
-rw-r--r--tests/ui/trait-bounds/unsized-bound.stderr28
-rw-r--r--tests/ui/traits/ignore-err-impls.stderr9
-rw-r--r--tests/ui/traits/impl-bounds-checking.stderr4
-rw-r--r--tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr8
-rw-r--r--tests/ui/traits/issue-43784-supertrait.stderr4
-rw-r--r--tests/ui/traits/issue-50480.stderr27
-rw-r--r--tests/ui/traits/issue-75627.stderr9
-rw-r--r--tests/ui/traits/issue-78372.stderr9
-rw-r--r--tests/ui/traits/issue-91594.stderr4
-rw-r--r--tests/ui/traits/item-privacy.stderr11
-rw-r--r--tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr8
-rw-r--r--tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr8
-rw-r--r--tests/ui/typeck/autoderef-with-param-env-error.stderr8
-rw-r--r--tests/ui/typeck/issue-104513-ice.stderr7
-rw-r--r--tests/ui/ufcs/ufcs-partially-resolved.stderr7
-rw-r--r--triagebot.toml2
383 files changed, 7044 insertions, 3156 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index b40066d05d3..d20f19e60e8 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -6,3 +6,7 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60
 971c549ca334b7b7406e61e958efcca9c4152822
 # refactor infcx building
 283abbf0e7d20176f76006825b5c52e9a4234e4c
+# format libstd/sys
+c34fbfaad38cf5829ef5cfe780dc9d58480adeaa
+# move tests
+cf2dff2b1e3fa55fa5415d524200070d0d7aacfe
diff --git a/Cargo.lock b/Cargo.lock
index 4bea3af7f3b..65436e2bac3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3013,9 +3013,9 @@ dependencies = [
 
 [[package]]
 name = "pest"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
+checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4"
 dependencies = [
  "thiserror",
  "ucd-trie",
@@ -3023,9 +3023,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
+checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603"
 dependencies = [
  "pest",
  "pest_generator",
@@ -3033,9 +3033,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
+checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7"
 dependencies = [
  "pest",
  "pest_meta",
@@ -3046,13 +3046,13 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
+checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065"
 dependencies = [
  "once_cell",
  "pest",
- "sha-1",
+ "sha1",
 ]
 
 [[package]]
@@ -4273,6 +4273,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_span",
  "tracing",
+ "tracing-core",
  "tracing-subscriber",
  "tracing-tree",
 ]
@@ -4683,7 +4684,7 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "scoped-tls",
- "sha-1",
+ "sha1",
  "sha2",
  "tracing",
  "unicode-width",
@@ -5093,17 +5094,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "sha-1"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
 name = "sha1"
 version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5528,18 +5518,18 @@ checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b"
 
 [[package]]
 name = "thiserror"
-version = "1.0.33"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.33"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5820,9 +5810,9 @@ dependencies = [
 
 [[package]]
 name = "ucd-trie"
-version = "0.1.3"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
 
 [[package]]
 name = "ui_test"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e656fb3740b..7de594719dd 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1307,6 +1307,7 @@ impl Expr {
 pub struct Closure {
     pub binder: ClosureBinder,
     pub capture_clause: CaptureBy,
+    pub constness: Const,
     pub asyncness: Async,
     pub movability: Movability,
     pub fn_decl: P<FnDecl>,
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index c572171e8f4..77f342d1eb3 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
         ExprKind::Closure(box Closure {
             binder,
             capture_clause: _,
+            constness,
             asyncness,
             movability: _,
             fn_decl,
@@ -1370,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             fn_arg_span: _,
         }) => {
             vis.visit_closure_binder(binder);
+            visit_constness(constness, vis);
             vis.visit_asyncness(asyncness);
             vis.visit_fn_decl(fn_decl);
             vis.visit_expr(body);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index df7145a722a..e8823eff83a 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -836,6 +836,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             binder,
             capture_clause: _,
             asyncness: _,
+            constness: _,
             movability: _,
             fn_decl,
             body,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 14f082be9ba..c3611b2f522 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::Closure(box Closure {
                     binder,
                     capture_clause,
+                    constness,
                     asyncness,
                     movability,
                     fn_decl,
@@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             binder,
                             *capture_clause,
                             e.id,
+                            *constness,
                             *movability,
                             fn_decl,
                             body,
@@ -651,6 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 fn_decl_span: self.lower_span(span),
                 fn_arg_span: None,
                 movability: Some(hir::Movability::Static),
+                constness: hir::Constness::NotConst,
             });
 
             hir::ExprKind::Closure(c)
@@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         binder: &ClosureBinder,
         capture_clause: CaptureBy,
         closure_id: NodeId,
+        constness: Const,
         movability: Movability,
         decl: &FnDecl,
         body: &Expr,
@@ -927,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             fn_decl_span: self.lower_span(fn_decl_span),
             fn_arg_span: Some(self.lower_span(fn_arg_span)),
             movability: generator_option,
+            constness: self.lower_constness(constness),
         });
 
         hir::ExprKind::Closure(c)
@@ -1041,6 +1046,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             fn_decl_span: self.lower_span(fn_decl_span),
             fn_arg_span: Some(self.lower_span(fn_arg_span)),
             movability: None,
+            constness: hir::Constness::NotConst,
         });
         hir::ExprKind::Closure(c)
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ea30bed5ace..065779d0670 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1239,7 +1239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    fn lower_constness(&mut self, c: Const) -> hir::Constness {
+    pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
         match c {
             Const::Yes(_) => hir::Constness::Const,
             Const::No => hir::Constness::NotConst,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2e135aafb1e..41d4a5679f1 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -416,8 +416,7 @@ fn compute_hir_hash(
 
 pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
     let sess = tcx.sess;
-    let krate = tcx.untracked_crate.steal();
-    let mut resolver = tcx.resolver_for_lowering(()).steal();
+    let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
 
     let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
     let mut owners = IndexVec::from_fn_n(
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 039338f543c..89ba6f936d1 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -385,6 +385,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::ExprKind::TryBlock(_) => {
                 gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
             }
+            ast::ExprKind::Closure(box ast::Closure { constness: ast::Const::Yes(_), .. }) => {
+                gate_feature_post!(
+                    &self,
+                    const_closures,
+                    e.span,
+                    "const closures are experimental"
+                );
+            }
             _ => {}
         }
         visit::walk_expr(self, e)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 3b17f6dd627..b125c6407d0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -399,6 +399,7 @@ impl<'a> State<'a> {
             ast::ExprKind::Closure(box ast::Closure {
                 binder,
                 capture_clause,
+                constness,
                 asyncness,
                 movability,
                 fn_decl,
@@ -407,6 +408,7 @@ impl<'a> State<'a> {
                 fn_arg_span: _,
             }) => {
                 self.print_closure_binder(binder);
+                self.print_constness(*constness);
                 self.print_movability(*movability);
                 self.print_asyncness(*asyncness);
                 self.print_capture_clause(*capture_clause);
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6658ee89ad6..968c1f49b95 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,6 +6,7 @@ use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 
@@ -29,6 +30,7 @@ use crate::borrowck_errors;
 
 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
 use crate::diagnostics::find_all_local_uses;
+use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -356,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if let Some(hir::Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(_, _, body_id),
             ..
-        })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
+        })) = hir.find(self.mir_hir_id())
             && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
         {
             let place = &self.move_data.move_paths[mpi].place;
@@ -948,7 +950,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
             (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
                 first_borrow_desc = "immutable ";
-                self.cannot_reborrow_already_borrowed(
+                let mut err = self.cannot_reborrow_already_borrowed(
                     span,
                     &desc_place,
                     &msg_place,
@@ -958,7 +960,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     "immutable",
                     &msg_borrow,
                     None,
-                )
+                );
+                self.suggest_binding_for_closure_capture_self(
+                    &mut err,
+                    issued_borrow.borrowed_place,
+                    &issued_spans,
+                );
+                err
             }
 
             (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
@@ -1240,6 +1248,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
+    fn suggest_binding_for_closure_capture_self(
+        &self,
+        err: &mut Diagnostic,
+        borrowed_place: Place<'tcx>,
+        issued_spans: &UseSpans<'tcx>,
+    ) {
+        let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+        let hir = self.infcx.tcx.hir();
+
+        // check whether the borrowed place is capturing `self` by mut reference
+        let local = borrowed_place.local;
+        let Some(_) = self
+            .body
+            .local_decls
+            .get(local)
+            .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+
+        struct ExpressionFinder<'hir> {
+            capture_span: Span,
+            closure_change_spans: Vec<Span>,
+            closure_arg_span: Option<Span>,
+            in_closure: bool,
+            suggest_arg: String,
+            hir: rustc_middle::hir::map::Map<'hir>,
+            closure_local_id: Option<hir::HirId>,
+            closure_call_changes: Vec<(Span, String)>,
+        }
+        impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+            fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
+                if e.span.contains(self.capture_span) {
+                    if let hir::ExprKind::Closure(&hir::Closure {
+                            movability: None,
+                            body,
+                            fn_arg_span,
+                            fn_decl: hir::FnDecl{ inputs, .. },
+                            ..
+                        }) = e.kind &&
+                        let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
+                            self.suggest_arg = "this: &Self".to_string();
+                            if inputs.len() > 0 {
+                                self.suggest_arg.push_str(", ");
+                            }
+                            self.in_closure = true;
+                            self.closure_arg_span = fn_arg_span;
+                            self.visit_expr(body);
+                            self.in_closure = false;
+                    }
+                }
+                if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
+                    if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+                        seg.ident.name == kw::SelfLower && self.in_closure {
+                            self.closure_change_spans.push(e.span);
+                    }
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+
+            fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+                if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
+                    let Some(init) = local.init
+                {
+                    if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
+                            movability: None,
+                            ..
+                        }), .. } = init &&
+                        init.span.contains(self.capture_span) {
+                            self.closure_local_id = Some(*hir_id);
+                    }
+                }
+                hir::intravisit::walk_local(self, local);
+            }
+
+            fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
+                if let hir::StmtKind::Semi(e) = s.kind &&
+                    let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
+                    let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+                    let Res::Local(hir_id) = seg.res &&
+                        Some(hir_id) == self.closure_local_id {
+                        let (span, arg_str) = if args.len() > 0 {
+                            (args[0].span.shrink_to_lo(), "self, ".to_string())
+                        } else {
+                            let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
+                            (span, "(self)".to_string())
+                        };
+                        self.closure_call_changes.push((span, arg_str));
+                }
+                hir::intravisit::walk_stmt(self, s);
+            }
+        }
+
+        if let Some(hir::Node::ImplItem(
+                    hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
+                )) = hir.find(self.mir_hir_id()) &&
+            let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
+            let mut finder = ExpressionFinder {
+                capture_span: *capture_kind_span,
+                closure_change_spans: vec![],
+                closure_arg_span: None,
+                in_closure: false,
+                suggest_arg: String::new(),
+                closure_local_id: None,
+                closure_call_changes: vec![],
+                hir,
+            };
+            finder.visit_expr(expr);
+
+            if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
+                return;
+            }
+
+            let mut sugg = vec![];
+            let sm = self.infcx.tcx.sess.source_map();
+
+            if let Some(span) = finder.closure_arg_span {
+                sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
+            }
+            for span in finder.closure_change_spans {
+                sugg.push((span, "this".to_string()));
+            }
+
+            for (span, suggest) in finder.closure_call_changes {
+                sugg.push((span, suggest));
+            }
+
+            err.multipart_suggestion_verbose(
+                "try explicitly pass `&Self` into the Closure as an argument",
+                sugg,
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     /// Returns the description of the root place for a conflicting borrow and the full
     /// descriptions of the places that caused the conflict.
     ///
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index b9cfc7e6961..45b15c2c5bd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1094,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     }
 }
 
-fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
     debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
 
     match local_decl.local_info.as_deref() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index e8a4d1c37c1..f3050a6ef3f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -79,7 +79,7 @@ impl<'tcx> RegionErrors<'tcx> {
     #[track_caller]
     pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
         let val = val.into();
-        self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}");
+        self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}"));
         self.0.push(val);
     }
     pub fn is_empty(&self) -> bool {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8ca7103ed48..342abf81f6a 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1231,12 +1231,21 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     sess.emit_fatal(errors::LinkerFileStem);
                 });
 
+                // Remove any version postfix.
+                let stem = stem
+                    .rsplit_once('-')
+                    .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
+                    .unwrap_or(stem);
+
+                // GCC can have an optional target prefix.
                 let flavor = if stem == "emcc" {
                     LinkerFlavor::EmCc
                 } else if stem == "gcc"
                     || stem.ends_with("-gcc")
+                    || stem == "g++"
+                    || stem.ends_with("-g++")
                     || stem == "clang"
-                    || stem.ends_with("-clang")
+                    || stem == "clang++"
                 {
                     LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
                 } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 51c5c375d51..5ad2744f61d 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -165,11 +165,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
                 };
             e_flags
         }
-        Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
-            // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
-            // that the `+d` target feature represents whether the double
-            // float abi is enabled.
-            let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+        Architecture::Riscv32 | Architecture::Riscv64 => {
+            // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
+            let mut e_flags: u32 = 0x0;
+            let features = &sess.target.options.features;
+            // Check if compressed is enabled
+            if features.contains("+c") {
+                e_flags |= elf::EF_RISCV_RVC;
+            }
+
+            // Select the appropriate floating-point ABI
+            if features.contains("+d") {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+            } else if features.contains("+f") {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
+            } else {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
+            }
             e_flags
         }
         _ => 0,
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index f1674d04f8d..351c701305a 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -41,6 +41,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
             };
             if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
         }
+        hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
         _ => {
             if let Some(fn_kind) = node.fn_kind() {
                 if fn_kind.constness() == hir::Constness::Const {
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 443c01fdb90..46e7b09a55e 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
+#![feature(if_let_guard)]
 #![feature(is_some_and)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 54213d55a2d..d4c75cd55ce 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -242,7 +242,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             // impl trait is gone in MIR, so check the return type of a const fn by its signature
             // instead of the type of the return place.
             self.span = body.local_decls[RETURN_PLACE].source_info.span;
-            let return_ty = tcx.fn_sig(def_id).output();
+            let return_ty = self.ccx.fn_sig().output();
             self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
         }
 
@@ -730,6 +730,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             substs,
                             span: *fn_span,
                             from_hir_call: *from_hir_call,
+                            feature: Some(sym::const_trait_impl),
                         });
                         return;
                     }
@@ -782,6 +783,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             );
                             return;
                         }
+                        Ok(Some(ImplSource::Closure(data))) => {
+                            if !tcx.is_const_fn_raw(data.closure_def_id) {
+                                self.check_op(ops::FnCallNonConst {
+                                    caller,
+                                    callee,
+                                    substs,
+                                    span: *fn_span,
+                                    from_hir_call: *from_hir_call,
+                                    feature: None,
+                                });
+
+                                return;
+                            }
+                        }
                         Ok(Some(ImplSource::UserDefined(data))) => {
                             let callee_name = tcx.item_name(callee);
                             if let Some(&did) = tcx
@@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                     substs,
                                     span: *fn_span,
                                     from_hir_call: *from_hir_call,
+                                    feature: None,
                                 });
                                 return;
                             }
@@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                     substs,
                                     span: *fn_span,
                                     from_hir_call: *from_hir_call,
+                                    feature: None,
                                 });
                                 return;
                             }
@@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             substs,
                             span: *fn_span,
                             from_hir_call: *from_hir_call,
+                            feature: None,
                         });
                         return;
                     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 0a90572d39e..54868e418c4 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -8,7 +8,7 @@ use rustc_attr as attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
 use rustc_span::Symbol;
 
 pub use self::qualifs::Qualif;
@@ -64,6 +64,17 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     fn is_async(&self) -> bool {
         self.tcx.asyncness(self.def_id()).is_async()
     }
+
+    pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
+        let did = self.def_id().to_def_id();
+        if self.tcx.is_closure(did) {
+            let ty = self.tcx.type_of(did);
+            let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") };
+            substs.as_closure().sig()
+        } else {
+            self.tcx.fn_sig(did)
+        }
+    }
 }
 
 pub fn rustc_allow_const_fn_unstable(
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index b19d270e610..0cb5d2ff8c7 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -111,6 +111,7 @@ pub struct FnCallNonConst<'tcx> {
     pub substs: SubstsRef<'tcx>,
     pub span: Span,
     pub from_hir_call: bool,
+    pub feature: Option<Symbol>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
@@ -119,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
         ccx: &ConstCx<'_, 'tcx>,
         _: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
+        let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
         let ConstCx { tcx, param_env, .. } = *ccx;
 
         let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@@ -318,6 +319,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
             ccx.const_kind(),
         ));
 
+        if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
+            err.help(&format!(
+                "add `#![feature({})]` to the crate attributes to enable",
+                feature,
+            ));
+        }
+
         if let ConstContext::Static(_) = ccx.const_kind() {
             err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
         }
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index a3ece655047..9a0fd52677d 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -41,6 +41,11 @@ impl<T> Steal<T> {
     }
 
     #[track_caller]
+    pub fn get_mut(&mut self) -> &mut T {
+        self.value.get_mut().as_mut().expect("attempt to read from stolen value")
+    }
+
+    #[track_caller]
     pub fn steal(&self) -> T {
         let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");
         let value = value_ref.take();
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index fcb73c64356..a62e5dec4b8 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -231,6 +231,10 @@ fn run_compiler(
         registry: diagnostics_registry(),
     };
 
+    if !tracing::dispatcher::has_been_set() {
+        init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
+    }
+
     match make_input(config.opts.error_format, &matches.free) {
         Err(reported) => return Err(reported),
         Ok(Some((input, input_file_path))) => {
@@ -309,8 +313,8 @@ fn run_compiler(
 
             if let Some(ppm) = &sess.opts.pretty {
                 if ppm.needs_ast_map() {
-                    let expanded_crate = queries.expansion()?.peek().0.clone();
-                    queries.global_ctxt()?.peek_mut().enter(|tcx| {
+                    let expanded_crate = queries.expansion()?.borrow().0.clone();
+                    queries.global_ctxt()?.enter(|tcx| {
                         pretty::print_after_hir_lowering(
                             tcx,
                             compiler.input(),
@@ -321,7 +325,7 @@ fn run_compiler(
                         Ok(())
                     })?;
                 } else {
-                    let krate = queries.parse()?.take();
+                    let krate = queries.parse()?.steal();
                     pretty::print_after_parsing(
                         sess,
                         compiler.input(),
@@ -343,7 +347,8 @@ fn run_compiler(
             }
 
             {
-                let (_, lint_store) = &*queries.register_plugins()?.peek();
+                let plugins = queries.register_plugins()?;
+                let (_, lint_store) = &*plugins.borrow();
 
                 // Lint plugins are registered; now we can process command line flags.
                 if sess.opts.describe_lints {
@@ -371,7 +376,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            queries.global_ctxt()?.peek_mut().enter(|tcx| {
+            queries.global_ctxt()?.enter(|tcx| {
                 let result = tcx.analysis(());
                 if sess.opts.unstable_opts.save_analysis {
                     let crate_name = tcx.crate_name(LOCAL_CRATE);
@@ -1299,7 +1304,14 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    if let Err(error) = rustc_log::init_rustc_env_logger() {
+    init_rustc_env_logger_with_backtrace_option(&None);
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
+/// choose a target module you wish to show backtraces along with its logging.
+pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
+    if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
         early_error(ErrorOutputType::default(), &error.to_string());
     }
 }
@@ -1365,7 +1377,6 @@ mod signal_handler {
 pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
-    init_rustc_env_logger();
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook();
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index a132a8146e9..24258974bb9 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -618,7 +618,7 @@ E0791: include_str!("./error_codes/E0791.md"),
 //  E0487, // unsafe use of destructor: destructor might be called while...
 //  E0488, // lifetime of variable does not enclose its declaration
 //  E0489, // type/lifetime parameter not in scope here
-    E0490, // a value of type `..` is borrowed for too long
+//  E0490, // removed: unreachable
     E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
index 0612dbae0b6..ca72b7faa92 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
@@ -46,3 +46,14 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par
 
 hir_typeck_op_trait_generic_params =
     `{$method_name}` must not have any generic parameters
+
+hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
+hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
+
+hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
+
+hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index c1cb07cf0df..ae0091b0373 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -101,7 +101,6 @@ infer_subtype_2 = ...so that {$requirement ->
 infer_reborrow = ...so that reference does not outlive borrowed content
 infer_reborrow_upvar = ...so that closure can access `{$name}`
 infer_relate_object_bound = ...so that it can be closed over into an object
-infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
 infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
 infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
     [true] ...
diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_error_messages/locales/en-US/interface.ftl
index bbcb8fc28cf..688b0447222 100644
--- a/compiler/rustc_error_messages/locales/en-US/interface.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/interface.ftl
@@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation =
 
 interface_failed_writing_file =
     failed to write file {$path}: {$error}"
+
+interface_proc_macro_crate_panic_abort =
+    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl
index 2eb409a5ddd..d63ff77d8e2 100644
--- a/compiler/rustc_error_messages/locales/en-US/lint.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl
@@ -15,6 +15,43 @@ lint_enum_intrinsics_mem_variant =
 
 lint_expectation = this lint expectation is unfulfilled
     .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+    .rationale = {$rationale}
+
+lint_for_loops_over_fallibles =
+    for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
+    .suggestion = consider using `if let` to clear intent
+    .remove_next = to iterate over `{$recv_snip}` remove the call to `next`
+    .use_while_let = to check pattern in a loop use `while let`
+    .use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
+
+lint_non_binding_let_on_sync_lock =
+    non-binding let on a synchronization lock
+
+lint_non_binding_let_on_drop_type =
+    non-binding let on a type that implements `Drop`
+
+lint_non_binding_let_suggestion =
+    consider binding to an unused variable to avoid immediately dropping the value
+
+lint_non_binding_let_multi_suggestion =
+    consider immediately dropping the value
+
+lint_deprecated_lint_name =
+    lint name `{$name}` is deprecated and may not have an effect in the future.
+    .suggestion = change it to
+
+lint_renamed_or_removed_lint = {$msg}
+    .suggestion = use the new name
+
+lint_unknown_lint =
+    unknown lint: `{$name}`
+    .suggestion = did you mean
+
+lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
+
+lint_unknown_gated_lint =
+    unknown lint: `{$name}`
+    .note = the `{$name}` lint is unstable
 
 lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
     .label = this {$label} contains {$count ->
@@ -55,6 +92,8 @@ lint_diag_out_of_impl =
 
 lint_untranslatable_diag = diagnostics should be created using translatable messages
 
+lint_bad_opt_access = {$msg}
+
 lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .as_ptr_label = this pointer will be invalid
     .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
@@ -331,6 +370,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be
     .suggestion = try naming the parameter or explicitly ignoring it
 
 lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
+    .msg_suggestion = {$msg}
+    .default_suggestion = remove this attribute
 lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
 lint_builtin_deprecated_attr_default_suggestion = remove this attribute
 
@@ -391,10 +432,16 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n
     .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
     .help = consider using `min_{$name}` instead, which is more stable and complete
 
-lint_builtin_clashing_extern_same_name = `{$this_fi}` redeclared with a different signature
+lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
+lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized
+
+lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
+lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+
+lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
     .previous_decl_label = `{$orig}` previously declared here
     .mismatch_label = this signature doesn't match the previous declaration
-lint_builtin_clashing_extern_diff_name = `{$this_fi}` redeclares `{$orig}` with a different signature
+lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
     .previous_decl_label = `{$orig}` previously declared here
     .mismatch_label = this signature doesn't match the previous declaration
 
@@ -403,6 +450,16 @@ lint_builtin_deref_nullptr = dereferencing a null pointer
 
 lint_builtin_asm_labels = avoid using named labels in inline assembly
 
+lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
+    .note = lib.rs is the root of this crate's library target
+    .help = to refer to it from other targets, use the library's name as the path
+
+lint_builtin_special_module_name_used_main = found module declaration for main.rs
+    .note = a binary crate cannot be used as library
+
+lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
+    .label = target type is set here
+
 lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
     .label = overruled by previous forbid
 
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 001e53d1d0e..91857dd227d 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -4,6 +4,9 @@
 -passes_see_issue =
     see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
 
+passes_incorrect_do_not_recommend_location =
+    `#[do_not_recommend]` can only be placed on trait implementations
+
 passes_outer_crate_level_attr =
     crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 93b3af4ab97..9b16e79d49a 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -533,6 +533,7 @@ impl<'a> ExtCtxt<'a> {
             ast::ExprKind::Closure(Box::new(ast::Closure {
                 binder: ast::ClosureBinder::NotPresent,
                 capture_clause: ast::CaptureBy::Ref,
+                constness: ast::Const::No,
                 asyncness: ast::Async::No,
                 movability: ast::Movability::Movable,
                 fn_decl,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index fcbc5bacfcc..aab4b604fad 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -48,6 +48,8 @@ declare_features! (
 
     /// Allows `#[target_feature(...)]` on aarch64 platforms
     (accepted, aarch64_target_feature, "1.61.0", Some(44839), None),
+    /// Allows using the `efiapi` ABI.
+    (accepted, abi_efiapi, "CURRENT_RUSTC_VERSION", Some(65815), None),
     /// Allows the sysV64 ABI to be specified on all platforms
     /// instead of just the platforms on which it is the C ABI.
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index f0bc35d06bf..196c31302a0 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -281,8 +281,6 @@ declare_features! (
     (active, abi_avr_interrupt, "1.45.0", Some(69664), None),
     /// Allows `extern "C-cmse-nonsecure-call" fn()`.
     (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
-    /// Allows using the `efiapi` ABI.
-    (active, abi_efiapi, "1.40.0", Some(65815), None),
     /// Allows `extern "msp430-interrupt" fn()`.
     (active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
     /// Allows `extern "ptx-*" fn()`.
@@ -341,7 +339,9 @@ declare_features! (
     (active, collapse_debuginfo, "1.65.0", Some(100758), None),
     /// Allows `async {}` expressions in const contexts.
     (active, const_async_blocks, "1.53.0", Some(85368), None),
-    // Allows limiting the evaluation steps of const expressions
+    /// Allows `const || {}` closures in const contexts.
+    (incomplete, const_closures, "CURRENT_RUSTC_VERSION", Some(106003), None),
+    /// Allows limiting the evaluation steps of const expressions
     (active, const_eval_limit, "1.43.0", Some(67217), None),
     /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
     (active, const_extern_fn, "1.40.0", Some(64926), None),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bc897ed8112..60f5b79de10 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -938,6 +938,7 @@ pub struct Crate<'hir> {
 pub struct Closure<'hir> {
     pub def_id: LocalDefId,
     pub binder: ClosureBinder,
+    pub constness: Constness,
     pub capture_clause: CaptureBy,
     pub bound_generic_params: &'hir [GenericParam<'hir>],
     pub fn_decl: &'hir FnDecl<'hir>,
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 6c475b659eb..02641b7cf8f 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -742,6 +742,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             fn_decl_span: _,
             fn_arg_span: _,
             movability: _,
+            constness: _,
         }) => {
             walk_list!(visitor, visit_generic_param, bound_generic_params);
             visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 9fa0e6e8eaa..3521911b055 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
@@ -1643,8 +1644,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     fn report_ambiguous_associated_type(
         &self,
         span: Span,
-        type_str: &str,
-        trait_str: &str,
+        types: &[String],
+        traits: &[String],
         name: Symbol,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
@@ -1655,19 +1656,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .keys()
             .any(|full_span| full_span.contains(span))
         {
-            err.span_suggestion(
+            err.span_suggestion_verbose(
                 span.shrink_to_lo(),
                 "you are looking for the module in `std`, not the primitive type",
                 "std::",
                 Applicability::MachineApplicable,
             );
         } else {
-            err.span_suggestion(
-                span,
-                "use fully-qualified syntax",
-                format!("<{} as {}>::{}", type_str, trait_str, name),
-                Applicability::HasPlaceholders,
-            );
+            match (types, traits) {
+                ([], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a type named `Type` that implements a trait named \
+                             `Trait` with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        format!("<Type as Trait>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], [trait_str]) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a type named `Example` that implemented `{trait_str}`, \
+                             you could use the fully-qualified path",
+                        ),
+                        format!("<Example as {trait_str}>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], traits) => {
+                    err.span_suggestions(
+                        span,
+                        &format!(
+                            "if there were a type named `Example` that implemented one of the \
+                             traits with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        traits
+                            .iter()
+                            .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+                            .collect::<Vec<_>>(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([type_str], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for `{type_str}`, you could use the fully-qualified path",
+                        ),
+                        format!("<{type_str} as Example>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, []) => {
+                    err.span_suggestions(
+                        span,
+                        &format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for one of the types, you could use the fully-qualified \
+                             path",
+                        ),
+                        types
+                            .into_iter()
+                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, traits) => {
+                    let mut suggestions = vec![];
+                    for type_str in types {
+                        for trait_str in traits {
+                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+                        }
+                    }
+                    err.span_suggestions(
+                        span,
+                        "use the fully-qualified path",
+                        suggestions,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
         }
         err.emit()
     }
@@ -2050,12 +2124,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     err.emit()
                 } else if let Err(reported) = qself_ty.error_reported() {
                     reported
+                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+                    // `<impl Trait as OtherTrait>::Assoc` makes no sense.
+                    struct_span_err!(
+                        tcx.sess,
+                        tcx.def_span(alias_ty.def_id),
+                        E0667,
+                        "`impl Trait` is not allowed in path parameters"
+                    )
+                    .emit() // Already reported in an earlier stage.
                 } else {
+                    // Find all the `impl`s that `qself_ty` has for any trait that has the
+                    // associated type, so that we suggest the right one.
+                    let infcx = tcx.infer_ctxt().build();
+                    // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
+                    // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
+                    let param_env = ty::ParamEnv::empty();
+                    let traits: Vec<_> = self
+                        .tcx()
+                        .all_traits()
+                        .filter(|trait_def_id| {
+                            // Consider only traits with the associated type
+                            tcx.associated_items(*trait_def_id)
+                                .in_definition_order()
+                                .any(|i| {
+                                    i.kind.namespace() == Namespace::TypeNS
+                                        && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+                                        && matches!(i.kind, ty::AssocKind::Type)
+                                })
+                            // Consider only accessible traits
+                            && tcx.visibility(*trait_def_id)
+                                .is_accessible_from(self.item_def_id(), tcx)
+                            && tcx.all_impls(*trait_def_id)
+                                .any(|impl_def_id| {
+                                    let trait_ref = tcx.bound_impl_trait_ref(impl_def_id);
+                                    trait_ref.map_or(false, |trait_ref| {
+                                        let impl_ = trait_ref.subst(
+                                            tcx,
+                                            infcx.fresh_substs_for_item(span, impl_def_id),
+                                        );
+                                        infcx
+                                            .can_eq(
+                                                param_env,
+                                                tcx.erase_regions(impl_.self_ty()),
+                                                tcx.erase_regions(qself_ty),
+                                            )
+                                            .is_ok()
+                                    })
+                                    && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                                })
+                        })
+                        .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+                        .collect();
+
                     // Don't print `TyErr` to the user.
                     self.report_ambiguous_associated_type(
                         span,
-                        &qself_ty.to_string(),
-                        "Trait",
+                        &[qself_ty.to_string()],
+                        &traits,
                         assoc_ident.name,
                     )
                 };
@@ -2173,16 +2299,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let is_part_of_self_trait_constraints = def_id == trait_def_id;
             let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
 
-            let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
-                "Self"
+            let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+                vec!["Self".to_string()]
             } else {
-                "Type"
+                // Find all the types that have an `impl` for the trait.
+                tcx.all_impls(trait_def_id)
+                    .filter(|impl_def_id| {
+                        // Consider only accessible traits
+                        tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
+                            && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                    })
+                    .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
+                    .map(|impl_| impl_.self_ty())
+                    // We don't care about blanket impls.
+                    .filter(|self_ty| !self_ty.has_non_region_param())
+                    .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+                    .collect()
             };
-
+            // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+            // references the trait. Relevant for the first case in
+            // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
             let reported = self.report_ambiguous_associated_type(
                 span,
-                type_name,
-                &path_str,
+                &type_names,
+                &[path_str],
                 item_segment.ident.name,
             );
             return tcx.ty_error_with_guaranteed(reported)
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 7af89934d14..2cdf7579471 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -2,7 +2,9 @@ use super::potentially_plural_count;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
 use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_errors::{
+    pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
@@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>(
             ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
         ));
     }
-    let emit_implied_wf_lint = || {
-        infcx.tcx.struct_span_lint_hir(
-            rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
-            impl_m_hir_id,
-            infcx.tcx.def_span(impl_m.def_id),
-            "impl method assumes more implied bounds than the corresponding trait method",
-            |lint| lint,
-        );
-    };
 
     // Check that all obligations are satisfied by the implementation's
     // version.
@@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>(
                 )
                 .map(|()| {
                     // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
+                    emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
                 });
             }
             CheckImpliedWfMode::Skip => {
@@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>(
                     CheckImpliedWfMode::Skip,
                 )
                 .map(|()| {
+                    let bad_args = extract_bad_args_for_implies_lint(
+                        tcx,
+                        &errors,
+                        (trait_m, trait_sig),
+                        // Unnormalized impl sig corresponds to the HIR types written
+                        (impl_m, unnormalized_impl_sig),
+                        impl_m_hir_id,
+                    );
                     // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
+                    emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
                 });
             }
             CheckImpliedWfMode::Skip => {
@@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>(
     Ok(())
 }
 
+fn extract_bad_args_for_implies_lint<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    errors: &[infer::RegionResolutionError<'tcx>],
+    (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    hir_id: hir::HirId,
+) -> Vec<(Span, Option<String>)> {
+    let mut blame_generics = vec![];
+    for error in errors {
+        // Look for the subregion origin that contains an input/output type
+        let origin = match error {
+            infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
+            infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
+            infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
+            infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
+        };
+        // Extract (possible) input/output types from origin
+        match origin {
+            infer::SubregionOrigin::Subtype(trace) => {
+                if let Some((a, b)) = trace.values.ty() {
+                    blame_generics.extend([a, b]);
+                }
+            }
+            infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
+            infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
+            _ => {}
+        }
+    }
+
+    let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
+    let opt_ret_ty = match fn_decl.output {
+        hir::FnRetTy::DefaultReturn(_) => None,
+        hir::FnRetTy::Return(ty) => Some(ty),
+    };
+
+    // Map late-bound regions from trait to impl, so the names are right.
+    let mapping = std::iter::zip(
+        tcx.fn_sig(trait_m.def_id).bound_vars(),
+        tcx.fn_sig(impl_m.def_id).bound_vars(),
+    )
+    .filter_map(|(impl_bv, trait_bv)| {
+        if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+            && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+        {
+            Some((impl_bv, trait_bv))
+        } else {
+            None
+        }
+    })
+    .collect();
+
+    // For each arg, see if it was in the "blame" of any of the region errors.
+    // If so, then try to produce a suggestion to replace the argument type with
+    // one from the trait.
+    let mut bad_args = vec![];
+    for (idx, (ty, hir_ty)) in
+        std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
+            .enumerate()
+    {
+        let expected_ty = trait_sig.inputs_and_output[idx]
+            .fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
+        if blame_generics.iter().any(|blame| ty.contains(*blame)) {
+            let expected_ty_sugg = expected_ty.to_string();
+            bad_args.push((
+                hir_ty.span,
+                // Only suggest something if it actually changed.
+                (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
+            ));
+        }
+    }
+
+    bad_args
+}
+
+struct RemapLateBound<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReFree(fr) = *r {
+            self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
+                bound_region: self
+                    .mapping
+                    .get(&fr.bound_region)
+                    .copied()
+                    .unwrap_or(fr.bound_region),
+                ..fr
+            }))
+        } else {
+            r
+        }
+    }
+}
+
+fn emit_implied_wf_lint<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    hir_id: hir::HirId,
+    bad_args: Vec<(Span, Option<String>)>,
+) {
+    let span: MultiSpan = if bad_args.is_empty() {
+        tcx.def_span(impl_m.def_id).into()
+    } else {
+        bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
+    };
+    tcx.struct_span_lint_hir(
+        rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+        hir_id,
+        span,
+        "impl method assumes more implied bounds than the corresponding trait method",
+        |lint| {
+            let bad_args: Vec<_> =
+                bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
+            if !bad_args.is_empty() {
+                lint.multipart_suggestion(
+                    format!(
+                        "replace {} type{} to make the impl signature compatible",
+                        pluralize!("this", bad_args.len()),
+                        pluralize!(bad_args.len())
+                    ),
+                    bad_args,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            lint
+        },
+    );
+}
+
 #[derive(Debug, PartialEq, Eq)]
 enum CheckImpliedWfMode {
     /// Checks implied well-formedness of the impl method. If it fails, we will
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d1f4dbc8d84..92fd4625ee8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1254,7 +1254,11 @@ fn check_impl<'tcx>(
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
                 let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
-                let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
+                let trait_ref = wfcx.normalize(
+                    ast_trait_ref.path.span,
+                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
+                    trait_ref,
+                );
                 let trait_pred = ty::TraitPredicate {
                     trait_ref,
                     constness: match constness {
@@ -1263,7 +1267,7 @@ fn check_impl<'tcx>(
                     },
                     polarity: ty::ImplPolarity::Positive,
                 };
-                let obligations = traits::wf::trait_obligations(
+                let mut obligations = traits::wf::trait_obligations(
                     wfcx.infcx,
                     wfcx.param_env,
                     wfcx.body_id,
@@ -1271,6 +1275,13 @@ fn check_impl<'tcx>(
                     ast_trait_ref.path.span,
                     item,
                 );
+                for obligation in &mut obligations {
+                    if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
+                        && pred.self_ty().skip_binder() == trait_ref.self_ty()
+                    {
+                        obligation.cause.span = ast_self_ty.span;
+                    }
+                }
                 debug!(?obligations);
                 wfcx.register_obligations(obligations);
             }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 96221c3e3d8..9a5f447c260 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -4,6 +4,7 @@ use hir::{
     GenericParamKind, HirId, Node,
 };
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
@@ -142,7 +143,20 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
+            ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin:
+                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                in_trait,
+                ..
+            }) => {
+                if in_trait {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                } else {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                }
+                Some(fn_def_id.to_def_id())
+            }
+            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 assert_ne!(parent_id, hir::CRATE_OWNER_ID);
                 debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 4f9d5826583..2dbfc1bc9a2 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -114,34 +114,46 @@ fn diagnostic_hir_wf_check<'tcx>(
     // Get the starting `hir::Ty` using our `WellFormedLoc`.
     // We will walk 'into' this type to try to find
     // a more precise span for our predicate.
-    let ty = match loc {
+    let tys = match loc {
         WellFormedLoc::Ty(_) => match hir.get(hir_id) {
             hir::Node::ImplItem(item) => match item.kind {
-                hir::ImplItemKind::Type(ty) => Some(ty),
-                hir::ImplItemKind::Const(ty, _) => Some(ty),
+                hir::ImplItemKind::Type(ty) => vec![ty],
+                hir::ImplItemKind::Const(ty, _) => vec![ty],
                 ref item => bug!("Unexpected ImplItem {:?}", item),
             },
             hir::Node::TraitItem(item) => match item.kind {
-                hir::TraitItemKind::Type(_, ty) => ty,
-                hir::TraitItemKind::Const(ty, _) => Some(ty),
+                hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(),
+                hir::TraitItemKind::Const(ty, _) => vec![ty],
                 ref item => bug!("Unexpected TraitItem {:?}", item),
             },
             hir::Node::Item(item) => match item.kind {
-                hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty),
-                hir::ItemKind::Impl(ref impl_) => {
-                    assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_);
-                    Some(impl_.self_ty)
-                }
+                hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
+                hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait {
+                    Some(t) => t
+                        .path
+                        .segments
+                        .last()
+                        .iter()
+                        .flat_map(|seg| seg.args().args)
+                        .filter_map(|arg| {
+                            if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
+                        })
+                        .chain([impl_.self_ty])
+                        .collect(),
+                    None => {
+                        vec![impl_.self_ty]
+                    }
+                },
                 ref item => bug!("Unexpected item {:?}", item),
             },
-            hir::Node::Field(field) => Some(field.ty),
+            hir::Node::Field(field) => vec![field.ty],
             hir::Node::ForeignItem(ForeignItem {
                 kind: ForeignItemKind::Static(ty, _), ..
-            }) => Some(*ty),
+            }) => vec![*ty],
             hir::Node::GenericParam(hir::GenericParam {
                 kind: hir::GenericParamKind::Type { default: Some(ty), .. },
                 ..
-            }) => Some(*ty),
+            }) => vec![*ty],
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
@@ -149,16 +161,16 @@ fn diagnostic_hir_wf_check<'tcx>(
             // Get return type
             if param_idx as usize == fn_decl.inputs.len() {
                 match fn_decl.output {
-                    hir::FnRetTy::Return(ty) => Some(ty),
+                    hir::FnRetTy::Return(ty) => vec![ty],
                     // The unit type `()` is always well-formed
-                    hir::FnRetTy::DefaultReturn(_span) => None,
+                    hir::FnRetTy::DefaultReturn(_span) => vec![],
                 }
             } else {
-                Some(&fn_decl.inputs[param_idx as usize])
+                vec![&fn_decl.inputs[param_idx as usize]]
             }
         }
     };
-    if let Some(ty) = ty {
+    for ty in tys {
         visitor.visit_ty(ty);
     }
     visitor.cause
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 3e3af8395a1..f74c551a45b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1464,6 +1464,7 @@ impl<'a> State<'a> {
             }
             hir::ExprKind::Closure(&hir::Closure {
                 binder,
+                constness,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
@@ -1474,6 +1475,7 @@ impl<'a> State<'a> {
                 def_id: _,
             }) => {
                 self.print_closure_binder(binder, bound_generic_params);
+                self.print_constness(constness);
                 self.print_capture_clause(capture_clause);
 
                 self.print_closure_params(fn_decl, body);
@@ -2272,10 +2274,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
-        match header.constness {
-            hir::Constness::NotConst => {}
-            hir::Constness::Const => self.word_nbsp("const"),
-        }
+        self.print_constness(header.constness);
 
         match header.asyncness {
             hir::IsAsync::NotAsync => {}
@@ -2292,6 +2291,13 @@ impl<'a> State<'a> {
         self.word("fn")
     }
 
+    pub fn print_constness(&mut self, s: hir::Constness) {
+        match s {
+            hir::Constness::NotConst => {}
+            hir::Constness::Const => self.word_nbsp("const"),
+        }
+    }
+
     pub fn print_unsafety(&mut self, s: hir::Unsafety) {
         match s {
             hir::Unsafety::Normal => {}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 32f86b8042c..57feefbcab6 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -1,4 +1,7 @@
 use crate::coercion::CoerceMany;
+use crate::errors::{
+    LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
+};
 use crate::gather_locals::GatherLocalsVisitor;
 use crate::FnCtxt;
 use crate::GeneratorTypes;
@@ -9,8 +12,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::check::fn_maybe_err;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::RegionVariableOrigin;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use std::cell::RefCell;
 
@@ -168,6 +172,10 @@ pub(super) fn check_fn<'a, 'tcx>(
         check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
+    if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
+        check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
+    }
+
     gen_ty
 }
 
@@ -223,3 +231,126 @@ fn check_panic_info_fn(
         tcx.sess.span_err(span, "should have no const parameters");
     }
 }
+
+fn check_lang_start_fn<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    def_id: LocalDefId,
+) {
+    let inputs = fn_sig.inputs();
+
+    let arg_count = inputs.len();
+    if arg_count != 4 {
+        tcx.sess.emit_err(LangStartIncorrectNumberArgs {
+            params_span: tcx.def_span(def_id),
+            found_param_count: arg_count,
+        });
+    }
+
+    // only check args if they should exist by checking the count
+    // note: this does not handle args being shifted or their order swapped very nicely
+    // but it's a lang item, users shouldn't frequently encounter this
+
+    // first arg is `main: fn() -> T`
+    if let Some(&main_arg) = inputs.get(0) {
+        // make a Ty for the generic on the fn for diagnostics
+        // FIXME: make the lang item generic checks check for the right generic *kind*
+        // for example `start`'s generic should be a type parameter
+        let generics = tcx.generics_of(def_id);
+        let fn_generic = generics.param_at(0, tcx);
+        let generic_tykind =
+            ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name });
+        let generic_ty = tcx.mk_ty(generic_tykind);
+        let expected_fn_sig =
+            tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
+        let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
+
+        // we emit the same error to suggest changing the arg no matter what's wrong with the arg
+        let emit_main_fn_arg_err = || {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[0].span,
+                param_num: 1,
+                expected_ty: expected_ty,
+                found_ty: main_arg,
+            });
+        };
+
+        if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
+            let main_fn_inputs = main_fn_sig.inputs();
+            if main_fn_inputs.iter().count() != 0 {
+                emit_main_fn_arg_err();
+            }
+
+            let output = main_fn_sig.output();
+            output.map_bound(|ret_ty| {
+                // if the output ty is a generic, it's probably the right one
+                if !matches!(ret_ty.kind(), ty::Param(_)) {
+                    emit_main_fn_arg_err();
+                }
+            });
+        } else {
+            emit_main_fn_arg_err();
+        }
+    }
+
+    // second arg is isize
+    if let Some(&argc_arg) = inputs.get(1) {
+        if argc_arg != tcx.types.isize {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[1].span,
+                param_num: 2,
+                expected_ty: tcx.types.isize,
+                found_ty: argc_arg,
+            });
+        }
+    }
+
+    // third arg is `*const *const u8`
+    if let Some(&argv_arg) = inputs.get(2) {
+        let mut argv_is_okay = false;
+        if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
+            if outer_ptr.mutbl.is_not() {
+                if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
+                    if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
+                        argv_is_okay = true;
+                    }
+                }
+            }
+        }
+
+        if !argv_is_okay {
+            let inner_ptr_ty =
+                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
+            let expected_ty =
+                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[2].span,
+                param_num: 3,
+                expected_ty,
+                found_ty: argv_arg,
+            });
+        }
+    }
+
+    // fourth arg is `sigpipe: u8`
+    if let Some(&sigpipe_arg) = inputs.get(3) {
+        if sigpipe_arg != tcx.types.u8 {
+            tcx.sess.emit_err(LangStartIncorrectParam {
+                param_span: decl.inputs[3].span,
+                param_num: 4,
+                expected_ty: tcx.types.u8,
+                found_ty: sigpipe_arg,
+            });
+        }
+    }
+
+    // output type is isize
+    if fn_sig.output() != tcx.types.isize {
+        tcx.sess.emit_err(LangStartIncorrectRetTy {
+            ret_span: decl.output.span(),
+            expected_ty: tcx.types.isize,
+            found_ty: fn_sig.output(),
+        });
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 507272fdec5..5b4fd5e4a52 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -172,3 +172,36 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
         );
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_number_params)]
+#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
+#[note(hir_typeck_lang_start_expected_sig_note)]
+pub struct LangStartIncorrectNumberArgs {
+    #[primary_span]
+    pub params_span: Span,
+    pub found_param_count: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_param)]
+pub struct LangStartIncorrectParam<'tcx> {
+    #[primary_span]
+    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
+    pub param_span: Span,
+
+    pub param_num: usize,
+    pub expected_ty: Ty<'tcx>,
+    pub found_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
+pub struct LangStartIncorrectRetTy<'tcx> {
+    #[primary_span]
+    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
+    pub ret_span: Span,
+
+    pub expected_ty: Ty<'tcx>,
+    pub found_ty: Ty<'tcx>,
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 080ae6b9466..533a3c768eb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1782,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             // like when you have two references but one is `usize` and the other
                             // is `f32`. In those cases we still want to show the `note`. If the
                             // value from `ef` is `Infer(_)`, then we ignore it.
-                            if !ef.expected.is_ty_infer() {
+                            if !ef.expected.is_ty_or_numeric_infer() {
                                 ef.expected != values.expected
-                            } else if !ef.found.is_ty_infer() {
+                            } else if !ef.found.is_ty_or_numeric_infer() {
                                 ef.found != values.found
                             } else {
                                 false
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index a4c36b4c9cd..b8c843a8a5a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -78,7 +78,7 @@ impl InferenceDiagnosticsData {
     }
 
     fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
-        if in_type.is_ty_infer() {
+        if in_type.is_ty_or_numeric_infer() {
             ""
         } else if self.name == "_" {
             // FIXME: Consider specializing this message if there is a single `_`
@@ -195,12 +195,12 @@ fn ty_to_string<'tcx>(
         // invalid pseudo-syntax, we want the `fn`-pointer output instead.
         (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
         (_, Some(def_id))
-            if ty.is_ty_infer()
+            if ty.is_ty_or_numeric_infer()
                 && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
         {
             "Vec<_>".to_string()
         }
-        _ if ty.is_ty_infer() => "/* Type */".to_string(),
+        _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(),
         // FIXME: The same thing for closures, but this only works when the closure
         // does not capture anything.
         //
@@ -680,7 +680,7 @@ impl<'tcx> InferSourceKind<'tcx> {
             | InferSourceKind::ClosureReturn { ty, .. } => {
                 if ty.is_closure() {
                     ("closure", closure_as_fn_str(infcx, ty))
-                } else if !ty.is_ty_infer() {
+                } else if !ty.is_ty_or_numeric_infer() {
                     ("normal", ty_to_string(infcx, ty, None))
                 } else {
                     ("other", String::new())
@@ -813,7 +813,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         self.attempt += 1;
         if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
             && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
-            && ty.is_ty_infer()
+            && ty.is_ty_or_numeric_infer()
         {
             // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
             // `let x: _ = iter.collect();`, as this is a very common case.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 7bb79d7bda8..7504ed094a3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -29,15 +29,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
                     .add_to_diagnostic(err);
             }
-            infer::DataBorrowed(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_data_borrowed,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
             infer::ReferenceOutlivesReferent(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
@@ -227,32 +218,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 err
             }
-            infer::DataBorrowed(ty, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0490,
-                    "a value of type `{}` is borrowed for too long",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the type is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but the borrow lasts for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
             infer::ReferenceOutlivesReferent(ty, span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index da2c6fbc05f..897545046c3 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -702,26 +702,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                     // Obtain the spans for all the places that can
                     // influence the constraints on this value for
                     // richer diagnostics in `static_impl_trait`.
-                    let influences: Vec<Span> = self
-                        .data
-                        .constraints
-                        .iter()
-                        .filter_map(|(constraint, origin)| match (constraint, origin) {
-                            (
-                                Constraint::VarSubVar(_, sup),
-                                SubregionOrigin::DataBorrowed(_, sp),
-                            ) if sup == &node_vid => Some(*sp),
-                            _ => None,
-                        })
-                        .collect();
-
-                    self.collect_error_for_expanding_node(
-                        graph,
-                        &mut dup_vec,
-                        node_vid,
-                        errors,
-                        influences,
-                    );
+
+                    self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
                 }
             }
         }
@@ -775,7 +757,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
         node_idx: RegionVid,
         errors: &mut Vec<RegionResolutionError<'tcx>>,
-        influences: Vec<Span>,
     ) {
         // Errors in expanding nodes result from a lower-bound that is
         // not contained by an upper-bound.
@@ -830,7 +811,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                         lower_bound.region,
                         upper_bound.origin.clone(),
                         upper_bound.region,
-                        influences,
+                        vec![],
                     ));
                     return;
                 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 8825b5e12c3..4acd0d0edfe 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -410,9 +410,6 @@ pub enum SubregionOrigin<'tcx> {
     /// Creating a pointer `b` to contents of another reference
     Reborrow(Span),
 
-    /// Data with type `Ty<'tcx>` was borrowed
-    DataBorrowed(Ty<'tcx>, Span),
-
     /// (&'a &'b T) where a >= b
     ReferenceOutlivesReferent(Ty<'tcx>, Span),
 
@@ -1978,7 +1975,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
             RelateParamBound(a, ..) => a,
             RelateRegionParamBound(a) => a,
             Reborrow(a) => a,
-            DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
             CompareImplItemObligation { span, .. } => span,
             AscribeUserTypeProvePredicate(span) => span,
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index e67dec31dce..f817c5bc1cd 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" }
 rustc_privacy = { path = "../rustc_privacy" }
 rustc_query_impl = { path = "../rustc_query_impl" }
 rustc_resolve = { path = "../rustc_resolve" }
+rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index f5135c78dc8..15d7e977bbe 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> {
     pub path: &'a Path,
     pub error: io::Error,
 }
+
+#[derive(Diagnostic)]
+#[diag(interface_proc_macro_crate_panic_abort)]
+pub struct ProcMacroCratePanicAbort;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 86d56385bc9..50c40206d80 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1,7 +1,8 @@
 use crate::errors::{
     CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
     GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
-    MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
+    MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
+    TempsDirError,
 };
 use crate::interface::{Compiler, Result};
 use crate::proc_macro_decls;
@@ -36,6 +37,7 @@ use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::FileName;
+use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 
 use std::any::Any;
@@ -380,6 +382,10 @@ pub fn configure_and_expand(
         }
     }
 
+    if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
+        sess.emit_warning(ProcMacroCratePanicAbort);
+    }
+
     // For backwards compatibility, we don't try to run proc macro injection
     // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
     // specified. This should only affect users who manually invoke 'rustdoc', as
@@ -817,23 +823,26 @@ pub fn create_global_ctxt<'tcx>(
                 lint_store,
                 arena,
                 hir_arena,
-                untracked_resolutions,
                 untracked,
-                krate,
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
                 queries.as_dyn(),
                 rustc_query_impl::query_callbacks(arena),
-                crate_name,
-                outputs,
             )
         })
     });
 
     let mut qcx = QueryContext { gcx };
     qcx.enter(|tcx| {
-        tcx.feed_unit_query()
-            .resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering)))
+        let feed = tcx.feed_unit_query();
+        feed.resolver_for_lowering(
+            tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
+        );
+        feed.resolutions(tcx.arena.alloc(untracked_resolutions));
+        feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs)));
+        feed.features_query(sess.features_untracked());
+        let feed = tcx.feed_local_crate();
+        feed.crate_name(crate_name);
     });
     qcx
 }
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 1d0c7f5b7a3..041bb9eb7a1 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -5,6 +5,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
 use rustc_ast as ast;
 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::{Lrc, OnceCell, WorkerLocal};
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -19,43 +20,53 @@ use rustc_session::{output::find_crate_name, Session};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 use std::any::Any;
-use std::cell::{Ref, RefCell, RefMut};
+use std::cell::{RefCell, RefMut};
 use std::rc::Rc;
 use std::sync::Arc;
 
 /// Represent the result of a query.
 ///
-/// This result can be stolen with the [`take`] method and generated with the [`compute`] method.
+/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method.
 ///
-/// [`take`]: Self::take
+/// [`steal`]: Steal::steal
 /// [`compute`]: Self::compute
 pub struct Query<T> {
-    result: RefCell<Option<Result<T>>>,
+    /// `None` means no value has been computed yet.
+    result: RefCell<Option<Result<Steal<T>>>>,
 }
 
 impl<T> Query<T> {
-    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
-        self.result.borrow_mut().get_or_insert_with(f).as_ref().map(|_| self).map_err(|&err| err)
+    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> {
+        RefMut::filter_map(
+            self.result.borrow_mut(),
+            |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> {
+                r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok()
+            },
+        )
+        .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err())
+        .map(QueryResult)
     }
+}
+
+pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>);
+
+impl<'a, T> std::ops::Deref for QueryResult<'a, T> {
+    type Target = RefMut<'a, Steal<T>>;
 
-    /// Takes ownership of the query result. Further attempts to take or peek the query
-    /// result will panic unless it is generated by calling the `compute` method.
-    pub fn take(&self) -> T {
-        self.result.borrow_mut().take().expect("missing query result").unwrap()
+    fn deref(&self) -> &Self::Target {
+        &self.0
     }
+}
 
-    /// Borrows the query result using the RefCell. Panics if the result is stolen.
-    pub fn peek(&self) -> Ref<'_, T> {
-        Ref::map(self.result.borrow(), |r| {
-            r.as_ref().unwrap().as_ref().expect("missing query result")
-        })
+impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
     }
+}
 
-    /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
-    pub fn peek_mut(&self) -> RefMut<'_, T> {
-        RefMut::map(self.result.borrow_mut(), |r| {
-            r.as_mut().unwrap().as_mut().expect("missing query result")
-        })
+impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> {
+    pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
+        (*self.0).get_mut().enter(f)
     }
 }
 
@@ -111,24 +122,24 @@ impl<'tcx> Queries<'tcx> {
         self.compiler.codegen_backend()
     }
 
-    fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
+    fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> {
         self.dep_graph_future.compute(|| {
             let sess = self.session();
             Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess)))
         })
     }
 
-    pub fn parse(&self) -> Result<&Query<ast::Crate>> {
+    pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
         self.parse.compute(|| {
             passes::parse(self.session(), &self.compiler.input)
                 .map_err(|mut parse_error| parse_error.emit())
         })
     }
 
-    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
+    pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
         self.register_plugins.compute(|| {
-            let crate_name = *self.crate_name()?.peek();
-            let krate = self.parse()?.take();
+            let crate_name = *self.crate_name()?.borrow();
+            let krate = self.parse()?.steal();
 
             let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
             let (krate, lint_store) = passes::register_plugins(
@@ -150,11 +161,11 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    pub fn crate_name(&self) -> Result<&Query<Symbol>> {
+    pub fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
         self.crate_name.compute(|| {
             Ok({
                 let parse_result = self.parse()?;
-                let krate = parse_result.peek();
+                let krate = parse_result.borrow();
                 // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
                 find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
             })
@@ -163,11 +174,12 @@ impl<'tcx> Queries<'tcx> {
 
     pub fn expansion(
         &self,
-    ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
+    ) -> Result<QueryResult<'_, (Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>>
+    {
         trace!("expansion");
         self.expansion.compute(|| {
-            let crate_name = *self.crate_name()?.peek();
-            let (krate, lint_store) = self.register_plugins()?.take();
+            let crate_name = *self.crate_name()?.borrow();
+            let (krate, lint_store) = self.register_plugins()?.steal();
             let _timer = self.session().timer("configure_and_expand");
             let sess = self.session();
             let mut resolver = passes::create_resolver(
@@ -183,10 +195,10 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    fn dep_graph(&self) -> Result<&Query<DepGraph>> {
+    fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> {
         self.dep_graph.compute(|| {
             let sess = self.session();
-            let future_opt = self.dep_graph_future()?.take();
+            let future_opt = self.dep_graph_future()?.steal();
             let dep_graph = future_opt
                 .and_then(|future| {
                     let (prev_graph, prev_work_products) =
@@ -199,10 +211,11 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
+    pub fn prepare_outputs(&self) -> Result<QueryResult<'_, OutputFilenames>> {
         self.prepare_outputs.compute(|| {
-            let (krate, boxed_resolver, _) = &*self.expansion()?.peek();
-            let crate_name = *self.crate_name()?.peek();
+            let expansion = self.expansion()?;
+            let (krate, boxed_resolver, _) = &*expansion.borrow();
+            let crate_name = *self.crate_name()?.borrow();
             passes::prepare_outputs(
                 self.session(),
                 self.compiler,
@@ -213,12 +226,12 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
+    pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
         self.global_ctxt.compute(|| {
-            let crate_name = *self.crate_name()?.peek();
-            let outputs = self.prepare_outputs()?.take();
-            let dep_graph = self.dep_graph()?.peek().clone();
-            let (krate, resolver, lint_store) = self.expansion()?.take();
+            let crate_name = *self.crate_name()?.borrow();
+            let outputs = self.prepare_outputs()?.steal();
+            let dep_graph = self.dep_graph()?.borrow().clone();
+            let (krate, resolver, lint_store) = self.expansion()?.steal();
             Ok(passes::create_global_ctxt(
                 self.compiler,
                 lint_store,
@@ -235,9 +248,9 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
+    pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> {
         self.ongoing_codegen.compute(|| {
-            self.global_ctxt()?.peek_mut().enter(|tcx| {
+            self.global_ctxt()?.enter(|tcx| {
                 tcx.analysis(()).ok();
 
                 // Don't do code generation if there were any errors
@@ -293,12 +306,10 @@ impl<'tcx> Queries<'tcx> {
         let sess = self.session().clone();
         let codegen_backend = self.codegen_backend().clone();
 
-        let dep_graph = self.dep_graph()?.peek().clone();
-        let (crate_hash, prepare_outputs) = self
-            .global_ctxt()?
-            .peek_mut()
-            .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone()));
-        let ongoing_codegen = self.ongoing_codegen()?.take();
+        let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| {
+            (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone(), tcx.dep_graph.clone())
+        });
+        let ongoing_codegen = self.ongoing_codegen()?.steal();
 
         Ok(Linker {
             sess,
@@ -382,6 +393,7 @@ impl Compiler {
         // NOTE: intentionally does not compute the global context if it hasn't been built yet,
         // since that likely means there was a parse error.
         if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
+            let gcx = gcx.get_mut();
             // We assume that no queries are run past here. If there are new queries
             // after this point, they'll show up as "<unknown>" in self-profiling data.
             {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a3b9891ee64..07b28cc86ce 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(link_only, true);
     tracked!(llvm_plugins, vec![String::from("plugin_name")]);
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
+    tracked!(log_backtrace, Some("filter".to_string()));
     tracked!(maximal_hir_to_mir_coverage, true);
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index abebc533cc1..3593f141df6 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -1,5 +1,5 @@
+use crate::lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub};
 use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
@@ -118,41 +118,23 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                 // to an array or to a slice.
                 _ => bug!("array type coerced to something other than array or slice"),
             };
-            cx.struct_span_lint(
+            let sub = if self.for_expr_span == expr.span {
+                Some(ArrayIntoIterDiagSub::RemoveIntoIter {
+                    span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                })
+            } else if receiver_ty.is_array() {
+                Some(ArrayIntoIterDiagSub::UseExplicitIntoIter {
+                    start_span: expr.span.shrink_to_lo(),
+                    end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                })
+            } else {
+                None
+            };
+            cx.emit_spanned_lint(
                 ARRAY_INTO_ITER,
                 call.ident.span,
-                fluent::lint_array_into_iter,
-                |diag| {
-                    diag.set_arg("target", target);
-                    diag.span_suggestion(
-                        call.ident.span,
-                        fluent::use_iter_suggestion,
-                        "iter",
-                        Applicability::MachineApplicable,
-                    );
-                    if self.for_expr_span == expr.span {
-                        diag.span_suggestion(
-                            receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                            fluent::remove_into_iter_suggestion,
-                            "",
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else if receiver_ty.is_array() {
-                        diag.multipart_suggestion(
-                            fluent::use_explicit_into_iter_suggestion,
-                            vec![
-                                (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
-                                (
-                                    receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                                    ")".into(),
-                                ),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    diag
-                },
-            )
+                ArrayIntoIterDiag { target, suggestion: call.ident.span, sub },
+            );
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d58168ff377..6f445426df7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -22,6 +22,23 @@
 
 use crate::{
     errors::BuiltinEllpisisInclusiveRangePatterns,
+    lints::{
+        BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
+        BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
+        BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
+        BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
+        BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures,
+        BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents,
+        BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
+        BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
+        BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
+        BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
+        BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue,
+        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit,
+        BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
+        BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
+        BuiltinWhileTrue, SuggestChangingAssocTypes,
+    },
     types::{transparent_newtype_field, CItemKind},
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
 };
@@ -33,10 +50,7 @@ use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{
-    fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
-    DiagnosticStyledString, MultiSpan,
-};
+use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan};
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -110,25 +124,17 @@ impl EarlyLintPass for WhileTrue {
             && !cond.span.from_expansion()
         {
             let condition_span = e.span.with_hi(cond.span.hi());
-            cx.struct_span_lint(
-                            WHILE_TRUE,
-                            condition_span,
-                fluent::lint_builtin_while_true,
-                            |lint| {
-                    lint.span_suggestion_short(
-                        condition_span,
-                        fluent::suggestion,
-                        format!(
+            let replace = format!(
                             "{}loop",
                             label.map_or_else(String::new, |label| format!(
                                 "{}: ",
                                 label.ident,
                             ))
-                        ),
-                        Applicability::MachineApplicable,
-                    )
-                },
-            )
+                        );
+            cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue {
+                suggestion: condition_span,
+                replace,
+            });
         }
     }
 }
@@ -164,12 +170,7 @@ impl BoxPointers {
         for leaf in ty.walk() {
             if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
                 if leaf_ty.is_box() {
-                    cx.struct_span_lint(
-                        BOX_POINTERS,
-                        span,
-                        fluent::lint_builtin_box_pointers,
-                        |lint| lint.set_arg("ty", ty),
-                    );
+                    cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
                 }
             }
         }
@@ -267,19 +268,13 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                     if cx.tcx.find_field_index(ident, &variant)
                         == Some(cx.typeck_results().field_index(fieldpat.hir_id))
                     {
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             NON_SHORTHAND_FIELD_PATTERNS,
                             fieldpat.span,
-                            fluent::lint_builtin_non_shorthand_field_patterns,
-                            |lint| {
-                                let suggested_ident =
-                                    format!("{}{}", binding_annot.prefix_str(), ident);
-                                lint.set_arg("ident", ident).span_suggestion(
-                                    fieldpat.span,
-                                    fluent::suggestion,
-                                    suggested_ident,
-                                    Applicability::MachineApplicable,
-                                )
+                            BuiltinNonShorthandFieldPatterns {
+                                ident,
+                                suggestion: fieldpat.span,
+                                prefix: binding_annot.prefix_str(),
                             },
                         );
                     }
@@ -321,48 +316,21 @@ impl UnsafeCode {
         &self,
         cx: &EarlyContext<'_>,
         span: Span,
-        msg: impl Into<DiagnosticMessage>,
-        decorate: impl for<'a, 'b> FnOnce(
-            &'b mut DiagnosticBuilder<'a, ()>,
-        ) -> &'b mut DiagnosticBuilder<'a, ()>,
+        decorate: impl for<'a> DecorateLint<'a, ()>,
     ) {
         // This comes from a macro that has `#[allow_internal_unsafe]`.
         if span.allows_unsafe() {
             return;
         }
 
-        cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
-    }
-
-    fn report_overridden_symbol_name(
-        &self,
-        cx: &EarlyContext<'_>,
-        span: Span,
-        msg: DiagnosticMessage,
-    ) {
-        self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint_builtin_overridden_symbol_name)
-        })
-    }
-
-    fn report_overridden_symbol_section(
-        &self,
-        cx: &EarlyContext<'_>,
-        span: Span,
-        msg: DiagnosticMessage,
-    ) {
-        self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint_builtin_overridden_symbol_section)
-        })
+        cx.emit_spanned_lint(UNSAFE_CODE, span, decorate);
     }
 }
 
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::allow_internal_unsafe) {
-            self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
-                lint
-            });
+            self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
         }
     }
 
@@ -371,7 +339,7 @@ impl EarlyLintPass for UnsafeCode {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
             // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
-                self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
+                self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock);
             }
         }
     }
@@ -379,62 +347,38 @@ impl EarlyLintPass for UnsafeCode {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
             ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
+                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
             }
 
             ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
+                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
             }
 
             ast::ItemKind::Fn(..) => {
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
-                    self.report_overridden_symbol_name(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_no_mangle_fn,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
                 }
 
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
-                    self.report_overridden_symbol_name(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_export_name_fn,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
                 }
 
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
-                    self.report_overridden_symbol_section(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_link_section_fn,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
                 }
             }
 
             ast::ItemKind::Static(..) => {
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
-                    self.report_overridden_symbol_name(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_no_mangle_static,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
                 }
 
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
-                    self.report_overridden_symbol_name(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_export_name_static,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
                 }
 
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
-                    self.report_overridden_symbol_section(
-                        cx,
-                        attr.span,
-                        fluent::lint_builtin_link_section_static,
-                    );
+                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
                 }
             }
 
@@ -445,18 +389,10 @@ impl EarlyLintPass for UnsafeCode {
     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         if let ast::AssocItemKind::Fn(..) = it.kind {
             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
-                self.report_overridden_symbol_name(
-                    cx,
-                    attr.span,
-                    fluent::lint_builtin_no_mangle_method,
-                );
+                self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
             }
             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
-                self.report_overridden_symbol_name(
-                    cx,
-                    attr.span,
-                    fluent::lint_builtin_export_name_method,
-                );
+                self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
             }
         }
     }
@@ -471,13 +407,13 @@ impl EarlyLintPass for UnsafeCode {
             body,
         ) = fk
         {
-            let msg = match ctxt {
+            let decorator = match ctxt {
                 FnCtxt::Foreign => return,
-                FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
-                FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
-                FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
+                FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn,
+                FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod,
+                FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod,
             };
-            self.report_unsafe(cx, span, msg, |lint| lint);
+            self.report_unsafe(cx, span, decorator);
         }
     }
 }
@@ -578,11 +514,10 @@ impl MissingDoc {
         let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
         let has_doc = attrs.iter().any(has_doc);
         if !has_doc {
-            cx.struct_span_lint(
+            cx.emit_spanned_lint(
                 MISSING_DOCS,
                 cx.tcx.def_span(def_id),
-                fluent::lint_builtin_missing_doc,
-                |lint| lint.set_arg("article", article).set_arg("desc", desc),
+                BuiltinMissingDoc { article, desc },
             );
         }
     }
@@ -799,12 +734,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         )
         .is_ok()
         {
-            cx.struct_span_lint(
-                MISSING_COPY_IMPLEMENTATIONS,
-                item.span,
-                fluent::lint_builtin_missing_copy_impl,
-                |lint| lint,
-            )
+            cx.emit_spanned_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl);
         }
     }
 }
@@ -878,11 +808,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
         }
 
         if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
-            cx.struct_span_lint(
+            cx.emit_spanned_lint(
                 MISSING_DEBUG_IMPLEMENTATIONS,
                 item.span,
-                fluent::lint_builtin_missing_debug_impl,
-                |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
+                BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug },
             );
         }
     }
@@ -958,19 +887,11 @@ impl EarlyLintPass for AnonymousParameters {
                         } else {
                             ("<type>", Applicability::HasPlaceholders)
                         };
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             ANONYMOUS_PARAMETERS,
                             arg.pat.span,
-                            fluent::lint_builtin_anonymous_params,
-                            |lint| {
-                                lint.span_suggestion(
-                                    arg.pat.span,
-                                    fluent::suggestion,
-                                    format!("_: {}", ty_snip),
-                                    appl,
-                                )
-                            },
-                        )
+                            BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
+                        );
                     }
                 }
             }
@@ -1005,42 +926,30 @@ impl EarlyLintPass for DeprecatedAttr {
                     _,
                 ) = gate
                 {
-                    // FIXME(davidtwco) translatable deprecated attr
-                    cx.struct_span_lint(
+                    let suggestion = match suggestion {
+                        Some(msg) => {
+                            BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
+                        }
+                        None => {
+                            BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
+                        }
+                    };
+                    cx.emit_spanned_lint(
                         DEPRECATED,
                         attr.span,
-                        fluent::lint_builtin_deprecated_attr_link,
-                        |lint| {
-                            lint.set_arg("name", name)
-                                .set_arg("reason", reason)
-                                .set_arg("link", link)
-                                .span_suggestion_short(
-                                    attr.span,
-                                    suggestion.map(|s| s.into()).unwrap_or(
-                                        fluent::lint_builtin_deprecated_attr_default_suggestion,
-                                    ),
-                                    "",
-                                    Applicability::MachineApplicable,
-                                )
-                        },
+                        BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
                     );
                 }
                 return;
             }
         }
         if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
-            cx.struct_span_lint(
+            cx.emit_spanned_lint(
                 DEPRECATED,
                 attr.span,
-                fluent::lint_builtin_deprecated_attr_used,
-                |lint| {
-                    lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
-                        .span_suggestion_short(
-                            attr.span,
-                            fluent::lint_builtin_deprecated_attr_default_suggestion,
-                            "",
-                            Applicability::MachineApplicable,
-                        )
+                BuiltinDeprecatedAttrUsed {
+                    name: pprust::path_to_string(&attr.get_normal_item().path),
+                    suggestion: attr.span,
                 },
             );
         }
@@ -1069,20 +978,18 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
         let span = sugared_span.take().unwrap_or(attr.span);
 
         if is_doc_comment || attr.has_name(sym::doc) {
-            cx.struct_span_lint(
+            let sub = match attr.kind {
+                AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
+                    BuiltinUnusedDocCommentSub::PlainHelp
+                }
+                AttrKind::DocComment(CommentKind::Block, _) => {
+                    BuiltinUnusedDocCommentSub::BlockHelp
+                }
+            };
+            cx.emit_spanned_lint(
                 UNUSED_DOC_COMMENTS,
                 span,
-                fluent::lint_builtin_unused_doc_comment,
-                |lint| {
-                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
-                        match attr.kind {
-                            AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
-                                fluent::plain_help
-                            }
-                            AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
-                        },
-                    )
-                },
+                BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub },
             );
         }
     }
@@ -1197,20 +1104,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
                     GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             NO_MANGLE_GENERIC_ITEMS,
                             span,
-                            fluent::lint_builtin_no_mangle_generic,
-                            |lint| {
-                                lint.span_suggestion_short(
-                                    no_mangle_attr.span,
-                                    fluent::suggestion,
-                                    "",
-                                    // Use of `#[no_mangle]` suggests FFI intent; correct
-                                    // fix may be to monomorphize source by hand
-                                    Applicability::MaybeIncorrect,
-                                )
-                            },
+                            BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span },
                         );
                         break;
                     }
@@ -1225,30 +1122,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
             }
             hir::ItemKind::Const(..) => {
                 if cx.sess().contains_name(attrs, sym::no_mangle) {
+                    // account for "pub const" (#45562)
+                    let start = cx
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(it.span)
+                        .map(|snippet| snippet.find("const").unwrap_or(0))
+                        .unwrap_or(0) as u32;
+                    // `const` is 5 chars
+                    let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
+
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         NO_MANGLE_CONST_ITEMS,
                         it.span,
-                        fluent::lint_builtin_const_no_mangle,
-                        |lint| {
-                            // account for "pub const" (#45562)
-                            let start = cx
-                                .tcx
-                                .sess
-                                .source_map()
-                                .span_to_snippet(it.span)
-                                .map(|snippet| snippet.find("const").unwrap_or(0))
-                                .unwrap_or(0) as u32;
-                            // `const` is 5 chars
-                            let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
-                            lint.span_suggestion(
-                                const_span,
-                                fluent::suggestion,
-                                "pub static",
-                                Applicability::MachineApplicable,
-                            )
-                        },
+                        BuiltinConstNoMangle { suggestion },
                     );
                 }
             }
@@ -1309,12 +1199,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
             if from_mutbl < to_mutbl {
-                cx.struct_span_lint(
-                    MUTABLE_TRANSMUTES,
-                    expr.span,
-                    fluent::lint_builtin_mutable_transmutes,
-                    |lint| lint,
-                );
+                cx.emit_spanned_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
             }
         }
 
@@ -1362,12 +1247,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
         if attr.has_name(sym::feature) {
             if let Some(items) = attr.meta_item_list() {
                 for item in items {
-                    cx.struct_span_lint(
-                        UNSTABLE_FEATURES,
-                        item.span(),
-                        fluent::lint_builtin_unstable_features,
-                        |lint| lint,
-                    );
+                    cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
                 }
             }
         }
@@ -1422,20 +1302,10 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
             // Now, check if the function has the `#[track_caller]` attribute
             && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller))
             {
-                cx.struct_span_lint(
-                    UNGATED_ASYNC_FN_TRACK_CALLER,
-                    attr.span,
-                    fluent::lint_ungated_async_fn_track_caller,
-                    |lint| {
-                        lint.span_label(span, fluent::label);
-                        rustc_session::parse::add_feature_diagnostics(
-                            lint,
-                            &cx.tcx.sess.parse_sess,
-                            sym::closure_track_caller,
-                        );
-                        lint
-                    },
-                );
+                cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
+                    label: span,
+                    parse_sess: &cx.tcx.sess.parse_sess,
+                });
             }
     }
 }
@@ -1493,18 +1363,13 @@ impl UnreachablePub {
                 applicability = Applicability::MaybeIncorrect;
             }
             let def_span = cx.tcx.def_span(def_id);
-            cx.struct_span_lint(
+            cx.emit_spanned_lint(
                 UNREACHABLE_PUB,
                 def_span,
-                fluent::lint_builtin_unreachable_pub,
-                |lint| {
-                    lint.set_arg("what", what);
-
-                    lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
-                    if exportable {
-                        lint.help(fluent::help);
-                    }
-                    lint
+                BuiltinUnreachablePub {
+                    what,
+                    suggestion: (vis_span, applicability),
+                    help: exportable.then_some(()),
                 },
             );
         }
@@ -1569,7 +1434,7 @@ declare_lint_pass!(
 );
 
 impl TypeAliasBounds {
-    fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
+    pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
         match *qpath {
             hir::QPath::TypeRelative(ref ty, _) => {
                 // If this is a type variable, we found a `T::Assoc`.
@@ -1583,29 +1448,6 @@ impl TypeAliasBounds {
             hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
         }
     }
-
-    fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) {
-        // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
-        // bound.  Let's see if this type does that.
-
-        // We use a HIR visitor to walk the type.
-        use rustc_hir::intravisit::{self, Visitor};
-        struct WalkAssocTypes<'a> {
-            err: &'a mut Diagnostic,
-        }
-        impl Visitor<'_> for WalkAssocTypes<'_> {
-            fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
-                if TypeAliasBounds::is_type_variable_assoc(qpath) {
-                    self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
-                }
-                intravisit::walk_qpath(self, qpath, id)
-            }
-        }
-
-        // Let's go for a walk!
-        let mut visitor = WalkAssocTypes { err };
-        visitor.visit_ty(ty);
-    }
 }
 
 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
@@ -1639,35 +1481,31 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
 
         let mut suggested_changing_assoc_types = false;
         if !where_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
-                lint.set_span(where_spans);
-                lint.span_suggestion(
-                    type_alias_generics.where_clause_span,
-                    fluent::suggestion,
-                    "",
-                    Applicability::MachineApplicable,
-                );
-                if !suggested_changing_assoc_types {
-                    TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
-                    suggested_changing_assoc_types = true;
-                }
-                lint
+            let sub = (!suggested_changing_assoc_types).then(|| {
+                suggested_changing_assoc_types = true;
+                SuggestChangingAssocTypes { ty }
             });
+            cx.emit_spanned_lint(
+                TYPE_ALIAS_BOUNDS,
+                where_spans,
+                BuiltinTypeAliasWhereClause {
+                    suggestion: type_alias_generics.where_clause_span,
+                    sub,
+                },
+            );
         }
 
         if !inline_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
-                lint.set_span(inline_spans);
-                lint.multipart_suggestion(
-                    fluent::suggestion,
-                    inline_sugg,
-                    Applicability::MachineApplicable,
-                );
-                if !suggested_changing_assoc_types {
-                    TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
-                }
-                lint
+            let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg };
+            let sub = (!suggested_changing_assoc_types).then(|| {
+                suggested_changing_assoc_types = true;
+                SuggestChangingAssocTypes { ty }
             });
+            cx.emit_spanned_lint(
+                TYPE_ALIAS_BOUNDS,
+                inline_spans,
+                BuiltinTypeAliasGenericBounds { suggestion, sub },
+            );
         }
     }
 }
@@ -1767,14 +1605,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     TypeWellFormedFromEnv(..) => continue,
                 };
                 if predicate.is_global() {
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         TRIVIAL_BOUNDS,
                         span,
-                        fluent::lint_builtin_trivial_bounds,
-                        |lint| {
-                            lint.set_arg("predicate_kind_name", predicate_kind_name)
-                                .set_arg("predicate", predicate)
-                        },
+                        BuiltinTrivialBounds { predicate_kind_name, predicate },
                     );
                 }
             }
@@ -1875,8 +1709,6 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
         };
 
         if let Some((start, end, join)) = endpoints {
-            let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
-            let suggestion = fluent::suggestion;
             if parenthesise {
                 self.node_id = Some(pat.id);
                 let end = expr_to_string(&end);
@@ -1891,14 +1723,14 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                         replace,
                     });
                 } else {
-                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
-                        lint.span_suggestion(
-                            pat.span,
-                            suggestion,
+                    cx.emit_spanned_lint(
+                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
+                        pat.span,
+                        BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {
+                            suggestion: pat.span,
                             replace,
-                            Applicability::MachineApplicable,
-                        )
-                    });
+                        },
+                    );
                 }
             } else {
                 let replace = "..=";
@@ -1909,14 +1741,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                         replace: replace.to_string(),
                     });
                 } else {
-                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
-                        lint.span_suggestion_short(
-                            join,
-                            suggestion,
-                            replace,
-                            Applicability::MachineApplicable,
-                        )
-                    });
+                    cx.emit_spanned_lint(
+                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
+                        join,
+                        BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {
+                            suggestion: join,
+                        },
+                    );
                 }
             };
         }
@@ -1996,12 +1827,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
-            cx.struct_span_lint(
-                UNNAMEABLE_TEST_ITEMS,
-                attr.span,
-                fluent::lint_builtin_unnameable_test_items,
-                |lint| lint,
-            );
+            cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
         }
     }
 
@@ -2117,18 +1943,10 @@ impl KeywordIdents {
             return;
         }
 
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             KEYWORD_IDENTS,
             ident.span,
-            fluent::lint_builtin_keyword_idents,
-            |lint| {
-                lint.set_arg("kw", ident).set_arg("next", next_edition).span_suggestion(
-                    ident.span,
-                    fluent::suggestion,
-                    format!("r#{}", ident),
-                    Applicability::MachineApplicable,
-                )
-            },
+            BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span },
         );
     }
 }
@@ -2405,16 +2223,15 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     Applicability::MaybeIncorrect
                 };
 
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
-                    fluent::lint_builtin_explicit_outlives,
-                    |lint| {
-                        lint.set_arg("count", bound_count).multipart_suggestion(
-                            fluent::suggestion,
-                            lint_spans.into_iter().map(|span| (span, String::new())).collect(),
+                    BuiltinExplicitOutlives {
+                        count: bound_count,
+                        suggestion: BuiltinExplicitOutlivesSuggestion {
+                            spans: lint_spans,
                             applicability,
-                        )
+                        },
                     },
                 );
             }
@@ -2463,24 +2280,18 @@ impl EarlyLintPass for IncompleteFeatures {
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
             .filter(|(&name, _)| features.incomplete(name))
             .for_each(|(&name, &span)| {
-                cx.struct_span_lint(
+                let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
+                    .map(|n| BuiltinIncompleteFeaturesNote { n });
+                let help = if HAS_MIN_FEATURES.contains(&name) {
+                    Some(BuiltinIncompleteFeaturesHelp)
+                } else {
+                    None
+                };
+                cx.emit_spanned_lint(
                     INCOMPLETE_FEATURES,
                     span,
-                    fluent::lint_builtin_incomplete_features,
-                    |lint| {
-                        lint.set_arg("name", name);
-                        if let Some(n) =
-                            rustc_feature::find_feature_issue(name, GateIssue::Language)
-                        {
-                            lint.set_arg("n", n);
-                            lint.note(fluent::note);
-                        }
-                        if HAS_MIN_FEATURES.contains(&name) {
-                            lint.help(fluent::help);
-                        }
-                        lint
-                    },
-                )
+                    BuiltinIncompleteFeatures { name, note, help },
+                );
             });
     }
 }
@@ -2525,6 +2336,36 @@ declare_lint! {
 
 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
 
+/// Information about why a type cannot be initialized this way.
+pub struct InitError {
+    pub(crate) message: String,
+    /// Spans from struct fields and similar that can be obtained from just the type.
+    pub(crate) span: Option<Span>,
+    /// Used to report a trace through adts.
+    pub(crate) nested: Option<Box<InitError>>,
+}
+impl InitError {
+    fn spanned(self, span: Span) -> InitError {
+        Self { span: Some(span), ..self }
+    }
+
+    fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
+        assert!(self.nested.is_none());
+        Self { nested: nested.into().map(Box::new), ..self }
+    }
+}
+
+impl<'a> From<&'a str> for InitError {
+    fn from(s: &'a str) -> Self {
+        s.to_owned().into()
+    }
+}
+impl From<String> for InitError {
+    fn from(message: String) -> Self {
+        Self { message, span: None, nested: None }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for InvalidValue {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
         #[derive(Debug, Copy, Clone, PartialEq)]
@@ -2533,36 +2374,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             Uninit,
         }
 
-        /// Information about why a type cannot be initialized this way.
-        struct InitError {
-            message: String,
-            /// Spans from struct fields and similar that can be obtained from just the type.
-            span: Option<Span>,
-            /// Used to report a trace through adts.
-            nested: Option<Box<InitError>>,
-        }
-        impl InitError {
-            fn spanned(self, span: Span) -> InitError {
-                Self { span: Some(span), ..self }
-            }
-
-            fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
-                assert!(self.nested.is_none());
-                Self { nested: nested.into().map(Box::new), ..self }
-            }
-        }
-
-        impl<'a> From<&'a str> for InitError {
-            fn from(s: &'a str) -> Self {
-                s.to_owned().into()
-            }
-        }
-        impl From<String> for InitError {
-            fn from(message: String) -> Self {
-                Self { message, span: None, nested: None }
-            }
-        }
-
         /// Test if this constant is all-0.
         fn is_zero(expr: &hir::Expr<'_>) -> bool {
             use hir::ExprKind::*;
@@ -2786,46 +2597,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             // using zeroed or uninitialized memory.
             // We are extremely conservative with what we warn about.
             let conjured_ty = cx.typeck_results().expr_ty(expr);
-            if let Some(mut err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
-            {
-                // FIXME(davidtwco): make translatable
-                cx.struct_span_lint(
+            if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
+                let msg = match init {
+                    InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
+                    InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint,
+                };
+                let sub = BuiltinUnpermittedTypeInitSub { err };
+                cx.emit_spanned_lint(
                     INVALID_VALUE,
                     expr.span,
-                    DelayDm(|| {
-                        format!(
-                            "the type `{}` does not permit {}",
-                            conjured_ty,
-                            match init {
-                                InitKind::Zeroed => "zero-initialization",
-                                InitKind::Uninit => "being left uninitialized",
-                            },
-                        )
-                    }),
-                    |lint| {
-                        lint.span_label(
-                            expr.span,
-                            "this code causes undefined behavior when executed",
-                        );
-                        lint.span_label(
-                            expr.span,
-                            "help: use `MaybeUninit<T>` instead, \
-                            and only call `assume_init` after initialization is done",
-                        );
-                        loop {
-                            if let Some(span) = err.span {
-                                lint.span_note(span, &err.message);
-                            } else {
-                                lint.note(&err.message);
-                            }
-                            if let Some(e) = err.nested {
-                                err = *e;
-                            } else {
-                                break;
-                            }
-                        }
-                        lint
-                    },
+                    BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub },
                 );
             }
         }
@@ -3171,31 +2952,39 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
                             SymbolName::Normal(_) => fi.span,
                             SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
                         };
-                    // Finally, emit the diagnostic.
 
-                    let msg = if orig.get_name() == this_fi.ident.name {
-                        fluent::lint_builtin_clashing_extern_same_name
+                    // Finally, emit the diagnostic.
+                    let this = this_fi.ident.name;
+                    let orig = orig.get_name();
+                    let previous_decl_label = get_relevant_span(orig_fi);
+                    let mismatch_label = get_relevant_span(this_fi);
+                    let sub = BuiltinClashingExternSub {
+                        tcx,
+                        expected: existing_decl_ty,
+                        found: this_decl_ty,
+                    };
+                    let decorator = if orig == this {
+                        BuiltinClashingExtern::SameName {
+                            this,
+                            orig,
+                            previous_decl_label,
+                            mismatch_label,
+                            sub,
+                        }
                     } else {
-                        fluent::lint_builtin_clashing_extern_diff_name
+                        BuiltinClashingExtern::DiffName {
+                            this,
+                            orig,
+                            previous_decl_label,
+                            mismatch_label,
+                            sub,
+                        }
                     };
-                    tcx.struct_span_lint_hir(
+                    tcx.emit_spanned_lint(
                         CLASHING_EXTERN_DECLARATIONS,
                         this_fi.hir_id(),
                         get_relevant_span(this_fi),
-                        msg,
-                        |lint| {
-                            let mut expected_str = DiagnosticStyledString::new();
-                            expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
-                            let mut found_str = DiagnosticStyledString::new();
-                            found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
-
-                            lint.set_arg("this_fi", this_fi.ident.name)
-                                .set_arg("orig", orig.get_name())
-                                .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
-                                .span_label(get_relevant_span(this_fi), fluent::mismatch_label)
-                                // FIXME(davidtwco): translatable expected/found
-                                .note_expected_found(&"", expected_str, &"", found_str)
-                        },
+                        decorator,
                     );
                 }
             }
@@ -3275,11 +3064,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
 
         if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
             if is_null_ptr(cx, expr_deref) {
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     DEREF_NULLPTR,
                     expr.span,
-                    fluent::lint_builtin_deref_nullptr,
-                    |lint| lint.span_label(expr.span, fluent::label),
+                    BuiltinDerefNullptr { label: expr.span },
                 );
             }
         }
@@ -3324,6 +3112,7 @@ declare_lint! {
 declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
 
 impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
+    #[allow(rustc::diagnostic_outside_of_impl)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::Expr {
             kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
@@ -3464,16 +3253,17 @@ impl EarlyLintPass for SpecialModuleName {
                 }
 
                 match item.ident.name.as_str() {
-                    "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
-                        lint
-                            .note("lib.rs is the root of this crate's library target")
-                            .help("to refer to it from other targets, use the library's name as the path")
-                    }),
-                    "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
-                        lint
-                            .note("a binary crate cannot be used as library")
-                    }),
-                    _ => continue
+                    "lib" => cx.emit_spanned_lint(
+                        SPECIAL_MODULE_NAME,
+                        item.span,
+                        BuiltinSpecialModuleNameUsed::Lib,
+                    ),
+                    "main" => cx.emit_spanned_lint(
+                        SPECIAL_MODULE_NAME,
+                        item.span,
+                        BuiltinSpecialModuleNameUsed::Main,
+                    ),
+                    _ => continue,
                 }
             }
         }
@@ -3489,31 +3279,16 @@ impl EarlyLintPass for UnexpectedCfgs {
         let cfg = &cx.sess().parse_sess.config;
         let check_cfg = &cx.sess().parse_sess.check_config;
         for &(name, value) in cfg {
-            if let Some(names_valid) = &check_cfg.names_valid {
-                if !names_valid.contains(&name) {
-                    cx.lookup(
-                        UNEXPECTED_CFGS,
-                        None::<MultiSpan>,
-                        fluent::lint_builtin_unexpected_cli_config_name,
-                        |diag| diag.help(fluent::help).set_arg("name", name),
-                    );
-                }
+            if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
+                cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
+                    name,
+                });
             }
-            if let Some(value) = value {
-                if let Some(values) = &check_cfg.values_valid.get(&name) {
-                    if !values.contains(&value) {
-                        cx.lookup(
-                            UNEXPECTED_CFGS,
-                            None::<MultiSpan>,
-                            fluent::lint_builtin_unexpected_cli_config_value,
-                            |diag| {
-                                diag.help(fluent::help)
-                                    .set_arg("name", name)
-                                    .set_arg("value", value)
-                            },
-                        );
-                    }
-                }
+            if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
+                cx.emit_lint(
+                    UNEXPECTED_CFGS,
+                    BuiltinUnexpectedCliConfigValue { name, value },
+                );
             }
         }
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index a16bb7f1a5f..c9b9a622571 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -965,6 +965,7 @@ pub trait LintContext: Sized {
     /// Note that this function should only be called for [`LintExpectationId`]s
     /// retrieved from the current lint pass. Buffered or manually created ids can
     /// cause ICEs.
+    #[rustc_lint_diagnostics]
     fn fulfill_expectation(&self, expectation: LintExpectationId) {
         // We need to make sure that submitted expectation ids are correctly fulfilled suppressed
         // and stored between compilation sessions. To not manually do these steps, we simply create
@@ -1011,6 +1012,7 @@ impl<'tcx> LintContext for LateContext<'tcx> {
         &*self.lint_store
     }
 
+    #[rustc_lint_diagnostics]
     fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -1045,6 +1047,7 @@ impl LintContext for EarlyContext<'_> {
         self.builder.lint_store()
     }
 
+    #[rustc_lint_diagnostics]
     fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 1d29a234a3c..dff5a645c17 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -1,6 +1,8 @@
-use crate::{LateContext, LateLintPass, LintContext};
+use crate::{
+    lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel},
+    LateContext, LateLintPass, LintContext,
+};
 
-use rustc_errors::DelayDm;
 use rustc_hir as hir;
 use rustc_middle::{traits::util::supertraits, ty};
 use rustc_span::sym;
@@ -71,22 +73,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
             && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
                 .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
         {
-            cx.struct_span_lint(
-                DEREF_INTO_DYN_SUPERTRAIT,
-                cx.tcx.def_span(item.owner_id.def_id),
-                DelayDm(|| {
-                    format!(
-                        "`{t}` implements `Deref` with supertrait `{target_principal}` as target"
-                    )
-                }),
-                |lint| {
-                    if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) {
-                        lint.span_label(target_span, "target type is set here");
-                    }
-
-                    lint
-                },
-            )
+            let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel {
+                label,
+            });
+            cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget {
+                t,
+                target_principal: target_principal.to_string(),
+                label,
+            });
         }
     }
 }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index d757471dcee..f9b2df49592 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -40,6 +40,7 @@ pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
 impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
     // This always-inlined function is for the hot call site.
     #[inline(always)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
             let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index f9d7466228a..73bd4173270 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -1,5 +1,8 @@
-use crate::{context::LintContext, LateContext, LateLintPass};
-use rustc_errors::fluent;
+use crate::{
+    context::LintContext,
+    lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant},
+    LateContext, LateLintPass,
+};
 use rustc_hir as hir;
 use rustc_middle::ty::{visit::TypeVisitable, Ty};
 use rustc_span::{symbol::sym, Span};
@@ -50,11 +53,10 @@ fn enforce_mem_discriminant(
 ) {
     let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
     if is_non_enum(ty_param) {
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             expr_span,
-            fluent::lint_enum_intrinsics_mem_discriminant,
-            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note),
+            EnumIntrinsicsMemDiscriminate { ty_param, note: args_span },
         );
     }
 }
@@ -62,11 +64,10 @@ fn enforce_mem_discriminant(
 fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
     let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
     if is_non_enum(ty_param) {
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             span,
-            fluent::lint_enum_intrinsics_mem_variant,
-            |lint| lint.set_arg("ty_param", ty_param).note(fluent::note),
+            EnumIntrinsicsMemVariant { ty_param },
         );
     }
 }
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 1a769893f55..f3ae2609186 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -8,12 +8,12 @@ use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
 #[diag(lint_overruled_attribute, code = "E0453")]
-pub struct OverruledAttribute {
+pub struct OverruledAttribute<'a> {
     #[primary_span]
     pub span: Span,
     #[label]
     pub overruled: Span,
-    pub lint_level: String,
+    pub lint_level: &'a str,
     pub lint_source: Symbol,
     #[subdiagnostic]
     pub sub: OverruledAttributeSub,
@@ -38,6 +38,7 @@ impl AddToDiagnostic for OverruledAttributeSub {
             OverruledAttributeSub::NodeSource { span, reason } => {
                 diag.span_label(span, fluent::lint_node_source);
                 if let Some(rationale) = reason {
+                    #[allow(rustc::untranslatable_diagnostic)]
                     diag.note(rationale.as_str());
                 }
             }
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index cf8f31bcbd0..e9eb14ea188 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,8 +1,7 @@
-use crate::builtin;
-use rustc_errors::fluent;
-use rustc_hir::HirId;
+use crate::lints::{Expectation, ExpectationNote};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
 use rustc_session::lint::LintExpectationId;
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -12,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) {
 }
 
 fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
-    if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
+    if !tcx.features().enabled(sym::lint_reasons) {
         return;
     }
 
@@ -28,34 +27,17 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
             if !fulfilled_expectations.contains(&id)
                 && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
             {
-                emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation);
+                let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
+                let note = expectation.is_unfulfilled_lint_expectations.then_some(());
+                tcx.emit_spanned_lint(
+                    UNFULFILLED_LINT_EXPECTATIONS,
+                    *hir_id,
+                    expectation.emission_span,
+                    Expectation { rationale, note },
+                );
             }
         } else {
             unreachable!("at this stage all `LintExpectationId`s are stable");
         }
     }
 }
-
-fn emit_unfulfilled_expectation_lint(
-    tcx: TyCtxt<'_>,
-    hir_id: HirId,
-    expectation: &LintExpectation,
-) {
-    tcx.struct_span_lint_hir(
-        builtin::UNFULFILLED_LINT_EXPECTATIONS,
-        hir_id,
-        expectation.emission_span,
-        fluent::lint_expectation,
-        |lint| {
-            if let Some(rationale) = expectation.reason {
-                lint.note(rationale.as_str());
-            }
-
-            if expectation.is_unfulfilled_lint_expectations {
-                lint.note(fluent::note);
-            }
-
-            lint
-        },
-    );
-}
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 182734fa9fc..5219992ee94 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -1,7 +1,12 @@
-use crate::{LateContext, LateLintPass, LintContext};
+use crate::{
+    lints::{
+        ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark,
+        ForLoopsOverFalliblesSuggestion,
+    },
+    LateContext, LateLintPass, LintContext,
+};
 
 use hir::{Expr, Pat};
-use rustc_errors::{Applicability, DelayDm};
 use rustc_hir as hir;
 use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
 use rustc_middle::ty::{self, List};
@@ -53,53 +58,29 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
             _ => return,
         };
 
-        let msg = DelayDm(|| {
-            format!(
-                "for loop over {article} `{ty}`. This is more readably written as an `if let` statement",
-            )
-        });
-
-        cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| {
-            if let Some(recv) = extract_iterator_next_call(cx, arg)
+        let sub =  if let Some(recv) = extract_iterator_next_call(cx, arg)
             && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
             {
-                lint.span_suggestion(
-                    recv.span.between(arg.span.shrink_to_hi()),
-                    format!("to iterate over `{recv_snip}` remove the call to `next`"),
-                    ".by_ref()",
-                    Applicability::MaybeIncorrect
-                );
+                ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip }
             } else {
-                lint.multipart_suggestion_verbose(
-                    "to check pattern in a loop use `while let`",
-                    vec![
-                        // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
-                        (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
-                        (pat.span.between(arg.span), ") = ".to_string()),
-                    ],
-                    Applicability::MaybeIncorrect
-                );
-            }
-
-            if suggest_question_mark(cx, adt, substs, expr.span) {
-                lint.span_suggestion(
-                    arg.span.shrink_to_hi(),
-                    "consider unwrapping the `Result` with `?` to iterate over its contents",
-                    "?",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-
-            lint.multipart_suggestion_verbose(
-                "consider using `if let` to clear intent",
-                vec![
-                    // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
-                    (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
-                    (pat.span.between(arg.span), ") = ".to_string()),
-                ],
-                Applicability::MaybeIncorrect,
-            )
-        })
+                ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var }
+            } ;
+        let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) {
+            Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() })
+        } else {
+            None
+        };
+        let suggestion = ForLoopsOverFalliblesSuggestion {
+            var,
+            start_span: expr.span.with_hi(pat.span.lo()),
+            end_span: pat.span.between(arg.span),
+        };
+
+        cx.emit_spanned_lint(
+            FOR_LOOPS_OVER_FALLIBLES,
+            arg.span,
+            ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion },
+        );
     }
 }
 
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index dc2f5c0e296..7c1af6bee1d 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -1,7 +1,12 @@
-use crate::{EarlyContext, EarlyLintPass, LintContext};
+use crate::{
+    lints::{
+        HiddenUnicodeCodepointsDiag, HiddenUnicodeCodepointsDiagLabels,
+        HiddenUnicodeCodepointsDiagSub,
+    },
+    EarlyContext, EarlyLintPass, LintContext,
+};
 use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
 use rustc_ast as ast;
-use rustc_errors::{fluent, Applicability, SuggestionStyle};
 use rustc_span::{BytePos, Span, Symbol};
 
 declare_lint! {
@@ -60,55 +65,19 @@ impl HiddenUnicodeCodepoints {
             })
             .collect();
 
-        cx.struct_span_lint(
+        let count = spans.len();
+        let labels = point_at_inner_spans
+            .then_some(HiddenUnicodeCodepointsDiagLabels { spans: spans.clone() });
+        let sub = if point_at_inner_spans && !spans.is_empty() {
+            HiddenUnicodeCodepointsDiagSub::Escape { spans }
+        } else {
+            HiddenUnicodeCodepointsDiagSub::NoEscape { spans }
+        };
+
+        cx.emit_spanned_lint(
             TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
             span,
-            fluent::lint_hidden_unicode_codepoints,
-            |lint| {
-                lint.set_arg("label", label);
-                lint.set_arg("count", spans.len());
-                lint.span_label(span, fluent::label);
-                lint.note(fluent::note);
-                if point_at_inner_spans {
-                    for (c, span) in &spans {
-                        lint.span_label(*span, format!("{:?}", c));
-                    }
-                }
-                if point_at_inner_spans && !spans.is_empty() {
-                    lint.multipart_suggestion_with_style(
-                        fluent::suggestion_remove,
-                        spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
-                        Applicability::MachineApplicable,
-                        SuggestionStyle::HideCodeAlways,
-                    );
-                    lint.multipart_suggestion(
-                        fluent::suggestion_escape,
-                        spans
-                            .into_iter()
-                            .map(|(c, span)| {
-                                let c = format!("{:?}", c);
-                                (span, c[1..c.len() - 1].to_string())
-                            })
-                            .collect(),
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
-                    // should do the same here to provide the same good suggestions as we do for
-                    // literals above.
-                    lint.set_arg(
-                        "escaped",
-                        spans
-                            .into_iter()
-                            .map(|(c, _)| format!("{:?}", c))
-                            .collect::<Vec<String>>()
-                            .join(", "),
-                    );
-                    lint.note(fluent::suggestion_remove);
-                    lint.note(fluent::no_suggestion_note_escape);
-                }
-                lint
-            },
+            HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub },
         );
     }
 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 48902cd0569..5eb54cc0034 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -1,9 +1,12 @@
 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
 //! Clippy.
 
+use crate::lints::{
+    BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistantDocKeyword,
+    QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+};
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
-use rustc_errors::{fluent, Applicability};
 use rustc_hir::def::Res;
 use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
 use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
@@ -29,20 +32,15 @@ impl LateLintPass<'_> for DefaultHashTypes {
             // don't lint imports, only actual usages
             return;
         }
-        let replace = match cx.tcx.get_diagnostic_name(def_id) {
+        let preferred = match cx.tcx.get_diagnostic_name(def_id) {
             Some(sym::HashMap) => "FxHashMap",
             Some(sym::HashSet) => "FxHashSet",
             _ => return,
         };
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             DEFAULT_HASH_TYPES,
             path.span,
-            fluent::lint_default_hash_types,
-            |lint| {
-                lint.set_arg("preferred", replace)
-                    .set_arg("used", cx.tcx.item_name(def_id))
-                    .note(fluent::note)
-            },
+            DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) },
         );
     }
 }
@@ -83,12 +81,11 @@ impl LateLintPass<'_> for QueryStability {
         if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     POTENTIAL_QUERY_INSTABILITY,
                     span,
-                    fluent::lint_query_instability,
-                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note),
-                )
+                    QueryInstability { query: cx.tcx.item_name(def_id) },
+                );
             }
         }
     }
@@ -126,14 +123,8 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
             let span = path.span.with_hi(
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
-            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| {
-                lint
-                    .span_suggestion(
-                        span,
-                        fluent::suggestion,
-                        "ty",
-                        Applicability::MaybeIncorrect, // ty maybe needs an import
-                    )
+            cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
+                suggestion: span,
             });
         }
     }
@@ -190,39 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
 
                     match span {
                         Some(span) => {
-                            cx.struct_span_lint(
-                                USAGE_OF_TY_TYKIND,
-                                path.span,
-                                fluent::lint_tykind_kind,
-                                |lint| lint.span_suggestion(
-                                    span,
-                                    fluent::suggestion,
-                                    "ty",
-                                    Applicability::MaybeIncorrect, // ty maybe needs an import
-                                )
-                            )
+                            cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
+                                suggestion: span,
+                            });
                         },
-                        None => cx.struct_span_lint(
-                            USAGE_OF_TY_TYKIND,
-                            path.span,
-                            fluent::lint_tykind,
-                            |lint| lint.help(fluent::help)
-                        )
-                    }
-                } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
-                    if path.segments.len() > 1 {
-                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| {
-                            lint
-                                .set_arg("ty", t.clone())
-                                .span_suggestion(
-                                    path.span,
-                                    fluent::suggestion,
-                                    t,
-                                    // The import probably needs to be changed
-                                    Applicability::MaybeIncorrect,
-                                )
-                        })
+                        None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
                     }
+                } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+                    cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
+                        ty: t.clone(),
+                        suggestion: path.span,
+                    });
                 }
             }
             _ => {}
@@ -303,12 +272,11 @@ impl EarlyLintPass for LintPassImpl {
                         && call_site.ctxt().outer_expn_data().kind
                             != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
                     {
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
-                            fluent::lint_lintpass_by_hand,
-                            |lint| lint.help(fluent::help),
-                        )
+                            LintPassByHand,
+                        );
                     }
                 }
             }
@@ -338,17 +306,16 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
             if let Some(list) = attr.meta_item_list() {
                 for nested in list {
                     if nested.has_name(sym::keyword) {
-                        let v = nested
+                        let keyword = nested
                             .value_str()
                             .expect("#[doc(keyword = \"...\")] expected a value!");
-                        if is_doc_keyword(v) {
+                        if is_doc_keyword(keyword) {
                             return;
                         }
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             EXISTING_DOC_KEYWORD,
                             attr.span,
-                            fluent::lint_non_existant_doc_keyword,
-                            |lint| lint.set_arg("keyword", v).help(fluent::help),
+                            NonExistantDocKeyword { keyword },
                         );
                     }
                 }
@@ -407,12 +374,7 @@ impl LateLintPass<'_> for Diagnostics {
         }
         debug!(?found_impl);
         if !found_parent_with_attr && !found_impl {
-            cx.struct_span_lint(
-                DIAGNOSTIC_OUTSIDE_OF_IMPL,
-                span,
-                fluent::lint_diag_out_of_impl,
-                |lint| lint,
-            )
+            cx.emit_spanned_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
         }
 
         let mut found_diagnostic_message = false;
@@ -428,12 +390,7 @@ impl LateLintPass<'_> for Diagnostics {
         }
         debug!(?found_diagnostic_message);
         if !found_parent_with_attr && !found_diagnostic_message {
-            cx.struct_span_lint(
-                UNTRANSLATABLE_DIAGNOSTIC,
-                span,
-                fluent::lint_untranslatable_diag,
-                |lint| lint,
-            )
+            cx.emit_spanned_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
         }
     }
 }
@@ -465,9 +422,9 @@ impl LateLintPass<'_> for BadOptAccess {
                 let Some(lit) = item.lit()  &&
                 let ast::LitKind::Str(val, _) = lit.kind
             {
-                cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint|
-                    lint
-                );
+                cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag {
+                    msg: val.as_str(),
+                });
             }
         }
     }
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index 04d844d21dc..b83a9665fc0 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -1,5 +1,8 @@
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
+use crate::{
+    lints::{NonBindingLet, NonBindingLetSub},
+    LateContext, LateLintPass, LintContext,
+};
+use rustc_errors::MultiSpan;
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_span::Symbol;
@@ -119,6 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 _ => false,
             };
 
+            let sub = NonBindingLetSub {
+                suggestion: local.pat.span,
+                multi_suggestion_start: local.span.until(init.span),
+                multi_suggestion_end: init.span.shrink_to_hi(),
+            };
             if is_sync_lock {
                 let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]);
                 span.push_span_label(
@@ -129,41 +137,14 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     init.span,
                     "this binding will immediately drop the value assigned to it".to_string(),
                 );
-                cx.struct_span_lint(
-                    LET_UNDERSCORE_LOCK,
-                    span,
-                    "non-binding let on a synchronization lock",
-                    |lint| build_lint(lint, local, init.span),
-                )
+                cx.emit_spanned_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub });
             } else {
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     LET_UNDERSCORE_DROP,
                     local.span,
-                    "non-binding let on a type that implements `Drop`",
-                    |lint| build_lint(lint, local, init.span),
-                )
+                    NonBindingLet::DropType { sub },
+                );
             }
         }
     }
 }
-
-fn build_lint<'a, 'b>(
-    lint: &'a mut DiagnosticBuilder<'b, ()>,
-    local: &hir::Local<'_>,
-    init_span: rustc_span::Span,
-) -> &'a mut DiagnosticBuilder<'b, ()> {
-    lint.span_suggestion_verbose(
-        local.pat.span,
-        "consider binding to an unused variable to avoid immediately dropping the value",
-        "_unused",
-        Applicability::MachineApplicable,
-    )
-    .multipart_suggestion(
-        "consider immediately dropping the value",
-        vec![
-            (local.span.until(init_span), "drop(".to_string()),
-            (init_span.shrink_to_hi(), ")".to_string()),
-        ],
-        Applicability::MachineApplicable,
-    )
-}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index e9d3d44a3f9..09dfb1022d8 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,9 +1,13 @@
 use crate::context::{CheckLintNameResult, LintStore};
 use crate::late::unerased_lint_store;
+use crate::lints::{
+    DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint,
+    RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion,
+};
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
+use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
@@ -15,6 +19,7 @@ use rustc_middle::lint::{
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
+use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
 use rustc_session::lint::{
     builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS},
     Level, Lint, LintExpectationId, LintId,
@@ -583,57 +588,32 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     old_src,
                     id_name
                 );
-
-                let decorate_diag = |diag: &mut Diagnostic| {
-                    diag.span_label(src.span(), "overruled by previous forbid");
-                    match old_src {
-                        LintLevelSource::Default => {
-                            diag.note(&format!(
-                                "`forbid` lint level is the default for {}",
-                                id.to_string()
-                            ));
-                        }
-                        LintLevelSource::Node { span, reason, .. } => {
-                            diag.span_label(span, "`forbid` level set here");
-                            if let Some(rationale) = reason {
-                                diag.note(rationale.as_str());
-                            }
-                        }
-                        LintLevelSource::CommandLine(_, _) => {
-                            diag.note("`forbid` lint level was set on command line");
-                        }
+                let sub = match old_src {
+                    LintLevelSource::Default => {
+                        OverruledAttributeSub::DefaultSource { id: id.to_string() }
                     }
+                    LintLevelSource::Node { span, reason, .. } => {
+                        OverruledAttributeSub::NodeSource { span, reason }
+                    }
+                    LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource,
                 };
                 if !fcw_warning {
                     self.sess.emit_err(OverruledAttribute {
                         span: src.span(),
                         overruled: src.span(),
-                        lint_level: level.as_str().to_string(),
+                        lint_level: level.as_str(),
                         lint_source: src.name(),
-                        sub: match old_src {
-                            LintLevelSource::Default => {
-                                OverruledAttributeSub::DefaultSource { id: id.to_string() }
-                            }
-                            LintLevelSource::Node { span, reason, .. } => {
-                                OverruledAttributeSub::NodeSource { span, reason }
-                            }
-                            LintLevelSource::CommandLine(_, _) => {
-                                OverruledAttributeSub::CommandLineSource
-                            }
-                        },
+                        sub,
                     });
                 } else {
-                    self.struct_lint(
+                    self.emit_spanned_lint(
                         FORBIDDEN_LINT_GROUPS,
-                        Some(src.span().into()),
-                        format!(
-                            "{}({}) incompatible with previous forbid",
-                            level.as_str(),
-                            src.name(),
-                        ),
-                        |lint| {
-                            decorate_diag(lint);
-                            lint
+                        src.span().into(),
+                        OverruledAtributeLint {
+                            overruled: src.span(),
+                            lint_level: level.as_str(),
+                            lint_source: src.name(),
+                            sub,
                         },
                     );
                 }
@@ -858,25 +838,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                             }
                             Err((Some(ids), ref new_lint_name)) => {
                                 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                                let (lvl, src) = self.provider.get_lint_level(lint, &sess);
-                                struct_lint_level(
-                                    self.sess,
+                                self.emit_spanned_lint(
                                     lint,
-                                    lvl,
-                                    src,
-                                    Some(sp.into()),
-                                    format!(
-                                        "lint name `{}` is deprecated \
-                                         and may not have an effect in the future.",
-                                        name
-                                    ),
-                                    |lint| {
-                                        lint.span_suggestion(
-                                            sp,
-                                            "change it to",
-                                            new_lint_name,
-                                            Applicability::MachineApplicable,
-                                        )
+                                    sp.into(),
+                                    DeprecatedLintName {
+                                        name,
+                                        suggestion: sp,
+                                        replace: &new_lint_name,
                                     },
                                 );
 
@@ -917,54 +885,29 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     _ if !self.warn_about_weird_lints => {}
 
                     CheckLintNameResult::Warning(msg, renamed) => {
-                        let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                        let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess);
-                        struct_lint_level(
-                            self.sess,
-                            lint,
-                            renamed_lint_level,
-                            src,
-                            Some(sp.into()),
-                            msg,
-                            |lint| {
-                                if let Some(new_name) = &renamed {
-                                    lint.span_suggestion(
-                                        sp,
-                                        "use the new name",
-                                        new_name,
-                                        Applicability::MachineApplicable,
-                                    );
-                                }
-                                lint
-                            },
+                        let suggestion =
+                            renamed.as_ref().map(|replace| RenamedOrRemovedLintSuggestion {
+                                suggestion: sp,
+                                replace: replace.as_str(),
+                            });
+                        self.emit_spanned_lint(
+                            RENAMED_AND_REMOVED_LINTS,
+                            sp.into(),
+                            RenamedOrRemovedLint { msg, suggestion },
                         );
                     }
                     CheckLintNameResult::NoLint(suggestion) => {
-                        let lint = builtin::UNKNOWN_LINTS;
-                        let (level, src) = self.provider.get_lint_level(lint, self.sess);
                         let name = if let Some(tool_ident) = tool_ident {
                             format!("{}::{}", tool_ident.name, name)
                         } else {
                             name.to_string()
                         };
-                        struct_lint_level(
-                            self.sess,
-                            lint,
-                            level,
-                            src,
-                            Some(sp.into()),
-                            format!("unknown lint: `{}`", name),
-                            |lint| {
-                                if let Some(suggestion) = suggestion {
-                                    lint.span_suggestion(
-                                        sp,
-                                        "did you mean",
-                                        suggestion,
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                                lint
-                            },
+                        let suggestion = suggestion
+                            .map(|replace| UnknownLintSuggestion { suggestion: sp, replace });
+                        self.emit_spanned_lint(
+                            UNKNOWN_LINTS,
+                            sp.into(),
+                            UnknownLint { name, suggestion },
                         );
                     }
                 }
@@ -1010,20 +953,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     continue
                 };
 
-                let lint = builtin::UNUSED_ATTRIBUTES;
-                let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess);
-                struct_lint_level(
-                    self.sess,
-                    lint,
-                    lint_level,
-                    lint_src,
-                    Some(lint_attr_span.into()),
-                    format!(
-                        "{}({}) is ignored unless specified at crate level",
-                        level.as_str(),
-                        lint_attr_name
-                    ),
-                    |lint| lint,
+                self.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    lint_attr_span.into(),
+                    IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name },
                 );
                 // don't set a separate error for every lint in the group
                 break;
@@ -1047,11 +980,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     level,
                     src,
                     Some(span.into()),
-                    format!("unknown lint: `{}`", lint_id.lint.name_lower()),
+                    fluent::lint_unknown_gated_lint,
                     |lint| {
-                        lint.note(
-                            &format!("the `{}` lint is unstable", lint_id.lint.name_lower(),),
-                        );
+                        lint.set_arg("name", lint_id.lint.name_lower());
+                        lint.note(fluent::note);
                         add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
                         lint
                     },
@@ -1086,6 +1018,25 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
         let (level, src) = self.lint_level(lint);
         struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
     }
+
+    pub fn emit_spanned_lint(
+        &self,
+        lint: &'static Lint,
+        span: MultiSpan,
+        decorate: impl for<'a> DecorateLint<'a, ()>,
+    ) {
+        let (level, src) = self.lint_level(lint);
+        struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| {
+            decorate.decorate_lint(lint)
+        });
+    }
+
+    pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) {
+        let (level, src) = self.lint_level(lint);
+        struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| {
+            decorate.decorate_lint(lint)
+        });
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 1275d6f223c..3d818154cb9 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -38,6 +38,8 @@
 #![feature(never_type)]
 #![feature(rustc_attrs)]
 #![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate rustc_middle;
@@ -60,6 +62,7 @@ mod internal;
 mod late;
 mod let_underscore;
 mod levels;
+mod lints;
 mod methods;
 mod non_ascii_idents;
 mod non_fmt_panic;
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
new file mode 100644
index 00000000000..c3782a49689
--- /dev/null
+++ b/compiler/rustc_lint/src/lints.rs
@@ -0,0 +1,1479 @@
+#![allow(rustc::untranslatable_diagnostic)]
+#![allow(rustc::diagnostic_outside_of_impl)]
+use std::num::NonZeroU32;
+
+use rustc_errors::{
+    fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage,
+    DiagnosticStyledString, SuggestionStyle,
+};
+use rustc_hir::def_id::DefId;
+use rustc_macros::{LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::{Predicate, Ty, TyCtxt};
+use rustc_session::parse::ParseSess;
+use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
+
+use crate::{
+    builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext,
+};
+
+// array_into_iter.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_array_into_iter)]
+pub struct ArrayIntoIterDiag<'a> {
+    pub target: &'a str,
+    #[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    #[subdiagnostic]
+    pub sub: Option<ArrayIntoIterDiagSub>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum ArrayIntoIterDiagSub {
+    #[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
+    RemoveIntoIter {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")]
+    UseExplicitIntoIter {
+        #[suggestion_part(code = "IntoIterator::into_iter(")]
+        start_span: Span,
+        #[suggestion_part(code = ")")]
+        end_span: Span,
+    },
+}
+
+// builtin.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_while_true)]
+pub struct BuiltinWhileTrue {
+    #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    pub replace: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_box_pointers)]
+pub struct BuiltinBoxPointers<'a> {
+    pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_non_shorthand_field_patterns)]
+pub struct BuiltinNonShorthandFieldPatterns {
+    pub ident: Ident,
+    #[suggestion(code = "{prefix}{ident}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    pub prefix: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+pub enum BuiltinUnsafe {
+    #[diag(lint_builtin_allow_internal_unsafe)]
+    AllowInternalUnsafe,
+    #[diag(lint_builtin_unsafe_block)]
+    UnsafeBlock,
+    #[diag(lint_builtin_unsafe_trait)]
+    UnsafeTrait,
+    #[diag(lint_builtin_unsafe_impl)]
+    UnsafeImpl,
+    #[diag(lint_builtin_no_mangle_fn)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    NoMangleFn,
+    #[diag(lint_builtin_export_name_fn)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    ExportNameFn,
+    #[diag(lint_builtin_link_section_fn)]
+    #[note(lint_builtin_overridden_symbol_section)]
+    LinkSectionFn,
+    #[diag(lint_builtin_no_mangle_static)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    NoMangleStatic,
+    #[diag(lint_builtin_export_name_static)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    ExportNameStatic,
+    #[diag(lint_builtin_link_section_static)]
+    #[note(lint_builtin_overridden_symbol_section)]
+    LinkSectionStatic,
+    #[diag(lint_builtin_no_mangle_method)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    NoMangleMethod,
+    #[diag(lint_builtin_export_name_method)]
+    #[note(lint_builtin_overridden_symbol_name)]
+    ExportNameMethod,
+    #[diag(lint_builtin_decl_unsafe_fn)]
+    DeclUnsafeFn,
+    #[diag(lint_builtin_decl_unsafe_method)]
+    DeclUnsafeMethod,
+    #[diag(lint_builtin_impl_unsafe_method)]
+    ImplUnsafeMethod,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_missing_doc)]
+pub struct BuiltinMissingDoc<'a> {
+    pub article: &'a str,
+    pub desc: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_missing_copy_impl)]
+pub struct BuiltinMissingCopyImpl;
+
+pub struct BuiltinMissingDebugImpl<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub def_id: DefId,
+}
+
+// Needed for def_path_str
+impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("debug", self.tcx.def_path_str(self.def_id));
+        diag
+    }
+
+    fn msg(&self) -> DiagnosticMessage {
+        fluent::lint_builtin_missing_debug_impl
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_anonymous_params)]
+pub struct BuiltinAnonymousParams<'a> {
+    #[suggestion(code = "_: {ty_snip}")]
+    pub suggestion: (Span, Applicability),
+    pub ty_snip: &'a str,
+}
+
+// FIXME(davidtwco) translatable deprecated attr
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_deprecated_attr_link)]
+pub struct BuiltinDeprecatedAttrLink<'a> {
+    pub name: Symbol,
+    pub reason: &'a str,
+    pub link: &'a str,
+    #[subdiagnostic]
+    pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
+    #[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")]
+    Msg {
+        #[primary_span]
+        suggestion: Span,
+        msg: &'a str,
+    },
+    #[suggestion(default_suggestion, code = "", applicability = "machine-applicable")]
+    Default {
+        #[primary_span]
+        suggestion: Span,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_deprecated_attr_used)]
+pub struct BuiltinDeprecatedAttrUsed {
+    pub name: String,
+    #[suggestion(
+        lint_builtin_deprecated_attr_default_suggestion,
+        style = "short",
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unused_doc_comment)]
+pub struct BuiltinUnusedDocComment<'a> {
+    pub kind: &'a str,
+    #[label]
+    pub label: Span,
+    #[subdiagnostic]
+    pub sub: BuiltinUnusedDocCommentSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum BuiltinUnusedDocCommentSub {
+    #[help(plain_help)]
+    PlainHelp,
+    #[help(block_help)]
+    BlockHelp,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_no_mangle_generic)]
+pub struct BuiltinNoMangleGeneric {
+    // Use of `#[no_mangle]` suggests FFI intent; correct
+    // fix may be to monomorphize source by hand
+    #[suggestion(style = "short", code = "", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_const_no_mangle)]
+pub struct BuiltinConstNoMangle {
+    #[suggestion(code = "pub static", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_mutable_transmutes)]
+pub struct BuiltinMutablesTransmutes;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unstable_features)]
+pub struct BuiltinUnstableFeatures;
+
+// lint_ungated_async_fn_track_caller
+pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
+    pub label: Span,
+    pub parse_sess: &'a ParseSess,
+}
+
+impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.span_label(self.label, fluent::label);
+        rustc_session::parse::add_feature_diagnostics(
+            diag,
+            &self.parse_sess,
+            sym::closure_track_caller,
+        );
+        diag
+    }
+
+    fn msg(&self) -> DiagnosticMessage {
+        fluent::lint_ungated_async_fn_track_caller
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unreachable_pub)]
+pub struct BuiltinUnreachablePub<'a> {
+    pub what: &'a str,
+    #[suggestion(code = "pub(crate)")]
+    pub suggestion: (Span, Applicability),
+    #[help]
+    pub help: Option<()>,
+}
+
+pub struct SuggestChangingAssocTypes<'a, 'b> {
+    pub ty: &'a rustc_hir::Ty<'b>,
+}
+
+impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
+        // bound.  Let's see if this type does that.
+
+        // We use a HIR visitor to walk the type.
+        use rustc_hir::intravisit::{self, Visitor};
+        struct WalkAssocTypes<'a> {
+            err: &'a mut rustc_errors::Diagnostic,
+        }
+        impl Visitor<'_> for WalkAssocTypes<'_> {
+            fn visit_qpath(
+                &mut self,
+                qpath: &rustc_hir::QPath<'_>,
+                id: rustc_hir::HirId,
+                span: Span,
+            ) {
+                if TypeAliasBounds::is_type_variable_assoc(qpath) {
+                    self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
+                }
+                intravisit::walk_qpath(self, qpath, id)
+            }
+        }
+
+        // Let's go for a walk!
+        let mut visitor = WalkAssocTypes { err: diag };
+        visitor.visit_ty(self.ty);
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_type_alias_where_clause)]
+pub struct BuiltinTypeAliasWhereClause<'a, 'b> {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    #[subdiagnostic]
+    pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_type_alias_generic_bounds)]
+pub struct BuiltinTypeAliasGenericBounds<'a, 'b> {
+    #[subdiagnostic]
+    pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion,
+    #[subdiagnostic]
+    pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
+}
+
+pub struct BuiltinTypeAliasGenericBoundsSuggestion {
+    pub suggestions: Vec<(Span, String)>,
+}
+
+impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        diag.multipart_suggestion(
+            fluent::suggestion,
+            self.suggestions,
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_trivial_bounds)]
+pub struct BuiltinTrivialBounds<'a> {
+    pub predicate_kind_name: &'a str,
+    pub predicate: Predicate<'a>,
+}
+
+#[derive(LintDiagnostic)]
+pub enum BuiltinEllipsisInclusiveRangePatternsLint {
+    #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
+    Parenthesise {
+        #[suggestion(code = "{replace}", applicability = "machine-applicable")]
+        suggestion: Span,
+        replace: String,
+    },
+    #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
+    NonParenthesise {
+        #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
+        suggestion: Span,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unnameable_test_items)]
+pub struct BuiltinUnnameableTestItems;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_keyword_idents)]
+pub struct BuiltinKeywordIdents {
+    pub kw: Ident,
+    pub next: Edition,
+    #[suggestion(code = "r#{kw}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_explicit_outlives)]
+pub struct BuiltinExplicitOutlives {
+    pub count: usize,
+    #[subdiagnostic]
+    pub suggestion: BuiltinExplicitOutlivesSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion)]
+pub struct BuiltinExplicitOutlivesSuggestion {
+    #[suggestion_part(code = "")]
+    pub spans: Vec<Span>,
+    #[applicability]
+    pub applicability: Applicability,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_incomplete_features)]
+pub struct BuiltinIncompleteFeatures {
+    pub name: Symbol,
+    #[subdiagnostic]
+    pub note: Option<BuiltinIncompleteFeaturesNote>,
+    #[subdiagnostic]
+    pub help: Option<BuiltinIncompleteFeaturesHelp>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(help)]
+pub struct BuiltinIncompleteFeaturesHelp;
+
+#[derive(Subdiagnostic)]
+#[note(note)]
+pub struct BuiltinIncompleteFeaturesNote {
+    pub n: NonZeroU32,
+}
+
+pub struct BuiltinUnpermittedTypeInit<'a> {
+    pub msg: DiagnosticMessage,
+    pub ty: Ty<'a>,
+    pub label: Span,
+    pub sub: BuiltinUnpermittedTypeInitSub,
+}
+
+impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("ty", self.ty);
+        diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
+        diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion);
+        self.sub.add_to_diagnostic(diag);
+        diag
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        self.msg.clone()
+    }
+}
+
+// FIXME(davidtwco): make translatable
+pub struct BuiltinUnpermittedTypeInitSub {
+    pub err: InitError,
+}
+
+impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        let mut err = self.err;
+        loop {
+            if let Some(span) = err.span {
+                diag.span_note(span, err.message);
+            } else {
+                diag.note(err.message);
+            }
+            if let Some(e) = err.nested {
+                err = *e;
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+#[derive(LintDiagnostic)]
+pub enum BuiltinClashingExtern<'a> {
+    #[diag(lint_builtin_clashing_extern_same_name)]
+    SameName {
+        this: Symbol,
+        orig: Symbol,
+        #[label(previous_decl_label)]
+        previous_decl_label: Span,
+        #[label(mismatch_label)]
+        mismatch_label: Span,
+        #[subdiagnostic]
+        sub: BuiltinClashingExternSub<'a>,
+    },
+    #[diag(lint_builtin_clashing_extern_diff_name)]
+    DiffName {
+        this: Symbol,
+        orig: Symbol,
+        #[label(previous_decl_label)]
+        previous_decl_label: Span,
+        #[label(mismatch_label)]
+        mismatch_label: Span,
+        #[subdiagnostic]
+        sub: BuiltinClashingExternSub<'a>,
+    },
+}
+
+// FIXME(davidtwco): translatable expected/found
+pub struct BuiltinClashingExternSub<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub expected: Ty<'a>,
+    pub found: Ty<'a>,
+}
+
+impl AddToDiagnostic for BuiltinClashingExternSub<'_> {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        let mut expected_str = DiagnosticStyledString::new();
+        expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
+        let mut found_str = DiagnosticStyledString::new();
+        found_str.push(self.found.fn_sig(self.tcx).to_string(), true);
+        diag.note_expected_found(&"", expected_str, &"", found_str);
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_deref_nullptr)]
+pub struct BuiltinDerefNullptr {
+    #[label]
+    pub label: Span,
+}
+
+// FIXME: migrate fluent::lint::builtin_asm_labels
+
+#[derive(LintDiagnostic)]
+pub enum BuiltinSpecialModuleNameUsed {
+    #[diag(lint_builtin_special_module_name_used_lib)]
+    #[note]
+    #[help]
+    Lib,
+    #[diag(lint_builtin_special_module_name_used_main)]
+    #[note]
+    Main,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unexpected_cli_config_name)]
+#[help]
+pub struct BuiltinUnexpectedCliConfigName {
+    pub name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_unexpected_cli_config_value)]
+#[help]
+pub struct BuiltinUnexpectedCliConfigValue {
+    pub name: Symbol,
+    pub value: Symbol,
+}
+
+// deref_into_dyn_supertrait.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_supertrait_as_deref_target)]
+pub struct SupertraitAsDerefTarget<'a> {
+    pub t: Ty<'a>,
+    pub target_principal: String,
+    // pub target_principal: Binder<'a, ExistentialTraitRef<'b>>,
+    #[subdiagnostic]
+    pub label: Option<SupertraitAsDerefTargetLabel>,
+}
+
+#[derive(Subdiagnostic)]
+#[label(label)]
+pub struct SupertraitAsDerefTargetLabel {
+    #[primary_span]
+    pub label: Span,
+}
+
+// enum_intrinsics_non_enums.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_enum_intrinsics_mem_discriminant)]
+pub struct EnumIntrinsicsMemDiscriminate<'a> {
+    pub ty_param: Ty<'a>,
+    #[note]
+    pub note: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_enum_intrinsics_mem_variant)]
+#[note]
+pub struct EnumIntrinsicsMemVariant<'a> {
+    pub ty_param: Ty<'a>,
+}
+
+// expect.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_expectation)]
+pub struct Expectation {
+    #[subdiagnostic]
+    pub rationale: Option<ExpectationNote>,
+    #[note]
+    pub note: Option<()>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(rationale)]
+pub struct ExpectationNote {
+    pub rationale: Symbol,
+}
+
+// for_loops_over_fallibles.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_for_loops_over_fallibles)]
+pub struct ForLoopsOverFalliblesDiag<'a> {
+    pub article: &'static str,
+    pub ty: &'static str,
+    #[subdiagnostic]
+    pub sub: ForLoopsOverFalliblesLoopSub<'a>,
+    #[subdiagnostic]
+    pub question_mark: Option<ForLoopsOverFalliblesQuestionMark>,
+    #[subdiagnostic]
+    pub suggestion: ForLoopsOverFalliblesSuggestion<'a>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum ForLoopsOverFalliblesLoopSub<'a> {
+    #[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
+    RemoveNext {
+        #[primary_span]
+        suggestion: Span,
+        recv_snip: String,
+    },
+    #[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")]
+    UseWhileLet {
+        #[suggestion_part(code = "while let {var}(")]
+        start_span: Span,
+        #[suggestion_part(code = ") = ")]
+        end_span: Span,
+        var: &'a str,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")]
+pub struct ForLoopsOverFalliblesQuestionMark {
+    #[primary_span]
+    pub suggestion: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
+pub struct ForLoopsOverFalliblesSuggestion<'a> {
+    pub var: &'a str,
+    #[suggestion_part(code = "if let {var}(")]
+    pub start_span: Span,
+    #[suggestion_part(code = ") = ")]
+    pub end_span: Span,
+}
+
+// hidden_unicode_codepoints.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_hidden_unicode_codepoints)]
+#[note]
+pub struct HiddenUnicodeCodepointsDiag<'a> {
+    pub label: &'a str,
+    pub count: usize,
+    #[label]
+    pub span_label: Span,
+    #[subdiagnostic]
+    pub labels: Option<HiddenUnicodeCodepointsDiagLabels>,
+    #[subdiagnostic]
+    pub sub: HiddenUnicodeCodepointsDiagSub,
+}
+
+pub struct HiddenUnicodeCodepointsDiagLabels {
+    pub spans: Vec<(char, Span)>,
+}
+
+impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        for (c, span) in self.spans {
+            diag.span_label(span, format!("{:?}", c));
+        }
+    }
+}
+
+pub enum HiddenUnicodeCodepointsDiagSub {
+    Escape { spans: Vec<(char, Span)> },
+    NoEscape { spans: Vec<(char, Span)> },
+}
+
+// Used because of multiple multipart_suggestion and note
+impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        match self {
+            HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
+                diag.multipart_suggestion_with_style(
+                    fluent::suggestion_remove,
+                    spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+                    Applicability::MachineApplicable,
+                    SuggestionStyle::HideCodeAlways,
+                );
+                diag.multipart_suggestion(
+                    fluent::suggestion_escape,
+                    spans
+                        .into_iter()
+                        .map(|(c, span)| {
+                            let c = format!("{:?}", c);
+                            (span, c[1..c.len() - 1].to_string())
+                        })
+                        .collect(),
+                    Applicability::MachineApplicable,
+                );
+            }
+            HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => {
+                // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+                // should do the same here to provide the same good suggestions as we do for
+                // literals above.
+                diag.set_arg(
+                    "escaped",
+                    spans
+                        .into_iter()
+                        .map(|(c, _)| format!("{:?}", c))
+                        .collect::<Vec<String>>()
+                        .join(", "),
+                );
+                diag.note(fluent::suggestion_remove);
+                diag.note(fluent::no_suggestion_note_escape);
+            }
+        }
+    }
+}
+
+// internal.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_default_hash_types)]
+#[note]
+pub struct DefaultHashTypesDiag<'a> {
+    pub preferred: &'a str,
+    pub used: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_query_instability)]
+#[note]
+pub struct QueryInstability {
+    pub query: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_tykind_kind)]
+pub struct TykindKind {
+    #[suggestion(code = "ty", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_tykind)]
+#[help]
+pub struct TykindDiag;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ty_qualified)]
+pub struct TyQualified {
+    pub ty: String,
+    #[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_lintpass_by_hand)]
+#[help]
+pub struct LintPassByHand;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_non_existant_doc_keyword)]
+#[help]
+pub struct NonExistantDocKeyword {
+    pub keyword: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_diag_out_of_impl)]
+pub struct DiagOutOfImpl;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_untranslatable_diag)]
+pub struct UntranslatableDiag;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_bad_opt_access)]
+pub struct BadOptAccessDiag<'a> {
+    pub msg: &'a str,
+}
+
+// let_underscore.rs
+#[derive(LintDiagnostic)]
+pub enum NonBindingLet {
+    #[diag(lint_non_binding_let_on_sync_lock)]
+    SyncLock {
+        #[subdiagnostic]
+        sub: NonBindingLetSub,
+    },
+    #[diag(lint_non_binding_let_on_drop_type)]
+    DropType {
+        #[subdiagnostic]
+        sub: NonBindingLetSub,
+    },
+}
+
+pub struct NonBindingLetSub {
+    pub suggestion: Span,
+    pub multi_suggestion_start: Span,
+    pub multi_suggestion_end: Span,
+}
+
+impl AddToDiagnostic for NonBindingLetSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        diag.span_suggestion_verbose(
+            self.suggestion,
+            fluent::lint_non_binding_let_suggestion,
+            "_unused",
+            Applicability::MachineApplicable,
+        );
+        diag.multipart_suggestion(
+            fluent::lint_non_binding_let_multi_suggestion,
+            vec![
+                (self.multi_suggestion_start, "drop(".to_string()),
+                (self.multi_suggestion_end, ")".to_string()),
+            ],
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+// levels.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_overruled_attribute)]
+pub struct OverruledAtributeLint<'a> {
+    #[label]
+    pub overruled: Span,
+    pub lint_level: &'a str,
+    pub lint_source: Symbol,
+    #[subdiagnostic]
+    pub sub: OverruledAttributeSub,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_deprecated_lint_name)]
+pub struct DeprecatedLintName<'a> {
+    pub name: String,
+    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    pub replace: &'a str,
+}
+
+// FIXME: Non-translatable msg
+#[derive(LintDiagnostic)]
+#[diag(lint_renamed_or_removed_lint)]
+pub struct RenamedOrRemovedLint<'a> {
+    pub msg: &'a str,
+    #[subdiagnostic]
+    pub suggestion: Option<RenamedOrRemovedLintSuggestion<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")]
+pub struct RenamedOrRemovedLintSuggestion<'a> {
+    #[primary_span]
+    pub suggestion: Span,
+    pub replace: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_lint)]
+pub struct UnknownLint {
+    pub name: String,
+    #[subdiagnostic]
+    pub suggestion: Option<UnknownLintSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+pub struct UnknownLintSuggestion {
+    #[primary_span]
+    pub suggestion: Span,
+    pub replace: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ignored_unless_crate_specified)]
+pub struct IgnoredUnlessCrateSpecified<'a> {
+    pub level: &'a str,
+    pub name: Symbol,
+}
+
+// methods.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_cstring_ptr)]
+#[note]
+#[help]
+pub struct CStringPtr {
+    #[label(as_ptr_label)]
+    pub as_ptr: Span,
+    #[label(unwrap_label)]
+    pub unwrap: Span,
+}
+
+// non_ascii_idents.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_identifier_non_ascii_char)]
+pub struct IdentifierNonAsciiChar;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_identifier_uncommon_codepoints)]
+pub struct IdentifierUncommonCodepoints;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_confusable_identifier_pair)]
+pub struct ConfusableIdentifierPair {
+    pub existing_sym: Symbol,
+    pub sym: Symbol,
+    #[label]
+    pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_mixed_script_confusables)]
+#[note(includes_note)]
+#[note]
+pub struct MixedScriptConfusables {
+    pub set: String,
+    pub includes: String,
+}
+
+// non_fmt_panic.rs
+pub struct NonFmtPanicUnused {
+    pub count: usize,
+    pub suggestion: Option<Span>,
+}
+
+// Used because of two suggestions based on one Option<Span>
+impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("count", self.count);
+        diag.note(fluent::note);
+        if let Some(span) = self.suggestion {
+            diag.span_suggestion(
+                span.shrink_to_hi(),
+                fluent::add_args_suggestion,
+                ", ...",
+                Applicability::HasPlaceholders,
+            );
+            diag.span_suggestion(
+                span.shrink_to_lo(),
+                fluent::add_fmt_suggestion,
+                "\"{}\", ",
+                Applicability::MachineApplicable,
+            );
+        }
+        diag
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        fluent::lint_non_fmt_panic_unused
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_non_fmt_panic_braces)]
+#[note]
+pub struct NonFmtPanicBraces {
+    pub count: usize,
+    #[suggestion(code = "\"{{}}\", ", applicability = "machine-applicable")]
+    pub suggestion: Option<Span>,
+}
+
+// nonstandard_style.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_non_camel_case_type)]
+pub struct NonCamelCaseType<'a> {
+    pub sort: &'a str,
+    pub name: &'a str,
+    #[subdiagnostic]
+    pub sub: NonCamelCaseTypeSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum NonCamelCaseTypeSub {
+    #[label(label)]
+    Label {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    Suggestion {
+        #[primary_span]
+        span: Span,
+        replace: String,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_non_snake_case)]
+pub struct NonSnakeCaseDiag<'a> {
+    pub sort: &'a str,
+    pub name: &'a str,
+    pub sc: String,
+    #[subdiagnostic]
+    pub sub: NonSnakeCaseDiagSub,
+}
+
+pub enum NonSnakeCaseDiagSub {
+    Label { span: Span },
+    Help,
+    RenameOrConvertSuggestion { span: Span, suggestion: Ident },
+    ConvertSuggestion { span: Span, suggestion: String },
+    SuggestionAndNote { span: Span },
+}
+
+impl AddToDiagnostic for NonSnakeCaseDiagSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        match self {
+            NonSnakeCaseDiagSub::Label { span } => {
+                diag.span_label(span, fluent::label);
+            }
+            NonSnakeCaseDiagSub::Help => {
+                diag.help(fluent::help);
+            }
+            NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => {
+                diag.span_suggestion(
+                    span,
+                    fluent::convert_suggestion,
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => {
+                diag.span_suggestion(
+                    span,
+                    fluent::rename_or_convert_suggestion,
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            NonSnakeCaseDiagSub::SuggestionAndNote { span } => {
+                diag.note(fluent::cannot_convert_note);
+                diag.span_suggestion(
+                    span,
+                    fluent::rename_suggestion,
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_non_upper_case_global)]
+pub struct NonUpperCaseGlobal<'a> {
+    pub sort: &'a str,
+    pub name: &'a str,
+    #[subdiagnostic]
+    pub sub: NonUpperCaseGlobalSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum NonUpperCaseGlobalSub {
+    #[label(label)]
+    Label {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    Suggestion {
+        #[primary_span]
+        span: Span,
+        replace: String,
+    },
+}
+
+// noop_method_call.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_noop_method_call)]
+#[note]
+pub struct NoopMethodCallDiag<'a> {
+    pub method: Symbol,
+    pub receiver_ty: Ty<'a>,
+    #[label]
+    pub label: Span,
+}
+
+// pass_by_value.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_pass_by_value)]
+pub struct PassByValueDiag {
+    pub ty: String,
+    #[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+}
+
+// redundant_semicolon.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_redundant_semicolons)]
+pub struct RedundantSemicolonsDiag {
+    pub multiple: bool,
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+}
+
+// traits.rs
+pub struct DropTraitConstraintsDiag<'a> {
+    pub predicate: Predicate<'a>,
+    pub tcx: TyCtxt<'a>,
+    pub def_id: DefId,
+}
+
+// Needed for def_path_str
+impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("predicate", self.predicate);
+        diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        fluent::lint_drop_trait_constraints
+    }
+}
+
+pub struct DropGlue<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub def_id: DefId,
+}
+
+// Needed for def_path_str
+impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        fluent::lint_drop_glue
+    }
+}
+
+// types.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_range_endpoint_out_of_range)]
+pub struct RangeEndpointOutOfRange<'a> {
+    pub ty: &'a str,
+    #[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    pub start: String,
+    pub literal: u128,
+    pub suffix: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_overflowing_bin_hex)]
+pub struct OverflowingBinHex<'a> {
+    pub ty: &'a str,
+    pub lit: String,
+    pub dec: u128,
+    pub actually: String,
+    #[subdiagnostic]
+    pub sign: OverflowingBinHexSign,
+    #[subdiagnostic]
+    pub sub: Option<OverflowingBinHexSub<'a>>,
+}
+
+pub enum OverflowingBinHexSign {
+    Positive,
+    Negative,
+}
+
+impl AddToDiagnostic for OverflowingBinHexSign {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        match self {
+            OverflowingBinHexSign::Positive => {
+                diag.note(fluent::positive_note);
+            }
+            OverflowingBinHexSign::Negative => {
+                diag.note(fluent::negative_note);
+                diag.note(fluent::negative_becomes_note);
+            }
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum OverflowingBinHexSub<'a> {
+    #[suggestion(
+        suggestion,
+        code = "{sans_suffix}{suggestion_ty}",
+        applicability = "machine-applicable"
+    )]
+    Suggestion {
+        #[primary_span]
+        span: Span,
+        suggestion_ty: &'a str,
+        sans_suffix: &'a str,
+    },
+    #[help(help)]
+    Help { suggestion_ty: &'a str },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_overflowing_int)]
+#[note]
+pub struct OverflowingInt<'a> {
+    pub ty: &'a str,
+    pub lit: String,
+    pub min: i128,
+    pub max: u128,
+    #[subdiagnostic]
+    pub help: Option<OverflowingIntHelp<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(help)]
+pub struct OverflowingIntHelp<'a> {
+    pub suggestion_ty: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_only_cast_u8_to_char)]
+pub struct OnlyCastu8ToChar {
+    #[suggestion(code = "'\\u{{{literal:X}}}'", applicability = "machine-applicable")]
+    pub span: Span,
+    pub literal: u128,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_overflowing_uint)]
+#[note]
+pub struct OverflowingUInt<'a> {
+    pub ty: &'a str,
+    pub lit: String,
+    pub min: u128,
+    pub max: u128,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_overflowing_literal)]
+#[note]
+pub struct OverflowingLiteral<'a> {
+    pub ty: &'a str,
+    pub lit: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_comparisons)]
+pub struct UnusedComparisons;
+
+pub struct ImproperCTypes<'a> {
+    pub ty: Ty<'a>,
+    pub desc: &'a str,
+    pub label: Span,
+    pub help: Option<DiagnosticMessage>,
+    pub note: DiagnosticMessage,
+    pub span_note: Option<Span>,
+}
+
+// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span>
+impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("ty", self.ty);
+        diag.set_arg("desc", self.desc);
+        diag.span_label(self.label, fluent::label);
+        if let Some(help) = self.help {
+            diag.help(help);
+        }
+        diag.note(self.note);
+        if let Some(note) = self.span_note {
+            diag.span_note(note, fluent::note);
+        }
+        diag
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        fluent::lint_improper_ctypes
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_variant_size_differences)]
+pub struct VariantSizeDifferencesDiag {
+    pub largest: u64,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_atomic_ordering_load)]
+#[help]
+pub struct AtomicOrderingLoad;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_atomic_ordering_store)]
+#[help]
+pub struct AtomicOrderingStore;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_atomic_ordering_fence)]
+#[help]
+pub struct AtomicOrderingFence;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_atomic_ordering_invalid)]
+#[help]
+pub struct InvalidAtomicOrderingDiag {
+    pub method: Symbol,
+    #[label]
+    pub fail_order_arg_span: Span,
+}
+
+// unused.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_op)]
+pub struct UnusedOp<'a> {
+    pub op: &'a str,
+    #[label]
+    pub label: Span,
+    #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_result)]
+pub struct UnusedResult<'a> {
+    pub ty: Ty<'a>,
+}
+
+// FIXME(davidtwco): this isn't properly translatable becauses of the
+// pre/post strings
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_closure)]
+#[note]
+pub struct UnusedClosure<'a> {
+    pub count: usize,
+    pub pre: &'a str,
+    pub post: &'a str,
+}
+
+// FIXME(davidtwco): this isn't properly translatable becauses of the
+// pre/post strings
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_generator)]
+#[note]
+pub struct UnusedGenerator<'a> {
+    pub count: usize,
+    pub pre: &'a str,
+    pub post: &'a str,
+}
+
+// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
+// strings
+pub struct UnusedDef<'a, 'b> {
+    pub pre: &'a str,
+    pub post: &'a str,
+    pub cx: &'a LateContext<'b>,
+    pub def_id: DefId,
+    pub note: Option<Symbol>,
+}
+
+// Needed because of def_path_str
+impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+        diag.set_arg("pre", self.pre);
+        diag.set_arg("post", self.post);
+        diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
+        // check for #[must_use = "..."]
+        if let Some(note) = self.note {
+            diag.note(note.as_str());
+        }
+        diag
+    }
+
+    fn msg(&self) -> rustc_errors::DiagnosticMessage {
+        fluent::lint_unused_def
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_path_statement_drop)]
+pub struct PathStatementDrop {
+    #[subdiagnostic]
+    pub sub: PathStatementDropSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum PathStatementDropSub {
+    #[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
+    Suggestion {
+        #[primary_span]
+        span: Span,
+        snippet: String,
+    },
+    #[help(help)]
+    Help {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_path_statement_no_effect)]
+pub struct PathStatementNoEffect;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_delim)]
+pub struct UnusedDelim<'a> {
+    pub delim: &'static str,
+    pub item: &'a str,
+    #[subdiagnostic]
+    pub suggestion: Option<UnusedDelimSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub struct UnusedDelimSuggestion {
+    #[suggestion_part(code = "{start_replace}")]
+    pub start_span: Span,
+    pub start_replace: &'static str,
+    #[suggestion_part(code = "{end_replace}")]
+    pub end_span: Span,
+    pub end_replace: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_import_braces)]
+pub struct UnusedImportBracesDiag {
+    pub node: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_allocation)]
+pub struct UnusedAllocationDiag;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_allocation_mut)]
+pub struct UnusedAllocationMutDiag;
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index e2d7d5b49f6..3045fc1a476 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -1,7 +1,7 @@
+use crate::lints::CStringPtr;
 use crate::LateContext;
 use crate::LateLintPass;
 use crate::LintContext;
-use rustc_errors::fluent;
 use rustc_hir::{Expr, ExprKind, PathSegment};
 use rustc_middle::ty;
 use rustc_span::{symbol::sym, ExpnKind, Span};
@@ -90,16 +90,10 @@ fn lint_cstring_as_ptr(
         if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
             if let ty::Adt(adt, _) = substs.type_at(0).kind() {
                 if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         TEMPORARY_CSTRING_AS_PTR,
                         as_ptr_span,
-                        fluent::lint_cstring_ptr,
-                        |diag| {
-                            diag.span_label(as_ptr_span, fluent::as_ptr_label)
-                                .span_label(unwrap.span, fluent::unwrap_label)
-                                .note(fluent::note)
-                                .help(fluent::help)
-                        },
+                        CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span },
                     );
                 }
             }
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index dea9506acb2..f130a98185d 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -1,7 +1,10 @@
+use crate::lints::{
+    ConfusableIdentifierPair, IdentifierNonAsciiChar, IdentifierUncommonCodepoints,
+    MixedScriptConfusables,
+};
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::fluent;
 use rustc_span::symbol::Symbol;
 
 declare_lint! {
@@ -180,21 +183,11 @@ impl EarlyLintPass for NonAsciiIdents {
                 continue;
             }
             has_non_ascii_idents = true;
-            cx.struct_span_lint(
-                NON_ASCII_IDENTS,
-                sp,
-                fluent::lint_identifier_non_ascii_char,
-                |lint| lint,
-            );
+            cx.emit_spanned_lint(NON_ASCII_IDENTS, sp, IdentifierNonAsciiChar);
             if check_uncommon_codepoints
                 && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
             {
-                cx.struct_span_lint(
-                    UNCOMMON_CODEPOINTS,
-                    sp,
-                    fluent::lint_identifier_uncommon_codepoints,
-                    |lint| lint,
-                )
+                cx.emit_spanned_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints);
             }
         }
 
@@ -222,14 +215,13 @@ impl EarlyLintPass for NonAsciiIdents {
                     .entry(skeleton_sym)
                     .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
                         if !*existing_is_ascii || !is_ascii {
-                            cx.struct_span_lint(
+                            cx.emit_spanned_lint(
                                 CONFUSABLE_IDENTS,
                                 sp,
-                                fluent::lint_confusable_identifier_pair,
-                                |lint| {
-                                    lint.set_arg("existing_sym", *existing_symbol)
-                                        .set_arg("sym", symbol)
-                                        .span_label(*existing_span, fluent::label)
+                                ConfusableIdentifierPair {
+                                    existing_sym: *existing_symbol,
+                                    sym: symbol,
+                                    label: *existing_span,
                                 },
                             );
                         }
@@ -331,24 +323,18 @@ impl EarlyLintPass for NonAsciiIdents {
                 }
 
                 for ((sp, ch_list), script_set) in lint_reports {
-                    cx.struct_span_lint(
+                    let mut includes = String::new();
+                    for (idx, ch) in ch_list.into_iter().enumerate() {
+                        if idx != 0 {
+                            includes += ", ";
+                        }
+                        let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+                        includes += &char_info;
+                    }
+                    cx.emit_spanned_lint(
                         MIXED_SCRIPT_CONFUSABLES,
                         sp,
-                        fluent::lint_mixed_script_confusables,
-                        |lint| {
-                            let mut includes = String::new();
-                            for (idx, ch) in ch_list.into_iter().enumerate() {
-                                if idx != 0 {
-                                    includes += ", ";
-                                }
-                                let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
-                                includes += &char_info;
-                            }
-                            lint.set_arg("set", script_set.to_string())
-                                .set_arg("includes", includes)
-                                .note(fluent::includes_note)
-                                .note(fluent::note)
-                        },
+                        MixedScriptConfusables { set: script_set.to_string(), includes },
                     );
                 }
             }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 8dccfe0046c..4a02c6cce47 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -1,3 +1,4 @@
+use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
 use crate::{LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_errors::{fluent, Applicability};
@@ -118,6 +119,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         arg_span = expn.call_site;
     }
 
+    #[allow(rustc::diagnostic_outside_of_impl)]
     cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
         lint.set_arg("name", symbol);
         lint.note(fluent::note);
@@ -253,25 +255,14 @@ fn check_panic_str<'tcx>(
                 .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
                 .collect(),
         };
-        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| {
-            lint.set_arg("count", n_arguments);
-            lint.note(fluent::note);
-            if is_arg_inside_call(arg.span, span) {
-                lint.span_suggestion(
-                    arg.span.shrink_to_hi(),
-                    fluent::add_args_suggestion,
-                    ", ...",
-                    Applicability::HasPlaceholders,
-                );
-                lint.span_suggestion(
-                    arg.span.shrink_to_lo(),
-                    fluent::add_fmt_suggestion,
-                    "\"{}\", ",
-                    Applicability::MachineApplicable,
-                );
-            }
-            lint
-        });
+        cx.emit_spanned_lint(
+            NON_FMT_PANICS,
+            arg_spans,
+            NonFmtPanicUnused {
+                count: n_arguments,
+                suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span),
+            },
+        );
     } else {
         let brace_spans: Option<Vec<_>> =
             snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
@@ -281,22 +272,12 @@ fn check_panic_str<'tcx>(
                     .collect()
             });
         let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             NON_FMT_PANICS,
             brace_spans.unwrap_or_else(|| vec![span]),
-            fluent::lint_non_fmt_panic_braces,
-            |lint| {
-                lint.set_arg("count", count);
-                lint.note(fluent::note);
-                if is_arg_inside_call(arg.span, span) {
-                    lint.span_suggestion(
-                        arg.span.shrink_to_lo(),
-                        fluent::suggestion,
-                        "\"{}\", ",
-                        Applicability::MachineApplicable,
-                    );
-                }
-                lint
+            NonFmtPanicBraces {
+                count,
+                suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span.shrink_to_lo()),
             },
         );
     }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index f37d6e9a63d..74d234fabea 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,7 +1,10 @@
+use crate::lints::{
+    NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
+    NonUpperCaseGlobal, NonUpperCaseGlobalSub,
+};
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
@@ -136,30 +139,17 @@ impl NonCamelCaseTypes {
         let name = ident.name.as_str();
 
         if !is_camel_case(name) {
-            cx.struct_span_lint(
+            let cc = to_camel_case(name);
+            let sub = if *name != cc {
+                NonCamelCaseTypeSub::Suggestion { span: ident.span, replace: cc }
+            } else {
+                NonCamelCaseTypeSub::Label { span: ident.span }
+            };
+            cx.emit_spanned_lint(
                 NON_CAMEL_CASE_TYPES,
                 ident.span,
-                fluent::lint_non_camel_case_type,
-                |lint| {
-                    let cc = to_camel_case(name);
-                    // We cannot provide meaningful suggestions
-                    // if the characters are in the category of "Lowercase Letter".
-                    if *name != cc {
-                        lint.span_suggestion(
-                            ident.span,
-                            fluent::suggestion,
-                            to_camel_case(name),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        lint.span_label(ident.span, fluent::label);
-                    }
-
-                    lint.set_arg("sort", sort);
-                    lint.set_arg("name", name);
-                    lint
-                },
-            )
+                NonCamelCaseType { sort, name, sub },
+            );
         }
     }
 }
@@ -294,47 +284,37 @@ impl NonSnakeCase {
         let name = ident.name.as_str();
 
         if !is_snake_case(name) {
-            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| {
-                let sc = NonSnakeCase::to_snake_case(name);
-                // We cannot provide meaningful suggestions
-                // if the characters are in the category of "Uppercase Letter".
-                if name != sc {
-                    // We have a valid span in almost all cases, but we don't have one when linting a crate
-                    // name provided via the command line.
-                    if !ident.span.is_dummy() {
-                        let sc_ident = Ident::from_str_and_span(&sc, ident.span);
-                        let (message, suggestion) = if sc_ident.is_reserved() {
-                            // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers.
-                            // Instead, recommend renaming the identifier entirely or, if permitted,
-                            // escaping it to create a raw identifier.
-                            if sc_ident.name.can_be_raw() {
-                                (fluent::rename_or_convert_suggestion, sc_ident.to_string())
-                            } else {
-                                lint.note(fluent::cannot_convert_note);
-                                (fluent::rename_suggestion, String::new())
+            let span = ident.span;
+            let sc = NonSnakeCase::to_snake_case(name);
+            // We cannot provide meaningful suggestions
+            // if the characters are in the category of "Uppercase Letter".
+            let sub = if name != sc {
+                // We have a valid span in almost all cases, but we don't have one when linting a crate
+                // name provided via the command line.
+                if !span.is_dummy() {
+                    let sc_ident = Ident::from_str_and_span(&sc, span);
+                    if sc_ident.is_reserved() {
+                        // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers.
+                        // Instead, recommend renaming the identifier entirely or, if permitted,
+                        // escaping it to create a raw identifier.
+                        if sc_ident.name.can_be_raw() {
+                            NonSnakeCaseDiagSub::RenameOrConvertSuggestion {
+                                span,
+                                suggestion: sc_ident,
                             }
                         } else {
-                            (fluent::convert_suggestion, sc.clone())
-                        };
-
-                        lint.span_suggestion(
-                            ident.span,
-                            message,
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
+                            NonSnakeCaseDiagSub::SuggestionAndNote { span }
+                        }
                     } else {
-                        lint.help(fluent::help);
+                        NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc.clone() }
                     }
                 } else {
-                    lint.span_label(ident.span, fluent::label);
+                    NonSnakeCaseDiagSub::Help
                 }
-
-                lint.set_arg("sort", sort);
-                lint.set_arg("name", name);
-                lint.set_arg("sc", sc);
-                lint
-            });
+            } else {
+                NonSnakeCaseDiagSub::Label { span }
+            };
+            cx.emit_spanned_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub });
         }
     }
 }
@@ -490,30 +470,19 @@ impl NonUpperCaseGlobals {
     fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
         let name = ident.name.as_str();
         if name.chars().any(|c| c.is_lowercase()) {
-            cx.struct_span_lint(
+            let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
+            // We cannot provide meaningful suggestions
+            // if the characters are in the category of "Lowercase Letter".
+            let sub = if *name != uc {
+                NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc }
+            } else {
+                NonUpperCaseGlobalSub::Label { span: ident.span }
+            };
+            cx.emit_spanned_lint(
                 NON_UPPER_CASE_GLOBALS,
                 ident.span,
-                fluent::lint_non_upper_case_global,
-                |lint| {
-                    let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
-                    // We cannot provide meaningful suggestions
-                    // if the characters are in the category of "Lowercase Letter".
-                    if *name != uc {
-                        lint.span_suggestion(
-                            ident.span,
-                            fluent::suggestion,
-                            uc,
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        lint.span_label(ident.span, fluent::label);
-                    }
-
-                    lint.set_arg("sort", sort);
-                    lint.set_arg("name", name);
-                    lint
-                },
-            )
+                NonUpperCaseGlobal { sort, name, sub },
+            );
         }
     }
 }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 2ef425a1093..d67a00619dd 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,7 +1,7 @@
 use crate::context::LintContext;
+use crate::lints::NoopMethodCallDiag;
 use crate::LateContext;
 use crate::LateLintPass;
-use rustc_errors::fluent;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_middle::ty;
@@ -85,11 +85,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         }
         let expr_span = expr.span;
         let span = expr_span.with_lo(receiver.span.hi());
-        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| {
-            lint.set_arg("method", call.ident.name)
-                .set_arg("receiver_ty", receiver_ty)
-                .span_label(span, fluent::label)
-                .note(fluent::note)
-        });
+        cx.emit_spanned_lint(
+            NOOP_METHOD_CALL,
+            span,
+            NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
+        );
     }
 }
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 22caadfab17..57482a9edba 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,5 +1,5 @@
+use crate::lints::PassByValueDiag;
 use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
@@ -29,20 +29,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
                     }
                 }
                 if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         PASS_BY_VALUE,
                         ty.span,
-                        fluent::lint_pass_by_value,
-                        |lint| {
-                            lint.set_arg("ty", t.clone()).span_suggestion(
-                                ty.span,
-                                fluent::suggestion,
-                                t,
-                                // Changing type of function argument
-                                Applicability::MaybeIncorrect,
-                            )
-                        },
-                    )
+                        PassByValueDiag { ty: t.clone(), suggestion: ty.span },
+                    );
                 }
             }
             _ => {}
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 3521de7fc08..9a8b14b4907 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -1,6 +1,5 @@
-use crate::{EarlyContext, EarlyLintPass, LintContext};
+use crate::{lints::RedundantSemicolonsDiag, EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::{Block, StmtKind};
-use rustc_errors::{fluent, Applicability};
 use rustc_span::Span;
 
 declare_lint! {
@@ -48,18 +47,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
             return;
         }
 
-        cx.struct_span_lint(
+        cx.emit_spanned_lint(
             REDUNDANT_SEMICOLONS,
             span,
-            fluent::lint_redundant_semicolons,
-            |lint| {
-                lint.set_arg("multiple", multiple).span_suggestion(
-                    span,
-                    fluent::suggestion,
-                    "",
-                    Applicability::MaybeIncorrect,
-                )
-            },
+            RedundantSemicolonsDiag { multiple, suggestion: span },
         );
     }
 }
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 1b21c2dac37..7ea1a138b7e 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -1,7 +1,7 @@
+use crate::lints::{DropGlue, DropTraitConstraintsDiag};
 use crate::LateContext;
 use crate::LateLintPass;
 use crate::LintContext;
-use rustc_errors::fluent;
 use rustc_hir as hir;
 use rustc_span::symbol::sym;
 
@@ -101,17 +101,13 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                 if trait_predicate.trait_ref.self_ty().is_impl_trait() {
                     continue;
                 }
-                let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
-                    continue;
+                let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+                    return
                 };
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     DROP_BOUNDS,
                     span,
-                    fluent::lint_drop_trait_constraints,
-                    |lint| {
-                        lint.set_arg("predicate", predicate)
-                            .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
-                    },
+                    DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id },
                 );
             }
         }
@@ -123,12 +119,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
         };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
-            if cx.tcx.lang_items().drop_trait() == def_id
-                && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
-            {
-                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| {
-                    lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
-                });
+            if cx.tcx.lang_items().drop_trait() == def_id {
+                let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+                    return
+                };
+                cx.emit_spanned_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
             }
         }
     }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fa415243ba0..f2ab44ac97c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,11 +1,16 @@
+use crate::lints::{
+    AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
+    InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
+    OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
+    RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag,
+};
 use crate::{LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{fluent, Applicability, DiagnosticMessage};
+use rustc_errors::{fluent, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
-use rustc_macros::LintDiagnostic;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
@@ -146,32 +151,22 @@ fn lint_overflowing_range_endpoint<'tcx>(
     };
     let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
 
-    cx.struct_span_lint(
+    use rustc_ast::{LitIntType, LitKind};
+    let suffix = match lit.node {
+        LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
+        LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
+        LitKind::Int(_, LitIntType::Unsuffixed) => "",
+        _ => bug!(),
+    };
+    cx.emit_spanned_lint(
         OVERFLOWING_LITERALS,
         struct_expr.span,
-        fluent::lint_range_endpoint_out_of_range,
-        |lint| {
-            use ast::{LitIntType, LitKind};
-
-            lint.set_arg("ty", ty);
-
-            // We need to preserve the literal's suffix,
-            // as it may determine typing information.
-            let suffix = match lit.node {
-                LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
-                LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
-                LitKind::Int(_, LitIntType::Unsuffixed) => "",
-                _ => bug!(),
-            };
-            let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
-            lint.span_suggestion(
-                struct_expr.span,
-                fluent::suggestion,
-                suggestion,
-                Applicability::MachineApplicable,
-            );
-
-            lint
+        RangeEndpointOutOfRange {
+            ty,
+            suggestion: struct_expr.span,
+            start,
+            literal: lit_val - 1,
+            suffix,
         },
     );
 
@@ -228,58 +223,37 @@ fn report_bin_hex_error(
     val: u128,
     negative: bool,
 ) {
-    cx.struct_span_lint(
-        OVERFLOWING_LITERALS,
-        expr.span,
-        fluent::lint_overflowing_bin_hex,
-        |lint| {
-            let (t, actually) = match ty {
-                attr::IntType::SignedInt(t) => {
-                    let actually = if negative {
-                        -(size.sign_extend(val) as i128)
-                    } else {
-                        size.sign_extend(val) as i128
-                    };
-                    (t.name_str(), actually.to_string())
-                }
-                attr::IntType::UnsignedInt(t) => {
-                    let actually = size.truncate(val);
-                    (t.name_str(), actually.to_string())
-                }
+    let (t, actually) = match ty {
+        attr::IntType::SignedInt(t) => {
+            let actually = if negative {
+                -(size.sign_extend(val) as i128)
+            } else {
+                size.sign_extend(val) as i128
             };
-
-            if negative {
-                // If the value is negative,
-                // emits a note about the value itself, apart from the literal.
-                lint.note(fluent::negative_note);
-                lint.note(fluent::negative_becomes_note);
+            (t.name_str(), actually.to_string())
+        }
+        attr::IntType::UnsignedInt(t) => {
+            let actually = size.truncate(val);
+            (t.name_str(), actually.to_string())
+        }
+    };
+    let sign =
+        if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive };
+    let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map(
+        |suggestion_ty| {
+            if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
+                let (sans_suffix, _) = repr_str.split_at(pos);
+                OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix }
             } else {
-                lint.note(fluent::positive_note);
-            }
-            if let Some(sugg_ty) =
-                get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
-            {
-                lint.set_arg("suggestion_ty", sugg_ty);
-                if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
-                    let (sans_suffix, _) = repr_str.split_at(pos);
-                    lint.span_suggestion(
-                        expr.span,
-                        fluent::suggestion,
-                        format!("{}{}", sans_suffix, sugg_ty),
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    lint.help(fluent::help);
-                }
+                OverflowingBinHexSub::Help { suggestion_ty }
             }
-            lint.set_arg("ty", t)
-                .set_arg("lit", repr_str)
-                .set_arg("dec", val)
-                .set_arg("actually", actually);
-
-            lint
         },
     );
+    cx.emit_spanned_lint(
+        OVERFLOWING_LITERALS,
+        expr.span,
+        OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub },
+    )
 }
 
 // This function finds the next fitting type and generates a suggestion string.
@@ -363,28 +337,19 @@ fn lint_int_literal<'tcx>(
             return;
         }
 
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| {
-            lint.set_arg("ty", t.name_str())
-                .set_arg(
-                    "lit",
-                    cx.sess()
-                        .source_map()
-                        .span_to_snippet(lit.span)
-                        .expect("must get snippet from literal"),
-                )
-                .set_arg("min", min)
-                .set_arg("max", max)
-                .note(fluent::note);
-
-            if let Some(sugg_ty) =
-                get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
-            {
-                lint.set_arg("suggestion_ty", sugg_ty);
-                lint.help(fluent::help);
-            }
-
-            lint
-        });
+        let lit = cx
+            .sess()
+            .source_map()
+            .span_to_snippet(lit.span)
+            .expect("must get snippet from literal");
+        let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
+            .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
+
+        cx.emit_spanned_lint(
+            OVERFLOWING_LITERALS,
+            e.span,
+            OverflowingInt { ty: t.name_str(), lit, min, max, help },
+        );
     }
 }
 
@@ -408,18 +373,10 @@ fn lint_uint_literal<'tcx>(
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
-                        cx.struct_span_lint(
+                        cx.emit_spanned_lint(
                             OVERFLOWING_LITERALS,
                             par_e.span,
-                            fluent::lint_only_cast_u8_to_char,
-                            |lint| {
-                                lint.span_suggestion(
-                                    par_e.span,
-                                    fluent::suggestion,
-                                    format!("'\\u{{{:X}}}'", lit_val),
-                                    Applicability::MachineApplicable,
-                                )
-                            },
+                            OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
                         );
                         return;
                     }
@@ -443,19 +400,20 @@ fn lint_uint_literal<'tcx>(
             );
             return;
         }
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| {
-            lint.set_arg("ty", t.name_str())
-                .set_arg(
-                    "lit",
-                    cx.sess()
-                        .source_map()
-                        .span_to_snippet(lit.span)
-                        .expect("must get snippet from literal"),
-                )
-                .set_arg("min", min)
-                .set_arg("max", max)
-                .note(fluent::note)
-        });
+        cx.emit_spanned_lint(
+            OVERFLOWING_LITERALS,
+            e.span,
+            OverflowingUInt {
+                ty: t.name_str(),
+                lit: cx
+                    .sess()
+                    .source_map()
+                    .span_to_snippet(lit.span)
+                    .expect("must get snippet from literal"),
+                min,
+                max,
+            },
+        );
     }
 }
 
@@ -484,20 +442,16 @@ fn lint_literal<'tcx>(
                 _ => bug!(),
             };
             if is_infinite == Ok(true) {
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     OVERFLOWING_LITERALS,
                     e.span,
-                    fluent::lint_overflowing_literal,
-                    |lint| {
-                        lint.set_arg("ty", t.name_str())
-                            .set_arg(
-                                "lit",
-                                cx.sess()
-                                    .source_map()
-                                    .span_to_snippet(lit.span)
-                                    .expect("must get snippet from literal"),
-                            )
-                            .note(fluent::note)
+                    OverflowingLiteral {
+                        ty: t.name_str(),
+                        lit: cx
+                            .sess()
+                            .source_map()
+                            .span_to_snippet(lit.span)
+                            .expect("must get snippet from literal"),
                     },
                 );
             }
@@ -517,12 +471,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
             }
             hir::ExprKind::Binary(binop, ref l, ref r) => {
                 if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
-                    cx.struct_span_lint(
-                        UNUSED_COMPARISONS,
-                        e.span,
-                        fluent::lint_unused_comparisons,
-                        |lint| lint,
-                    );
+                    cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
                 }
             }
             hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
@@ -878,39 +827,39 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
-        if def.repr().transparent() {
+        let transparent_safety = def.repr().transparent().then(|| {
             // Can assume that at most one field is not a ZST, so only check
             // that field's type for FFI-safety.
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
-                self.check_field_type_for_ffi(cache, field, substs)
+                return self.check_field_type_for_ffi(cache, field, substs);
             } else {
                 // All fields are ZSTs; this means that the type should behave
-                // like (), which is FFI-unsafe
+                // like (), which is FFI-unsafe... except if all fields are PhantomData,
+                // which is tested for below
                 FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
             }
-        } else {
-            // We can't completely trust repr(C) markings; make sure the fields are
-            // actually safe.
-            let mut all_phantom = !variant.fields.is_empty();
-            for field in &variant.fields {
-                match self.check_field_type_for_ffi(cache, &field, substs) {
-                    FfiSafe => {
-                        all_phantom = false;
-                    }
-                    FfiPhantom(..) if def.is_enum() => {
-                        return FfiUnsafe {
-                            ty,
-                            reason: fluent::lint_improper_ctypes_enum_phantomdata,
-                            help: None,
-                        };
-                    }
-                    FfiPhantom(..) => {}
-                    r => return r,
+        });
+        // We can't completely trust repr(C) markings; make sure the fields are
+        // actually safe.
+        let mut all_phantom = !variant.fields.is_empty();
+        for field in &variant.fields {
+            match self.check_field_type_for_ffi(cache, &field, substs) {
+                FfiSafe => {
+                    all_phantom = false;
+                }
+                FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
+                    return FfiUnsafe {
+                        ty,
+                        reason: fluent::lint_improper_ctypes_enum_phantomdata,
+                        help: None,
+                    };
                 }
+                FfiPhantom(..) => {}
+                r => return transparent_safety.unwrap_or(r),
             }
-
-            if all_phantom { FfiPhantom(ty) } else { FfiSafe }
         }
+
+        if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
     }
 
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1174,26 +1123,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             CItemKind::Declaration => IMPROPER_CTYPES,
             CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
         };
-
-        self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| {
-            let item_description = match self.mode {
-                CItemKind::Declaration => "block",
-                CItemKind::Definition => "fn",
+        let desc = match self.mode {
+            CItemKind::Declaration => "block",
+            CItemKind::Definition => "fn",
+        };
+        let span_note = if let ty::Adt(def, _) = ty.kind()
+            && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
+                Some(sp)
+            } else {
+                None
             };
-            lint.set_arg("ty", ty);
-            lint.set_arg("desc", item_description);
-            lint.span_label(sp, fluent::label);
-            if let Some(help) = help {
-                lint.help(help);
-            }
-            lint.note(note);
-            if let ty::Adt(def, _) = ty.kind() {
-                if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
-                    lint.span_note(sp, fluent::note);
-                }
-            }
-            lint
-        });
+        self.cx.emit_spanned_lint(
+            lint,
+            sp,
+            ImproperCTypes { ty, desc, label: sp, help, note, span_note },
+        );
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
@@ -1397,11 +1341,10 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
             // We only warn if the largest variant is at least thrice as large as
             // the second-largest.
             if largest > slargest * 3 && slargest > 0 {
-                cx.struct_span_lint(
+                cx.emit_spanned_lint(
                     VARIANT_SIZE_DIFFERENCES,
                     enum_definition.variants[largest_index].span,
-                    fluent::lint_variant_size_differences,
-                    |lint| lint.set_arg("largest", largest),
+                    VariantSizeDifferencesDiag { largest },
                 );
             }
         }
@@ -1509,17 +1452,19 @@ impl InvalidAtomicOrdering {
 
     fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
-            && let Some((ordering_arg, invalid_ordering, msg)) = match method {
-                sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)),
-                sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)),
+            && let Some((ordering_arg, invalid_ordering)) = match method {
+                sym::load => Some((&args[0], sym::Release)),
+                sym::store => Some((&args[1], sym::Acquire)),
                 _ => None,
             }
             && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
             && (ordering == invalid_ordering || ordering == sym::AcqRel)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
-                lint.help(fluent::help)
-            });
+            if method == sym::load {
+                cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad);
+            } else {
+                cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore);
+            };
         }
     }
 
@@ -1530,10 +1475,7 @@ impl InvalidAtomicOrdering {
             && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
             && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| {
-                lint
-                    .help(fluent::help)
-            });
+            cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, args[0].span, AtomicOrderingFence);
         }
     }
 
@@ -1550,15 +1492,6 @@ impl InvalidAtomicOrdering {
         let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return };
 
         if matches!(fail_ordering, sym::Release | sym::AcqRel) {
-            #[derive(LintDiagnostic)]
-            #[diag(lint_atomic_ordering_invalid)]
-            #[help]
-            struct InvalidAtomicOrderingDiag {
-                method: Symbol,
-                #[label]
-                fail_order_arg_span: Span,
-            }
-
             cx.emit_spanned_lint(
                 INVALID_ATOMIC_ORDERING,
                 fail_order_arg.span,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 525079681ca..ac2b32b44e6 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1,9 +1,14 @@
+use crate::lints::{
+    PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
+    UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion,
+    UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
+};
 use crate::Lint;
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{ExprKind, StmtKind};
-use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
+use rustc_errors::{pluralize, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -163,23 +168,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         let mut op_warned = false;
 
         if let Some(must_use_op) = must_use_op {
-            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
-                lint.set_arg("op", must_use_op)
-                    .span_label(expr.span, fluent::label)
-                    .span_suggestion_verbose(
-                        expr.span.shrink_to_lo(),
-                        fluent::suggestion,
-                        "let _ = ",
-                        Applicability::MachineApplicable,
-                    )
-            });
+            cx.emit_spanned_lint(
+                UNUSED_MUST_USE,
+                expr.span,
+                UnusedOp {
+                    op: must_use_op,
+                    label: expr.span,
+                    suggestion: expr.span.shrink_to_lo(),
+                },
+            );
             op_warned = true;
         }
 
         if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
-            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
-                lint.set_arg("ty", ty)
-            });
+            cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
         }
 
         fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
@@ -402,47 +404,31 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     );
                 }
                 MustUsePath::Closure(span) => {
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         UNUSED_MUST_USE,
                         *span,
-                        fluent::lint_unused_closure,
-                        |lint| {
-                            // FIXME(davidtwco): this isn't properly translatable because of the
-                            // pre/post strings
-                            lint.set_arg("count", plural_len)
-                                .set_arg("pre", descr_pre)
-                                .set_arg("post", descr_post)
-                                .note(fluent::note)
-                        },
+                        UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
                     );
                 }
                 MustUsePath::Generator(span) => {
-                    cx.struct_span_lint(
+                    cx.emit_spanned_lint(
                         UNUSED_MUST_USE,
                         *span,
-                        fluent::lint_unused_generator,
-                        |lint| {
-                            // FIXME(davidtwco): this isn't properly translatable because of the
-                            // pre/post strings
-                            lint.set_arg("count", plural_len)
-                                .set_arg("pre", descr_pre)
-                                .set_arg("post", descr_post)
-                                .note(fluent::note)
-                        },
+                        UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post },
                     );
                 }
                 MustUsePath::Def(span, def_id, reason) => {
-                    cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| {
-                        // FIXME(davidtwco): this isn't properly translatable because of the pre/post
-                        // strings
-                        lint.set_arg("pre", descr_pre);
-                        lint.set_arg("post", descr_post);
-                        lint.set_arg("def", cx.tcx.def_path_str(*def_id));
-                        if let Some(note) = reason {
-                            lint.note(note.as_str());
-                        }
-                        lint
-                    });
+                    cx.emit_spanned_lint(
+                        UNUSED_MUST_USE,
+                        *span,
+                        UnusedDef {
+                            pre: descr_pre,
+                            post: descr_post,
+                            cx,
+                            def_id: *def_id,
+                            note: *reason,
+                        },
+                    );
                 }
             }
         }
@@ -478,31 +464,15 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
             if let hir::ExprKind::Path(_) = expr.kind {
                 let ty = cx.typeck_results().expr_ty(expr);
                 if ty.needs_drop(cx.tcx, cx.param_env) {
-                    cx.struct_span_lint(
-                        PATH_STATEMENTS,
-                        s.span,
-                        fluent::lint_path_statement_drop,
-                        |lint| {
-                            if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
-                                lint.span_suggestion(
-                                    s.span,
-                                    fluent::suggestion,
-                                    format!("drop({});", snippet),
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                lint.span_help(s.span, fluent::suggestion);
-                            }
-                            lint
-                        },
-                    );
+                    let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
+                    {
+                        PathStatementDropSub::Suggestion { span: s.span, snippet }
+                    } else {
+                        PathStatementDropSub::Help { span: s.span }
+                    };
+                    cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
                 } else {
-                    cx.struct_span_lint(
-                        PATH_STATEMENTS,
-                        s.span,
-                        fluent::lint_path_statement_no_effect,
-                        |lint| lint,
-                    );
+                    cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
                 }
             }
         }
@@ -695,36 +665,35 @@ trait UnusedDelimLint {
         } else {
             MultiSpan::from(value_span)
         };
-        cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| {
-            lint.set_arg("delim", Self::DELIM_STR);
-            lint.set_arg("item", msg);
-            if let Some((lo, hi)) = spans {
-                let sm = cx.sess().source_map();
-                let lo_replace =
+        let suggestion = spans.map(|(lo, hi)| {
+            let sm = cx.sess().source_map();
+            let lo_replace =
                     if keep_space.0 &&
                         let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') {
-                        " ".to_string()
+                        " "
                         } else {
-                            "".to_string()
+                            ""
                         };
 
-                let hi_replace =
+            let hi_replace =
                     if keep_space.1 &&
                         let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') {
-                        " ".to_string()
+                        " "
                         } else {
-                            "".to_string()
+                            ""
                         };
-
-                let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
-                lint.multipart_suggestion(
-                    fluent::suggestion,
-                    replacement,
-                    Applicability::MachineApplicable,
-                );
+            UnusedDelimSuggestion {
+                start_span: lo,
+                start_replace: lo_replace,
+                end_span: hi,
+                end_replace: hi_replace,
             }
-            lint
         });
+        cx.emit_spanned_lint(
+            self.lint(),
+            primary_span,
+            UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion },
+        );
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
@@ -1297,11 +1266,10 @@ impl UnusedImportBraces {
                 ast::UseTreeKind::Nested(_) => return,
             };
 
-            cx.struct_span_lint(
+            cx.emit_spanned_lint(
                 UNUSED_IMPORT_BRACES,
                 item.span,
-                fluent::lint_unused_import_braces,
-                |lint| lint.set_arg("node", node_name),
+                UnusedImportBracesDiag { node: node_name },
             );
         }
     }
@@ -1351,17 +1319,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
 
         for adj in cx.typeck_results().expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
-                cx.struct_span_lint(
-                    UNUSED_ALLOCATION,
-                    e.span,
-                    match m {
-                        adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation,
-                        adjustment::AutoBorrowMutability::Mut { .. } => {
-                            fluent::lint_unused_allocation_mut
-                        }
-                    },
-                    |lint| lint,
-                );
+                match m {
+                    adjustment::AutoBorrowMutability::Not => {
+                        cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag);
+                    }
+                    adjustment::AutoBorrowMutability::Mut { .. } => {
+                        cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag);
+                    }
+                };
             }
         }
     }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 28317d6cea0..6cdf5097083 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4033,10 +4033,10 @@ declare_lint! {
     ///
     /// This can be used to implement an unsound API if used incorrectly.
     pub IMPLIED_BOUNDS_ENTAILMENT,
-    Warn,
+    Deny,
     "impl method assumes more implied bounds than its corresponding trait method",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
-        reason: FutureIncompatibilityReason::FutureReleaseError,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
index 3c50827c1ab..7f955b0a750 100644
--- a/compiler/rustc_log/Cargo.toml
+++ b/compiler/rustc_log/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 tracing = "0.1.28"
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.2.0"
+tracing-core = "0.1.28"
 
 [dev-dependencies]
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 4cac88aff64..fc1cabd2de9 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -45,16 +45,34 @@
 use std::env::{self, VarError};
 use std::fmt::{self, Display};
 use std::io::{self, IsTerminal};
+use tracing_core::{Event, Subscriber};
 use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::fmt::{
+    format::{self, FormatEvent, FormatFields},
+    FmtContext,
+};
 use tracing_subscriber::layer::SubscriberExt;
 
 pub fn init_rustc_env_logger() -> Result<(), Error> {
-    init_env_logger("RUSTC_LOG")
+    init_rustc_env_logger_with_backtrace_option(&None)
+}
+
+pub fn init_rustc_env_logger_with_backtrace_option(
+    backtrace_target: &Option<String>,
+) -> Result<(), Error> {
+    init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
 }
 
 /// In contrast to `init_rustc_env_logger` this allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    init_env_logger_with_backtrace_option(env, &None)
+}
+
+pub fn init_env_logger_with_backtrace_option(
+    env: &str,
+    backtrace_target: &Option<String>,
+) -> Result<(), Error> {
     let filter = match env::var(env) {
         Ok(env) => EnvFilter::new(env),
         _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
@@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
     let layer = layer.with_thread_ids(true).with_thread_names(true);
 
     let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    match backtrace_target {
+        Some(str) => {
+            let fmt_layer = tracing_subscriber::fmt::layer()
+                .with_writer(io::stderr)
+                .without_time()
+                .event_format(BacktraceFormatter { backtrace_target: str.to_string() });
+            let subscriber = subscriber.with(fmt_layer);
+            tracing::subscriber::set_global_default(subscriber).unwrap();
+        }
+        None => {
+            tracing::subscriber::set_global_default(subscriber).unwrap();
+        }
+    };
 
     Ok(())
 }
 
+struct BacktraceFormatter {
+    backtrace_target: String,
+}
+
+impl<S, N> FormatEvent<S, N> for BacktraceFormatter
+where
+    S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
+    N: for<'a> FormatFields<'a> + 'static,
+{
+    fn format_event(
+        &self,
+        _ctx: &FmtContext<'_, S, N>,
+        mut writer: format::Writer<'_>,
+        event: &Event<'_>,
+    ) -> fmt::Result {
+        let target = event.metadata().target();
+        if !target.contains(&self.backtrace_target) {
+            return Ok(());
+        }
+        let backtrace = std::backtrace::Backtrace::capture();
+        writeln!(writer, "stack backtrace: \n{:?}", backtrace)
+    }
+}
+
 pub fn stdout_isatty() -> bool {
     io::stdout().is_terminal()
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 82f6812026a..e405462bbb8 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -382,10 +382,26 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                     return Ok(quote! { #diag.subdiagnostic(#binding); });
                 }
             }
-            (Meta::List(_), "subdiagnostic") => {
-                throw_invalid_attr!(attr, &meta, |diag| {
-                    diag.help("`subdiagnostic` does not support nested attributes")
-                })
+            (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
+                if nested.len() == 1
+                    && let Some(NestedMeta::Meta(Meta::Path(path))) = nested.first()
+                    && path.is_ident("eager") {
+                        let handler = match &self.parent.kind {
+                            DiagnosticDeriveKind::Diagnostic { handler } => handler,
+                            DiagnosticDeriveKind::LintDiagnostic => {
+                                throw_invalid_attr!(attr, &meta, |diag| {
+                                    diag.help("eager subdiagnostics are not supported on lints")
+                                })
+                            }
+                        };
+                        return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+                } else {
+                    throw_invalid_attr!(attr, &meta, |diag| {
+                        diag.help(
+                            "`eager` is the only supported nested attribute for `subdiagnostic`",
+                        )
+                    })
+                }
             }
             _ => (),
         }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index ac916bb6068..bb3722fe156 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(allow_internal_unstable)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_span)]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index bdc4ae391f0..030328d1e26 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1686,6 +1686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
 
             ty::Closure(_, substs) => {
+                let constness = self.tcx.constness(def_id.to_def_id());
+                self.tables.constness.set(def_id.to_def_id().index, constness);
                 record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig());
             }
 
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 75282f958b5..f816d614500 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -30,7 +30,12 @@ macro_rules! arena_types {
             [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
             [decode] borrowck_result:
                 rustc_middle::mir::BorrowCheckResult<'tcx>,
-            [] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>,
+            [] resolver: rustc_data_structures::steal::Steal<(
+                rustc_middle::ty::ResolverAstLowering,
+                rustc_data_structures::sync::Lrc<rustc_ast::Crate>,
+            )>,
+            [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>,
+            [] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 883554f959c..48bae7a2d4e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -485,7 +485,9 @@ impl<'hir> Map<'hir> {
             BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
 
             BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
-            BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
+            BodyOwnerKind::Fn | BodyOwnerKind::Closure
+                if self.tcx.is_const_fn_raw(def_id.to_def_id()) =>
+            {
                 ConstContext::ConstFn
             }
             BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 076ce1bdb34..86655915736 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -27,12 +27,12 @@ rustc_queries! {
     }
 
     query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
-        eval_always
+        feedable
         no_hash
         desc { "getting the resolver outputs" }
     }
 
-    query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
+    query resolver_for_lowering(_: ()) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
         feedable
         no_hash
         desc { "getting the resolver for lowering" }
@@ -1673,7 +1673,7 @@ rustc_queries! {
 
     /// Gets the name of the crate.
     query crate_name(_: CrateNum) -> Symbol {
-        eval_always
+        feedable
         desc { "fetching what a crate is named" }
         separate_provide_extern
     }
@@ -1857,7 +1857,7 @@ rustc_queries! {
     /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
     /// has been destroyed.
     query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
-        eval_always
+        feedable
         desc { "getting output filenames" }
     }
 
@@ -2041,7 +2041,7 @@ rustc_queries! {
     }
 
     query features_query(_: ()) -> &'tcx rustc_feature::Features {
-        eval_always
+        feedable
         desc { "looking up enabled feature gates" }
     }
 
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ec69864c951..1cc9fd526b4 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -131,7 +131,9 @@ pub enum SelectionCandidate<'tcx> {
 
     /// Implementation of a `Fn`-family trait by one of the anonymous types
     /// generated for an `||` expression.
-    ClosureCandidate,
+    ClosureCandidate {
+        is_const: bool,
+    },
 
     /// Implementation of a `Generator` trait by one of the anonymous types
     /// generated for a generator.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5de414077a2..63f31e5a11f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -51,7 +51,7 @@ use rustc_macros::HashStable;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-use rustc_session::config::{CrateType, OutputFilenames};
+use rustc_session::config::CrateType;
 use rustc_session::cstore::{CrateStoreDyn, Untracked};
 use rustc_session::lint::Lint;
 use rustc_session::Limit;
@@ -74,7 +74,6 @@ use std::hash::{Hash, Hasher};
 use std::iter;
 use std::mem;
 use std::ops::{Bound, Deref};
-use std::sync::Arc;
 
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
@@ -363,6 +362,9 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> {
         TyCtxtFeed { tcx: self, key: () }
     }
+    pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> {
+        TyCtxtFeed { tcx: self, key: LOCAL_CRATE }
+    }
 }
 
 impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
@@ -428,11 +430,6 @@ pub struct GlobalCtxt<'tcx> {
     pub consts: CommonConsts<'tcx>,
 
     untracked: Untracked,
-    /// Output of the resolver.
-    pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
-    /// The entire crate as AST. This field serves as the input for the hir_crate query,
-    /// which lowers it from AST to HIR. It must not be read or used by anything else.
-    pub untracked_crate: Steal<Lrc<ast::Crate>>,
 
     /// This provides access to the incremental compilation on-disk cache for query results.
     /// Do not access this directly. It is only meant to be used by
@@ -457,17 +454,11 @@ pub struct GlobalCtxt<'tcx> {
     /// Merge this with `selection_cache`?
     pub evaluation_cache: traits::EvaluationCache<'tcx>,
 
-    /// The definite name of the current crate after taking into account
-    /// attributes, commandline parameters, etc.
-    crate_name: Symbol,
-
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
-
-    output_filenames: Arc<OutputFilenames>,
 }
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -592,15 +583,11 @@ impl<'tcx> TyCtxt<'tcx> {
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
         hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
-        untracked_resolutions: ty::ResolverGlobalCtxt,
         untracked: Untracked,
-        krate: Lrc<ast::Crate>,
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
         query_kinds: &'tcx [DepKindStruct<'tcx>],
-        crate_name: Symbol,
-        output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
             s.emit_fatal(err);
@@ -622,8 +609,6 @@ impl<'tcx> TyCtxt<'tcx> {
             lifetimes: common_lifetimes,
             consts: common_consts,
             untracked,
-            untracked_resolutions,
-            untracked_crate: Steal::new(krate),
             on_disk_cache,
             queries,
             query_caches: query::QueryCaches::default(),
@@ -632,10 +617,8 @@ impl<'tcx> TyCtxt<'tcx> {
             pred_rcache: Default::default(),
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
-            crate_name,
             data_layout,
             alloc_map: Lock::new(interpret::AllocMap::new()),
-            output_filenames: Arc::new(output_filenames),
         }
     }
 
@@ -810,7 +793,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // statements within the query system and we'd run into endless
         // recursion otherwise.
         let (crate_name, stable_crate_id) = if def_id.is_local() {
-            (self.crate_name, self.sess.local_stable_crate_id())
+            (self.crate_name(LOCAL_CRATE), self.sess.local_stable_crate_id())
         } else {
             let cstore = &*self.untracked.cstore;
             (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
@@ -2407,13 +2390,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
     providers.module_reexports =
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
-    providers.crate_name = |tcx, id| {
-        assert_eq!(id, LOCAL_CRATE);
-        tcx.crate_name
-    };
     providers.maybe_unused_trait_imports =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
     providers.maybe_unused_extern_crates =
@@ -2424,8 +2402,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
 
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
-    providers.output_filenames = |tcx, ()| &tcx.output_filenames;
-    providers.features_query = |tcx, ()| tcx.sess.features_untracked();
     providers.is_panic_runtime = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
         tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index fa571d480b6..993e95b3514 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2465,8 +2465,10 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
-        matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
-            && self.constness(def_id) == hir::Constness::Const
+        matches!(
+            self.def_kind(def_id),
+            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
+        ) && self.constness(def_id) == hir::Constness::Const
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index f7e4c821569..bd5b04d5b2b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1686,7 +1686,7 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn is_ty_infer(self) -> bool {
+    pub fn is_ty_or_numeric_infer(self) -> bool {
         matches!(self.kind(), Infer(_))
     }
 
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 0c33e5bda1a..2dec58ea82a 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -202,7 +202,7 @@ impl<'tcx> GenericArg<'tcx> {
     pub fn is_non_region_infer(self) -> bool {
         match self.unpack() {
             GenericArgKind::Lifetime(_) => false,
-            GenericArgKind::Type(ty) => ty.is_ty_infer(),
+            GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
             GenericArgKind::Const(ct) => ct.is_ct_infer(),
         }
     }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f5093fb02a8..dd2b03988c3 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1325,7 +1325,10 @@ impl<'a> Parser<'a> {
             self.parse_array_or_repeat_expr(Delimiter::Bracket)
         } else if self.check_path() {
             self.parse_path_start_expr()
-        } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
+        } else if self.check_keyword(kw::Move)
+            || self.check_keyword(kw::Static)
+            || self.check_const_closure()
+        {
             self.parse_closure_expr()
         } else if self.eat_keyword(kw::If) {
             self.parse_if_expr()
@@ -2065,6 +2068,8 @@ impl<'a> Parser<'a> {
             ClosureBinder::NotPresent
         };
 
+        let constness = self.parse_constness(Case::Sensitive);
+
         let movability =
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
 
@@ -2111,6 +2116,7 @@ impl<'a> Parser<'a> {
             ExprKind::Closure(Box::new(ast::Closure {
                 binder,
                 capture_clause,
+                constness,
                 asyncness,
                 movability,
                 fn_decl,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 49d31981539..2fd2a4e5154 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -736,6 +736,16 @@ impl<'a> Parser<'a> {
         self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
     }
 
+    fn check_const_closure(&self) -> bool {
+        self.is_keyword_ahead(0, &[kw::Const])
+            && self.look_ahead(1, |t| match &t.kind {
+                token::Ident(kw::Move | kw::Static | kw::Async, _)
+                | token::OrOr
+                | token::BinOp(token::Or) => true,
+                _ => false,
+            })
+    }
+
     fn check_inline_const(&self, dist: usize) -> bool {
         self.is_keyword_ahead(dist, &[kw::Const])
             && self.look_ahead(dist + 1, |t| match &t.kind {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c59c06ac31e..f9f9799d3e4 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -82,6 +82,7 @@ impl CheckAttrVisitor<'_> {
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
             let attr_is_valid = 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::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
@@ -241,6 +242,16 @@ impl CheckAttrVisitor<'_> {
         );
     }
 
+    /// Checks if `#[do_not_recommend]` is applied on a trait impl.
+    fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
+        if let Target::Impl = target {
+            true
+        } else {
+            self.tcx.sess.emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
+            false
+        }
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
     fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
         match target {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c6cd69add28..9c6519ea4bb 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -14,6 +14,13 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
 
 use crate::lang_items::Duplicate;
 
+#[derive(Diagnostic)]
+#[diag(passes_incorrect_do_not_recommend_location)]
+pub struct IncorrectDoNotRecommendLocation {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(passes_outer_crate_level_attr)]
 pub struct OuterCrateLevelAttr;
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 58f6fd2b006..b1b04c92a75 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -334,6 +334,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         self.r.field_names.insert(def_id, field_names);
     }
 
+    fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
+        let field_vis = vdata
+            .fields()
+            .iter()
+            .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span)))
+            .collect();
+        self.r.field_visibility_spans.insert(def_id, field_vis);
+    }
+
     fn insert_field_names_extern(&mut self, def_id: DefId) {
         let field_names =
             self.r.cstore().struct_field_names_untracked(def_id, self.r.session).collect();
@@ -737,6 +746,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
 
                 // Record field names for error reporting.
                 self.insert_field_names_local(def_id, vdata);
+                self.insert_field_visibilities_local(def_id, vdata);
 
                 // If this is a tuple or unit struct, define a name
                 // in the value namespace as well.
@@ -770,6 +780,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id.to_def_id());
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.visibilities.insert(ctor_def_id, ctor_vis);
+                    // We need the field visibility spans also for the constructor for E0603.
+                    self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata);
 
                     self.r
                         .struct_constructors
@@ -783,6 +795,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
 
                 // Record field names for error reporting.
                 self.insert_field_names_local(def_id, vdata);
+                self.insert_field_visibilities_local(def_id, vdata);
             }
 
             ItemKind::Trait(..) => {
@@ -1510,6 +1523,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
 
         // Record field names for error reporting.
         self.insert_field_names_local(def_id.to_def_id(), &variant.data);
+        self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data);
 
         visit::walk_variant(self, variant);
     }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7d62d67d64f..fb2aebbd18a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -6,7 +6,9 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{
+    pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
+};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
@@ -165,7 +167,7 @@ impl<'a> Resolver<'a> {
                 );
                 err.emit();
             } else if let Some((span, msg, sugg, appl)) = suggestion {
-                err.span_suggestion(span, msg, sugg, appl);
+                err.span_suggestion_verbose(span, msg, sugg, appl);
                 err.emit();
             } else if let [segment] = path.as_slice() && is_call {
                 err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
@@ -1604,6 +1606,16 @@ impl<'a> Resolver<'a> {
         err.span_label(ident.span, &format!("private {}", descr));
         if let Some(span) = ctor_fields_span {
             err.span_label(span, "a constructor is private if any of the fields is private");
+            if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) {
+                err.multipart_suggestion_verbose(
+                    &format!(
+                        "consider making the field{} publicly accessible",
+                        pluralize!(fields.len())
+                    ),
+                    fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
         }
 
         // Print the whole import chain to make it easier to see what happens.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 74522f18542..d92b046d0b9 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1451,6 +1451,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         .collect();
 
                     if non_visible_spans.len() > 0 {
+                        if let Some(fields) = self.r.field_visibility_spans.get(&def_id) {
+                            err.multipart_suggestion_verbose(
+                                &format!(
+                                    "consider making the field{} publicly accessible",
+                                    pluralize!(fields.len())
+                                ),
+                                fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+
                         let mut m: MultiSpan = non_visible_spans.clone().into();
                         non_visible_spans
                             .into_iter()
@@ -2054,7 +2065,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         path: &[Segment],
     ) -> Option<(Span, &'static str, String, Applicability)> {
         let (ident, span) = match path {
-            [segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => {
+            [segment]
+                if !segment.has_generic_args
+                    && segment.ident.name != kw::SelfUpper
+                    && segment.ident.name != kw::Dyn =>
+            {
                 (segment.ident.to_string(), segment.ident.span)
             }
             _ => return None,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 2182b736937..f950e4a9bee 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -881,6 +881,10 @@ pub struct Resolver<'a> {
     /// Used for hints during error reporting.
     field_names: FxHashMap<DefId, Vec<Spanned<Symbol>>>,
 
+    /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax.
+    /// Used for hints during error reporting.
+    field_visibility_spans: FxHashMap<DefId, Vec<Span>>,
+
     /// All imports known to succeed or fail.
     determined_imports: Vec<&'a Import<'a>>,
 
@@ -1133,7 +1137,7 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
     }
 }
 
-impl Resolver<'_> {
+impl<'a> Resolver<'a> {
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
         self.node_id_to_def_id.get(&node).copied()
     }
@@ -1190,6 +1194,10 @@ impl Resolver<'_> {
             self.cstore().item_generics_num_lifetimes(def_id, self.session)
         }
     }
+
+    pub fn sess(&self) -> &'a Session {
+        self.session
+    }
 }
 
 impl<'a> Resolver<'a> {
@@ -1268,6 +1276,7 @@ impl<'a> Resolver<'a> {
 
             has_self: FxHashSet::default(),
             field_names: FxHashMap::default(),
+            field_visibility_spans: FxHashMap::default(),
 
             determined_imports: Vec::new(),
             indeterminate_imports: Vec::new(),
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b062b43873b..7b5fd6cc2a8 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1411,6 +1411,8 @@ 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`)"),
+    log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
+        "add a backtrace along with logging"),
     ls: bool = (false, parse_bool, [UNTRACKED],
         "list the symbols defined by a library crate (default: no)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 5ce2577b63c..ae81d95e279 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -15,6 +15,6 @@ scoped-tls = "1.0"
 unicode-width = "0.1.4"
 cfg-if = "1.0"
 tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.10.0" }
+sha1 = "0.10.0"
 sha2 = "0.10.1"
 md5 = { package = "md-5", version = "0.10.0" }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fbb12701d96..706002f79b1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -498,6 +498,7 @@ symbols! {
         console,
         const_allocate,
         const_async_blocks,
+        const_closures,
         const_compare_raw_pointers,
         const_constructor,
         const_deallocate,
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index cb2a0c04c6a..d4f7ed31b89 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -149,7 +149,7 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
     match name {
         // Stable
         "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
-        | "system" => Ok(()),
+        | "system" | "efiapi" => Ok(()),
         "rust-intrinsic" => Err(AbiDisabled::Unstable {
             feature: sym::intrinsics,
             explain: "intrinsics are subject to change",
@@ -198,10 +198,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
             feature: sym::abi_avr_interrupt,
             explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
         }),
-        "efiapi" => Err(AbiDisabled::Unstable {
-            feature: sym::abi_efiapi,
-            explain: "efiapi ABI is experimental and subject to change",
-        }),
         "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
             feature: sym::abi_c_cmse_nonsecure_call,
             explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index 27c207528c7..ba9ee57d409 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         self.infcx.probe(|_| {
-            if a.is_ty_infer() || b.is_ty_infer() {
+            if a.is_ty_var() || b.is_ty_var() {
                 Ok(a)
             } else {
                 self.infcx.super_combine_tys(self, a, b).or_else(|e| {
@@ -71,10 +71,13 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
         a: ty::Const<'tcx>,
         b: ty::Const<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        if a == b {
-            return Ok(a);
-        }
-        relate::super_relate_consts(self, a, b) // could do something similar here for constants!
+        self.infcx.probe(|_| {
+            if a.is_ct_infer() || b.is_ct_infer() {
+                Ok(a)
+            } else {
+                relate::super_relate_consts(self, a, b) // could do something similar here for constants!
+            }
+        })
     }
 
     fn binders<T: Relate<'tcx>>(
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 20bede22c34..0c7ffb056cc 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2252,8 +2252,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     Ok(None) => {
                         let ambiguities =
                             ambiguity::recompute_applicable_impls(self.infcx, &obligation);
-                        let has_non_region_infer =
-                            trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
+                        let has_non_region_infer = trait_ref
+                            .skip_binder()
+                            .substs
+                            .types()
+                            .any(|t| !t.is_ty_or_numeric_infer());
                         // It doesn't make sense to talk about applicable impls if there are more
                         // than a handful of them.
                         if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 170c1673dbd..8c291d1595d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -255,18 +255,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters
         match *obligation.self_ty().skip_binder().kind() {
-            ty::Closure(_, closure_substs) => {
+            ty::Closure(def_id, closure_substs) => {
+                let is_const = self.tcx().is_const_fn_raw(def_id);
                 debug!(?kind, ?obligation, "assemble_unboxed_candidates");
                 match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         debug!(?closure_kind, "assemble_unboxed_candidates");
                         if closure_kind.extends(kind) {
-                            candidates.vec.push(ClosureCandidate);
+                            candidates.vec.push(ClosureCandidate { is_const });
                         }
                     }
                     None => {
                         debug!("assemble_unboxed_candidates: closure_kind not yet known");
-                        candidates.vec.push(ClosureCandidate);
+                        candidates.vec.push(ClosureCandidate { is_const });
                     }
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 15526b34ed2..a41d10f1043 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -84,7 +84,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Object(data)
             }
 
-            ClosureCandidate => {
+            ClosureCandidate { .. } => {
                 let vtable_closure = self.confirm_closure_candidate(obligation)?;
                 ImplSource::Closure(vtable_closure)
             }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2615e262282..305902af7c8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1365,15 +1365,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     // const param
                     ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
                     // const projection
-                    ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {}
+                    ProjectionCandidate(_, ty::BoundConstness::ConstIfConst)
                     // auto trait impl
-                    AutoImplCandidate => {}
+                    | AutoImplCandidate
                     // generator / future, this will raise error in other places
                     // or ignore error with const_async_blocks feature
-                    GeneratorCandidate => {}
-                    FutureCandidate => {}
+                    | GeneratorCandidate
+                    | FutureCandidate
                     // FnDef where the function is const
-                    FnPointerCandidate { is_const: true } => {}
+                    | FnPointerCandidate { is_const: true }
+                    | ConstDestructCandidate(_)
+                    | ClosureCandidate { is_const: true } => {}
+
                     FnPointerCandidate { is_const: false } => {
                         if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
                             // Trait methods are not seen as const unless the trait is implemented as const.
@@ -1382,7 +1385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             continue
                         }
                     }
-                    ConstDestructCandidate(_) => {}
+
                     _ => {
                         // reject all other types of candidates
                         continue;
@@ -1844,7 +1847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (
                 ParamCandidate(ref cand),
                 ImplCandidate(..)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
@@ -1863,7 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
             (
                 ImplCandidate(_)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
@@ -1894,7 +1897,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (
                 ObjectCandidate(_) | ProjectionCandidate(..),
                 ImplCandidate(..)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
@@ -1907,7 +1910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             (
                 ImplCandidate(..)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
@@ -1989,7 +1992,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // Everything else is ambiguous
             (
                 ImplCandidate(_)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
@@ -1999,7 +2002,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | BuiltinCandidate { has_nested: true }
                 | TraitAliasCandidate,
                 ImplCandidate(_)
-                | ClosureCandidate
+                | ClosureCandidate { .. }
                 | GeneratorCandidate
                 | FutureCandidate
                 | FnPointerCandidate { .. }
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 4583bc9a158..4583bc9a158 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index ebf5baa3c02..a7d6fec7d3d 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1234,17 +1234,23 @@ where
     F: ~const Destruct,
     K: ~const Destruct,
 {
-    const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
-        f: &mut F,
-        (v1, v2): (&T, &T),
-    ) -> Ordering
-    where
-        T: ~const Destruct,
-        K: ~const Destruct,
-    {
-        f(v1).cmp(&f(v2))
+    cfg_if! {
+        if #[cfg(bootstrap)] {
+            const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
+                f: &mut F,
+                (v1, v2): (&T, &T),
+            ) -> Ordering
+            where
+                T: ~const Destruct,
+                K: ~const Destruct,
+            {
+                f(v1).cmp(&f(v2))
+            }
+            min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
+        } else {
+            min_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
+        }
     }
-    min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
 }
 
 /// Compares and returns the maximum of two values.
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 51e6a76cea8..fa5073e3304 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -174,6 +174,11 @@ pub trait Write {
     /// This method should generally not be invoked manually, but rather through
     /// the [`write!`] macro itself.
     ///
+    /// # Errors
+    ///
+    /// This function will return an instance of [`Error`] on error. Please see
+    /// [write_str](Write::write_str) for details.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 99aaf798e41..a4a665d48d5 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -58,6 +58,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
               syntax `start..end` or the inclusive range syntax `start..=end`"
     ),
+    on(
+        _Self = "{float}",
+        note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
+              syntax `start..end` or the inclusive range syntax `start..=end`"
+    ),
     label = "`{Self}` is not an iterator",
     message = "`{Self}` is not an iterator"
 )]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index e898bca88e4..8790649abe6 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -191,6 +191,7 @@
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
+#![cfg_attr(not(bootstrap), feature(const_closures))]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 39462dca4ff..7cc00e3f8d1 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -652,13 +652,14 @@ impl<T> Option<T> {
     ///
     /// # Examples
     ///
-    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving
-    /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
-    /// so this technique uses `as_ref` to first take an `Option` to a reference
-    /// to the value inside the original.
+    /// Calculates the length of an <code>Option<[String]></code> as an <code>Option<[usize]></code>
+    /// without moving the [`String`]. The [`map`] method takes the `self` argument by value,
+    /// consuming the original, so this technique uses `as_ref` to first take an `Option` to a
+    /// reference to the value inside the original.
     ///
     /// [`map`]: Option::map
     /// [String]: ../../std/string/struct.String.html "String"
+    /// [`String`]: ../../std/string/struct.String.html "String"
     ///
     /// ```
     /// let text: Option<String> = Some("Hello, world!".to_string());
@@ -946,8 +947,8 @@ impl<T> Option<T> {
     ///
     /// # Examples
     ///
-    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming
-    /// the original:
+    /// Calculates the length of an <code>Option<[String]></code> as an
+    /// <code>Option<[usize]></code>, consuming the original:
     ///
     /// [String]: ../../std/string/struct.String.html "String"
     /// ```
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index edc68d6fae5..14367eb09bc 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1786,6 +1786,42 @@ impl<T> AtomicPtr<T> {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
     }
+
+    /// Returns a mutable pointer to the underlying pointer.
+    ///
+    /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+    /// This method is mostly useful for FFI, where the function signature may use
+    /// `*mut *mut T` instead of `&AtomicPtr<T>`.
+    ///
+    /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+    /// atomic types work with interior mutability. All modifications of an atomic change the value
+    /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+    /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+    /// restriction: operations on it must be atomic.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// #![feature(atomic_mut_ptr)]
+    //// use std::sync::atomic::AtomicPtr;
+    ///
+    /// extern "C" {
+    ///     fn my_atomic_op(arg: *mut *mut u32);
+    /// }
+    ///
+    /// let mut value = 17;
+    /// let atomic = AtomicPtr::new(&mut value);
+    ///
+    /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
+    /// unsafe {
+    ///     my_atomic_op(atomic.as_mut_ptr());
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
+    pub fn as_mut_ptr(&self) -> *mut *mut T {
+        self.p.get()
+    }
 }
 
 #[cfg(target_has_atomic_load_store = "8")]
@@ -2678,9 +2714,9 @@ macro_rules! atomic_int {
             #[doc = concat!("    fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")]
             /// }
             ///
-            #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")]
+            #[doc = concat!("let atomic = ", stringify!($atomic_type), "::new(1);")]
             ///
-            // SAFETY: Safe as long as `my_atomic_op` is atomic.
+            /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
             /// unsafe {
             ///     my_atomic_op(atomic.as_mut_ptr());
             /// }
diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs
index a783e187004..87585a8fcd0 100644
--- a/library/std/src/personality/dwarf/eh.rs
+++ b/library/std/src/personality/dwarf/eh.rs
@@ -84,7 +84,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
             let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
             let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
             let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
-            let cs_action = reader.read_uleb128();
+            let cs_action_entry = reader.read_uleb128();
             // Callsite table is sorted by cs_start, so if we've passed the ip, we
             // may stop searching.
             if ip < func_start + cs_start {
@@ -95,7 +95,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
                     return Ok(EHAction::None);
                 } else {
                     let lpad = lpad_base + cs_lpad;
-                    return Ok(interpret_cs_action(cs_action, lpad));
+                    return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad));
                 }
             }
         }
@@ -113,26 +113,39 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
         let mut idx = ip;
         loop {
             let cs_lpad = reader.read_uleb128();
-            let cs_action = reader.read_uleb128();
+            let cs_action_entry = reader.read_uleb128();
             idx -= 1;
             if idx == 0 {
                 // Can never have null landing pad for sjlj -- that would have
                 // been indicated by a -1 call site index.
                 let lpad = (cs_lpad + 1) as usize;
-                return Ok(interpret_cs_action(cs_action, lpad));
+                return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad));
             }
         }
     }
 }
 
-fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
-    if cs_action == 0 {
-        // If cs_action is 0 then this is a cleanup (Drop::drop). We run these
+unsafe fn interpret_cs_action(
+    action_table: *mut u8,
+    cs_action_entry: u64,
+    lpad: usize,
+) -> EHAction {
+    if cs_action_entry == 0 {
+        // If cs_action_entry is 0 then this is a cleanup (Drop::drop). We run these
         // for both Rust panics and foreign exceptions.
         EHAction::Cleanup(lpad)
     } else {
-        // Stop unwinding Rust panics at catch_unwind.
-        EHAction::Catch(lpad)
+        // If lpad != 0 and cs_action_entry != 0, we have to check ttype_index.
+        // If ttype_index == 0 under the condition, we take cleanup action.
+        let action_record = (action_table as *mut u8).offset(cs_action_entry as isize - 1);
+        let mut action_reader = DwarfReader::new(action_record);
+        let ttype_index = action_reader.read_sleb128();
+        if ttype_index == 0 {
+            EHAction::Cleanup(lpad)
+        } else {
+            // Stop unwinding Rust panics at catch_unwind.
+            EHAction::Catch(lpad)
+        }
     }
 }
 
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index f71edc6c525..c1e3e48b044 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -168,7 +168,7 @@ impl<T> Channel<T> {
                         return true;
                     }
                     Err(_) => {
-                        backoff.spin();
+                        backoff.spin_light();
                         tail = self.tail.load(Ordering::Relaxed);
                     }
                 }
@@ -182,11 +182,11 @@ impl<T> Channel<T> {
                     return false;
                 }
 
-                backoff.spin();
+                backoff.spin_light();
                 tail = self.tail.load(Ordering::Relaxed);
             } else {
                 // Snooze because we need to wait for the stamp to get updated.
-                backoff.snooze();
+                backoff.spin_heavy();
                 tail = self.tail.load(Ordering::Relaxed);
             }
         }
@@ -251,7 +251,7 @@ impl<T> Channel<T> {
                         return true;
                     }
                     Err(_) => {
-                        backoff.spin();
+                        backoff.spin_light();
                         head = self.head.load(Ordering::Relaxed);
                     }
                 }
@@ -273,11 +273,11 @@ impl<T> Channel<T> {
                     }
                 }
 
-                backoff.spin();
+                backoff.spin_light();
                 head = self.head.load(Ordering::Relaxed);
             } else {
                 // Snooze because we need to wait for the stamp to get updated.
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.load(Ordering::Relaxed);
             }
         }
@@ -330,7 +330,7 @@ impl<T> Channel<T> {
                 if backoff.is_completed() {
                     break;
                 } else {
-                    backoff.spin();
+                    backoff.spin_light();
                 }
             }
 
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
index 2d5b2fb3b23..ec6c0726ac7 100644
--- a/library/std/src/sync/mpmc/list.rs
+++ b/library/std/src/sync/mpmc/list.rs
@@ -46,7 +46,7 @@ impl<T> Slot<T> {
     fn wait_write(&self) {
         let backoff = Backoff::new();
         while self.state.load(Ordering::Acquire) & WRITE == 0 {
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 }
@@ -82,7 +82,7 @@ impl<T> Block<T> {
             if !next.is_null() {
                 return next;
             }
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 
@@ -191,7 +191,7 @@ impl<T> Channel<T> {
 
             // If we reached the end of the block, wait until the next one is installed.
             if offset == BLOCK_CAP {
-                backoff.snooze();
+                backoff.spin_heavy();
                 tail = self.tail.index.load(Ordering::Acquire);
                 block = self.tail.block.load(Ordering::Acquire);
                 continue;
@@ -247,7 +247,7 @@ impl<T> Channel<T> {
                     return true;
                 },
                 Err(_) => {
-                    backoff.spin();
+                    backoff.spin_light();
                     tail = self.tail.index.load(Ordering::Acquire);
                     block = self.tail.block.load(Ordering::Acquire);
                 }
@@ -286,7 +286,7 @@ impl<T> Channel<T> {
 
             // If we reached the end of the block, wait until the next one is installed.
             if offset == BLOCK_CAP {
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.index.load(Ordering::Acquire);
                 block = self.head.block.load(Ordering::Acquire);
                 continue;
@@ -320,7 +320,7 @@ impl<T> Channel<T> {
             // The block can be null here only if the first message is being sent into the channel.
             // In that case, just wait until it gets initialized.
             if block.is_null() {
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.index.load(Ordering::Acquire);
                 block = self.head.block.load(Ordering::Acquire);
                 continue;
@@ -351,7 +351,7 @@ impl<T> Channel<T> {
                     return true;
                 },
                 Err(_) => {
-                    backoff.spin();
+                    backoff.spin_light();
                     head = self.head.index.load(Ordering::Acquire);
                     block = self.head.block.load(Ordering::Acquire);
                 }
@@ -542,7 +542,7 @@ impl<T> Channel<T> {
             // New updates to tail will be rejected by MARK_BIT and aborted unless it's
             // at boundary. We need to wait for the updates take affect otherwise there
             // can be memory leaks.
-            backoff.snooze();
+            backoff.spin_heavy();
             tail = self.tail.index.load(Ordering::Acquire);
         }
 
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index cef99c58843..7a602cecd3b 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -43,7 +43,7 @@ mod zero;
 use crate::fmt;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
-use error::*;
+pub use error::*;
 
 /// Creates a channel of unbounded capacity.
 ///
diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs
index e030c55ce8f..cfe42750d52 100644
--- a/library/std/src/sync/mpmc/utils.rs
+++ b/library/std/src/sync/mpmc/utils.rs
@@ -91,9 +91,8 @@ impl<T> DerefMut for CachePadded<T> {
 }
 
 const SPIN_LIMIT: u32 = 6;
-const YIELD_LIMIT: u32 = 10;
 
-/// Performs exponential backoff in spin loops.
+/// Performs quadratic backoff in spin loops.
 pub struct Backoff {
     step: Cell<u32>,
 }
@@ -104,25 +103,27 @@ impl Backoff {
         Backoff { step: Cell::new(0) }
     }
 
-    /// Backs off in a lock-free loop.
+    /// Backs off using lightweight spinning.
     ///
-    /// This method should be used when we need to retry an operation because another thread made
-    /// progress.
+    /// This method should be used for:
+    ///     - Retrying an operation because another thread made progress. i.e. on CAS failure.
+    ///     - Waiting for an operation to complete by spinning optimistically for a few iterations
+    ///     before falling back to parking the thread (see `Backoff::is_completed`).
     #[inline]
-    pub fn spin(&self) {
+    pub fn spin_light(&self) {
         let step = self.step.get().min(SPIN_LIMIT);
         for _ in 0..step.pow(2) {
             crate::hint::spin_loop();
         }
 
-        if self.step.get() <= SPIN_LIMIT {
-            self.step.set(self.step.get() + 1);
-        }
+        self.step.set(self.step.get() + 1);
     }
 
-    /// Backs off in a blocking loop.
+    /// Backs off using heavyweight spinning.
+    ///
+    /// This method should be used in blocking loops where parking the thread is not an option.
     #[inline]
-    pub fn snooze(&self) {
+    pub fn spin_heavy(&self) {
         if self.step.get() <= SPIN_LIMIT {
             for _ in 0..self.step.get().pow(2) {
                 crate::hint::spin_loop()
@@ -131,14 +132,12 @@ impl Backoff {
             crate::thread::yield_now();
         }
 
-        if self.step.get() <= YIELD_LIMIT {
-            self.step.set(self.step.get() + 1);
-        }
+        self.step.set(self.step.get() + 1);
     }
 
-    /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
+    /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
     #[inline]
     pub fn is_completed(&self) -> bool {
-        self.step.get() > YIELD_LIMIT
+        self.step.get() > SPIN_LIMIT
     }
 }
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index fccd6c29a7e..33f768dcbe9 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -57,7 +57,7 @@ impl<T> Packet<T> {
     fn wait_ready(&self) {
         let backoff = Backoff::new();
         while !self.ready.load(Ordering::Acquire) {
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 }
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index adb488d4378..6e3c28f10bb 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -738,6 +738,15 @@ impl<T> SyncSender<T> {
     pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
         self.inner.try_send(t)
     }
+
+    // Attempts to send for a value on this receiver, returning an error if the
+    // corresponding channel has hung up, or if it waits more than `timeout`.
+    //
+    // This method is currently private and only used for tests.
+    #[allow(unused)]
+    fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> {
+        self.inner.send_timeout(t, timeout)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
index 63c79436974..9d2f92ffc9b 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/src/sync/mpsc/sync_tests.rs
@@ -1,5 +1,6 @@
 use super::*;
 use crate::env;
+use crate::sync::mpmc::SendTimeoutError;
 use crate::thread;
 use crate::time::Duration;
 
@@ -42,6 +43,13 @@ fn recv_timeout() {
 }
 
 #[test]
+fn send_timeout() {
+    let (tx, _rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(()));
+    assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1)));
+}
+
+#[test]
 fn smoke_threads() {
     let (tx, rx) = sync_channel::<i32>(0);
     let _t = thread::spawn(move || {
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index adf6bb4b377..d5bc76eeb23 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -45,6 +45,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
            # Build both public and internal documentation.
+           RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
            RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
            /scripts/validate-toolstate.sh && \
            /scripts/validate-error-codes.sh && \
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index bff01d7cb7c..45db3bb9b00 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -261,7 +261,7 @@ typo mistakes for some common attributes.
 
 ## `invalid_html_tags`
 
-This lint is **allowed by default** and is **nightly-only**. It detects unclosed
+This lint **warns by default**. It detects unclosed
 or invalid HTML tags. For example:
 
 ```rust
diff --git a/src/doc/unstable-book/src/language-features/abi-efiapi.md b/src/doc/unstable-book/src/language-features/abi-efiapi.md
deleted file mode 100644
index b492da88474..00000000000
--- a/src/doc/unstable-book/src/language-features/abi-efiapi.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# `abi_efiapi`
-
-The tracking issue for this feature is: [#65815]
-
-[#65815]: https://github.com/rust-lang/rust/issues/65815
-
-------------------------
-
-The `efiapi` calling convention can be used for defining a function with
-an ABI compatible with the UEFI Interfaces as defined in the [UEFI
-Specification].
-
-Example:
-
-```rust,ignore (not-all-targets-support-uefi)
-#![feature(abi_efiapi)]
-
-extern "efiapi" { fn f1(); }
-
-extern "efiapi" fn f2() { todo!() }
-```
-
-[UEFI Specification]: https://uefi.org/specs/UEFI/2.10/
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5c63efef717..87de41fde63 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -676,7 +676,8 @@ impl Item {
         }
         let header = match *self.kind {
             ItemKind::ForeignFunctionItem(_) => {
-                let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi();
+                let def_id = self.item_id.as_def_id().unwrap();
+                let abi = tcx.fn_sig(def_id).abi();
                 hir::FnHeader {
                     unsafety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap())
@@ -684,7 +685,14 @@ impl Item {
                         hir::Unsafety::Unsafe
                     },
                     abi,
-                    constness: hir::Constness::NotConst,
+                    constness: if abi == Abi::RustIntrinsic
+                        && tcx.is_const_fn(def_id)
+                        && is_unstable_const_fn(tcx, def_id).is_none()
+                    {
+                        hir::Constness::Const
+                    } else {
+                        hir::Constness::NotConst
+                    },
                     asyncness: hir::IsAsync::NotAsync,
                 }
             }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 81d9c46447a..d1b6d470e86 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -115,9 +115,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
     let (tests, unused_extern_reports, compiling_test_count) =
         interface::run_compiler(config, |compiler| {
             compiler.enter(|queries| {
-                let mut global_ctxt = queries.global_ctxt()?.take();
-
-                let collector = global_ctxt.enter(|tcx| {
+                let collector = queries.global_ctxt()?.enter(|tcx| {
                     let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
 
                     let opts = scrape_test_config(crate_attrs);
@@ -156,9 +154,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
 
                 let unused_extern_reports = collector.unused_extern_reports.clone();
                 let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
-                let ret: Result<_, ErrorGuaranteed> =
-                    Ok((collector.tests, unused_extern_reports, compiling_test_count));
-                ret
+                Ok((collector.tests, unused_extern_reports, compiling_test_count))
             })
         })?;
 
@@ -1225,7 +1221,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
     ) {
         let ast_attrs = self.tcx.hir().attrs(hir_id);
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
-            if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
+            if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) {
                 return;
             }
         }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 8bccf68029a..19f7b2270a7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -513,7 +513,7 @@ fn document_full_inner(
         debug!("Doc block: =====\n{}\n=====", s);
         if is_collapsible {
             w.write_str(
-                "<details class=\"rustdoc-toggle top-doc\" open>\
+                "<details class=\"toggle top-doc\" open>\
                 <summary class=\"hideme\">\
                      <span>Expand description</span>\
                 </summary>",
@@ -1514,7 +1514,7 @@ fn render_impl(
         let toggled = !doc_buffer.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
+            write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
         }
         match &*item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
@@ -1730,7 +1730,7 @@ fn render_impl(
             close_tags.insert_str(0, "</details>");
             write!(
                 w,
-                "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
+                "<details class=\"toggle implementors-toggle\"{}>",
                 if rendering_params.toggle_open_by_default { " open" } else { "" }
             );
             write!(w, "<summary>")
@@ -2999,7 +2999,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
     if it.peek().is_some() {
         write!(
             w,
-            "<details class=\"rustdoc-toggle more-examples-toggle\">\
+            "<details class=\"toggle more-examples-toggle\">\
                   <summary class=\"hideme\">\
                      <span>More examples</span>\
                   </summary>\
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c16d6477fc3..d6e57decdcf 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool {
 fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
     write!(
         w,
-        "<details class=\"rustdoc-toggle type-contents-toggle\">\
+        "<details class=\"toggle type-contents-toggle\">\
             <summary class=\"hideme\">\
                 <span>Show {}</span>\
             </summary>",
@@ -733,7 +733,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
         let toggled = !content.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"rustdoc-toggle{method_toggle_class}\" open><summary>");
+            write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
         }
         write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
         render_rightside(w, cx, m, t, RenderMode::Normal);
@@ -1840,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
     if item.is_non_exhaustive() {
         write!(
             w,
-            "<details class=\"rustdoc-toggle non-exhaustive\">\
+            "<details class=\"toggle non-exhaustive\">\
                  <summary class=\"hideme\"><span>{}</span></summary>\
                  <div class=\"docblock\">",
             {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index b2fa6e82acc..8773bd2f114 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -317,7 +317,7 @@ main {
 	margin-right: auto;
 }
 
-details:not(.rustdoc-toggle) summary {
+details:not(.toggle) summary {
 	margin-bottom: .6em;
 }
 
@@ -1401,7 +1401,7 @@ details.dir-entry a {
 	Unfortunately we can't yet specify contain: content or contain: strict
 	because the [-]/[+] toggles extend past the boundaries of the <details>
 	https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
-details.rustdoc-toggle {
+details.toggle {
 	contain: layout;
 	position: relative;
 }
@@ -1409,26 +1409,26 @@ details.rustdoc-toggle {
 /* The hideme class is used on summary tags that contain a span with
 	placeholder text shown only when the toggle is closed. For instance,
 	"Expand description" or "Show methods". */
-details.rustdoc-toggle > summary.hideme {
+details.toggle > summary.hideme {
 	cursor: pointer;
 	font-size: 1rem;
 }
 
-details.rustdoc-toggle > summary {
+details.toggle > summary {
 	list-style: none;
 	/* focus outline is shown on `::before` instead of this */
 	outline: none;
 }
-details.rustdoc-toggle > summary::-webkit-details-marker,
-details.rustdoc-toggle > summary::marker {
+details.toggle > summary::-webkit-details-marker,
+details.toggle > summary::marker {
 	display: none;
 }
 
-details.rustdoc-toggle > summary.hideme > span {
+details.toggle > summary.hideme > span {
 	margin-left: 9px;
 }
 
-details.rustdoc-toggle > summary::before {
+details.toggle > summary::before {
 	background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
 	content: "";
 	cursor: pointer;
@@ -1440,14 +1440,14 @@ details.rustdoc-toggle > summary::before {
 	filter: var(--toggle-filter);
 }
 
-details.rustdoc-toggle > summary.hideme > span,
+details.toggle > summary.hideme > span,
 .more-examples-toggle summary, .more-examples-toggle .hide-more {
 	color: var(--toggles-color);
 }
 
 /* Screen readers see the text version at the end the line.
 	Visual readers see the icon at the start of the line, but small and transparent. */
-details.rustdoc-toggle > summary::after {
+details.toggle > summary::after {
 	content: "Expand";
 	overflow: hidden;
 	width: 0;
@@ -1455,17 +1455,17 @@ details.rustdoc-toggle > summary::after {
 	position: absolute;
 }
 
-details.rustdoc-toggle > summary.hideme::after {
+details.toggle > summary.hideme::after {
 	/* "hideme" toggles already have a description when they're contracted */
 	content: "";
 }
 
-details.rustdoc-toggle > summary:focus::before,
-details.rustdoc-toggle > summary:hover::before {
+details.toggle > summary:focus::before,
+details.toggle > summary:hover::before {
 	opacity: 1;
 }
 
-details.rustdoc-toggle > summary:focus-visible::before {
+details.toggle > summary:focus-visible::before {
 	/* The SVG is black, and gets turned white using a filter in the dark themes.
 	   Do the same with the outline.
 	   The dotted 1px style is copied from Firefox's focus ring style.
@@ -1478,17 +1478,17 @@ details.non-exhaustive {
 	margin-bottom: 8px;
 }
 
-details.rustdoc-toggle > summary.hideme::before {
+details.toggle > summary.hideme::before {
 	position: relative;
 }
 
-details.rustdoc-toggle > summary:not(.hideme)::before {
+details.toggle > summary:not(.hideme)::before {
 	position: absolute;
 	left: -24px;
 	top: 4px;
 }
 
-.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
+.impl-items > details.toggle > summary:not(.hideme)::before {
 	position: absolute;
 	left: -24px;
 }
@@ -1498,19 +1498,19 @@ details.rustdoc-toggle > summary:not(.hideme)::before {
 	affect the layout of the items to its right. To do that, we use
 	absolute positioning. Note that we also set position: relative
 	on the parent <details> to make this work properly. */
-details.rustdoc-toggle[open] > summary.hideme {
+details.toggle[open] > summary.hideme {
 	position: absolute;
 }
 
-details.rustdoc-toggle[open] > summary.hideme > span {
+details.toggle[open] > summary.hideme > span {
 	display: none;
 }
 
-details.rustdoc-toggle[open] > summary::before {
+details.toggle[open] > summary::before {
 	background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
 }
 
-details.rustdoc-toggle[open] > summary::after {
+details.toggle[open] > summary::after {
 	content: "Collapse";
 }
 
@@ -1660,8 +1660,8 @@ in storage.js
 		display: block;
 	}
 
-	#main-content > details.rustdoc-toggle > summary::before,
-	#main-content > div > details.rustdoc-toggle > summary::before {
+	#main-content > details.toggle > summary::before,
+	#main-content > div > details.toggle > summary::before {
 		left: -11px;
 	}
 
@@ -1715,12 +1715,12 @@ in storage.js
 	}
 
 	/* Position of the "[-]" element. */
-	details.rustdoc-toggle:not(.top-doc) > summary {
+	details.toggle:not(.top-doc) > summary {
 		margin-left: 10px;
 	}
-	.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
-	#main-content > details.rustdoc-toggle:not(.top-doc) > summary::before,
-	#main-content > div > details.rustdoc-toggle > summary::before {
+	.impl-items > details.toggle > summary:not(.hideme)::before,
+	#main-content > details.toggle:not(.top-doc) > summary::before,
+	#main-content > div > details.toggle > summary::before {
 		left: -11px;
 	}
 
@@ -1753,8 +1753,8 @@ in storage.js
 
 @media print {
 	nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
-	details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
-	details.rustdoc-toggle.top-doc > summary {
+	details.toggle[open] > summary::before, details.toggle > summary::before,
+	details.toggle.top-doc > summary {
 		display: none;
 	}
 
@@ -1796,24 +1796,24 @@ in storage.js
 .impl,
 #implementors-list > .docblock,
 .impl-items > section,
-.impl-items > .rustdoc-toggle > summary,
+.impl-items > .toggle > summary,
 .methods > section,
-.methods > .rustdoc-toggle > summary
+.methods > .toggle > summary
 {
 	margin-bottom: 0.75em;
 }
 
 .variants > .docblock,
 .implementors-toggle > .docblock,
-.impl-items > .rustdoc-toggle[open]:not(:last-child),
-.methods > .rustdoc-toggle[open]:not(:last-child),
+.impl-items > .toggle[open]:not(:last-child),
+.methods > .toggle[open]:not(:last-child),
 .implementors-toggle[open]:not(:last-child) {
 	margin-bottom: 2em;
 }
 
-#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
+#trait-implementations-list .impl-items > .toggle:not(:last-child),
+#synthetic-implementations-list .impl-items > .toggle:not(:last-child),
+#blanket-implementations-list .impl-items > .toggle:not(:last-child) {
 	margin-bottom: 1em;
 }
 
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 875a260c811..91419093147 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -9,7 +9,7 @@
 }
 
 .setting-line .radio-line input,
-.setting-line .toggle input {
+.setting-line .settings-toggle input {
 	margin-right: 0.3em;
 	height: 1.2rem;
 	width: 1.2rem;
@@ -22,14 +22,14 @@
 .setting-line .radio-line input {
 	border-radius: 50%;
 }
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
 	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-line .radio-line input + span,
-.setting-line .toggle span {
+.setting-line .settings-toggle span {
 	padding-bottom: 1px;
 }
 
@@ -50,7 +50,7 @@
 	margin-left: 0.5em;
 }
 
-.toggle {
+.settings-toggle {
 	position: relative;
 	width: 100%;
 	margin-right: 20px;
@@ -67,11 +67,11 @@
 	box-shadow: inset 0 0 0 3px var(--main-background-color);
 	background-color: var(--settings-input-color);
 }
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
 	background-color: var(--settings-input-color);
 }
 .setting-line .radio-line input:focus,
-.setting-line .toggle input:focus {
+.setting-line .settings-toggle input:focus {
 	box-shadow: 0 0 1px 1px var(--settings-input-color);
 }
 /* In here we combine both `:focus` and `:checked` properties. */
@@ -80,6 +80,6 @@
 		0 0 2px 2px var(--settings-input-color);
 }
 .setting-line .radio-line input:hover,
-.setting-line .toggle input:hover {
+.setting-line .settings-toggle 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 51aee8e7c89..b05151f39b8 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -620,7 +620,7 @@ function loadCss(cssUrl) {
     function expandAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         removeClass(innerToggle, "will-expand");
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
                 e.open = true;
             }
@@ -632,7 +632,7 @@ function loadCss(cssUrl) {
     function collapseAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         addClass(innerToggle, "will-expand");
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (e.parentNode.id !== "implementations-list" ||
                 (!hasClass(e, "implementors-toggle") &&
                  !hasClass(e, "type-contents-toggle"))
@@ -680,7 +680,7 @@ function loadCss(cssUrl) {
             setImplementorsTogglesOpen("blanket-implementations-list", false);
         }
 
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
             }
@@ -823,7 +823,7 @@ function loadCss(cssUrl) {
         });
     });
 
-    onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => {
+    onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
         el.addEventListener("click", e => {
             if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
                 e.preventDefault();
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 589bfc79360..9ed8f63610f 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -150,10 +150,10 @@
                 });
                 output += "</div></div>";
             } else {
-                // This is a toggle.
+                // This is a checkbox toggle.
                 const checked = setting["default"] === true ? " checked" : "";
                 output += `\
-<label class="toggle">\
+<label class="settings-toggle">\
     <input type="checkbox" id="${js_data_name}"${checked}>\
     <span class="label">${setting_name}</span>\
 </label>`;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ef1d7da5a34..86454e1f2eb 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -772,7 +772,6 @@ fn main_args(at_args: &[String]) -> MainResult {
     let crate_version = options.crate_version.clone();
 
     let output_format = options.output_format;
-    let externs = options.externs.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
@@ -800,13 +799,12 @@ fn main_args(at_args: &[String]) -> MainResult {
             // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
             // two copies because one of the copies can be modified after `TyCtxt` construction.
             let (resolver, resolver_caches) = {
-                let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
+                let expansion = abort_on_err(queries.expansion(), sess);
+                let (krate, resolver, _) = &*expansion.borrow();
                 let resolver_caches = resolver.borrow_mut().access(|resolver| {
                     collect_intra_doc_links::early_resolve_intra_doc_links(
                         resolver,
-                        sess,
                         krate,
-                        externs,
                         render_options.document_private,
                     )
                 });
@@ -817,7 +815,7 @@ fn main_args(at_args: &[String]) -> MainResult {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
-            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut();
+            let global_ctxt = abort_on_err(queries.global_ctxt(), sess);
 
             global_ctxt.enter(|tcx| {
                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 1b373cfe5bb..42677bd8497 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -12,8 +12,6 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, CRATE_DEF_ID};
 use rustc_hir::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
-use rustc_session::config::Externs;
-use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Symbol, SyntaxContext};
 
@@ -22,16 +20,13 @@ use std::mem;
 
 pub(crate) fn early_resolve_intra_doc_links(
     resolver: &mut Resolver<'_>,
-    sess: &Session,
     krate: &ast::Crate,
-    externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
     let parent_scope =
         ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
-        sess,
         parent_scope,
         visited_mods: Default::default(),
         markdown_links: Default::default(),
@@ -52,7 +47,9 @@ pub(crate) fn early_resolve_intra_doc_links(
     // the known necessary crates. Load them all unconditionally until we find a way to fix this.
     // DO NOT REMOVE THIS without first testing on the reproducer in
     // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
-    for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
+    for (extern_name, _) in
+        link_resolver.resolver.sess().opts.externs.iter().filter(|(_, entry)| entry.add_prelude)
+    {
         link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
     }
 
@@ -73,7 +70,6 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
 
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
-    sess: &'r Session,
     parent_scope: ParentScope<'ra>,
     visited_mods: DefIdSet,
     markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
@@ -166,7 +162,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
     fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
         self.resolve_doc_links_extern_outer_fixme(def_id, def_id);
         let assoc_item_def_ids = Vec::from_iter(
-            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.resolver.sess()),
         );
         for assoc_def_id in assoc_item_def_ids {
             if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public()
@@ -191,7 +187,9 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let attrs = Vec::from_iter(
+            self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+        );
         let parent_scope = ParentScope::module(
             self.resolver.get_nearest_non_block_module(
                 self.resolver.opt_parent(scope_id).unwrap_or(scope_id),
@@ -205,7 +203,9 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let attrs = Vec::from_iter(
+            self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+        );
         let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver);
         self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
     }
@@ -321,7 +321,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
                         let field_def_ids = Vec::from_iter(
                             self.resolver
                                 .cstore()
-                                .associated_item_def_ids_untracked(def_id, self.sess),
+                                .associated_item_def_ids_untracked(def_id, self.resolver.sess()),
                         );
                         for field_def_id in field_def_ids {
                             self.resolve_doc_links_extern_outer(field_def_id, scope_id);
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index 3bac5a8e5d7..4c992e94833 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -12,5 +12,6 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass {
 };
 
 pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
-    ImportStripper { tcx: cx.tcx }.fold_crate(krate)
+    let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
+    ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(krate)
 }
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index 8fc42462de9..bb6dccb7c94 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -28,7 +28,8 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
             is_json_output,
             tcx: cx.tcx,
         };
-        krate = ImportStripper { tcx: cx.tcx }.fold_crate(stripper.fold_crate(krate));
+        krate =
+            ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(stripper.fold_crate(krate));
     }
 
     // strip all impls referencing private items
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index f8a0d77538d..048ed264623 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -97,17 +97,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             }
 
             // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem { .. } => {}
-            clean::ImportItem(ref imp) => {
-                // Because json doesn't inline imports from private modules, we need to mark
-                // the imported item as retained so it's impls won't be stripped.
-                //
-                // FIXME: Is it necessary to check for json output here: See
-                // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215
-                if let Some(did) = imp.source.did && self.is_json_output {
-                    self.retained.insert(did.into());
-                }
-            }
+            clean::ExternCrateItem { .. } | clean::ImportItem(_) => {}
 
             clean::ImplItem(..) => {}
 
@@ -243,12 +233,25 @@ impl<'a> DocFolder for ImplStripper<'a, '_> {
 /// This stripper discards all private import statements (`use`, `extern crate`)
 pub(crate) struct ImportStripper<'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
+    pub(crate) is_json_output: bool,
+}
+
+impl<'tcx> ImportStripper<'tcx> {
+    fn import_should_be_hidden(&self, i: &Item, imp: &clean::Import) -> bool {
+        if self.is_json_output {
+            // FIXME: This should be handled the same way as for HTML output.
+            imp.imported_item_is_doc_hidden(self.tcx)
+        } else {
+            i.attrs.lists(sym::doc).has_word(sym::hidden)
+        }
+    }
 }
 
 impl<'tcx> DocFolder for ImportStripper<'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match *i.kind {
-            clean::ImportItem(imp) if imp.imported_item_is_doc_hidden(self.tcx) => None,
+            clean::ImportItem(imp) if self.import_should_be_hidden(&i, &imp) => None,
+            clean::ImportItem(_) if i.attrs.lists(sym::doc).has_word(sym::hidden) => None,
             clean::ExternCrateItem { .. } | clean::ImportItem(..)
                 if i.visibility(self.tcx) != Some(Visibility::Public) =>
             {
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 6ff189fc859..798782340ee 100644
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -17,6 +17,13 @@ test "$sysroot" = $desired_sysroot
 sysroot=$(SYSROOT=$desired_sysroot ./target/debug/clippy-driver --print sysroot)
 test "$sysroot" = $desired_sysroot
 
+# Check that the --sysroot argument is only passed once (SYSROOT is ignored)
+(
+    cd rustc_tools_util
+    touch src/lib.rs
+    SYSROOT=/tmp RUSTFLAGS="--sysroot=$(rustc --print sysroot)" ../target/debug/cargo-clippy clippy --verbose
+)
+
 # Make sure this isn't set - clippy-driver should cope without it
 unset CARGO_MANIFEST_DIR
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 02f3188f8be..8e31e8f0d98 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4137,6 +4137,7 @@ Released 2018-09-13
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
+[`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq
 [`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
 [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
diff --git a/src/tools/clippy/book/src/installation.md b/src/tools/clippy/book/src/installation.md
index b2a28d0be62..cce888b17d4 100644
--- a/src/tools/clippy/book/src/installation.md
+++ b/src/tools/clippy/book/src/installation.md
@@ -1,6 +1,6 @@
 # Installation
 
-If you're using `rustup` to install and manage you're Rust toolchains, Clippy is
+If you're using `rustup` to install and manage your Rust toolchains, Clippy is
 usually **already installed**. In that case you can skip this chapter and go to
 the [Usage] chapter.
 
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 80bb83af43b..e70488165b9 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -5,6 +5,9 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
+// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
 extern crate rustc_lexer;
 
 use std::path::PathBuf;
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 0710ac0bb0a..751c262673b 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -472,7 +472,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe
 
 fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem], attr: &'_ Attribute) {
     // Check for the feature
-    if !cx.tcx.sess.features_untracked().lint_reasons {
+    if !cx.tcx.features().lint_reasons {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 91900542af8..9d98a6bab71 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -8,7 +8,7 @@ use rustc_hir::{
     Block, Expr, ExprKind, Local, Node, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
+use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
@@ -59,7 +59,7 @@ impl LateLintPass<'_> for BoxDefault {
                 if is_plain_default(arg_path) || given_type(cx, expr) {
                     "Box::default()".into()
                 } else {
-                    format!("Box::<{arg_ty}>::default()")
+                    with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
                 },
                 Applicability::MachineApplicable
             );
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 0e3d9317590..f10c35cde52 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -525,7 +525,11 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
             .iter()
             .filter(|&&(_, name)| !name.as_str().starts_with('_'))
             .any(|&(_, name)| {
-                let mut walker = ContainsName { name, result: false };
+                let mut walker = ContainsName {
+                    name,
+                    result: false,
+                    cx,
+                };
 
                 // Scan block
                 block
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index fe9f4f9ae3c..799e71e847a 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -10,11 +10,11 @@ use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of dbg!() macro.
+    /// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro.
     ///
     /// ### Why is this bad?
-    /// `dbg!` macro is intended as a debugging tool. It
-    /// should not be in version control.
+    /// The `dbg!` macro is intended as a debugging tool. It should not be present in released
+    /// software or committed to a version control system.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -91,8 +91,8 @@ impl LateLintPass<'_> for DbgMacro {
                 cx,
                 DBG_MACRO,
                 macro_call.span,
-                "`dbg!` macro is intended as a debugging tool",
-                "ensure to avoid having uses of it in version control",
+                "the `dbg!` macro is intended as a debugging tool",
+                "remove the invocation before committing it to a version control system",
                 suggestion,
                 applicability,
             );
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 2982460c9cf..91ca73633f0 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -111,7 +111,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::dereference::NEEDLESS_BORROW_INFO,
     crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
     crate::derivable_impls::DERIVABLE_IMPLS_INFO,
-    crate::derive::DERIVE_HASH_XOR_EQ_INFO,
+    crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO,
     crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
     crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
     crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 7f937de1dd3..a04693f4637 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -11,6 +11,7 @@ use rustc_hir::def::Res;
 use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -98,9 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             if let ty::Adt(def, ..) = expr_ty.kind();
             if !is_from_proc_macro(cx, expr);
             then {
-                // TODO: Work out a way to put "whatever the imported way of referencing
-                // this type in this file" rather than a fully-qualified type.
-                let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did()));
+                let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did())));
                 span_lint_and_sugg(
                     cx,
                     DEFAULT_TRAIT_ACCESS,
@@ -170,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 // find out if and which field was set by this `consecutive_statement`
                 if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
                     // interrupt and cancel lint if assign_rhs references the original binding
-                    if contains_name(binding_name, assign_rhs) {
+                    if contains_name(binding_name, assign_rhs, cx) {
                         cancel_lint = true;
                         break;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index f327c9a71b3..05f2b92c037 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
             possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
         }
         let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
-        // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
-        // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
-        // borrower of itself. See the comment in that method for an explanation as to why.
-        possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
+        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
+        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
+        // itself. See the comment in that method for an explanation as to why.
+        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
             && used_exactly_once(mir, place.local).unwrap_or(false)
     } else {
         false
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index ae8f6b79449..bc18e2e5ed5 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -1,12 +1,15 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::indent_of;
 use clippy_utils::{is_default_equivalent, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{
-    def::{DefKind, Res},
-    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
+    def::{CtorKind, CtorOf, DefKind, Res},
+    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_middle::ty::{AdtDef, DefIdTree};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
 declare_clippy_lint! {
@@ -51,7 +54,18 @@ declare_clippy_lint! {
     "manual implementation of the `Default` trait which is equal to a derive"
 }
 
-declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);
+pub struct DerivableImpls {
+    msrv: Msrv,
+}
+
+impl DerivableImpls {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        DerivableImpls { msrv }
+    }
+}
+
+impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);
 
 fn is_path_self(e: &Expr<'_>) -> bool {
     if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind {
@@ -61,6 +75,98 @@ fn is_path_self(e: &Expr<'_>) -> bool {
     }
 }
 
+fn check_struct<'tcx>(
+    cx: &LateContext<'tcx>,
+    item: &'tcx Item<'_>,
+    self_ty: &Ty<'_>,
+    func_expr: &Expr<'_>,
+    adt_def: AdtDef<'_>,
+) {
+    if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
+        if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
+            for arg in a.args {
+                if !matches!(arg, GenericArg::Lifetime(_)) {
+                    return;
+                }
+            }
+        }
+    }
+    let should_emit = match peel_blocks(func_expr).kind {
+        ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
+        ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
+        ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
+        _ => false,
+    };
+
+    if should_emit {
+        let struct_span = cx.tcx.def_span(adt_def.did());
+        span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
+            diag.span_suggestion_hidden(
+                item.span,
+                "remove the manual implementation...",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+            diag.span_suggestion(
+                struct_span.shrink_to_lo(),
+                "...and instead derive it",
+                "#[derive(Default)]\n".to_string(),
+                Applicability::MachineApplicable,
+            );
+        });
+    }
+}
+
+fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) {
+    if_chain! {
+        if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind;
+        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res;
+        if let variant_id = cx.tcx.parent(id);
+        if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id);
+        if variant_def.fields.is_empty();
+        if !variant_def.is_field_list_non_exhaustive();
+
+        then {
+            let enum_span = cx.tcx.def_span(adt_def.did());
+            let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
+            let variant_span = cx.tcx.def_span(variant_def.def_id);
+            let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
+            span_lint_and_then(
+                cx,
+                DERIVABLE_IMPLS,
+                item.span,
+                "this `impl` can be derived",
+                |diag| {
+                    diag.span_suggestion_hidden(
+                        item.span,
+                        "remove the manual implementation...",
+                        String::new(),
+                        Applicability::MachineApplicable
+                    );
+                    diag.span_suggestion(
+                        enum_span.shrink_to_lo(),
+                        "...and instead derive it...",
+                        format!(
+                            "#[derive(Default)]\n{indent}",
+                            indent = " ".repeat(indent_enum),
+                        ),
+                        Applicability::MachineApplicable
+                    );
+                    diag.span_suggestion(
+                        variant_span.shrink_to_lo(),
+                        "...and mark the default variant",
+                        format!(
+                            "#[default]\n{indent}",
+                            indent = " ".repeat(indent_variant),
+                        ),
+                        Applicability::MachineApplicable
+                    );
+                }
+            );
+        }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if_chain! {
@@ -83,49 +189,16 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             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 adt_def.is_struct();
-            then {
-                if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
-                    if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
-                        for arg in a.args {
-                            if !matches!(arg, GenericArg::Lifetime(_)) {
-                                return;
-                            }
-                        }
-                    }
-                }
-                let should_emit = match peel_blocks(func_expr).kind {
-                    ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
-                    ExprKind::Call(callee, args)
-                        if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
-                    ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
-                    _ => false,
-                };
 
-                if should_emit {
-                    let struct_span = cx.tcx.def_span(adt_def.did());
-                    span_lint_and_then(
-                        cx,
-                        DERIVABLE_IMPLS,
-                        item.span,
-                        "this `impl` can be derived",
-                        |diag| {
-                            diag.span_suggestion_hidden(
-                                item.span,
-                                "remove the manual implementation...",
-                                String::new(),
-                                Applicability::MachineApplicable
-                            );
-                            diag.span_suggestion(
-                                struct_span.shrink_to_lo(),
-                                "...and instead derive it",
-                                "#[derive(Default)]\n".to_string(),
-                                Applicability::MachineApplicable
-                            );
-                        }
-                    );
+            then {
+                if adt_def.is_struct() {
+                    check_struct(cx, item, self_ty, func_expr, adt_def);
+                } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
+                    check_enum(cx, item, func_expr, adt_def);
                 }
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index cf3483d4c00..f4b15e0916d 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
-    Ty, TyCtxt,
+    self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind,
+    TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     #[clippy::version = "pre 1.29.0"]
-    pub DERIVE_HASH_XOR_EQ,
+    pub DERIVED_HASH_WITH_MANUAL_EQ,
     correctness,
     "deriving `Hash` but implementing `PartialEq` explicitly"
 }
@@ -197,7 +197,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(Derive => [
     EXPL_IMPL_CLONE_ON_COPY,
-    DERIVE_HASH_XOR_EQ,
+    DERIVED_HASH_WITH_MANUAL_EQ,
     DERIVE_ORD_XOR_PARTIAL_ORD,
     UNSAFE_DERIVE_DESERIALIZE,
     DERIVE_PARTIAL_EQ_WITHOUT_EQ
@@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
     }
 }
 
-/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
+/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
 fn check_hash_peq<'tcx>(
     cx: &LateContext<'tcx>,
     span: Span,
@@ -243,7 +243,7 @@ fn check_hash_peq<'tcx>(
             cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
                 let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
 
-                if peq_is_automatically_derived == hash_is_automatically_derived {
+                if !hash_is_automatically_derived || peq_is_automatically_derived {
                     return;
                 }
 
@@ -252,17 +252,11 @@ fn check_hash_peq<'tcx>(
                 // Only care about `impl PartialEq<Foo> for Foo`
                 // For `impl PartialEq<B> for A, input_types is [A, B]
                 if trait_ref.substs.type_at(1) == ty {
-                    let mess = if peq_is_automatically_derived {
-                        "you are implementing `Hash` explicitly but have derived `PartialEq`"
-                    } else {
-                        "you are deriving `Hash` but have implemented `PartialEq` explicitly"
-                    };
-
                     span_lint_and_then(
                         cx,
-                        DERIVE_HASH_XOR_EQ,
+                        DERIVED_HASH_WITH_MANUAL_EQ,
                         span,
-                        mess,
+                        "you are deriving `Hash` but have implemented `PartialEq` explicitly",
                         |diag| {
                             if let Some(local_def_id) = impl_id.as_local() {
                                 let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
@@ -366,6 +360,15 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
     if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
         return;
     }
+    // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
+    // https://github.com/rust-lang/rust-clippy/issues/10188
+    if ty_adt.repr().packed()
+        && ty_subs
+            .iter()
+            .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
+    {
+        return;
+    }
 
     span_lint_and_note(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 4721a7b3705..11e1bcdf12d 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let (lint, msg) = match fn_name {
-                sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
+                sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY),
                 sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
                 sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
                 sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
index 08bf80a4229..c3a020433de 100644
--- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
@@ -45,7 +45,7 @@ impl EarlyLintPass for EmptyStructsWithBrackets {
                         span_after_ident,
                         "remove the brackets",
                         ";",
-                        Applicability::MachineApplicable);
+                        Applicability::Unspecified);
                     },
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index dcd8ca81ae8..d8e2ae02c5a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -639,7 +639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
     store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|_| Box::new(derive::Derive));
-    store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls));
+    store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
     store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
     store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
     store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 27ba27202bf..3bca93d80aa 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
 
                 let skip = if starts_at_zero {
                     String::new()
-                } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
+                } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) {
                     return;
                 } else {
                     format!(".skip({})", snippet(cx, start.span, ".."))
@@ -109,7 +109,7 @@ pub(super) fn check<'tcx>(
 
                     if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
                         String::new()
-                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
+                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) {
                         return;
                     } else {
                         match limits {
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index f4b47808dfa..744fd61bd13 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -1,6 +1,7 @@
 use super::SINGLE_ELEMENT_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, snippet_with_applicability};
+use clippy_utils::visitors::contains_break_or_continue;
 use if_chain::if_chain;
 use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_ast::Mutability;
@@ -67,6 +68,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let ExprKind::Block(block, _) = body.kind;
         if !block.stmts.is_empty();
+        if !contains_break_or_continue(body);
         then {
             let mut applicability = Applicability::MachineApplicable;
             let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index d226c0bba65..0b3bf22743f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,7 +1,10 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{indent_of, reindent_multiline};
 use clippy_utils::ty::is_type_lang_item;
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
 use rustc_span::{source_map::Spanned, Span};
@@ -15,6 +18,15 @@ pub(super) fn check<'tcx>(
     recv: &'tcx Expr<'_>,
     arg: &'tcx Expr<'_>,
 ) {
+    if let ExprKind::MethodCall(path_segment, ..) = recv.kind {
+        if matches!(
+            path_segment.ident.name.as_str(),
+            "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase"
+        ) {
+            return;
+        }
+    }
+
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
@@ -28,13 +40,37 @@ pub(super) fn check<'tcx>(
         let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
         if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String);
         then {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-                call_span,
+                recv.span.to(call_span),
                 "case-sensitive file extension comparison",
-                None,
-                "consider using a case-insensitive comparison instead",
+                |diag| {
+                    diag.help("consider using a case-insensitive comparison instead");
+                    if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
+
+                        if !cx.typeck_results().expr_ty(recv).is_ref() {
+                            recv_source = format!("&{recv_source}");
+                        }
+
+                        let suggestion_source = reindent_multiline(
+                            format!(
+                                "std::path::Path::new({})
+                                    .extension()
+                                    .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
+                                recv_source, ext_str.strip_prefix('.').unwrap()).into(),
+                            true,
+                            Some(indent_of(cx, call_span).unwrap_or(0) + 4)
+                        );
+
+                        diag.span_suggestion(
+                            recv.span.to(call_span),
+                            "use std::path::Path",
+                            suggestion_source,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 7c7938dd2e8..3795c0ec250 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -6,7 +6,7 @@ use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
 use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, adjustment::Adjust};
+use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
 use rustc_span::symbol::{sym, Symbol};
 
 use super::CLONE_DOUBLE_REF;
@@ -47,10 +47,10 @@ pub(super) fn check(
                 cx,
                 CLONE_DOUBLE_REF,
                 expr.span,
-                &format!(
+                &with_forced_trimmed_paths!(format!(
                     "using `clone` on a double-reference; \
                     this will copy the reference of type `{ty}` instead of cloning the inner type"
-                ),
+                )),
                 |diag| {
                     if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
                         let mut ty = innermost;
@@ -61,11 +61,11 @@ pub(super) fn check(
                         }
                         let refs = "&".repeat(n + 1);
                         let derefs = "*".repeat(n);
-                        let explicit = format!("<{refs}{ty}>::clone({snip})");
+                        let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})"));
                         diag.span_suggestion(
                             expr.span,
                             "try dereferencing it",
-                            format!("{refs}({derefs}{}).clone()", snip.deref()),
+                            with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())),
                             Applicability::MaybeIncorrect,
                         );
                         diag.span_suggestion(
@@ -129,7 +129,9 @@ pub(super) fn check(
             cx,
             CLONE_ON_COPY,
             expr.span,
-            &format!("using `clone` on type `{ty}` which implements the `Copy` trait"),
+            &with_forced_trimmed_paths!(format!(
+                "using `clone` on type `{ty}` which implements the `Copy` trait"
+            )),
             help,
             sugg,
             app,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index f888c58a72d..fc80f2eeae0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
             match closure_expr.kind {
                 hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
                     if_chain! {
-                    if ident.name == method_name;
-                    if let hir::ExprKind::Path(path) = &receiver.kind;
-                    if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
-                    then {
-                        return arg_id == *local
-                    }
+                        if ident.name == method_name;
+                        if let hir::ExprKind::Path(path) = &receiver.kind;
+                        if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
+                        then {
+                            return arg_id == *local
+                        }
                     }
                     false
                 },
@@ -92,92 +92,92 @@ pub(super) fn check(
     }
 
     if_chain! {
-            if is_trait_method(cx, map_recv, sym::Iterator);
-
-            // filter(|x| ...is_some())...
-            if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
-            let filter_body = cx.tcx.hir().body(filter_body_id);
-            if let [filter_param] = filter_body.params;
-            // optional ref pattern: `filter(|&x| ..)`
-            let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
-                (ref_pat, true)
-            } else {
-                (filter_param.pat, false)
+        if is_trait_method(cx, map_recv, sym::Iterator);
+
+        // filter(|x| ...is_some())...
+        if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
+        let filter_body = cx.tcx.hir().body(filter_body_id);
+        if let [filter_param] = filter_body.params;
+        // optional ref pattern: `filter(|&x| ..)`
+        let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
+            (ref_pat, true)
+        } else {
+            (filter_param.pat, false)
+        };
+        // closure ends with is_some() or is_ok()
+        if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
+        if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
+        if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
+        if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
+            Some(false)
+        } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
+            Some(true)
+        } else {
+            None
+        };
+        if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+
+        // ...map(|x| ...unwrap())
+        if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
+        let map_body = cx.tcx.hir().body(map_body_id);
+        if let [map_param] = map_body.params;
+        if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
+        // closure ends with expect() or unwrap()
+        if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
+        if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
+
+        // .filter(..).map(|y| f(y).copied().unwrap())
+        //                     ~~~~
+        let map_arg_peeled = match map_arg.kind {
+            ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
+                original_arg
+            },
+            _ => map_arg,
+        };
+
+        // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
+        let simple_equal = path_to_local_id(filter_arg, filter_param_id)
+            && path_to_local_id(map_arg_peeled, map_param_id);
+
+        let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+            // in `filter(|x| ..)`, replace `*x` with `x`
+            let a_path = if_chain! {
+                if !is_filter_param_ref;
+                if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
+                then { expr_path } else { a }
             };
-            // closure ends with is_some() or is_ok()
-            if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-            if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
-            if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
-            if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
-                Some(false)
-            } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
-                Some(true)
+            // let the filter closure arg and the map closure arg be equal
+            path_to_local_id(a_path, filter_param_id)
+                && path_to_local_id(b, map_param_id)
+                && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+        };
+
+        if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
+        then {
+            let span = filter_span.with_hi(expr.span.hi());
+            let (filter_name, lint) = if is_find {
+                ("find", MANUAL_FIND_MAP)
             } else {
-                None
-            };
-            if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
-
-            // ...map(|x| ...unwrap())
-            if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
-            let map_body = cx.tcx.hir().body(map_body_id);
-            if let [map_param] = map_body.params;
-            if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
-            // closure ends with expect() or unwrap()
-            if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
-            if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
-
-            // .filter(..).map(|y| f(y).copied().unwrap())
-            //                     ~~~~
-            let map_arg_peeled = match map_arg.kind {
-                ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
-                    original_arg
-                },
-                _ => map_arg,
+                ("filter", MANUAL_FILTER_MAP)
             };
+            let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
+            let (to_opt, deref) = if is_result {
+                (".ok()", String::new())
+            } else {
+                let derefs = cx.typeck_results()
+                    .expr_adjustments(map_arg)
+                    .iter()
+                    .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
+                    .count();
 
-            // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
-            let simple_equal = path_to_local_id(filter_arg, filter_param_id)
-                && path_to_local_id(map_arg_peeled, map_param_id);
-
-            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-                // in `filter(|x| ..)`, replace `*x` with `x`
-                let a_path = if_chain! {
-                    if !is_filter_param_ref;
-                    if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
-                    then { expr_path } else { a }
-                };
-                // let the filter closure arg and the map closure arg be equal
-                path_to_local_id(a_path, filter_param_id)
-                    && path_to_local_id(b, map_param_id)
-                    && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+                ("", "*".repeat(derefs))
             };
-
-            if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
-            then {
-                let span = filter_span.with_hi(expr.span.hi());
-                let (filter_name, lint) = if is_find {
-                    ("find", MANUAL_FIND_MAP)
-                } else {
-                    ("filter", MANUAL_FILTER_MAP)
-                };
-                let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
-                let (to_opt, deref) = if is_result {
-                    (".ok()", String::new())
-                } else {
-                    let derefs = cx.typeck_results()
-                        .expr_adjustments(map_arg)
-                        .iter()
-                        .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                        .count();
-
-                    ("", "*".repeat(derefs))
-                };
-                let sugg = format!(
-                    "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
-                    snippet(cx, map_arg.span, ".."),
-                );
-                span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
-            }
+            let sugg = format!(
+                "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
+                snippet(cx, map_arg.span, ".."),
+            );
+            span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 2244ebfb129..c87f5daab6f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::is_local_used;
-use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
 use rustc_span::sym;
@@ -30,9 +30,9 @@ pub(super) fn check<'tcx>(
         if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
         if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
 
-        let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
-            (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
-            (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
+        let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
+            (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
+            (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
             _ => return,
         };
 
@@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
             if_chain! {
                 if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
                 if let [local_ident] = path.segments;
-                if local_ident.ident.as_str() == binded_ident.as_str();
+                if local_ident.ident.as_str() == bound_ident.as_str();
 
                 then {
                     span_lint_and_sugg(
@@ -60,13 +60,23 @@ pub(super) fn check<'tcx>(
                         applicability,
                     );
                 } else {
+                    let ref_annotation = if annotation.0 == ByRef::Yes {
+                        "ref "
+                    } else {
+                        ""
+                    };
+                    let mut_annotation = if annotation.1 == Mutability::Mut {
+                        "mut "
+                    } else {
+                        ""
+                    };
                     span_lint_and_sugg(
                         cx,
                         ITER_KV_MAP,
                         expr.span,
                         &format!("iterating on a map's {replacement_kind}s"),
                         "try",
-                        format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})",
+                        format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
                             snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
                         applicability,
                     );
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index 15c1c618c51..fe88fa41fd9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -5,7 +5,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, print::with_forced_trimmed_paths};
 use rustc_span::sym;
 
 use super::SUSPICIOUS_TO_OWNED;
@@ -24,7 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
                 cx,
                 SUSPICIOUS_TO_OWNED,
                 expr.span,
-                &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"),
+                &with_forced_trimmed_paths!(format!(
+                    "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
+                )),
                 "consider using, depending on intent",
                 format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"),
                 app,
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 09cb5333176..dc866ab6373 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -1,6 +1,6 @@
 //! Checks for uses of mutex where an atomic value could be used
 //!
-//! This lint is **warn** by default
+//! This lint is **allow** by default
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -20,6 +20,10 @@ declare_clippy_lint! {
     /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
     /// faster.
     ///
+    /// On the other hand, `Mutex`es are, in general, easier to
+    /// verify correctness. An atomic does not behave the same as
+    /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details.
+    ///
     /// ### Known problems
     /// This lint cannot detect if the mutex is actually used
     /// for waiting before a critical section.
@@ -39,8 +43,8 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub MUTEX_ATOMIC,
-    nursery,
-    "using a mutex where an atomic value could be used instead"
+    restriction,
+    "using a mutex where an atomic value could be used instead."
 }
 
 declare_clippy_lint! {
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 4fbc8398e37..cff82b875f1 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
@@ -2,7 +2,7 @@ use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::{
     consts::{constant, constant_simple},
     diagnostics::span_lint,
-    peel_hir_expr_refs,
+    peel_hir_expr_refs, peel_hir_expr_unary,
 };
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -98,8 +98,11 @@ impl ArithmeticSideEffects {
     }
 
     /// If `expr` is not a literal integer like `1`, returns `None`.
+    ///
+    /// Returns the absolute value of the expression, if this is an integer literal.
     fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
-        if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
+        let actual = peel_hir_expr_unary(expr).0;
+        if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             Some(n)
         }
         else {
@@ -123,12 +126,12 @@ impl ArithmeticSideEffects {
         if !matches!(
             op.node,
             hir::BinOpKind::Add
-                | hir::BinOpKind::Sub
-                | hir::BinOpKind::Mul
                 | hir::BinOpKind::Div
+                | hir::BinOpKind::Mul
                 | hir::BinOpKind::Rem
                 | hir::BinOpKind::Shl
                 | hir::BinOpKind::Shr
+                | hir::BinOpKind::Sub
         ) {
             return;
         };
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 0a1b9d173cf..fc655fe2d0b 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -103,7 +103,7 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for range expressions `x..y` where both `x` and `y`
-    /// are constant and `x` is greater or equal to `y`.
+    /// are constant and `x` is greater to `y`. Also triggers if `x` is equal to `y` when they are conditions to a `for` loop.
     ///
     /// ### Why is this bad?
     /// Empty ranges yield no values so iterating them is a no-op.
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 0e7c5cca724..c1677fb3da1 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 // `res = clone(arg)` can be turned into `res = move arg;`
                 // if `arg` is the only borrow of `cloned` at this point.
 
-                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
+                if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
                     continue;
                 }
 
@@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 // StorageDead(pred_arg);
                 // res = to_path_buf(cloned);
                 // ```
-                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
+                if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
                     continue;
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 72c25592609..9f487dedb8c 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::box_vec", "clippy::box_collection"),
     ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
     ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
+    ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
     ("clippy::disallowed_method", "clippy::disallowed_methods"),
     ("clippy::disallowed_type", "clippy::disallowed_types"),
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index d4d50660520..bbbd9e4989e 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -210,22 +210,25 @@ fn check_final_expr<'tcx>(
             // if desugar of `do yeet`, don't lint
             if let Some(inner_expr) = inner
                 && let ExprKind::Call(path_expr, _) = inner_expr.kind
-                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
-                    return;
+                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
+            {
+                return;
             }
-            if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
-                let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
-                if !borrows {
-                    // check if expr return nothing
-                    let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
-                        extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
-                    } else {
-                        peeled_drop_expr.span
-                    };
-
-                    emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
-                }
+            if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
+                return;
+            }
+            let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
+            if borrows {
+                return;
             }
+            // check if expr return nothing
+            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+            } else {
+                peeled_drop_expr.span
+            };
+
+            emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, semi_spans.clone());
@@ -292,7 +295,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
         {
             ControlFlow::Break(())
         } else {
-            ControlFlow::Continue(Descend::from(!expr.span.from_expansion()))
+            ControlFlow::Continue(Descend::from(!e.span.from_expansion()))
         }
     })
     .is_some()
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c14f056a1f2..229478b7ce3 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -127,7 +127,7 @@ declare_clippy_lint! {
     /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
     ///
     /// ### Why is this bad?
-    /// Gankro says:
+    /// Gankra says:
     ///
     /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
     /// pointers and indirection.
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 42bccc7212b..f864c520302 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,9 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::visitors::is_local_used;
 use if_chain::if_chain;
-use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind};
+use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,6 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let parent_item = cx.tcx.hir().expect_item(parent);
         let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
+        let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
+            clippy_utils::visitors::for_each_expr(body.value, |e| {
+                if let Some(macro_call) = root_macro_call_first_node(cx, e) {
+                    if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(())
+                    }
+                } else {
+                    ControlFlow::Continue(())
+                }
+            })
+            .is_some()
+        };
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
             if assoc_item.fn_has_self_parameter;
@@ -65,6 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
             let body = cx.tcx.hir().body(*body_id);
             if let [self_param, ..] = body.params;
             if !is_local_used(cx, body, self_param.pat.hir_id);
+            if !contains_todo(cx, body);
             then {
                 span_lint_and_help(
                     cx,
@@ -72,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
                     self_param.span,
                     "unused `self` argument",
                     None,
-                    "consider refactoring to a associated function",
+                    "consider refactoring to an associated function",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index c86f24cbd37..c4d8c28f060 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
 fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     let map = cx.tcx.hir();
 
-    match map.find_parent((hir_id)) {
+    match map.find_parent(hir_id) {
         Some(hir::Node::Local(local)) => Some(local),
         Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
         _ => None,
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8290fe9ecb4..7a4a9036dd3 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -22,6 +22,9 @@ extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
 extern crate rustc_data_structures;
+// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
 extern crate rustc_errors;
 extern crate rustc_hir;
 extern crate rustc_hir_typeck;
@@ -116,6 +119,8 @@ use crate::consts::{constant, Constant};
 use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
 use crate::visitors::for_each_expr;
 
+use rustc_middle::hir::nested_filter;
+
 #[macro_export]
 macro_rules! extract_msrv_attr {
     ($context:ident) => {
@@ -1253,22 +1258,33 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     }
 }
 
-pub struct ContainsName {
+pub struct ContainsName<'a, 'tcx> {
+    pub cx: &'a LateContext<'tcx>,
     pub name: Symbol,
     pub result: bool,
 }
 
-impl<'tcx> Visitor<'tcx> for ContainsName {
+impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
+
     fn visit_name(&mut self, name: Symbol) {
         if self.name == name {
             self.result = true;
         }
     }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
 }
 
 /// Checks if an `Expr` contains a certain name.
-pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
-    let mut cn = ContainsName { name, result: false };
+pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
+    let mut cn = ContainsName {
+        name,
+        result: false,
+        cx,
+    };
     cn.visit_expr(expr);
     cn.result
 }
@@ -1304,6 +1320,7 @@ pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId)
     }
 }
 
+/// Gets the enclosing block, if any.
 pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
     let map = &cx.tcx.hir();
     let enclosing_node = map
@@ -2244,6 +2261,18 @@ pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'
     (e, count - remaining)
 }
 
+/// Peels off all unary operators of an expression. Returns the underlying expression and the number
+/// of operators removed.
+pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
+    let mut count: usize = 0;
+    let mut curr_expr = expr;
+    while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
+        count = count.wrapping_add(1);
+        curr_expr = local_expr;
+    }
+    (curr_expr, count)
+}
+
 /// Peels off all references on the expression. Returns the underlying expression and the number of
 /// references removed.
 pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 395d46e7a2f..9adae773389 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -1,16 +1,11 @@
-use super::possible_origin::PossibleOriginVisitor;
+use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation};
 use crate::ty::is_copy;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_lint::LateContext;
-use rustc_middle::mir::{
-    self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
-};
-use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
-use rustc_mir_dataflow::{
-    fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
-    CallReturnPlaces, ResultsCursor,
-};
+use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
+use rustc_middle::ty::{self, visit::TypeVisitor};
+use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
@@ -18,120 +13,78 @@ use std::ops::ControlFlow;
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
 #[allow(clippy::module_name_repetitions)]
-struct PossibleBorrowerAnalysis<'b, 'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    possible_borrower: TransitiveRelation,
     body: &'b mir::Body<'tcx>,
+    cx: &'a LateContext<'tcx>,
     possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
-struct PossibleBorrowerState {
-    map: FxIndexMap<Local, BitSet<Local>>,
-    domain_size: usize,
-}
-
-impl PossibleBorrowerState {
-    fn new(domain_size: usize) -> Self {
+impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    fn new(
+        cx: &'a LateContext<'tcx>,
+        body: &'b mir::Body<'tcx>,
+        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    ) -> Self {
         Self {
-            map: FxIndexMap::default(),
-            domain_size,
+            possible_borrower: TransitiveRelation::default(),
+            cx,
+            body,
+            possible_origin,
         }
     }
 
-    #[allow(clippy::similar_names)]
-    fn add(&mut self, borrowed: Local, borrower: Local) {
-        self.map
-            .entry(borrowed)
-            .or_insert(BitSet::new_empty(self.domain_size))
-            .insert(borrower);
-    }
-}
-
-impl<C> DebugWithContext<C> for PossibleBorrowerState {
-    fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        <_ as std::fmt::Debug>::fmt(self, f)
-    }
-    fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        unimplemented!()
-    }
-}
+    fn into_map(
+        self,
+        cx: &'a LateContext<'tcx>,
+        maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
+    ) -> PossibleBorrowerMap<'b, 'tcx> {
+        let mut map = FxHashMap::default();
+        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
+            if is_copy(cx, self.body.local_decls[row].ty) {
+                continue;
+            }
 
-impl JoinSemiLattice for PossibleBorrowerState {
-    fn join(&mut self, other: &Self) -> bool {
-        let mut changed = false;
-        for (&borrowed, borrowers) in other.map.iter() {
+            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
+            borrowers.remove(mir::Local::from_usize(0));
             if !borrowers.is_empty() {
-                changed |= self
-                    .map
-                    .entry(borrowed)
-                    .or_insert(BitSet::new_empty(self.domain_size))
-                    .union(borrowers);
+                map.insert(row, borrowers);
             }
         }
-        changed
-    }
-}
-
-impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
-    type Domain = PossibleBorrowerState;
-
-    const NAME: &'static str = "possible_borrower";
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        PossibleBorrowerState::new(body.local_decls.len())
-    }
-
-    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
-}
 
-impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'b mir::Body<'tcx>,
-        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    ) -> Self {
-        Self {
-            tcx,
-            body,
-            possible_origin,
+        let bs = BitSet::new_empty(self.body.local_decls.len());
+        PossibleBorrowerMap {
+            map,
+            maybe_live,
+            bitset: (bs.clone(), bs),
         }
     }
 }
 
-impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
-    fn apply_call_return_effect(
-        &self,
-        _state: &mut Self::Domain,
-        _block: BasicBlock,
-        _return_places: CallReturnPlaces<'_, 'tcx>,
-    ) {
-    }
-
-    fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
-        if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
-            let lhs = place.local;
-            match rvalue {
-                mir::Rvalue::Ref(_, _, borrowed) => {
-                    state.add(borrowed.local, lhs);
-                },
-                other => {
-                    if ContainsRegion
-                        .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
-                        .is_continue()
-                    {
-                        return;
+impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
+        let lhs = place.local;
+        match rvalue {
+            mir::Rvalue::Ref(_, _, borrowed) => {
+                self.possible_borrower.add(borrowed.local, lhs);
+            },
+            other => {
+                if ContainsRegion
+                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
+                    .is_continue()
+                {
+                    return;
+                }
+                rvalue_locals(other, |rhs| {
+                    if lhs != rhs {
+                        self.possible_borrower.add(rhs, lhs);
                     }
-                    rvalue_locals(other, |rhs| {
-                        if lhs != rhs {
-                            state.add(rhs, lhs);
-                        }
-                    });
-                },
-            }
+                });
+            },
         }
     }
 
-    fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
         if let mir::TerminatorKind::Call {
             args,
             destination: mir::Place { local: dest, .. },
@@ -171,10 +124,10 @@ impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
 
             for y in mutable_variables {
                 for x in &immutable_borrowers {
-                    state.add(*x, y);
+                    self.possible_borrower.add(*x, y);
                 }
                 for x in &mutable_borrowers {
-                    state.add(*x, y);
+                    self.possible_borrower.add(*x, y);
                 }
             }
         }
@@ -210,98 +163,73 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
     }
 }
 
-/// Result of `PossibleBorrowerAnalysis`.
+/// Result of `PossibleBorrowerVisitor`.
 #[allow(clippy::module_name_repetitions)]
 pub struct PossibleBorrowerMap<'b, 'tcx> {
-    body: &'b mir::Body<'tcx>,
-    possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
-    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
-    pushed: BitSet<Local>,
-    stack: Vec<Local>,
+    /// Mapping `Local -> its possible borrowers`
+    pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
+    // Caches to avoid allocation of `BitSet` on every query
+    pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
 }
 
-impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
-    pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+    pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
         let possible_origin = {
             let mut vis = PossibleOriginVisitor::new(mir);
             vis.visit_body(mir);
             vis.into_map(cx)
         };
-        let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
+        let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
             .into_engine(cx.tcx, mir)
-            .pass_name("possible_borrower")
+            .pass_name("redundant_clone")
             .iterate_to_fixpoint()
             .into_results_cursor(mir);
-        let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
-            .into_engine(cx.tcx, mir)
-            .pass_name("possible_borrower")
-            .iterate_to_fixpoint()
-            .into_results_cursor(mir);
-        PossibleBorrowerMap {
-            body: mir,
-            possible_borrower,
-            maybe_live,
-            pushed: BitSet::new_empty(mir.local_decls.len()),
-            stack: Vec::with_capacity(mir.local_decls.len()),
-        }
+        let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
+        vis.visit_body(mir);
+        vis.into_map(cx, maybe_storage_live_result)
     }
 
-    /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
-    /// `borrowers`.
-    /// Notes:
-    /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
-    /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
-    /// `Dereferencing`, which outlives any `LateContext`.
-    /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
-    /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
-    /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
-    /// adjusted.
-    pub fn at_most_borrowers(
+    /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
+    pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
+        self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+    }
+
+    /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
+    /// but no more than `above`.
+    pub fn bounded_borrowers(
         &mut self,
-        cx: &LateContext<'tcx>,
-        borrowers: &[mir::Local],
+        below: &[mir::Local],
+        above: &[mir::Local],
         borrowed: mir::Local,
         at: mir::Location,
     ) -> bool {
-        if is_copy(cx, self.body.local_decls[borrowed].ty) {
-            return true;
-        }
-
-        self.possible_borrower.seek_before_primary_effect(at);
-        self.maybe_live.seek_before_primary_effect(at);
-
-        let possible_borrower = &self.possible_borrower.get().map;
-        let maybe_live = &self.maybe_live;
-
-        self.pushed.clear();
-        self.stack.clear();
+        self.maybe_live.seek_after_primary_effect(at);
 
-        if let Some(borrowers) = possible_borrower.get(&borrowed) {
-            for b in borrowers.iter() {
-                if self.pushed.insert(b) {
-                    self.stack.push(b);
-                }
+        self.bitset.0.clear();
+        let maybe_live = &mut self.maybe_live;
+        if let Some(bitset) = self.map.get(&borrowed) {
+            for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
+                self.bitset.0.insert(b);
             }
         } else {
-            // Nothing borrows `borrowed` at `at`.
-            return true;
+            return false;
         }
 
-        while let Some(borrower) = self.stack.pop() {
-            if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
-                return false;
-            }
+        self.bitset.1.clear();
+        for b in below {
+            self.bitset.1.insert(*b);
+        }
 
-            if let Some(borrowers) = possible_borrower.get(&borrower) {
-                for b in borrowers.iter() {
-                    if self.pushed.insert(b) {
-                        self.stack.push(b);
-                    }
-                }
-            }
+        if !self.bitset.0.superset(&self.bitset.1) {
+            return false;
+        }
+
+        for b in above {
+            self.bitset.0.remove(*b);
         }
 
-        true
+        self.bitset.0.is_empty()
     }
 
     pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index ba5bc9c3135..dbf9f3b621d 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -20,8 +20,9 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,65,0 { LET_ELSE }
-    1,62,0 { BOOL_THEN_SOME }
+    1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
+    1,55,0 { SEEK_REWIND }
     1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
     1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
     1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
@@ -45,7 +46,6 @@ msrv_aliases! {
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
     1,16,0 { STR_REPEAT }
-    1,55,0 { SEEK_REWIND }
 }
 
 fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 9ca50105ae5..95eebab7567 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -47,7 +47,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 #[cfg(feature = "internal")]
 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_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
 pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 863fb60fcfc..14c01a60b4c 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>(
         ControlFlow::Continue(())
     }
 }
+
+pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
+    for_each_expr(expr, |e| {
+        if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 9399d422036..40a6f47095e 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-29"
+channel = "nightly-2023-01-12"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index bcc096c570e..d521e8d8839 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -256,11 +256,14 @@ pub fn main() {
     LazyLock::force(&ICE_HOOK);
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
+        let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();
 
         let sys_root_env = std::env::var("SYSROOT").ok();
         let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| {
             if let Some(sys_root) = sys_root_env {
-                args.extend(vec!["--sysroot".into(), sys_root]);
+                if !has_sysroot_arg {
+                    args.extend(vec!["--sysroot".into(), sys_root]);
+                }
             };
         };
 
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 818ff70b33f..a771d8b87c8 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -1,3 +1,12 @@
+//! This test is meant to only be run in CI. To run it locally use:
+//!
+//! `env INTEGRATION=rust-lang/log cargo test --test integration --features=integration`
+//!
+//! You can use a different `INTEGRATION` value to test different repositories.
+//!
+//! This test will clone the specified repository and run Clippy on it. The test succeeds, if
+//! Clippy doesn't produce an ICE. Lint warnings are ignored by this test.
+
 #![cfg(feature = "integration")]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
index 36db9e54a22..fb5b1b193f8 100644
--- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
@@ -107,7 +107,7 @@ fn rhs_is_different() {
 fn unary() {
     // is explicitly on the list
     let _ = -OutOfNames;
-    // is specifically on the list
+    // is explicitly on the list
     let _ = -Foo;
     // not on the list
     let _ = -Bar;
diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
index 46efb86dcfc..859383a7119 100644
--- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
@@ -1,99 +1,99 @@
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:5:22
    |
 LL |     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::dbg-macro` implied by `-D warnings`
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
    |                      ~~~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:9:8
    |
 LL |     if dbg!(n <= 1) {
    |        ^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     if n <= 1 {
    |        ~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:10:9
    |
 LL |         dbg!(1)
    |         ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         1
    |
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:12:9
    |
 LL |         dbg!(n * factorial(n - 1))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         n * factorial(n - 1)
    |
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:17:5
    |
 LL |     dbg!(42);
    |     ^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     42;
    |     ~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:18:5
    |
 LL |     dbg!(dbg!(dbg!(42)));
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     dbg!(dbg!(42));
    |     ~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:19:14
    |
 LL |     foo(3) + dbg!(factorial(4));
    |              ^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     foo(3) + factorial(4);
    |              ~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:20:5
    |
 LL |     dbg!(1, 2, dbg!(3, 4));
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     (1, 2, dbg!(3, 4));
    |     ~~~~~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:21:5
    |
 LL |     dbg!(1, 2, 3, 4, 5);
    |     ^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index b5ed8988a51..918cf81c600 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -2,6 +2,7 @@
     clippy::assign_op_pattern,
     clippy::erasing_op,
     clippy::identity_op,
+    clippy::no_effect,
     clippy::op_ref,
     clippy::unnecessary_owned_empty_strings,
     arithmetic_overflow,
@@ -12,31 +13,95 @@
 
 use core::num::{Saturating, Wrapping};
 
+#[derive(Clone, Copy)]
 pub struct Custom;
 
 macro_rules! impl_arith {
-    ( $( $_trait:ident, $ty:ty, $method:ident; )* ) => {
+    ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => {
         $(
-            impl core::ops::$_trait<$ty> for Custom {
-                type Output = Self;
-                fn $method(self, _: $ty) -> Self::Output { Self }
+            impl core::ops::$_trait<$lhs> for $rhs {
+                type Output = Custom;
+                fn $method(self, _: $lhs) -> Self::Output { todo!() }
+            }
+        )*
+    }
+}
+
+macro_rules! impl_assign_arith {
+    ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => {
+        $(
+            impl core::ops::$_trait<$lhs> for $rhs {
+                fn $method(&mut self, _: $lhs) {}
             }
         )*
     }
 }
 
 impl_arith!(
-    Add, i32, add;
-    Div, i32, div;
-    Mul, i32, mul;
-    Sub, i32, sub;
-
-    Add, f64, add;
-    Div, f64, div;
-    Mul, f64, mul;
-    Sub, f64, sub;
+    Add, Custom, Custom, add;
+    Div, Custom, Custom, div;
+    Mul, Custom, Custom, mul;
+    Rem, Custom, Custom, rem;
+    Sub, Custom, Custom, sub;
+
+    Add, Custom, &Custom, add;
+    Div, Custom, &Custom, div;
+    Mul, Custom, &Custom, mul;
+    Rem, Custom, &Custom, rem;
+    Sub, Custom, &Custom, sub;
+
+    Add, &Custom, Custom, add;
+    Div, &Custom, Custom, div;
+    Mul, &Custom, Custom, mul;
+    Rem, &Custom, Custom, rem;
+    Sub, &Custom, Custom, sub;
+
+    Add, &Custom, &Custom, add;
+    Div, &Custom, &Custom, div;
+    Mul, &Custom, &Custom, mul;
+    Rem, &Custom, &Custom, rem;
+    Sub, &Custom, &Custom, sub;
+);
+
+impl_assign_arith!(
+    AddAssign, Custom, Custom, add_assign;
+    DivAssign, Custom, Custom, div_assign;
+    MulAssign, Custom, Custom, mul_assign;
+    RemAssign, Custom, Custom, rem_assign;
+    SubAssign, Custom, Custom, sub_assign;
+
+    AddAssign, Custom, &Custom, add_assign;
+    DivAssign, Custom, &Custom, div_assign;
+    MulAssign, Custom, &Custom, mul_assign;
+    RemAssign, Custom, &Custom, rem_assign;
+    SubAssign, Custom, &Custom, sub_assign;
+
+    AddAssign, &Custom, Custom, add_assign;
+    DivAssign, &Custom, Custom, div_assign;
+    MulAssign, &Custom, Custom, mul_assign;
+    RemAssign, &Custom, Custom, rem_assign;
+    SubAssign, &Custom, Custom, sub_assign;
+
+    AddAssign, &Custom, &Custom, add_assign;
+    DivAssign, &Custom, &Custom, div_assign;
+    MulAssign, &Custom, &Custom, mul_assign;
+    RemAssign, &Custom, &Custom, rem_assign;
+    SubAssign, &Custom, &Custom, sub_assign;
 );
 
+impl core::ops::Neg for Custom {
+    type Output = Custom;
+    fn neg(self) -> Self::Output {
+        todo!()
+    }
+}
+impl core::ops::Neg for &Custom {
+    type Output = Custom;
+    fn neg(self) -> Self::Output {
+        todo!()
+    }
+}
+
 pub fn association_with_structures_should_not_trigger_the_lint() {
     enum Foo {
         Bar = -2,
@@ -125,6 +190,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n *= &0;
     _n *= 1;
     _n *= &1;
+    _n += -0;
+    _n += &-0;
+    _n -= -0;
+    _n -= &-0;
+    _n /= -99;
+    _n /= &-99;
+    _n %= -99;
+    _n %= &-99;
+    _n *= -0;
+    _n *= &-0;
+    _n *= -1;
+    _n *= &-1;
 
     // Binary
     _n = _n + 0;
@@ -158,8 +235,9 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n = -&i32::MIN;
 }
 
-pub fn runtime_ops() {
+pub fn unknown_ops_or_runtime_ops_that_can_overflow() {
     let mut _n = i32::MAX;
+    let mut _custom = Custom;
 
     // Assign
     _n += 1;
@@ -172,6 +250,36 @@ pub fn runtime_ops() {
     _n %= &0;
     _n *= 2;
     _n *= &2;
+    _n += -1;
+    _n += &-1;
+    _n -= -1;
+    _n -= &-1;
+    _n /= -0;
+    _n /= &-0;
+    _n %= -0;
+    _n %= &-0;
+    _n *= -2;
+    _n *= &-2;
+    _custom += Custom;
+    _custom += &Custom;
+    _custom -= Custom;
+    _custom -= &Custom;
+    _custom /= Custom;
+    _custom /= &Custom;
+    _custom %= Custom;
+    _custom %= &Custom;
+    _custom *= Custom;
+    _custom *= &Custom;
+    _custom += -Custom;
+    _custom += &-Custom;
+    _custom -= -Custom;
+    _custom -= &-Custom;
+    _custom /= -Custom;
+    _custom /= &-Custom;
+    _custom %= -Custom;
+    _custom %= &-Custom;
+    _custom *= -Custom;
+    _custom *= &-Custom;
 
     // Binary
     _n = _n + 1;
@@ -193,36 +301,73 @@ pub fn runtime_ops() {
     _n = 23 + &85;
     _n = &23 + 85;
     _n = &23 + &85;
-
-    // Custom
-    let _ = Custom + 0;
-    let _ = Custom + 1;
-    let _ = Custom + 2;
-    let _ = Custom + 0.0;
-    let _ = Custom + 1.0;
-    let _ = Custom + 2.0;
-    let _ = Custom - 0;
-    let _ = Custom - 1;
-    let _ = Custom - 2;
-    let _ = Custom - 0.0;
-    let _ = Custom - 1.0;
-    let _ = Custom - 2.0;
-    let _ = Custom / 0;
-    let _ = Custom / 1;
-    let _ = Custom / 2;
-    let _ = Custom / 0.0;
-    let _ = Custom / 1.0;
-    let _ = Custom / 2.0;
-    let _ = Custom * 0;
-    let _ = Custom * 1;
-    let _ = Custom * 2;
-    let _ = Custom * 0.0;
-    let _ = Custom * 1.0;
-    let _ = Custom * 2.0;
+    _custom = _custom + _custom;
+    _custom = _custom + &_custom;
+    _custom = Custom + _custom;
+    _custom = &Custom + _custom;
+    _custom = _custom - Custom;
+    _custom = _custom - &Custom;
+    _custom = Custom - _custom;
+    _custom = &Custom - _custom;
+    _custom = _custom / Custom;
+    _custom = _custom / &Custom;
+    _custom = _custom % Custom;
+    _custom = _custom % &Custom;
+    _custom = _custom * Custom;
+    _custom = _custom * &Custom;
+    _custom = Custom * _custom;
+    _custom = &Custom * _custom;
+    _custom = Custom + &Custom;
+    _custom = &Custom + Custom;
+    _custom = &Custom + &Custom;
 
     // Unary
     _n = -_n;
     _n = -&_n;
+    _custom = -_custom;
+    _custom = -&_custom;
+}
+
+// Copied and pasted from the `integer_arithmetic` lint for comparison.
+pub fn integer_arithmetic() {
+    let mut i = 1i32;
+    let mut var1 = 0i32;
+    let mut var2 = -1i32;
+
+    1 + i;
+    i * 2;
+    1 % i / 2;
+    i - 2 + 2 - i;
+    -i;
+    i >> 1;
+    i << 1;
+
+    -1;
+    -(-1);
+
+    i & 1;
+    i | 1;
+    i ^ 1;
+
+    i += 1;
+    i -= 1;
+    i *= 2;
+    i /= 2;
+    i /= 0;
+    i /= -1;
+    i /= var1;
+    i /= var2;
+    i %= 2;
+    i %= 0;
+    i %= -1;
+    i %= var1;
+    i %= var2;
+    i <<= 3;
+    i >>= 2;
+
+    i |= 1;
+    i &= 1;
+    i ^= i;
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 9fe4b7cf28d..5e349f6b497 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -1,5 +1,5 @@
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:165:5
+  --> $DIR/arithmetic_side_effects.rs:243:5
    |
 LL |     _n += 1;
    |     ^^^^^^^
@@ -7,328 +7,592 @@ LL |     _n += 1;
    = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:166:5
+  --> $DIR/arithmetic_side_effects.rs:244:5
    |
 LL |     _n += &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:167:5
+  --> $DIR/arithmetic_side_effects.rs:245:5
    |
 LL |     _n -= 1;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:168:5
+  --> $DIR/arithmetic_side_effects.rs:246:5
    |
 LL |     _n -= &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:169:5
+  --> $DIR/arithmetic_side_effects.rs:247:5
    |
 LL |     _n /= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:170:5
+  --> $DIR/arithmetic_side_effects.rs:248:5
    |
 LL |     _n /= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:171:5
+  --> $DIR/arithmetic_side_effects.rs:249:5
    |
 LL |     _n %= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:172:5
+  --> $DIR/arithmetic_side_effects.rs:250:5
    |
 LL |     _n %= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:173:5
+  --> $DIR/arithmetic_side_effects.rs:251:5
    |
 LL |     _n *= 2;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:174:5
+  --> $DIR/arithmetic_side_effects.rs:252:5
    |
 LL |     _n *= &2;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:177:10
+  --> $DIR/arithmetic_side_effects.rs:253:5
+   |
+LL |     _n += -1;
+   |     ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:254:5
+   |
+LL |     _n += &-1;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:255:5
+   |
+LL |     _n -= -1;
+   |     ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:256:5
+   |
+LL |     _n -= &-1;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:257:5
+   |
+LL |     _n /= -0;
+   |     ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:258:5
+   |
+LL |     _n /= &-0;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:259:5
+   |
+LL |     _n %= -0;
+   |     ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:260:5
+   |
+LL |     _n %= &-0;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:261:5
+   |
+LL |     _n *= -2;
+   |     ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:262:5
+   |
+LL |     _n *= &-2;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:263:5
+   |
+LL |     _custom += Custom;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:264:5
+   |
+LL |     _custom += &Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:265:5
+   |
+LL |     _custom -= Custom;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:266:5
+   |
+LL |     _custom -= &Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:267:5
+   |
+LL |     _custom /= Custom;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:268:5
+   |
+LL |     _custom /= &Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:269:5
+   |
+LL |     _custom %= Custom;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:270:5
+   |
+LL |     _custom %= &Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:271:5
+   |
+LL |     _custom *= Custom;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:272:5
+   |
+LL |     _custom *= &Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:273:5
+   |
+LL |     _custom += -Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:274:5
+   |
+LL |     _custom += &-Custom;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:275:5
+   |
+LL |     _custom -= -Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:276:5
+   |
+LL |     _custom -= &-Custom;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:277:5
+   |
+LL |     _custom /= -Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:278:5
+   |
+LL |     _custom /= &-Custom;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:279:5
+   |
+LL |     _custom %= -Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:280:5
+   |
+LL |     _custom %= &-Custom;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:281:5
+   |
+LL |     _custom *= -Custom;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:282:5
+   |
+LL |     _custom *= &-Custom;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:285:10
    |
 LL |     _n = _n + 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:178:10
+  --> $DIR/arithmetic_side_effects.rs:286:10
    |
 LL |     _n = _n + &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:179:10
+  --> $DIR/arithmetic_side_effects.rs:287:10
    |
 LL |     _n = 1 + _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:180:10
+  --> $DIR/arithmetic_side_effects.rs:288:10
    |
 LL |     _n = &1 + _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:181:10
+  --> $DIR/arithmetic_side_effects.rs:289:10
    |
 LL |     _n = _n - 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:182:10
+  --> $DIR/arithmetic_side_effects.rs:290:10
    |
 LL |     _n = _n - &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:183:10
+  --> $DIR/arithmetic_side_effects.rs:291:10
    |
 LL |     _n = 1 - _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:184:10
+  --> $DIR/arithmetic_side_effects.rs:292:10
    |
 LL |     _n = &1 - _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:185:10
+  --> $DIR/arithmetic_side_effects.rs:293:10
    |
 LL |     _n = _n / 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:186:10
+  --> $DIR/arithmetic_side_effects.rs:294:10
    |
 LL |     _n = _n / &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:187:10
+  --> $DIR/arithmetic_side_effects.rs:295:10
    |
 LL |     _n = _n % 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:188:10
+  --> $DIR/arithmetic_side_effects.rs:296:10
    |
 LL |     _n = _n % &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:189:10
+  --> $DIR/arithmetic_side_effects.rs:297:10
    |
 LL |     _n = _n * 2;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:190:10
+  --> $DIR/arithmetic_side_effects.rs:298:10
    |
 LL |     _n = _n * &2;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:191:10
+  --> $DIR/arithmetic_side_effects.rs:299:10
    |
 LL |     _n = 2 * _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:192:10
+  --> $DIR/arithmetic_side_effects.rs:300:10
    |
 LL |     _n = &2 * _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:193:10
+  --> $DIR/arithmetic_side_effects.rs:301:10
    |
 LL |     _n = 23 + &85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:194:10
+  --> $DIR/arithmetic_side_effects.rs:302:10
    |
 LL |     _n = &23 + 85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:195:10
+  --> $DIR/arithmetic_side_effects.rs:303:10
    |
 LL |     _n = &23 + &85;
    |          ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:198:13
+  --> $DIR/arithmetic_side_effects.rs:304:15
    |
-LL |     let _ = Custom + 0;
-   |             ^^^^^^^^^^
+LL |     _custom = _custom + _custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:199:13
+  --> $DIR/arithmetic_side_effects.rs:305:15
    |
-LL |     let _ = Custom + 1;
-   |             ^^^^^^^^^^
+LL |     _custom = _custom + &_custom;
+   |               ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:200:13
+  --> $DIR/arithmetic_side_effects.rs:306:15
    |
-LL |     let _ = Custom + 2;
-   |             ^^^^^^^^^^
+LL |     _custom = Custom + _custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:201:13
+  --> $DIR/arithmetic_side_effects.rs:307:15
    |
-LL |     let _ = Custom + 0.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = &Custom + _custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:202:13
+  --> $DIR/arithmetic_side_effects.rs:308:15
    |
-LL |     let _ = Custom + 1.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = _custom - Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:203:13
+  --> $DIR/arithmetic_side_effects.rs:309:15
    |
-LL |     let _ = Custom + 2.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = _custom - &Custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:204:13
+  --> $DIR/arithmetic_side_effects.rs:310:15
    |
-LL |     let _ = Custom - 0;
-   |             ^^^^^^^^^^
+LL |     _custom = Custom - _custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:205:13
+  --> $DIR/arithmetic_side_effects.rs:311:15
    |
-LL |     let _ = Custom - 1;
-   |             ^^^^^^^^^^
+LL |     _custom = &Custom - _custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:206:13
+  --> $DIR/arithmetic_side_effects.rs:312:15
    |
-LL |     let _ = Custom - 2;
-   |             ^^^^^^^^^^
+LL |     _custom = _custom / Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:207:13
+  --> $DIR/arithmetic_side_effects.rs:313:15
    |
-LL |     let _ = Custom - 0.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = _custom / &Custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:208:13
+  --> $DIR/arithmetic_side_effects.rs:314:15
    |
-LL |     let _ = Custom - 1.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = _custom % Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:209:13
+  --> $DIR/arithmetic_side_effects.rs:315:15
    |
-LL |     let _ = Custom - 2.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = _custom % &Custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:210:13
+  --> $DIR/arithmetic_side_effects.rs:316:15
    |
-LL |     let _ = Custom / 0;
-   |             ^^^^^^^^^^
+LL |     _custom = _custom * Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:211:13
+  --> $DIR/arithmetic_side_effects.rs:317:15
    |
-LL |     let _ = Custom / 1;
-   |             ^^^^^^^^^^
+LL |     _custom = _custom * &Custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:212:13
+  --> $DIR/arithmetic_side_effects.rs:318:15
    |
-LL |     let _ = Custom / 2;
-   |             ^^^^^^^^^^
+LL |     _custom = Custom * _custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:213:13
+  --> $DIR/arithmetic_side_effects.rs:319:15
    |
-LL |     let _ = Custom / 0.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = &Custom * _custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:214:13
+  --> $DIR/arithmetic_side_effects.rs:320:15
    |
-LL |     let _ = Custom / 1.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = Custom + &Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:215:13
+  --> $DIR/arithmetic_side_effects.rs:321:15
    |
-LL |     let _ = Custom / 2.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = &Custom + Custom;
+   |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:216:13
+  --> $DIR/arithmetic_side_effects.rs:322:15
    |
-LL |     let _ = Custom * 0;
-   |             ^^^^^^^^^^
+LL |     _custom = &Custom + &Custom;
+   |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:217:13
+  --> $DIR/arithmetic_side_effects.rs:325:10
    |
-LL |     let _ = Custom * 1;
-   |             ^^^^^^^^^^
+LL |     _n = -_n;
+   |          ^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:218:13
+  --> $DIR/arithmetic_side_effects.rs:326:10
    |
-LL |     let _ = Custom * 2;
-   |             ^^^^^^^^^^
+LL |     _n = -&_n;
+   |          ^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:219:13
+  --> $DIR/arithmetic_side_effects.rs:327:15
    |
-LL |     let _ = Custom * 0.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = -_custom;
+   |               ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:220:13
+  --> $DIR/arithmetic_side_effects.rs:328:15
    |
-LL |     let _ = Custom * 1.0;
-   |             ^^^^^^^^^^^^
+LL |     _custom = -&_custom;
+   |               ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:221:13
+  --> $DIR/arithmetic_side_effects.rs:337:5
    |
-LL |     let _ = Custom * 2.0;
-   |             ^^^^^^^^^^^^
+LL |     1 + i;
+   |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:224:10
+  --> $DIR/arithmetic_side_effects.rs:338:5
    |
-LL |     _n = -_n;
-   |          ^^^
+LL |     i * 2;
+   |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:225:10
+  --> $DIR/arithmetic_side_effects.rs:340:5
    |
-LL |     _n = -&_n;
-   |          ^^^^
+LL |     i - 2 + 2 - i;
+   |     ^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:341:5
+   |
+LL |     -i;
+   |     ^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:342:5
+   |
+LL |     i >> 1;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:343:5
+   |
+LL |     i << 1;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:352:5
+   |
+LL |     i += 1;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:353:5
+   |
+LL |     i -= 1;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:354:5
+   |
+LL |     i *= 2;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:356:5
+   |
+LL |     i /= 0;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:358:5
+   |
+LL |     i /= var1;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:359:5
+   |
+LL |     i /= var2;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:361:5
+   |
+LL |     i %= 0;
+   |     ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:363:5
+   |
+LL |     i %= var1;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:364:5
+   |
+LL |     i %= var2;
+   |     ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:365:5
+   |
+LL |     i <<= 3;
+   |     ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects.rs:366:5
+   |
+LL |     i >>= 2;
+   |     ^^^^^^^
 
-error: aborting due to 55 previous errors
+error: aborting due to 99 previous errors
 
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 911fa856aa0..7e9f074fdca 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -21,16 +21,16 @@ macro_rules! outer {
 fn main() {
     let _string: Box<String> = Box::default();
     let _byte = Box::<u8>::default();
-    let _vec = Box::<std::vec::Vec<u8>>::default();
+    let _vec = Box::<Vec<u8>>::default();
     let _impl = Box::<ImplementsDefault>::default();
     let _impl2 = Box::<ImplementsDefault>::default();
     let _impl3: Box<ImplementsDefault> = Box::default();
     let _own = Box::new(OwnDefault::default()); // should not lint
-    let _in_macro = outer!(Box::<std::string::String>::default());
-    let _string_default = outer!(Box::<std::string::String>::default());
+    let _in_macro = outer!(Box::<String>::default());
+    let _string_default = outer!(Box::<String>::default());
     let _vec2: Box<Vec<ImplementsDefault>> = Box::default();
     let _vec3: Box<Vec<bool>> = Box::default();
-    let _vec4: Box<_> = Box::<std::vec::Vec<bool>>::default();
+    let _vec4: Box<_> = Box::<Vec<bool>>::default();
     let _more = ret_ty_fn();
     call_ty_fn(Box::default());
 }
@@ -54,4 +54,14 @@ impl Read for ImplementsDefault {
 
 fn issue_9621_dyn_trait() {
     let _: Box<dyn Read> = Box::<ImplementsDefault>::default();
+    issue_10089();
+}
+
+fn issue_10089() {
+    let _closure = || {
+        #[derive(Default)]
+        struct WeirdPathed;
+
+        let _ = Box::<WeirdPathed>::default();
+    };
 }
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 20019c2ee5a..5c8d0b8354c 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -54,4 +54,14 @@ impl Read for ImplementsDefault {
 
 fn issue_9621_dyn_trait() {
     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
+    issue_10089();
+}
+
+fn issue_10089() {
+    let _closure = || {
+        #[derive(Default)]
+        struct WeirdPathed;
+
+        let _ = Box::new(WeirdPathed::default());
+    };
 }
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 5ea410331af..249eb340f96 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -16,7 +16,7 @@ error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:24:16
    |
 LL |     let _vec = Box::new(Vec::<u8>::new());
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<u8>>::default()`
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()`
 
 error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:25:17
@@ -40,13 +40,13 @@ error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:29:28
    |
 LL |     let _in_macro = outer!(Box::new(String::new()));
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:30:34
    |
 LL |     let _string_default = outer!(Box::new(String::from("")));
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:31:46
@@ -64,7 +64,7 @@ error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:33:25
    |
 LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<bool>>::default()`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
 
 error: `Box::new(_)` of default value
   --> $DIR/box_default.rs:35:16
@@ -84,5 +84,11 @@ error: `Box::new(_)` of default value
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
-error: aborting due to 14 previous errors
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:65:17
+   |
+LL |         let _ = Box::new(WeirdPathed::default());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
new file mode 100644
index 00000000000..5fbaa64db39
--- /dev/null
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
@@ -0,0 +1,67 @@
+// run-rustfix
+#![warn(clippy::case_sensitive_file_extension_comparisons)]
+
+use std::string::String;
+
+struct TestStruct;
+
+impl TestStruct {
+    fn ends_with(self, _arg: &str) {}
+}
+
+#[allow(dead_code)]
+fn is_rust_file(filename: &str) -> bool {
+    std::path::Path::new(filename)
+        .extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+}
+
+fn main() {
+    // std::string::String and &str should trigger the lint failure with .ext12
+    let _ = std::path::Path::new(&String::new())
+        .extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+    let _ = std::path::Path::new("str")
+        .extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+
+    // The fixup should preserve the indentation level
+    {
+        let _ = std::path::Path::new("str")
+            .extension()
+            .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+    }
+
+    // The test struct should not trigger the lint failure with .ext12
+    TestStruct {}.ends_with(".ext12");
+
+    // std::string::String and &str should trigger the lint failure with .EXT12
+    let _ = std::path::Path::new(&String::new())
+        .extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+    let _ = std::path::Path::new("str")
+        .extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+
+    // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase
+    let _ = String::new().to_lowercase().ends_with(".EXT12");
+    let _ = String::new().to_uppercase().ends_with(".EXT12");
+
+    // The test struct should not trigger the lint failure with .EXT12
+    TestStruct {}.ends_with(".EXT12");
+
+    // Should not trigger the lint failure with .eXT12
+    let _ = String::new().ends_with(".eXT12");
+    let _ = "str".ends_with(".eXT12");
+    TestStruct {}.ends_with(".eXT12");
+
+    // Should not trigger the lint failure with .EXT123 (too long)
+    let _ = String::new().ends_with(".EXT123");
+    let _ = "str".ends_with(".EXT123");
+    TestStruct {}.ends_with(".EXT123");
+
+    // Shouldn't fail if it doesn't start with a dot
+    let _ = String::new().ends_with("a.ext");
+    let _ = "str".ends_with("a.extA");
+    TestStruct {}.ends_with("a.ext");
+}
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
index 6f0485b5279..3c0d4821f9f 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #![warn(clippy::case_sensitive_file_extension_comparisons)]
 
 use std::string::String;
@@ -5,9 +6,10 @@ use std::string::String;
 struct TestStruct;
 
 impl TestStruct {
-    fn ends_with(self, arg: &str) {}
+    fn ends_with(self, _arg: &str) {}
 }
 
+#[allow(dead_code)]
 fn is_rust_file(filename: &str) -> bool {
     filename.ends_with(".rs")
 }
@@ -17,6 +19,11 @@ fn main() {
     let _ = String::new().ends_with(".ext12");
     let _ = "str".ends_with(".ext12");
 
+    // The fixup should preserve the indentation level
+    {
+        let _ = "str".ends_with(".ext12");
+    }
+
     // The test struct should not trigger the lint failure with .ext12
     TestStruct {}.ends_with(".ext12");
 
@@ -24,6 +31,10 @@ fn main() {
     let _ = String::new().ends_with(".EXT12");
     let _ = "str".ends_with(".EXT12");
 
+    // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase
+    let _ = String::new().to_lowercase().ends_with(".EXT12");
+    let _ = String::new().to_uppercase().ends_with(".EXT12");
+
     // The test struct should not trigger the lint failure with .EXT12
     TestStruct {}.ends_with(".EXT12");
 
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
index a28dd8bd5ad..44c8e3fdf74 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
@@ -1,43 +1,87 @@
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:12:14
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:14:5
    |
 LL |     filename.ends_with(".rs")
-   |              ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
    = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings`
+help: use std::path::Path
+   |
+LL ~     std::path::Path::new(filename)
+LL +         .extension()
+LL +         .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+   |
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:19:13
    |
 LL |     let _ = String::new().ends_with(".ext12");
-   |                           ^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+   |
+LL ~     let _ = std::path::Path::new(&String::new())
+LL +         .extension()
+LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+   |
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:18:19
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:20:13
    |
 LL |     let _ = "str".ends_with(".ext12");
-   |                   ^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+   |
+LL ~     let _ = std::path::Path::new("str")
+LL +         .extension()
+LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+   |
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:17
+   |
+LL |         let _ = "str".ends_with(".ext12");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+   |
+LL ~         let _ = std::path::Path::new("str")
+LL +             .extension()
+LL ~             .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+   |
+
+error: case-sensitive file extension comparison
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13
    |
 LL |     let _ = String::new().ends_with(".EXT12");
-   |                           ^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+   |
+LL ~     let _ = std::path::Path::new(&String::new())
+LL +         .extension()
+LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+   |
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:25:19
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:32:13
    |
 LL |     let _ = "str".ends_with(".EXT12");
-   |                   ^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+   |
+LL ~     let _ = std::path::Path::new("str")
+LL +         .extension()
+LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+   |
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index 42ae227777c..862234d204b 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -48,7 +48,7 @@ error: using `clone` on type `i32` which implements the `Copy` trait
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
 
-error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
+error: using `clone` on type `Option<i32>` which implements the `Copy` trait
   --> $DIR/clone_on_copy.rs:77:17
    |
 LL |     let value = opt.clone()?; // operator precedence needed (*opt)?
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index 638e4a54849..efdd56dd47d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -17,9 +17,12 @@ error[E0412]: cannot find type `VAL` in this scope
   --> $DIR/ice-6252.rs:10:63
    |
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
-   |          -                                                    ^^^ not found in this scope
-   |          |
-   |          help: you might be missing a type parameter: `, VAL`
+   |                                                               ^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   |          +++++
 
 error[E0046]: not all trait items implemented, missing: `VAL`
   --> $DIR/ice-6252.rs:10:1
diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr
index e6a65b46d97..ddb5f1342e9 100644
--- a/src/tools/clippy/tests/ui/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro.stderr
@@ -1,143 +1,143 @@
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:5:22
    |
 LL |     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::dbg-macro` implied by `-D warnings`
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
    |                      ~~~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:9:8
    |
 LL |     if dbg!(n <= 1) {
    |        ^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     if n <= 1 {
    |        ~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:10:9
    |
 LL |         dbg!(1)
    |         ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         1
    |
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:12:9
    |
 LL |         dbg!(n * factorial(n - 1))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         n * factorial(n - 1)
    |
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:17:5
    |
 LL |     dbg!(42);
    |     ^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     42;
    |     ~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:18:5
    |
 LL |     dbg!(dbg!(dbg!(42)));
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     dbg!(dbg!(42));
    |     ~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:19:14
    |
 LL |     foo(3) + dbg!(factorial(4));
    |              ^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     foo(3) + factorial(4);
    |              ~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:20:5
    |
 LL |     dbg!(1, 2, dbg!(3, 4));
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     (1, 2, dbg!(3, 4));
    |     ~~~~~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:21:5
    |
 LL |     dbg!(1, 2, 3, 4, 5);
    |     ^^^^^^^^^^^^^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:41:9
    |
 LL |         dbg!(2);
    |         ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         2;
    |         ~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:47:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     1;
    |     ~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:52:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |     1;
    |     ~
 
-error: `dbg!` macro is intended as a debugging tool
+error: the `dbg!` macro is intended as a debugging tool
   --> $DIR/dbg_macro.rs:58:9
    |
 LL |         dbg!(1);
    |         ^^^^^^^
    |
-help: ensure to avoid having uses of it in version control
+help: remove the invocation before committing it to a version control system
    |
 LL |         1;
    |         ~
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index a7da8f89aa3..1af77d1a25b 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -15,7 +15,7 @@ pub trait Copy {}
 pub unsafe trait Freeze {}
 
 #[lang = "start"]
-fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
     0
 }
 
diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed
index eedd4361939..5640599d48a 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.fixed
+++ b/src/tools/clippy/tests/ui/default_trait_access.fixed
@@ -12,17 +12,17 @@ use std::default::Default as D2;
 use std::string;
 
 fn main() {
-    let s1: String = std::string::String::default();
+    let s1: String = String::default();
 
     let s2 = String::default();
 
-    let s3: String = std::string::String::default();
+    let s3: String = String::default();
 
-    let s4: String = std::string::String::default();
+    let s4: String = String::default();
 
     let s5 = string::String::default();
 
-    let s6: String = std::string::String::default();
+    let s6: String = String::default();
 
     let s7 = std::string::String::default();
 
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
index 49b2dde3f1e..e4f73c08d19 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.stderr
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -1,8 +1,8 @@
-error: calling `std::string::String::default()` is more clear than this expression
+error: calling `String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:15:22
    |
 LL |     let s1: String = Default::default();
-   |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |                      ^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
    |
 note: the lint level is defined here
   --> $DIR/default_trait_access.rs:3:9
@@ -10,23 +10,23 @@ note: the lint level is defined here
 LL | #![deny(clippy::default_trait_access)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: calling `std::string::String::default()` is more clear than this expression
+error: calling `String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:19:22
    |
 LL |     let s3: String = D2::default();
-   |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |                      ^^^^^^^^^^^^^ help: try: `String::default()`
 
-error: calling `std::string::String::default()` is more clear than this expression
+error: calling `String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:21:22
    |
 LL |     let s4: String = std::default::Default::default();
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
 
-error: calling `std::string::String::default()` is more clear than this expression
+error: calling `String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:25:22
    |
 LL |     let s6: String = default::Default::default();
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
 
 error: calling `GenericDerivedDefault::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:35:46
diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed
index 7dcdfb0937e..ee8456f5deb 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.fixed
+++ b/src/tools/clippy/tests/ui/derivable_impls.fixed
@@ -210,4 +210,25 @@ impl Default for IntOrString {
     }
 }
 
+#[derive(Default)]
+pub enum SimpleEnum {
+    Foo,
+    #[default]
+    Bar,
+}
+
+
+
+pub enum NonExhaustiveEnum {
+    Foo,
+    #[non_exhaustive]
+    Bar,
+}
+
+impl Default for NonExhaustiveEnum {
+    fn default() -> Self {
+        NonExhaustiveEnum::Bar
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs
index 625cbcdde23..14af419bcad 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.rs
+++ b/src/tools/clippy/tests/ui/derivable_impls.rs
@@ -244,4 +244,27 @@ impl Default for IntOrString {
     }
 }
 
+pub enum SimpleEnum {
+    Foo,
+    Bar,
+}
+
+impl Default for SimpleEnum {
+    fn default() -> Self {
+        SimpleEnum::Bar
+    }
+}
+
+pub enum NonExhaustiveEnum {
+    Foo,
+    #[non_exhaustive]
+    Bar,
+}
+
+impl Default for NonExhaustiveEnum {
+    fn default() -> Self {
+        NonExhaustiveEnum::Bar
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr
index c1db5a58b1f..81963c3be5b 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.stderr
+++ b/src/tools/clippy/tests/ui/derivable_impls.stderr
@@ -113,5 +113,26 @@ help: ...and instead derive it
 LL | #[derive(Default)]
    |
 
-error: aborting due to 7 previous errors
+error: this `impl` can be derived
+  --> $DIR/derivable_impls.rs:252:1
+   |
+LL | / impl Default for SimpleEnum {
+LL | |     fn default() -> Self {
+LL | |         SimpleEnum::Bar
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: remove the manual implementation...
+help: ...and instead derive it...
+   |
+LL | #[derive(Default)]
+   |
+help: ...and mark the default variant
+   |
+LL ~     #[default]
+LL ~     Bar,
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index b276c384c04..6e0ce55f57d 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -86,4 +86,15 @@ impl<T: Clone, U> Clone for GenericRef<'_, T, U> {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/10188
+#[repr(packed)]
+#[derive(Copy)]
+struct Packed<T>(T);
+
+impl<T: Copy> Clone for Packed<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
deleted file mode 100644
index 16c92397804..00000000000
--- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
+++ /dev/null
@@ -1,59 +0,0 @@
-error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive_hash_xor_eq.rs:12:10
-   |
-LL | #[derive(Hash)]
-   |          ^^^^
-   |
-note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:15:1
-   |
-LL | impl PartialEq for Bar {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
-   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive_hash_xor_eq.rs:21:10
-   |
-LL | #[derive(Hash)]
-   |          ^^^^
-   |
-note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:24:1
-   |
-LL | impl PartialEq<Baz> for Baz {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: you are implementing `Hash` explicitly but have derived `PartialEq`
-  --> $DIR/derive_hash_xor_eq.rs:33:1
-   |
-LL | / impl std::hash::Hash for Bah {
-LL | |     fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
-LL | | }
-   | |_^
-   |
-note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:30:10
-   |
-LL | #[derive(PartialEq)]
-   |          ^^^^^^^^^
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: you are implementing `Hash` explicitly but have derived `PartialEq`
-  --> $DIR/derive_hash_xor_eq.rs:51:5
-   |
-LL | /     impl Hash for Foo3 {
-LL | |         fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
-LL | |     }
-   | |_____^
-   |
-note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:48:14
-   |
-LL |     #[derive(PartialEq)]
-   |              ^^^^^^^^^
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs
index 813ddc56646..8ad09a8de43 100644
--- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
+++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs
@@ -27,6 +27,8 @@ impl PartialEq<Baz> for Baz {
     }
 }
 
+// Implementing `Hash` with a derived `PartialEq` is fine. See #2627
+
 #[derive(PartialEq)]
 struct Bah;
 
@@ -34,23 +36,4 @@ impl std::hash::Hash for Bah {
     fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
 }
 
-#[derive(PartialEq)]
-struct Foo2;
-
-trait Hash {}
-
-// We don't want to lint on user-defined traits called `Hash`
-impl Hash for Foo2 {}
-
-mod use_hash {
-    use std::hash::{Hash, Hasher};
-
-    #[derive(PartialEq)]
-    struct Foo3;
-
-    impl Hash for Foo3 {
-        fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
-    }
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr
new file mode 100644
index 00000000000..230940f25fb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr
@@ -0,0 +1,29 @@
+error: you are deriving `Hash` but have implemented `PartialEq` explicitly
+  --> $DIR/derived_hash_with_manual_eq.rs:12:10
+   |
+LL | #[derive(Hash)]
+   |          ^^^^
+   |
+note: `PartialEq` implemented here
+  --> $DIR/derived_hash_with_manual_eq.rs:15:1
+   |
+LL | impl PartialEq for Bar {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default
+   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `Hash` but have implemented `PartialEq` explicitly
+  --> $DIR/derived_hash_with_manual_eq.rs:21:10
+   |
+LL | #[derive(Hash)]
+   |          ^^^^
+   |
+note: `PartialEq` implemented here
+  --> $DIR/derived_hash_with_manual_eq.rs:24:1
+   |
+LL | impl PartialEq<Baz> for Baz {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/src/tools/clippy/tests/ui/drop_ref.rs
index 7de0b0bbdf9..10044e65f11 100644
--- a/src/tools/clippy/tests/ui/drop_ref.rs
+++ b/src/tools/clippy/tests/ui/drop_ref.rs
@@ -72,3 +72,26 @@ fn test_owl_result_2() -> Result<u8, ()> {
     produce_half_owl_ok().map(drop)?;
     Ok(1)
 }
+
+#[allow(unused)]
+#[allow(clippy::unit_cmp)]
+fn issue10122(x: u8) {
+    // This is a function which returns a reference and has a side-effect, which means
+    // that calling drop() on the function is considered an idiomatic way of achieving the side-effect
+    // in a match arm.
+    fn println_and<T>(t: &T) -> &T {
+        println!("foo");
+        t
+    }
+
+    match x {
+        0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects
+        1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects
+        2 => {
+            drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
+        },
+        3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+        4 => drop(&2),                           // Lint, not a fn/method call
+        _ => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr
index 4743cf79b5d..293b9f6de83 100644
--- a/src/tools/clippy/tests/ui/drop_ref.stderr
+++ b/src/tools/clippy/tests/ui/drop_ref.stderr
@@ -107,5 +107,41 @@ note: argument has type `&SomeStruct`
 LL |     std::mem::drop(&SomeStruct);
    |                    ^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
+  --> $DIR/drop_ref.rs:91:13
+   |
+LL |             drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&i32`
+  --> $DIR/drop_ref.rs:91:18
+   |
+LL |             drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
+   |                  ^^^^^^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
+  --> $DIR/drop_ref.rs:93:14
+   |
+LL |         3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+   |              ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&i32`
+  --> $DIR/drop_ref.rs:93:19
+   |
+LL |         3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+   |                   ^^^^^^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
+  --> $DIR/drop_ref.rs:94:14
+   |
+LL |         4 => drop(&2),                           // Lint, not a fn/method call
+   |              ^^^^^^^^
+   |
+note: argument has type `&i32`
+  --> $DIR/drop_ref.rs:94:19
+   |
+LL |         4 => drop(&2),                           // Lint, not a fn/method call
+   |                   ^^
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
index 7367910eaa1..1f989bb1220 100644
--- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
@@ -247,3 +247,24 @@ mod issue6312 {
         }
     }
 }
+
+struct Collection {
+    items: Vec<i32>,
+    len: usize,
+}
+
+impl Default for Collection {
+    fn default() -> Self {
+        Self {
+            items: vec![1, 2, 3],
+            len: 0,
+        }
+    }
+}
+
+#[allow(clippy::redundant_closure_call)]
+fn issue10136() {
+    let mut c = Collection::default();
+    // don't lint, since c.items was used to calculate this value
+    c.len = (|| c.items.len())();
+}
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed
index 83fee04080f..f2a4c284cb1 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed
@@ -1,14 +1,15 @@
 // run-rustfix
 
 #![warn(clippy::iter_kv_map)]
-#![allow(clippy::redundant_clone)]
-#![allow(clippy::suspicious_map)]
-#![allow(clippy::map_identity)]
+#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
 
 use std::collections::{BTreeMap, HashMap};
 
 fn main() {
     let get_key = |(key, _val)| key;
+    fn ref_acceptor(v: &u32) -> u32 {
+        *v
+    }
 
     let map: HashMap<u32, u32> = HashMap::new();
 
@@ -36,6 +37,20 @@ fn main() {
     let _ = map.keys().map(|key| key * 9).count();
     let _ = map.values().map(|value| value * 17).count();
 
+    // Preserve the ref in the fix.
+    let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
+
+    // Preserve the mut in the fix.
+    let _ = map
+        .clone().into_values().map(|mut val| {
+            val += 2;
+            val
+        })
+        .count();
+
+    // Don't let a mut interfere.
+    let _ = map.clone().into_values().count();
+
     let map: BTreeMap<u32, u32> = BTreeMap::new();
 
     let _ = map.keys().collect::<Vec<_>>();
@@ -61,4 +76,18 @@ fn main() {
     // Lint
     let _ = map.keys().map(|key| key * 9).count();
     let _ = map.values().map(|value| value * 17).count();
+
+    // Preserve the ref in the fix.
+    let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
+
+    // Preserve the mut in the fix.
+    let _ = map
+        .clone().into_values().map(|mut val| {
+            val += 2;
+            val
+        })
+        .count();
+
+    // Don't let a mut interfere.
+    let _ = map.clone().into_values().count();
 }
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs
index 7a1f1fb0198..ad6564df408 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.rs
+++ b/src/tools/clippy/tests/ui/iter_kv_map.rs
@@ -1,14 +1,15 @@
 // run-rustfix
 
 #![warn(clippy::iter_kv_map)]
-#![allow(clippy::redundant_clone)]
-#![allow(clippy::suspicious_map)]
-#![allow(clippy::map_identity)]
+#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
 
 use std::collections::{BTreeMap, HashMap};
 
 fn main() {
     let get_key = |(key, _val)| key;
+    fn ref_acceptor(v: &u32) -> u32 {
+        *v
+    }
 
     let map: HashMap<u32, u32> = HashMap::new();
 
@@ -36,6 +37,22 @@ fn main() {
     let _ = map.iter().map(|(key, _value)| key * 9).count();
     let _ = map.iter().map(|(_key, value)| value * 17).count();
 
+    // Preserve the ref in the fix.
+    let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
+
+    // Preserve the mut in the fix.
+    let _ = map
+        .clone()
+        .into_iter()
+        .map(|(_, mut val)| {
+            val += 2;
+            val
+        })
+        .count();
+
+    // Don't let a mut interfere.
+    let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
+
     let map: BTreeMap<u32, u32> = BTreeMap::new();
 
     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
@@ -61,4 +78,20 @@ fn main() {
     // Lint
     let _ = map.iter().map(|(key, _value)| key * 9).count();
     let _ = map.iter().map(|(_key, value)| value * 17).count();
+
+    // Preserve the ref in the fix.
+    let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
+
+    // Preserve the mut in the fix.
+    let _ = map
+        .clone()
+        .into_iter()
+        .map(|(_, mut val)| {
+            val += 2;
+            val
+        })
+        .count();
+
+    // Don't let a mut interfere.
+    let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
 }
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr
index 9b9b04c97d8..e00da223b4d 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr
@@ -1,5 +1,5 @@
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:15:13
+  --> $DIR/iter_kv_map.rs:16:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
@@ -7,130 +7,198 @@ LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    = note: `-D clippy::iter-kv-map` implied by `-D warnings`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:16:13
+  --> $DIR/iter_kv_map.rs:17:13
    |
 LL |     let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:17:13
+  --> $DIR/iter_kv_map.rs:18:13
    |
 LL |     let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:19:13
+  --> $DIR/iter_kv_map.rs:20:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:20:13
+  --> $DIR/iter_kv_map.rs:21:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:22:13
+  --> $DIR/iter_kv_map.rs:23:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:23:13
+  --> $DIR/iter_kv_map.rs:24:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:25:13
+  --> $DIR/iter_kv_map.rs:26:13
    |
 LL |     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:26:13
+  --> $DIR/iter_kv_map.rs:27:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:36:13
+  --> $DIR/iter_kv_map.rs:37:13
    |
 LL |     let _ = map.iter().map(|(key, _value)| key * 9).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:37:13
+  --> $DIR/iter_kv_map.rs:38:13
    |
 LL |     let _ = map.iter().map(|(_key, value)| value * 17).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
 
-error: iterating on a map's keys
+error: iterating on a map's values
   --> $DIR/iter_kv_map.rs:41:13
    |
+LL |     let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
+
+error: iterating on a map's values
+  --> $DIR/iter_kv_map.rs:44:13
+   |
+LL |       let _ = map
+   |  _____________^
+LL | |         .clone()
+LL | |         .into_iter()
+LL | |         .map(|(_, mut val)| {
+LL | |             val += 2;
+LL | |             val
+LL | |         })
+   | |__________^
+   |
+help: try
+   |
+LL ~     let _ = map
+LL +         .clone().into_values().map(|mut val| {
+LL +             val += 2;
+LL +             val
+LL +         })
+   |
+
+error: iterating on a map's values
+  --> $DIR/iter_kv_map.rs:54:13
+   |
+LL |     let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
+
+error: iterating on a map's keys
+  --> $DIR/iter_kv_map.rs:58:13
+   |
 LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:42:13
+  --> $DIR/iter_kv_map.rs:59:13
    |
 LL |     let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:43:13
+  --> $DIR/iter_kv_map.rs:60:13
    |
 LL |     let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:45:13
+  --> $DIR/iter_kv_map.rs:62:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:46:13
+  --> $DIR/iter_kv_map.rs:63:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:48:13
+  --> $DIR/iter_kv_map.rs:65:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:49:13
+  --> $DIR/iter_kv_map.rs:66:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:51:13
+  --> $DIR/iter_kv_map.rs:68:13
    |
 LL |     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:52:13
+  --> $DIR/iter_kv_map.rs:69:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's keys
-  --> $DIR/iter_kv_map.rs:62:13
+  --> $DIR/iter_kv_map.rs:79:13
    |
 LL |     let _ = map.iter().map(|(key, _value)| key * 9).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
 
 error: iterating on a map's values
-  --> $DIR/iter_kv_map.rs:63:13
+  --> $DIR/iter_kv_map.rs:80:13
    |
 LL |     let _ = map.iter().map(|(_key, value)| value * 17).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
 
-error: aborting due to 22 previous errors
+error: iterating on a map's values
+  --> $DIR/iter_kv_map.rs:83:13
+   |
+LL |     let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
+
+error: iterating on a map's values
+  --> $DIR/iter_kv_map.rs:86:13
+   |
+LL |       let _ = map
+   |  _____________^
+LL | |         .clone()
+LL | |         .into_iter()
+LL | |         .map(|(_, mut val)| {
+LL | |             val += 2;
+LL | |             val
+LL | |         })
+   | |__________^
+   |
+help: try
+   |
+LL ~     let _ = map
+LL +         .clone().into_values().map(|mut val| {
+LL +             val += 2;
+LL +             val
+LL +         })
+   |
+
+error: iterating on a map's values
+  --> $DIR/iter_kv_map.rs:96:13
+   |
+LL |     let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 31e1cb6c3d7..4cb7f6b687f 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
+#![feature(lint_reasons)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,14 +491,3 @@ mod issue_9782_method_variant {
         S.foo::<&[u8; 100]>(&a);
     }
 }
-
-extern crate rustc_lint;
-extern crate rustc_span;
-
-#[allow(dead_code)]
-mod span_lint {
-    use rustc_lint::{LateContext, Lint, LintContext};
-    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
-        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
-    }
-}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 55c2738fcf2..9a01190ed8d 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
+#![feature(lint_reasons)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,14 +491,3 @@ mod issue_9782_method_variant {
         S.foo::<&[u8; 100]>(&a);
     }
 }
-
-extern crate rustc_lint;
-extern crate rustc_span;
-
-#[allow(dead_code)]
-mod span_lint {
-    use rustc_lint::{LateContext, Lint, LintContext};
-    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
-        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
-    }
-}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 98a48d68317..d26c317124b 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -216,11 +216,5 @@ error: the borrowed expression implements the required traits
 LL |         foo(&a);
    |             ^^ help: change this to: `a`
 
-error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:502:85
-   |
-LL |         cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
-   |                                                                                     ^^^^^^^^^^^^^^ help: change this to: `String::new()`
-
-error: aborting due to 37 previous errors
+error: aborting due to 36 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index d451be1f389..ab1c0e590bb 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -277,4 +277,14 @@ fn issue9947() -> Result<(), String> {
     do yeet "hello";
 }
 
+// without anyhow, but triggers the same bug I believe
+#[expect(clippy::useless_format)]
+fn issue10051() -> Result<String, String> {
+    if true {
+        Ok(format!("ok!"))
+    } else {
+        Err(format!("err!"))
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index e1a1bea2c0b..abed338bb9b 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -287,4 +287,14 @@ fn issue9947() -> Result<(), String> {
     do yeet "hello";
 }
 
+// without anyhow, but triggers the same bug I believe
+#[expect(clippy::useless_format)]
+fn issue10051() -> Result<String, String> {
+    if true {
+        return Ok(format!("ok!"));
+    } else {
+        return Err(format!("err!"));
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index ca2253e6586..52eabf6e137 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -386,5 +386,21 @@ LL |         let _ = 42; return;
    |
    = help: remove `return`
 
-error: aborting due to 46 previous errors
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:294:9
+   |
+LL |         return Ok(format!("ok!"));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:296:9
+   |
+LL |         return Err(format!("err!"));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove `return`
+
+error: aborting due to 48 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index a157b6a6f9a..00b42745093 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -239,9 +239,3 @@ fn false_negative_5707() {
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
-
-#[allow(unused, clippy::manual_retain)]
-fn possible_borrower_improvements() {
-    let mut s = String::from("foobar");
-    s = s.chars().filter(|&c| c != 'o').collect();
-}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index 430672e8b8d..f899127db8d 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -239,9 +239,3 @@ fn false_negative_5707() {
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
-
-#[allow(unused, clippy::manual_retain)]
-fn possible_borrower_improvements() {
-    let mut s = String::from("foobar");
-    s = s.chars().filter(|&c| c != 'o').to_owned().collect();
-}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
index 1bacc2c76af..782590034d0 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.stderr
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -179,17 +179,5 @@ note: this value is dropped without further use
 LL |     foo(&x.clone(), move || {
    |          ^
 
-error: redundant clone
-  --> $DIR/redundant_clone.rs:246:40
-   |
-LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
-   |                                        ^^^^^^^^^^^ help: remove this
-   |
-note: this value is dropped without further use
-  --> $DIR/redundant_clone.rs:246:9
-   |
-LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 16 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 2f76b575296..5076f61334d 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -10,6 +10,7 @@
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
+#![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
@@ -45,6 +46,7 @@
 #![warn(clippy::box_collection)]
 #![warn(clippy::redundant_static_lifetimes)]
 #![warn(clippy::cognitive_complexity)]
+#![warn(clippy::derived_hash_with_manual_eq)]
 #![warn(clippy::disallowed_methods)]
 #![warn(clippy::disallowed_types)]
 #![warn(clippy::mixed_read_write_in_expression)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 699c0ff464e..64bc1ca7116 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -10,6 +10,7 @@
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
+#![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
@@ -45,6 +46,7 @@
 #![warn(clippy::box_vec)]
 #![warn(clippy::const_static_lifetime)]
 #![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::derive_hash_xor_eq)]
 #![warn(clippy::disallowed_method)]
 #![warn(clippy::disallowed_type)]
 #![warn(clippy::eval_order_dependence)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 9af58dc75a6..27a0263292e 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:41:9
+  --> $DIR/rename.rs:42:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,244 +7,250 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:43: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:43:9
+  --> $DIR/rename.rs:44: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:44:9
+  --> $DIR/rename.rs:45: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:45:9
+  --> $DIR/rename.rs:46: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:46:9
+  --> $DIR/rename.rs:47: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:47:9
+  --> $DIR/rename.rs:48: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:49: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:48:9
+  --> $DIR/rename.rs:50: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:49:9
+  --> $DIR/rename.rs:51: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:50:9
+  --> $DIR/rename.rs:52: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:51:9
+  --> $DIR/rename.rs:53: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:52:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:55: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:54:9
+  --> $DIR/rename.rs:56: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:55:9
+  --> $DIR/rename.rs:57: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:56:9
+  --> $DIR/rename.rs:58: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:57:9
+  --> $DIR/rename.rs:59: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:58:9
+  --> $DIR/rename.rs:60: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:59:9
+  --> $DIR/rename.rs:61: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:60:9
+  --> $DIR/rename.rs:62: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:61:9
+  --> $DIR/rename.rs:63: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:62:9
+  --> $DIR/rename.rs:64: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:63:9
+  --> $DIR/rename.rs:65: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:64:9
+  --> $DIR/rename.rs:66: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:65:9
+  --> $DIR/rename.rs:67: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:66:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:71: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:70:9
+  --> $DIR/rename.rs:72: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:71:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:74: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:73:9
+  --> $DIR/rename.rs:75: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:74:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:77: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:76:9
+  --> $DIR/rename.rs:78: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:77:9
+  --> $DIR/rename.rs:79: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:78:9
+  --> $DIR/rename.rs:80: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:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:82: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:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 41 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_element_loop.fixed b/src/tools/clippy/tests/ui/single_element_loop.fixed
index 63d31ff83f9..a0dcc0172e8 100644
--- a/src/tools/clippy/tests/ui/single_element_loop.fixed
+++ b/src/tools/clippy/tests/ui/single_element_loop.fixed
@@ -33,4 +33,31 @@ fn main() {
         let item = 0..5;
         dbg!(item);
     }
+
+    // should not lint (issue #10018)
+    for e in [42] {
+        if e > 0 {
+            continue;
+        }
+    }
+
+    // should not lint (issue #10018)
+    for e in [42] {
+        if e > 0 {
+            break;
+        }
+    }
+
+    // should lint (issue #10018)
+    {
+        let _ = 42;
+        let _f = |n: u32| {
+            for i in 0..n {
+                if i > 10 {
+                    dbg!(i);
+                    break;
+                }
+            }
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/single_element_loop.rs b/src/tools/clippy/tests/ui/single_element_loop.rs
index 2cda5a329d2..bc014035c98 100644
--- a/src/tools/clippy/tests/ui/single_element_loop.rs
+++ b/src/tools/clippy/tests/ui/single_element_loop.rs
@@ -27,4 +27,30 @@ fn main() {
     for item in [0..5].into_iter() {
         dbg!(item);
     }
+
+    // should not lint (issue #10018)
+    for e in [42] {
+        if e > 0 {
+            continue;
+        }
+    }
+
+    // should not lint (issue #10018)
+    for e in [42] {
+        if e > 0 {
+            break;
+        }
+    }
+
+    // should lint (issue #10018)
+    for _ in [42] {
+        let _f = |n: u32| {
+            for i in 0..n {
+                if i > 10 {
+                    dbg!(i);
+                    break;
+                }
+            }
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/single_element_loop.stderr b/src/tools/clippy/tests/ui/single_element_loop.stderr
index 0aeb8da1a2e..14437a59745 100644
--- a/src/tools/clippy/tests/ui/single_element_loop.stderr
+++ b/src/tools/clippy/tests/ui/single_element_loop.stderr
@@ -95,5 +95,32 @@ LL +         dbg!(item);
 LL +     }
    |
 
-error: aborting due to 6 previous errors
+error: for loop over a single element
+  --> $DIR/single_element_loop.rs:46:5
+   |
+LL | /     for _ in [42] {
+LL | |         let _f = |n: u32| {
+LL | |             for i in 0..n {
+LL | |                 if i > 10 {
+...  |
+LL | |         };
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     {
+LL +         let _ = 42;
+LL +         let _f = |n: u32| {
+LL +             for i in 0..n {
+LL +                 if i > 10 {
+LL +                     dbg!(i);
+LL +                     break;
+LL +                 }
+LL +             }
+LL +         };
+LL +     }
+   |
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
index ae1aec34d82..dec3f50d6f1 100644
--- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
@@ -1,4 +1,4 @@
-error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
+error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
   --> $DIR/suspicious_to_owned.rs:16:13
    |
 LL |     let _ = cow.to_owned();
@@ -6,19 +6,19 @@ LL |     let _ = cow.to_owned();
    |
    = note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
 
-error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned
+error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned
   --> $DIR/suspicious_to_owned.rs:26:13
    |
 LL |     let _ = cow.to_owned();
    |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
 
-error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec<char>> contents to become owned
+error: this `to_owned` call clones the Cow<'_, Vec<char>> itself and does not cause the Cow<'_, Vec<char>> contents to become owned
   --> $DIR/suspicious_to_owned.rs:36:13
    |
 LL |     let _ = cow.to_owned();
    |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
 
-error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
+error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
   --> $DIR/suspicious_to_owned.rs:46:13
    |
 LL |     let _ = cow.to_owned();
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
index 94cc7777aca..6022d9fa4c5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
@@ -38,13 +38,13 @@ LL |     t.clone();
    |
    = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
-error: using `clone` on type `std::option::Option<T>` which implements the `Copy` trait
+error: using `clone` on type `Option<T>` which implements the `Copy` trait
   --> $DIR/unnecessary_clone.rs:42:5
    |
 LL |     Some(t).clone();
    |     ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
 
-error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec<i32>` instead of cloning the inner type
+error: using `clone` on a double-reference; this will copy the reference of type `&Vec<i32>` instead of cloning the inner type
   --> $DIR/unnecessary_clone.rs:48:22
    |
 LL |     let z: &Vec<_> = y.clone();
@@ -57,10 +57,10 @@ LL |     let z: &Vec<_> = &(*y).clone();
    |                      ~~~~~~~~~~~~~
 help: or try being explicit if you are sure, that you want to clone a reference
    |
-LL |     let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
-   |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let z: &Vec<_> = <&Vec<i32>>::clone(y);
+   |                      ~~~~~~~~~~~~~~~~~~~~~
 
-error: using `clone` on type `many_derefs::E` which implements the `Copy` trait
+error: using `clone` on type `E` which implements the `Copy` trait
   --> $DIR/unnecessary_clone.rs:84:20
    |
 LL |         let _: E = a.clone();
diff --git a/src/tools/clippy/tests/ui/unused_self.rs b/src/tools/clippy/tests/ui/unused_self.rs
index 92e8e1dba69..55bd5607185 100644
--- a/src/tools/clippy/tests/ui/unused_self.rs
+++ b/src/tools/clippy/tests/ui/unused_self.rs
@@ -60,6 +60,16 @@ mod unused_self_allow {
         // shouldn't trigger for public methods
         pub fn unused_self_move(self) {}
     }
+
+    pub struct E;
+
+    impl E {
+        // shouldn't trigger if body contains todo!()
+        pub fn unused_self_todo(self) {
+            let x = 42;
+            todo!()
+        }
+    }
 }
 
 pub use unused_self_allow::D;
diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr
index 23186122a9a..919f9b6efda 100644
--- a/src/tools/clippy/tests/ui/unused_self.stderr
+++ b/src/tools/clippy/tests/ui/unused_self.stderr
@@ -4,7 +4,7 @@ error: unused `self` argument
 LL |         fn unused_self_move(self) {}
    |                             ^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
    = note: `-D clippy::unused-self` implied by `-D warnings`
 
 error: unused `self` argument
@@ -13,7 +13,7 @@ error: unused `self` argument
 LL |         fn unused_self_ref(&self) {}
    |                            ^^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:13:32
@@ -21,7 +21,7 @@ error: unused `self` argument
 LL |         fn unused_self_mut_ref(&mut self) {}
    |                                ^^^^^^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:14:32
@@ -29,7 +29,7 @@ error: unused `self` argument
 LL |         fn unused_self_pin_ref(self: Pin<&Self>) {}
    |                                ^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:15:36
@@ -37,7 +37,7 @@ error: unused `self` argument
 LL |         fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {}
    |                                    ^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:16:35
@@ -45,7 +45,7 @@ error: unused `self` argument
 LL |         fn unused_self_pin_nested(self: Pin<Arc<Self>>) {}
    |                                   ^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:17:28
@@ -53,7 +53,7 @@ error: unused `self` argument
 LL |         fn unused_self_box(self: Box<Self>) {}
    |                            ^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:18:40
@@ -61,7 +61,7 @@ error: unused `self` argument
 LL |         fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 {
    |                                        ^^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: unused `self` argument
   --> $DIR/unused_self.rs:21:37
@@ -69,7 +69,7 @@ error: unused `self` argument
 LL |         fn unused_self_class_method(&self) {
    |                                     ^^^^^
    |
-   = help: consider refactoring to a associated function
+   = help: consider refactoring to an associated function
 
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 8c01748613c..6a147de3be2 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
     ) -> Compilation {
         compiler.session().abort_if_errors();
 
-        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
+        queries.global_ctxt().unwrap().enter(|tcx| {
             init_late_loggers(tcx);
             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index 244d4427c56..8fd0fcf8f5c 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -26,6 +26,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
 
 pub(crate) fn rewrite_closure(
     binder: &ast::ClosureBinder,
+    constness: ast::Const,
     capture: ast::CaptureBy,
     is_async: &ast::Async,
     movability: ast::Movability,
@@ -38,7 +39,7 @@ pub(crate) fn rewrite_closure(
     debug!("rewrite_closure {:?}", body);
 
     let (prefix, extra_offset) = rewrite_closure_fn_decl(
-        binder, capture, is_async, movability, fn_decl, body, span, context, shape,
+        binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape,
     )?;
     // 1 = space between `|...|` and body.
     let body_shape = shape.offset_left(extra_offset)?;
@@ -230,6 +231,7 @@ fn rewrite_closure_block(
 // Return type is (prefix, extra_offset)
 fn rewrite_closure_fn_decl(
     binder: &ast::ClosureBinder,
+    constness: ast::Const,
     capture: ast::CaptureBy,
     asyncness: &ast::Async,
     movability: ast::Movability,
@@ -250,6 +252,12 @@ fn rewrite_closure_fn_decl(
         ast::ClosureBinder::NotPresent => "".to_owned(),
     };
 
+    let const_ = if matches!(constness, ast::Const::Yes(_)) {
+        "const "
+    } else {
+        ""
+    };
+
     let immovable = if movability == ast::Movability::Static {
         "static "
     } else {
@@ -264,7 +272,7 @@ fn rewrite_closure_fn_decl(
     // 4 = "|| {".len(), which is overconservative when the closure consists of
     // a single expression.
     let nested_shape = shape
-        .shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())?
+        .shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())?
         .sub_width(4)?;
 
     // 1 = |
@@ -302,7 +310,10 @@ fn rewrite_closure_fn_decl(
         .tactic(tactic)
         .preserve_newline(true);
     let list_str = write_list(&item_vec, &fmt)?;
-    let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str);
+    let mut prefix = format!(
+        "{}{}{}{}{}|{}|",
+        binder, const_, immovable, is_async, mover, list_str
+    );
 
     if !ret_str.is_empty() {
         if prefix.contains('\n') {
@@ -329,6 +340,7 @@ pub(crate) fn rewrite_last_closure(
     if let ast::ExprKind::Closure(ref closure) = expr.kind {
         let ast::Closure {
             ref binder,
+            constness,
             capture_clause,
             ref asyncness,
             movability,
@@ -349,6 +361,7 @@ pub(crate) fn rewrite_last_closure(
         };
         let (prefix, extra_offset) = rewrite_closure_fn_decl(
             binder,
+            constness,
             capture_clause,
             asyncness,
             movability,
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 414e767690b..868ff045ab7 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -205,6 +205,7 @@ pub(crate) fn format_expr(
         }
         ast::ExprKind::Closure(ref cl) => closures::rewrite_closure(
             &cl.binder,
+            cl.constness,
             cl.capture_clause,
             &cl.asyncness,
             cl.movability,
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 29501d2d3b6..845eb5af0d6 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -217,7 +217,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "serde",
     "serde_derive",
     "serde_json",
-    "sha-1",
+    "sha1",
     "sha2",
     "sharded-slab",
     "smallvec",
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index ac8b5f6834c..bc9fd35ecde 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -31,10 +31,8 @@ const IGNORE_DOCTEST_CHECK: &[&str] =
     &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"];
 
 // Error codes that don't yet have a UI test. This list will eventually be removed.
-const IGNORE_UI_TEST_CHECK: &[&str] = &[
-    "E0461", "E0465", "E0476", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729",
-    "E0789",
-];
+const IGNORE_UI_TEST_CHECK: &[&str] =
+    &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729", "E0789"];
 
 macro_rules! verbose_print {
     ($verbose:expr, $($fmt:tt)*) => {
diff --git a/tests/codegen/abi-efiapi.rs b/tests/codegen/abi-efiapi.rs
index 9061d7432a3..9502ebf59af 100644
--- a/tests/codegen/abi-efiapi.rs
+++ b/tests/codegen/abi-efiapi.rs
@@ -14,7 +14,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(no_core, lang_items, abi_efiapi)]
+#![feature(no_core, lang_items)]
 #![no_core]
 
 #[lang="sized"]
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index a6c60df83a6..9cd504f004d 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -62,7 +62,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
         compiler.session().abort_if_errors();
-        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
+        queries.global_ctxt().unwrap().enter(|tcx| {
             // Collect definition ids of MIR bodies.
             let hir = tcx.hir();
             let mut bodies = Vec::new();
diff --git a/tests/run-make-fulldeps/target-specs/foo.rs b/tests/run-make-fulldeps/target-specs/foo.rs
index d576a1dd281..22939e87912 100644
--- a/tests/run-make-fulldeps/target-specs/foo.rs
+++ b/tests/run-make-fulldeps/target-specs/foo.rs
@@ -11,7 +11,7 @@ trait Sized {}
 auto trait Freeze {}
 
 #[lang = "start"]
-fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
     0
 }
 
diff --git a/tests/rustdoc-gui/method-margins.goml b/tests/rustdoc-gui/method-margins.goml
index ed36bcdec17..720268a9e7e 100644
--- a/tests/rustdoc-gui/method-margins.goml
+++ b/tests/rustdoc-gui/method-margins.goml
@@ -1,18 +1,18 @@
 // This test ensures that the margins on methods are coherent inside an impl block.
 goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
 
-assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
+assert-count: ("#trait-implementations-list > .toggle", 1)
 
 compare-elements-css: (
     // compare margin on type with margin on method
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary",
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(1) > summary",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(2) > summary",
     ["margin"]
 )
 
 compare-elements-css: (
     // compare margin on type with margin on method
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)",
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(1)",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(2)",
     ["margin"]
 )
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index fc3beaa53fa..f236dc3e0fe 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -159,7 +159,7 @@ assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
 // We now check that clicking on the toggles' text is like clicking on the checkbox.
 // To test it, we use the "Disable keyboard shortcuts".
 local-storage: {"rustdoc-disable-shortcuts": "false"}
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
 // Make sure that "Disable keyboard shortcuts" actually took effect.
@@ -169,7 +169,7 @@ assert-false: "#help-button .popover"
 wait-for-css: ("#settings-menu .popover", {"display": "block"})
 
 // Now turn keyboard shortcuts back on, and see if they work.
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
 press-key: "Escape"
 press-key: "?"
diff --git a/tests/rustdoc-gui/toggle-click-deadspace.goml b/tests/rustdoc-gui/toggle-click-deadspace.goml
index 029403ee13e..689e562f730 100644
--- a/tests/rustdoc-gui/toggle-click-deadspace.goml
+++ b/tests/rustdoc-gui/toggle-click-deadspace.goml
@@ -1,14 +1,14 @@
 // This test ensures that clicking on a method summary, but not on the "[-]",
 // doesn't toggle the <details>.
 goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
 click: "h4.code-header" // This is the position of "pub" in "pub fn a_method"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
 click-with-offset: (
-    ".impl-items .rustdoc-toggle summary",
+    ".impl-items .toggle summary",
     {"x": -24, "y": 8}, // This is the position of "[-]" next to that pub fn.
 )
-assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute-false: (".impl-items .toggle", {"open": ""})
 
 // Click the "Trait" part of "impl Trait" and verify it navigates.
 click: "#impl-Trait-for-Foo h3 a:first-of-type"
diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml
index 89ce78e3aab..c9d236e9bba 100644
--- a/tests/rustdoc-gui/toggle-docs.goml
+++ b/tests/rustdoc-gui/toggle-docs.goml
@@ -20,10 +20,10 @@ assert-text: ("#toggle-all-docs", "[−]")
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 // We first check that everything is visible.
 assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
-assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
 assert-attribute-false: (
-    "#blanket-implementations-list > details.rustdoc-toggle",
+    "#blanket-implementations-list > details.toggle",
     {"open": ""},
     ALL,
 )
@@ -32,18 +32,18 @@ assert-attribute-false: (
 click: "#toggle-all-docs"
 wait-for-text: ("#toggle-all-docs", "[+]")
 // We check that all <details> are collapsed (except for the impl block ones).
-assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
+assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
 assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
 // We now check that the other impl blocks are collapsed.
 assert-attribute-false: (
-    "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
+    "#blanket-implementations-list > details.toggle.implementors-toggle",
     {"open": ""},
     ALL,
 )
 // We open them all again.
 click: "#toggle-all-docs"
 wait-for-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("details.toggle", {"open": ""}, ALL)
 
 // Checking the toggles style.
 show-text: true
@@ -56,12 +56,12 @@ define-function: (
         // We reload the page so the local storage settings are being used.
         reload:
 
-        assert-css: ("details.rustdoc-toggle > summary::before", {
+        assert-css: ("details.toggle > summary::before", {
             "opacity": "0.5",
             "filter": |filter|,
         }, ALL)
-        move-cursor-to: "details.rustdoc-toggle summary"
-        assert-css: ("details.rustdoc-toggle > summary:hover::before", {
+        move-cursor-to: "details.toggle summary"
+        assert-css: ("details.toggle > summary:hover::before", {
             "opacity": "1",
             "filter": |filter|,
         })
diff --git a/tests/rustdoc-gui/toggled-open-implementations.goml b/tests/rustdoc-gui/toggled-open-implementations.goml
index e4d59b5d728..000293b555f 100644
--- a/tests/rustdoc-gui/toggled-open-implementations.goml
+++ b/tests/rustdoc-gui/toggled-open-implementations.goml
@@ -2,4 +2,4 @@
 // has all the implementations toggled open by default, so users can
 // find method names in those implementations with Ctrl-F.
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: (".toggle.implementors-toggle", {"open": ""})
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 43f30f3d6e8..4bdecdc1b79 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -76,6 +76,7 @@
     -Z                            llvm-plugins=val -- a list LLVM plugins to enable (space separated)
     -Z                         llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
     -Z                         location-detail=val -- 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`)
+    -Z                           log-backtrace=val -- add a backtrace along with logging
     -Z                                      ls=val -- list the symbols defined by a library crate (default: no)
     -Z                         macro-backtrace=val -- show macro backtraces (default: no)
     -Z             maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no)
diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs
new file mode 100644
index 00000000000..2fc486d01da
--- /dev/null
+++ b/tests/rustdoc/const-intrinsic.rs
@@ -0,0 +1,25 @@
+#![feature(intrinsics)]
+#![feature(staged_api)]
+
+#![crate_name = "foo"]
+#![stable(since="1.0.0", feature="rust1")]
+
+extern "rust-intrinsic" {
+    // @has 'foo/fn.transmute.html'
+    // @has - '//pre[@class="rust fn"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U'
+    #[stable(since="1.0.0", feature="rust1")]
+    #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
+    pub fn transmute<T, U>(_: T) -> U;
+
+    // @has 'foo/fn.unreachable.html'
+    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    #[stable(since="1.0.0", feature="rust1")]
+    pub fn unreachable() -> !;
+}
+
+extern "C" {
+    // @has 'foo/fn.needs_drop.html'
+    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    #[stable(since="1.0.0", feature="rust1")]
+    pub fn needs_drop() -> !;
+}
diff --git a/tests/rustdoc/issue-41783.rs b/tests/rustdoc/issue-41783.rs
index 769f984a274..7578d49daa5 100644
--- a/tests/rustdoc/issue-41783.rs
+++ b/tests/rustdoc/issue-41783.rs
@@ -5,7 +5,7 @@
 // @!hasraw - '<span class="attr">#[outer]</span>'
 // @hasraw - '#![inner]</span>'
 // @!hasraw - '<span class="attr">#![inner]</span>'
-// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
+// @snapshot 'codeblock' - '//*[@class="toggle top-doc"]/*[@class="docblock"]//pre/code'
 
 /// ```no_run
 /// # # space
diff --git a/tests/rustdoc/local-reexport-doc.rs b/tests/rustdoc/local-reexport-doc.rs
index 1c8468008dd..5dc857773a3 100644
--- a/tests/rustdoc/local-reexport-doc.rs
+++ b/tests/rustdoc/local-reexport-doc.rs
@@ -4,7 +4,7 @@
 #![crate_name = "foo"]
 
 // @has 'foo/fn.g.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' \
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' \
 // 'outer module inner module'
 
 mod inner_mod {
diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.rs b/tests/rustdoc/mixing-doc-comments-and-attrs.rs
index a27c5ae6d01..010058361fa 100644
--- a/tests/rustdoc/mixing-doc-comments-and-attrs.rs
+++ b/tests/rustdoc/mixing-doc-comments-and-attrs.rs
@@ -1,7 +1,7 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.S1.html'
-// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S1_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 
 #[doc = "Hello world!\n\n"]
 /// Goodbye!
@@ -9,7 +9,7 @@
 pub struct S1;
 
 // @has 'foo/struct.S2.html'
-// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S2_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 
 /// Hello world!
 ///
@@ -18,7 +18,7 @@ pub struct S1;
 pub struct S2;
 
 // @has 'foo/struct.S3.html'
-// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S3_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 /** Par 1
 */ ///
 /// Par 2
diff --git a/tests/rustdoc/multiple-import-levels.rs b/tests/rustdoc/multiple-import-levels.rs
index 1daae49cde9..29b67c6b2b1 100644
--- a/tests/rustdoc/multiple-import-levels.rs
+++ b/tests/rustdoc/multiple-import-levels.rs
@@ -21,14 +21,14 @@ mod c {
 }
 
 // @has 'foo/struct.Type.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
 /// foo
 pub use b::Type;
 // @has 'foo/struct.Whatever.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
 /// whatever
 pub use c::Type as Whatever;
 // @has 'foo/struct.Woof.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
 /// a dog
 pub use c::Woof;
diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs
new file mode 100644
index 00000000000..3ea5fde72f7
--- /dev/null
+++ b/tests/rustdoc/reexport-doc-hidden.rs
@@ -0,0 +1,26 @@
+// Part of <https://github.com/rust-lang/rust/issues/59368>.
+// This test ensures that reexporting a `doc(hidden)` item will
+// still show the reexport.
+
+#![crate_name = "foo"]
+
+#[doc(hidden)]
+pub type Type = u32;
+
+// @has 'foo/index.html'
+// @has - '//*[@id="reexport.Type2"]/code' 'pub use crate::Type as Type2;'
+pub use crate::Type as Type2;
+
+// @count - '//*[@id="reexport.Type3"]' 0
+#[doc(hidden)]
+pub use crate::Type as Type3;
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! foo {
+    () => {};
+}
+
+// This is a bug: https://github.com/rust-lang/rust/issues/59368
+// @!has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
+pub use crate::foo as Macro;
diff --git a/tests/rustdoc/strip-block-doc-comments-stars.rs b/tests/rustdoc/strip-block-doc-comments-stars.rs
index ea28d84f1ff..ca4c93f92e0 100644
--- a/tests/rustdoc/strip-block-doc-comments-stars.rs
+++ b/tests/rustdoc/strip-block-doc-comments-stars.rs
@@ -4,7 +4,7 @@
 // block doc comments can have their lines starting with a star.
 
 // @has foo/fn.foo.html
-// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]'
+// @snapshot docblock - '//*[@class="toggle top-doc"]//*[@class="docblock"]'
 /**
  *     a
  */
diff --git a/tests/rustdoc/toggle-item-contents.rs b/tests/rustdoc/toggle-item-contents.rs
index 47a1d62f5a7..87240f233ff 100644
--- a/tests/rustdoc/toggle-item-contents.rs
+++ b/tests/rustdoc/toggle-item-contents.rs
@@ -1,15 +1,15 @@
 #![allow(unused)]
 
 // @has 'toggle_item_contents/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub struct PubStruct {
     pub a: usize,
     pub b: usize,
 }
 
 // @has 'toggle_item_contents/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
 pub struct BigPubStruct {
     pub a: usize,
     pub b: usize,
@@ -27,8 +27,8 @@ pub struct BigPubStruct {
 }
 
 // @has 'toggle_item_contents/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
 pub union BigUnion {
     pub a: usize,
     pub b: usize,
@@ -46,7 +46,7 @@ pub union BigUnion {
 }
 
 // @has 'toggle_item_contents/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub union Union {
     pub a: usize,
     pub b: usize,
@@ -54,7 +54,7 @@ pub union Union {
 }
 
 // @has 'toggle_item_contents/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 // @has - '//div[@class="item-decl"]' '/* private fields */'
 pub struct PrivStruct {
     a: usize,
@@ -62,7 +62,7 @@ pub struct PrivStruct {
 }
 
 // @has 'toggle_item_contents/enum.Enum.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
 pub enum Enum {
     A, B, C,
     D {
@@ -72,7 +72,7 @@ pub enum Enum {
 }
 
 // @has 'toggle_item_contents/enum.EnumStructVariant.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
 pub enum EnumStructVariant {
     A, B, C,
     D {
@@ -81,14 +81,14 @@ pub enum EnumStructVariant {
 }
 
 // @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
 pub enum LargeEnum {
     A, B, C, D, E, F(u8), G, H, I, J, K, L, M
 }
 
 // @has 'toggle_item_contents/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub trait Trait {
     type A;
     #[must_use]
@@ -97,8 +97,8 @@ pub trait Trait {
 }
 
 // @has 'toggle_item_contents/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 16 associated items'
 pub trait GinormousTrait {
     type A;
     type B;
@@ -120,8 +120,8 @@ pub trait GinormousTrait {
 }
 
 // @has 'toggle_item_contents/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
 pub trait HugeTrait {
     type A;
     const M: usize = 1;
@@ -142,8 +142,8 @@ pub trait HugeTrait {
 }
 
 // @has 'toggle_item_contents/trait.GiganticTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
 pub trait GiganticTrait {
     type A;
     type B;
@@ -163,8 +163,8 @@ pub trait GiganticTrait {
 }
 
 // @has 'toggle_item_contents/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 14 methods'
 pub trait BigTrait {
     type A;
     #[must_use]
diff --git a/tests/rustdoc/toggle-method.rs b/tests/rustdoc/toggle-method.rs
index 1aa74e59659..ebc316ca8ad 100644
--- a/tests/rustdoc/toggle-method.rs
+++ b/tests/rustdoc/toggle-method.rs
@@ -4,9 +4,9 @@
 // summary. Struct methods with no documentation should not be wrapped.
 //
 // @has foo/struct.Foo.html
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
 pub struct Foo {
 }
 
diff --git a/tests/rustdoc/toggle-trait-fn.rs b/tests/rustdoc/toggle-trait-fn.rs
index 0a1f088b9ab..686a174fc8f 100644
--- a/tests/rustdoc/toggle-trait-fn.rs
+++ b/tests/rustdoc/toggle-trait-fn.rs
@@ -4,14 +4,14 @@
 // summary. Trait methods with no documentation should not be wrapped.
 //
 // @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item2'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+// @has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item'
+// @!has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item2'
+// @has -  '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has -  '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has -  '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
+// @has -  '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
 pub trait Foo {
     /// is documented
     type Item;
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index 6dbabc8eb34..7a91dcf0dad 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                     g(ExprKind::Closure(Box::new(Closure {
                         binder: ClosureBinder::NotPresent,
                         capture_clause: CaptureBy::Value,
+                        constness: Const::No,
                         asyncness: Async::No,
                         movability: Movability::Movable,
                         fn_decl: decl.clone(),
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index c19b639a8d5..65d9601e78a 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -723,7 +723,6 @@ struct SubdiagnosticEagerLint {
 #[diag(compiletest_example)]
 struct SubdiagnosticEagerCorrect {
     #[subdiagnostic(eager)]
-    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -744,7 +743,6 @@ pub(crate) struct SubdiagnosticWithSuggestion {
 #[diag(compiletest_example)]
 struct SubdiagnosticEagerSuggestion {
     #[subdiagnostic(eager)]
-    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     sub: SubdiagnosticWithSuggestion,
 }
 
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index f39d32a221c..13e806a434f 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -539,7 +539,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic(bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `subdiagnostic` does not support nested attributes
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:693:5
@@ -553,7 +553,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic(bad, bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `subdiagnostic` does not support nested attributes
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:709:5
@@ -561,7 +561,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic("bad")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `subdiagnostic` does not support nested attributes
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:717:5
@@ -569,38 +569,22 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic(eager)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `subdiagnostic` does not support nested attributes
-
-error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:725:5
-   |
-LL |     #[subdiagnostic(eager)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `subdiagnostic` does not support nested attributes
-
-error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:746:5
-   |
-LL |     #[subdiagnostic(eager)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `subdiagnostic` does not support nested attributes
+   = help: eager subdiagnostics are not supported on lints
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:777:18
+  --> $DIR/diagnostic-derive.rs:775:18
    |
 LL |     #[suggestion(code())]
    |                  ^^^^^^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:785:23
+  --> $DIR/diagnostic-derive.rs:783:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
 error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:793:18
+  --> $DIR/diagnostic-derive.rs:791:18
    |
 LL |     #[suggestion(code = 3)]
    |                  ^^^^^^^^
@@ -676,7 +660,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 85 previous errors
+error: aborting due to 83 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed b/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed
new file mode 100644
index 00000000000..23f71520040
--- /dev/null
+++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+    type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+    type Ty = i32;
+}
+
+fn main() {
+    let _x: <dyn Trait<i32> as Assoc>::Ty; //~ ERROR ambiguous associated type
+}
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs b/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs
new file mode 100644
index 00000000000..9c26e339a44
--- /dev/null
+++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+    type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+    type Ty = i32;
+}
+
+fn main() {
+    let _x: <dyn Trait<i32>>::Ty; //~ ERROR ambiguous associated type
+}
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
new file mode 100644
index 00000000000..97088b79fd6
--- /dev/null
+++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
@@ -0,0 +1,9 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-associated-type-with-generics.rs:13:13
+   |
+LL |     let _x: <dyn Trait<i32>>::Ty;
+   |             ^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<dyn Trait<i32> as Assoc>::Ty`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
index bf4bd634cf1..d0c17062076 100644
--- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
+++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
@@ -13,7 +13,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-item-duplicate-names-3.rs:18:12
    |
 LL |     let x: Baz::Bar = 5;
-   |            ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar`
+   |            ^^^^^^^^ help: use the fully-qualified path: `<Baz as Foo>::Bar`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index 289911779ff..00856b55df5 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -2,31 +2,46 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:6:36
    |
 LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
-   |                                    ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+   |                                    ^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+   |
+LL | fn get<T:Get,U:Get>(x: T, y: U) -> <Example as Get>::Value {}
+   |                                    ~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:20:17
    |
 LL | trait Foo where Foo::Assoc: Bar {
-   |                 ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc`
+   |                 ^^^^^^^^^^ help: use the fully-qualified path: `<Self as Foo>::Assoc`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:25:10
    |
 LL | type X = std::ops::Deref::Target;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Deref>::Target`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Deref`, you could use the fully-qualified path
+   |
+LL | type X = <Example as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:11:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+   |                       ^^^^^^^^^^^ help: use the fully-qualified path: `<Self as Grab>::Value`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:14:22
    |
 LL |     fn get(&self) -> Get::Value;
-   |                      ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+   |                      ^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+   |
+LL |     fn get(&self) -> <Example as Get>::Value;
+   |                      ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/async-await/in-trait/nested-rpit.rs b/tests/ui/async-await/in-trait/nested-rpit.rs
index ae8e0aed0cc..41d72ebb4d4 100644
--- a/tests/ui/async-await/in-trait/nested-rpit.rs
+++ b/tests/ui/async-await/in-trait/nested-rpit.rs
@@ -1,5 +1,7 @@
-// check-pass
 // edition: 2021
+// known-bug: #105197
+// failure-status:101
+// dont-check-compiler-stderr
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/attributes/log-backtrace.rs b/tests/ui/attributes/log-backtrace.rs
new file mode 100644
index 00000000000..3979d2001fc
--- /dev/null
+++ b/tests/ui/attributes/log-backtrace.rs
@@ -0,0 +1,9 @@
+// run-pass
+//
+// This test makes sure that log-backtrace option doesn't give a compilation error.
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+// rustc-env:RUSTC_LOG=info
+// compile-flags: -Zlog-backtrace=rustc_metadata::creader
+fn main() {}
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
index 492316f0027..592aa4369ce 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/builtin-superkinds-double-superkind.rs:6:24
+  --> $DIR/builtin-superkinds-double-superkind.rs:6:32
    |
 LL | impl <T: Sync+'static> Foo for (T,) { }
-   |                        ^^^ `T` cannot be sent between threads safely
+   |                                ^^^^ `T` cannot be sent between threads safely
    |
    = note: required because it appears within the type `(T,)`
 note: required by a bound in `Foo`
@@ -16,10 +16,10 @@ LL | impl <T: Sync+'static + std::marker::Send> Foo for (T,) { }
    |                       +++++++++++++++++++
 
 error[E0277]: `T` cannot be shared between threads safely
-  --> $DIR/builtin-superkinds-double-superkind.rs:9:16
+  --> $DIR/builtin-superkinds-double-superkind.rs:9:24
    |
 LL | impl <T: Send> Foo for (T,T) { }
-   |                ^^^ `T` cannot be shared between threads safely
+   |                        ^^^^^ `T` cannot be shared between threads safely
    |
    = note: required because it appears within the type `(T, T)`
 note: required by a bound in `Foo`
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
index a46e4b2337c..f9d548bb8fb 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/builtin-superkinds-in-metadata.rs:13:23
+  --> $DIR/builtin-superkinds-in-metadata.rs:13:56
    |
 LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely
+   |                                                        ^^^^ `T` cannot be sent between threads safely
    |
 note: required because it appears within the type `X<T>`
   --> $DIR/builtin-superkinds-in-metadata.rs:9:8
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr
index 9db9cbfdb91..8b19170b0f1 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `Rc<i8>` cannot be sent between threads safely
-  --> $DIR/builtin-superkinds-simple.rs:6:6
+  --> $DIR/builtin-superkinds-simple.rs:6:14
    |
 LL | impl Foo for std::rc::Rc<i8> { }
-   |      ^^^ `Rc<i8>` cannot be sent between threads safely
+   |              ^^^^^^^^^^^^^^^ `Rc<i8>` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `Rc<i8>`
 note: required by a bound in `Foo`
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
index 3ec0b907d0c..0cfea72d5f1 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/builtin-superkinds-typaram-not-send.rs:5:24
+  --> $DIR/builtin-superkinds-typaram-not-send.rs:5:32
    |
 LL | impl <T: Sync+'static> Foo for T { }
-   |                        ^^^ `T` cannot be sent between threads safely
+   |                                ^ `T` cannot be sent between threads safely
    |
 note: required by a bound in `Foo`
   --> $DIR/builtin-superkinds-typaram-not-send.rs:3:13
diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs
index 087743e505d..fce6210b2f4 100644
--- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs
+++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs
@@ -1,5 +1,3 @@
-#![feature(abi_efiapi)]
-
 fn efiapi(f: extern "efiapi" fn(usize, ...)) {
     //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
     //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr
index 007d7d7953c..5b97b396fb1 100644
--- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr
+++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr
@@ -1,5 +1,5 @@
 error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14
    |
 LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@ LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
    = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
 
 error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14
    |
 LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
 
 error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12
    |
 LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,13 +23,13 @@ LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
    = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
 
 error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12
    |
 LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
 
 error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11
    |
 LL | fn win(f: extern "win64" fn(usize, ...)) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | fn win(f: extern "win64" fn(usize, ...)) {
    = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
 
 error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
-  --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
+  --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11
    |
 LL | fn win(f: extern "win64" fn(usize, ...)) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs
index 96cea87546e..c34b7e55f6a 100644
--- a/tests/ui/c-variadic/variadic-ffi-2.rs
+++ b/tests/ui/c-variadic/variadic-ffi-2.rs
@@ -1,6 +1,5 @@
 // ignore-arm stdcall isn't supported
 #![feature(extended_varargs_abi_support)]
-#![feature(abi_efiapi)]
 
 fn baz(f: extern "stdcall" fn(usize, ...)) {
     //~^ ERROR: C-variadic function must have a compatible calling convention,
diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr
index 4e74c9d9227..e21001ecaf8 100644
--- a/tests/ui/c-variadic/variadic-ffi-2.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-2.stderr
@@ -1,5 +1,5 @@
 error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `win64`, `sysv64` or `efiapi`
-  --> $DIR/variadic-ffi-2.rs:5:11
+  --> $DIR/variadic-ffi-2.rs:4:11
    |
 LL | fn baz(f: extern "stdcall" fn(usize, ...)) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs
index 86ce42631b4..1c69b07e3d4 100644
--- a/tests/ui/chalkify/bugs/async.rs
+++ b/tests/ui/chalkify/bugs/async.rs
@@ -2,12 +2,21 @@
 // known-bug
 // unset-rustc-env:RUST_BACKTRACE
 // compile-flags:-Z trait-solver=chalk --edition=2021
-// error-pattern:stack backtrace:
+// error-pattern:internal compiler error
 // failure-status:101
-// normalize-stderr-test "note: .*" -> ""
-// normalize-stderr-test "thread 'rustc' .*" -> ""
-// normalize-stderr-test "  .*\n" -> ""
 // normalize-stderr-test "DefId([^)]*)" -> "..."
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "stack backtrace:\n" -> ""
+// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
+// normalize-stderr-test ".*note: Some details.*\n" -> ""
+// normalize-stderr-test "\n\n[ ]*\n" -> ""
+// normalize-stderr-test "compiler/.*: projection" -> "projection"
 
 fn main() -> () {}
 
diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr
index 7e2466dece4..d1508cb1700 100644
--- a/tests/ui/chalkify/bugs/async.stderr
+++ b/tests/ui/chalkify/bugs/async.stderr
@@ -1,29 +1,47 @@
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
-LL |LL | |LL | | }
-
-
-error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:14:29: 16:2] as Future>::Output` cannot be known at compilation time
-LL |LL | |LL | | }
-
-
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+  --> $DIR/async.rs:23:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________-
+LL | |     x
+LL | | }
+   | | ^
+   | | |
+   | |_`[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+   |   required by a bound introduced by this call
+   |
+   = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+   = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `identity_future`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` cannot be known at compilation time
+  --> $DIR/async.rs:23:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________^
+LL | |     x
+LL | | }
+   | |_^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output`
+note: required by a bound in `identity_future`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+  --> $DIR/async.rs:23:25
+   |
 LL | async fn foo(x: u32) -> u32 {
-
-error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:14:29: 16:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+   |                         ^^^ `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+   |
+   = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+   = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+
+error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+  --> $DIR/async.rs:23:25
+   |
 LL | async fn foo(x: u32) -> u32 {
-
-
-stack backtrace:
-
-
-
-
-
-
-
-
-
-query stack during panic:
+   |                         ^^^query stack during panic:
 #0 [typeck] type-checking `foo`
 #1 [thir_body] building THIR for `foo`
 #2 [mir_built] building MIR for `foo`
diff --git a/tests/ui/chalkify/impl_wf.stderr b/tests/ui/chalkify/impl_wf.stderr
index a142459bcb4..84c32fa3771 100644
--- a/tests/ui/chalkify/impl_wf.stderr
+++ b/tests/ui/chalkify/impl_wf.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/impl_wf.rs:11:6
+  --> $DIR/impl_wf.rs:11:14
    |
 LL | impl Foo for str { }
-   |      ^^^ doesn't have a size known at compile-time
+   |              ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
 note: required by a bound in `Foo`
@@ -12,10 +12,10 @@ LL | trait Foo: Sized { }
    |            ^^^^^ required by this bound in `Foo`
 
 error[E0277]: the trait bound `f32: Foo` is not satisfied
-  --> $DIR/impl_wf.rs:22:6
+  --> $DIR/impl_wf.rs:22:19
    |
 LL | impl Baz<f32> for f32 { }
-   |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
+   |                   ^^^ the trait `Foo` is not implemented for `f32`
    |
    = help: the trait `Foo` is implemented for `i32`
 note: required by a bound in `Baz`
diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/check-static-values-constraints.stderr
index b13700a4ea5..49056678448 100644
--- a/tests/ui/check-static-values-constraints.stderr
+++ b/tests/ui/check-static-values-constraints.stderr
@@ -22,6 +22,7 @@ LL |     field2: SafeEnum::Variant4("str".to_string())
    |                                      ^^^^^^^^^^^
    |
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
 
 error[E0010]: allocations are not allowed in statics
diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.stderr b/tests/ui/coherence/coherence-overlap-trait-alias.stderr
index e324c1e799f..668b8319b38 100644
--- a/tests/ui/coherence/coherence-overlap-trait-alias.stderr
+++ b/tests/ui/coherence/coherence-overlap-trait-alias.stderr
@@ -1,8 +1,8 @@
 error[E0283]: type annotations needed: cannot satisfy `u32: C`
-  --> $DIR/coherence-overlap-trait-alias.rs:15:6
+  --> $DIR/coherence-overlap-trait-alias.rs:15:12
    |
 LL | impl C for u32 {}
-   |      ^
+   |            ^^^
    |
 note: multiple `impl`s satisfying `u32: C` found
   --> $DIR/coherence-overlap-trait-alias.rs:14:1
diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr
index e2048ecd60f..18370eea571 100644
--- a/tests/ui/const-generics/issue-93647.stderr
+++ b/tests/ui/const-generics/issue-93647.stderr
@@ -6,6 +6,7 @@ LL |     (||1usize)()
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index f6b532fb658..f735b3d53ce 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -22,6 +22,7 @@ LL |     for i in 0..x {
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/const-fn-error.rs:5:14
@@ -39,6 +40,7 @@ LL |     for i in 0..x {
    |              ^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 294ea627d85..3fb9787c0d8 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -7,6 +7,7 @@ LL |     for _ in 0..5 {}
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for.rs:5:14
@@ -15,6 +16,7 @@ LL |     for _ in 0..5 {}
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.rs b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs
new file mode 100644
index 00000000000..5fb633de983
--- /dev/null
+++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs
@@ -0,0 +1,20 @@
+struct Foo<T, const N: usize> {
+    array: [T; N],
+}
+
+trait Bar<const N: usize> {}
+
+impl<T, const N: usize> Foo<T, N> {
+    fn trigger(self) {
+        self.unsatisfied()
+        //~^ ERROR the trait bound `T: Bar<N>` is not satisfied
+    }
+
+    fn unsatisfied(self)
+    where
+        T: Bar<N>,
+    {
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr
new file mode 100644
index 00000000000..43fba2573ff
--- /dev/null
+++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `T: Bar<N>` is not satisfied
+  --> $DIR/ct-var-in-collect_all_mismatches.rs:9:14
+   |
+LL |         self.unsatisfied()
+   |              ^^^^^^^^^^^ the trait `Bar<N>` is not implemented for `T`
+   |
+note: required by a bound in `Foo::<T, N>::unsatisfied`
+  --> $DIR/ct-var-in-collect_all_mismatches.rs:15:12
+   |
+LL |     fn unsatisfied(self)
+   |        ----------- required by a bound in this
+LL |     where
+LL |         T: Bar<N>,
+   |            ^^^^^^ required by this bound in `Foo::<T, N>::unsatisfied`
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: Bar<N>, const N: usize> Foo<T, N> {
+   |       ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
index ab594c921f9..257ecd7f3cf 100644
--- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
+++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
@@ -6,6 +6,7 @@ LL |         const { (|| {})() } => {}
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr
index 7ad1f752eb0..1294cc99bf7 100644
--- a/tests/ui/consts/issue-28113.stderr
+++ b/tests/ui/consts/issue-28113.stderr
@@ -6,6 +6,7 @@ LL |     || -> u8 { 5 }()
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr
index 2579b3e7827..845b23d5d87 100644
--- a/tests/ui/consts/issue-56164.stderr
+++ b/tests/ui/consts/issue-56164.stderr
@@ -6,6 +6,7 @@ LL | const fn foo() { (||{})() }
    |
    = note: closures need an RFC before allowed to be called in constant functions
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: function pointer calls are not allowed in constant functions
   --> $DIR/issue-56164.rs:5:5
diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
index 74fbbc680f7..d23513ed7ff 100644
--- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr
+++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
@@ -6,6 +6,7 @@ LL |     a: [(); (|| { 0 })()]
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/issue-90870.fixed b/tests/ui/consts/issue-90870.fixed
index 0d28e06e532..df44689efed 100644
--- a/tests/ui/consts/issue-90870.fixed
+++ b/tests/ui/consts/issue-90870.fixed
@@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool {
     *a == *b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
+    //~| HELP: add `#![feature(const_trait_impl)]`
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     ****a == ****b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
+    //~| HELP: add `#![feature(const_trait_impl)]`
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
@@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
         if *l == *r {
         //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
+        //~| HELP: add `#![feature(const_trait_impl)]`
             a = at;
             b = bt;
         } else {
diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs
index c6bfffd2c5c..676ac73c64d 100644
--- a/tests/ui/consts/issue-90870.rs
+++ b/tests/ui/consts/issue-90870.rs
@@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool {
     a == b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
+    //~| HELP: add `#![feature(const_trait_impl)]`
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     a == b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
+    //~| HELP: add `#![feature(const_trait_impl)]`
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
@@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
         if l == r {
         //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
+        //~| HELP: add `#![feature(const_trait_impl)]`
             a = at;
             b = bt;
         } else {
diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr
index 478445cfb39..8825efd1449 100644
--- a/tests/ui/consts/issue-90870.stderr
+++ b/tests/ui/consts/issue-90870.stderr
@@ -5,30 +5,33 @@ LL |     a == b
    |     ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 help: consider dereferencing here
    |
 LL |     *a == *b
    |     +     +
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:14:5
+  --> $DIR/issue-90870.rs:15:5
    |
 LL |     a == b
    |     ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 help: consider dereferencing here
    |
 LL |     ****a == ****b
    |     ++++     ++++
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:21:12
+  --> $DIR/issue-90870.rs:23:12
    |
 LL |         if l == r {
    |            ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 help: consider dereferencing here
    |
 LL |         if *l == *r {
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr
index 21f957ab549..55096e95df7 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr
@@ -61,25 +61,45 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:1:10
    |
 LL | type A = [u8; 4]::AssocTy;
-   |          ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8; 4] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8; 4]`, you could use the fully-qualified path
+   |
+LL | type A = <[u8; 4] as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:5:10
    |
 LL | type B = [u8]::AssocTy;
-   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8]`, you could use the fully-qualified path
+   |
+LL | type B = <[u8] as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:9:10
    |
 LL | type C = (u8)::AssocTy;
-   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type C = <u8 as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:13:10
    |
 LL | type D = (u8, u8)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(u8, u8)`, you could use the fully-qualified path
+   |
+LL | type D = <(u8, u8) as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/bad-assoc-ty.rs:17:10
@@ -91,13 +111,23 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:21:19
    |
 LL | type F = &'static (u8)::AssocTy;
-   |                   ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |                   ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type F = &'static <u8 as Example>::AssocTy;
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:27:10
    |
 LL | type G = dyn 'static + (Send)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(dyn Send + 'static)`, you could use the fully-qualified path
+   |
+LL | type G = <(dyn Send + 'static) as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/bad-assoc-ty.rs:33:10
@@ -117,24 +147,33 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:33:10
    |
 LL | type H = Fn(u8) -> (u8)::Output;
-   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output`
+   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:39:19
    |
 LL |     ($ty: ty) => ($ty::AssocTy);
-   |                   ^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |                   ^^^^^^^^^^^^
 ...
 LL | type J = ty!(u8);
    |          ------- in this macro invocation
    |
    = note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL |     ($ty: ty) => (<u8 as Example>::AssocTy);
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:46:10
    |
 LL | type I = ty!()::AssocTy;
-   |          ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type I = <u8 as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:51:13
diff --git a/tests/ui/dst/dst-sized-trait-param.stderr b/tests/ui/dst/dst-sized-trait-param.stderr
index 8ec94f5a3c0..60e9de90332 100644
--- a/tests/ui/dst/dst-sized-trait-param.stderr
+++ b/tests/ui/dst/dst-sized-trait-param.stderr
@@ -16,10 +16,10 @@ LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is siz
    |            ++++++++
 
 error[E0277]: the size for values of type `[usize]` cannot be known at compilation time
-  --> $DIR/dst-sized-trait-param.rs:10:6
+  --> $DIR/dst-sized-trait-param.rs:10:21
    |
 LL | impl Foo<isize> for [usize] { }
-   |      ^^^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[usize]`
 note: required by a bound in `Foo`
diff --git a/tests/ui/error-codes/E0223.rs b/tests/ui/error-codes/E0223.rs
index 6031b682d72..2fe252de256 100644
--- a/tests/ui/error-codes/E0223.rs
+++ b/tests/ui/error-codes/E0223.rs
@@ -1,4 +1,8 @@
 trait MyTrait { type X; }
+struct MyStruct;
+impl MyTrait for MyStruct {
+    type X = ();
+}
 
 fn main() {
     let foo: MyTrait::X;
diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr
index 726f39e11f1..42945e42f6e 100644
--- a/tests/ui/error-codes/E0223.stderr
+++ b/tests/ui/error-codes/E0223.stderr
@@ -1,8 +1,8 @@
 error[E0223]: ambiguous associated type
-  --> $DIR/E0223.rs:4:14
+  --> $DIR/E0223.rs:8:14
    |
 LL |     let foo: MyTrait::X;
-   |              ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as MyTrait>::X`
+   |              ^^^^^^^^^^ help: use the fully-qualified path: `<MyStruct as MyTrait>::X`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0308-2.stderr b/tests/ui/error-codes/E0308-2.stderr
index de54a417253..3a8a81a73a6 100644
--- a/tests/ui/error-codes/E0308-2.stderr
+++ b/tests/ui/error-codes/E0308-2.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
-  --> $DIR/E0308-2.rs:9:6
+  --> $DIR/E0308-2.rs:9:13
    |
 LL | impl Eq for &dyn DynEq {}
-   |      ^^ lifetime mismatch
+   |             ^^^^^^^^^^ lifetime mismatch
    |
    = note: expected trait `<&dyn DynEq as PartialEq>`
               found trait `<&(dyn DynEq + 'static) as PartialEq>`
diff --git a/tests/ui/feature-gates/feature-gate-abi-efiapi.rs b/tests/ui/feature-gates/feature-gate-abi-efiapi.rs
deleted file mode 100644
index 0c0d736acd0..00000000000
--- a/tests/ui/feature-gates/feature-gate-abi-efiapi.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// needs-llvm-components: x86
-// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
-#![no_core]
-#![feature(no_core, lang_items)]
-#[lang="sized"]
-trait Sized { }
-
-// Functions
-extern "efiapi" fn f1() {} //~ ERROR efiapi ABI is experimental
-
-// Methods in trait defintion
-trait Tr {
-    extern "efiapi" fn f2(); //~ ERROR efiapi ABI is experimental
-    extern "efiapi" fn f3() {} //~ ERROR efiapi ABI is experimental
-}
-
-struct S;
-
-// Methods in trait impl
-impl Tr for S {
-    extern "efiapi" fn f2() {} //~ ERROR efiapi ABI is experimental
-}
-
-// Methods in inherent impl
-impl S {
-    extern "efiapi" fn f4() {} //~ ERROR efiapi ABI is experimental
-}
-
-// Function pointer types
-type A = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental
-
-// Foreign modules
-extern "efiapi" {} //~ ERROR efiapi ABI is experimental
diff --git a/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr b/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr
deleted file mode 100644
index 5b01dcc6d85..00000000000
--- a/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr
+++ /dev/null
@@ -1,66 +0,0 @@
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:9:8
-   |
-LL | extern "efiapi" fn f1() {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:13:12
-   |
-LL |     extern "efiapi" fn f2();
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:14:12
-   |
-LL |     extern "efiapi" fn f3() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:21:12
-   |
-LL |     extern "efiapi" fn f2() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:26:12
-   |
-LL |     extern "efiapi" fn f4() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:30:17
-   |
-LL | type A = extern "efiapi" fn();
-   |                 ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-efiapi.rs:33:8
-   |
-LL | extern "efiapi" {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
index 26bdf460f5e..9d4ea01152c 100644
--- a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
+++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
@@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope
   --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13
    |
 LL | impl Struct<T>
-   |     -       ^ not found in this scope
-   |     |
-   |     help: you might be missing a type parameter: `<T>`
+   |             ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<T> Struct<T>
+   |     +++
 
 error[E0412]: cannot find type `T` in this scope
   --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5
diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs
index fd0986d7c0a..b3ff2ce5a7b 100644
--- a/tests/ui/impl-trait/impl_trait_projections.rs
+++ b/tests/ui/impl-trait/impl_trait_projections.rs
@@ -11,7 +11,7 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
 
 fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
 //~^ ERROR `impl Trait` is not allowed in path parameters
-//~^^ ERROR ambiguous associated type
+//~| ERROR `impl Trait` is not allowed in path parameters
     x.next().unwrap()
 }
 
diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr
index 82d2422c407..4deb24731bc 100644
--- a/tests/ui/impl-trait/impl_trait_projections.stderr
+++ b/tests/ui/impl-trait/impl_trait_projections.stderr
@@ -22,13 +22,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters
 LL |     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
    |                             ^^^^^^^^^^
 
-error[E0223]: ambiguous associated type
-  --> $DIR/impl_trait_projections.rs:12:50
+error[E0667]: `impl Trait` is not allowed in path parameters
+  --> $DIR/impl_trait_projections.rs:12:51
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<impl Iterator as Trait>::Item`
+   |                                                   ^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0223, E0667.
-For more information about an error, try `rustc --explain E0223`.
+For more information about this error, try `rustc --explain E0667`.
diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
index 0ac31c642eb..ebe07027d2f 100644
--- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
+++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
@@ -1,8 +1,8 @@
 error: impl method assumes more implied bounds than the corresponding trait method
-  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
    |
 LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
+   |
+LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
index 0dfa8167a99..43d3e058ffe 100644
--- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
+++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
@@ -1,8 +1,8 @@
 error: impl method assumes more implied bounds than the corresponding trait method
-  --> $DIR/impl-implied-bounds-compatibility.rs:14:5
+  --> $DIR/impl-implied-bounds-compatibility.rs:14:35
    |
 LL |     fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility.rs:14:35
+   |
+LL |     fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/issues/issue-23073.stderr b/tests/ui/issues/issue-23073.stderr
index 3a10a1ab11a..3a9f49ef167 100644
--- a/tests/ui/issues/issue-23073.stderr
+++ b/tests/ui/issues/issue-23073.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-23073.rs:6:17
    |
 LL |     type FooT = <<Self as Bar>::Foo>::T;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<Self as Bar>::Foo as Trait>::T`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `T` implemented for `<Self as Bar>::Foo`, you could use the fully-qualified path
+   |
+LL |     type FooT = <<Self as Bar>::Foo as Example>::T;
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-58712.stderr b/tests/ui/issues/issue-58712.stderr
index 87c16aa993b..f4bd4d1e826 100644
--- a/tests/ui/issues/issue-58712.stderr
+++ b/tests/ui/issues/issue-58712.stderr
@@ -2,9 +2,12 @@ error[E0412]: cannot find type `DeviceId` in this scope
   --> $DIR/issue-58712.rs:6:20
    |
 LL | impl<H> AddrVec<H, DeviceId> {
-   |       -            ^^^^^^^^ not found in this scope
-   |       |
-   |       help: you might be missing a type parameter: `, DeviceId`
+   |                    ^^^^^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<H, DeviceId> AddrVec<H, DeviceId> {
+   |       ++++++++++
 
 error[E0412]: cannot find type `DeviceId` in this scope
   --> $DIR/issue-58712.rs:8:29
diff --git a/tests/ui/issues/issue-65230.stderr b/tests/ui/issues/issue-65230.stderr
index fcabcdea74f..7ccab889483 100644
--- a/tests/ui/issues/issue-65230.stderr
+++ b/tests/ui/issues/issue-65230.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-65230.rs:8:6
+  --> $DIR/issue-65230.rs:8:13
    |
 LL | impl T1 for &dyn T2 {}
-   |      ^^ lifetime mismatch
+   |             ^^^^^^^ lifetime mismatch
    |
    = note: expected trait `<&dyn T2 as T0>`
               found trait `<&(dyn T2 + 'static) as T0>`
diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr
index ca256847b1f..d154bfe0cb5 100644
--- a/tests/ui/issues/issue-77919.stderr
+++ b/tests/ui/issues/issue-77919.stderr
@@ -13,9 +13,12 @@ error[E0412]: cannot find type `VAL` in this scope
   --> $DIR/issue-77919.rs:11:63
    |
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
-   |          -                                                    ^^^ not found in this scope
-   |          |
-   |          help: you might be missing a type parameter: `, VAL`
+   |                                                               ^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   |          +++++
 
 error[E0046]: not all trait items implemented, missing: `VAL`
   --> $DIR/issue-77919.rs:11:1
diff --git a/tests/ui/issues/issue-78622.stderr b/tests/ui/issues/issue-78622.stderr
index f7d44f21d3b..70daf8a2f1a 100644
--- a/tests/ui/issues/issue-78622.stderr
+++ b/tests/ui/issues/issue-78622.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-78622.rs:5:5
    |
 LL |     S::A::<f> {}
-   |     ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |     ^^^^
+   |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     <S as Example>::A::<f> {}
+   |     ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr
index 6c5917bdf6e..bfa7459ab4a 100644
--- a/tests/ui/issues/issue-86756.stderr
+++ b/tests/ui/issues/issue-86756.stderr
@@ -9,8 +9,6 @@ LL | trait Foo<T, T = T> {}
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/issue-86756.rs:5:10
    |
-LL | fn eq<A, B>() {
-   |           - help: you might be missing a type parameter: `, dyn`
 LL |     eq::<dyn, Foo>
    |          ^^^ not found in this scope
 
diff --git a/tests/ui/iterators/float_iterator_hint.rs b/tests/ui/iterators/float_iterator_hint.rs
new file mode 100644
index 00000000000..a3335ca41f7
--- /dev/null
+++ b/tests/ui/iterators/float_iterator_hint.rs
@@ -0,0 +1,15 @@
+// #106728
+
+fn main() {
+    for i in 0.2 {
+        //~^ ERROR `{float}` is not an iterator
+        //~| `{float}` is not an iterator
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+        //~| NOTE required for `{float}` to implement `IntoIterator`
+        println!();
+    }
+}
diff --git a/tests/ui/iterators/float_iterator_hint.stderr b/tests/ui/iterators/float_iterator_hint.stderr
new file mode 100644
index 00000000000..bae23a1f8ff
--- /dev/null
+++ b/tests/ui/iterators/float_iterator_hint.stderr
@@ -0,0 +1,13 @@
+error[E0277]: `{float}` is not an iterator
+  --> $DIR/float_iterator_hint.rs:4:14
+   |
+LL |     for i in 0.2 {
+   |              ^^^ `{float}` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `{float}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required for `{float}` to implement `IntoIterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/iterators/integral.stderr b/tests/ui/iterators/integral.stderr
index 047a71f98d9..c142fec8da0 100644
--- a/tests/ui/iterators/integral.stderr
+++ b/tests/ui/iterators/integral.stderr
@@ -115,6 +115,7 @@ LL |     for _ in 42.0 {}
    |              ^^^^ `{float}` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `{float}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `{float}` to implement `IntoIterator`
 
 error: aborting due to 12 previous errors
diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs
new file mode 100644
index 00000000000..882a1d13954
--- /dev/null
+++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let x = Some(()).iter().map(|()| 1).sum::<f32>();
+    //~^ ERROR a value of type `f32` cannot be made by summing an iterator over elements of type `{integer}`
+}
diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr
new file mode 100644
index 00000000000..3cb5e44c711
--- /dev/null
+++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr
@@ -0,0 +1,24 @@
+error[E0277]: a value of type `f32` cannot be made by summing an iterator over elements of type `{integer}`
+  --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:41
+   |
+LL |     let x = Some(()).iter().map(|()| 1).sum::<f32>();
+   |                                         ^^^ value of type `f32` cannot be made by summing a `std::iter::Iterator<Item={integer}>`
+   |
+   = help: the trait `Sum<{integer}>` is not implemented for `f32`
+   = help: the following other types implement trait `Sum<A>`:
+             <f32 as Sum<&'a f32>>
+             <f32 as Sum>
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29
+   |
+LL |     let x = Some(()).iter().map(|()| 1).sum::<f32>();
+   |             -------- ------ ^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here
+   |             |        |
+   |             |        `Iterator::Item` is `&()` here
+   |             this expression has type `Option<()>`
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr
new file mode 100644
index 00000000000..65c99a93c75
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr
@@ -0,0 +1,8 @@
+error: parameter 2 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:75:38
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                                      ^^ help: change the type from `i8` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr
new file mode 100644
index 00000000000..f0947a9b3e9
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr
@@ -0,0 +1,8 @@
+error: parameter 3 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:89:52
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
+   |                                                    ^^ help: change the type from `u8` to `*const *const u8`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
new file mode 100644
index 00000000000..08efd5088f9
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
@@ -0,0 +1,13 @@
+error: parameter 3 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:82:52
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
+   |                                                    ^^^^^^^^^^^^^^^^^^^
+   |
+help: change the type from `*const *const usize` to `*const *const u8`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                                                    ~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
new file mode 100644
index 00000000000..c20a744661d
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
@@ -0,0 +1,13 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:61:20
+   |
+LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^^^^^^^^^^
+   |
+help: change the type from `fn(i32) -> T` to `fn() -> T`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
new file mode 100644
index 00000000000..8f967252f49
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
@@ -0,0 +1,13 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:68:20
+   |
+LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^^^^^^^^^
+   |
+help: change the type from `fn() -> u16` to `fn() -> T`
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
new file mode 100644
index 00000000000..deb37b868ea
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
@@ -0,0 +1,8 @@
+error: parameter 1 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:54:20
+   |
+LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   |                    ^^^ help: change the type from `u64` to `fn() -> T`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
new file mode 100644
index 00000000000..004c2a67f62
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:15:1
+   |
+LL | fn start<T>() -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 0
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
new file mode 100644
index 00000000000..1d8285b5900
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
@@ -0,0 +1,8 @@
+error: the return type of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:29:84
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
+   |                                                                                    ^ help: change the type from `()` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
new file mode 100644
index 00000000000..e545a750f24
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:22:1
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 3
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs
new file mode 100644
index 00000000000..0dbfba39cb6
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.rs
@@ -0,0 +1,101 @@
+// check-fail
+// revisions: missing_all_args missing_sigpipe_arg missing_ret start_ret too_many_args
+// revisions: main_ty main_args main_ret argc argv_inner_ptr argv sigpipe
+
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "sized"]
+pub trait Sized {}
+
+#[cfg(missing_all_args)]
+#[lang = "start"]
+fn start<T>() -> isize {
+    //[missing_all_args]~^ ERROR incorrect number of parameters
+    100
+}
+
+#[cfg(missing_sigpipe_arg)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+    //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters
+    100
+}
+
+#[cfg(missing_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
+//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect
+
+#[cfg(start_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
+    //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(too_many_args)]
+#[lang = "start"]
+fn start<T>(
+    //[too_many_args]~^ ERROR incorrect number of parameters
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+    _extra_arg: (),
+) -> isize {
+    100
+}
+
+#[cfg(main_ty)]
+#[lang = "start"]
+fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(main_args)]
+#[lang = "start"]
+fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(main_ret)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argc)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argv_inner_ptr)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
+    //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(argv)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
+    //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    100
+}
+
+#[cfg(sigpipe)]
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
+    //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect
+    100
+}
+
+fn main() {}
diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
new file mode 100644
index 00000000000..b20ae312801
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
@@ -0,0 +1,8 @@
+error: parameter 4 of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:96:80
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
+   |                                                                                ^^^ help: change the type from `i64` to `u8`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
new file mode 100644
index 00000000000..935d5f3c8b4
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
@@ -0,0 +1,8 @@
+error: the return type of the `start` lang item is incorrect
+  --> $DIR/start_lang_item_args.rs:34:87
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
+   |                                                                                       ^^ help: change the type from `u8` to `isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
new file mode 100644
index 00000000000..30a7ed18a3d
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
@@ -0,0 +1,17 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/start_lang_item_args.rs:41:1
+   |
+LL | / fn start<T>(
+LL | |
+LL | |     _main: fn() -> T,
+LL | |     _argc: isize,
+...  |
+LL | |     _extra_arg: (),
+LL | | ) -> isize {
+   | |__________^
+   |
+   = note: the `start` lang item should have four parameters, but found 5
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index 8ed303ca606..a19f4963c23 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -16,7 +16,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
-   |            ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
+   |            ^^^^^^^ help: use the fully-qualified path: `<dyn Dyn as Assoc>::Ty`
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/bare-trait-objects-path.rs:14:5
diff --git a/tests/ui/lint/lint-ffi-safety-all-phantom.rs b/tests/ui/lint/lint-ffi-safety-all-phantom.rs
new file mode 100644
index 00000000000..7419d345800
--- /dev/null
+++ b/tests/ui/lint/lint-ffi-safety-all-phantom.rs
@@ -0,0 +1,22 @@
+// This is a regression test for issue https://github.com/rust-lang/rust/issues/106629.
+// It ensures that transparent types where all fields are PhantomData are marked as
+// FFI-safe.
+
+// check-pass
+
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+struct MyPhantom(core::marker::PhantomData<u8>);
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct Bar {
+    pub x: i32,
+    _marker: MyPhantom,
+}
+
+extern "C" {
+    pub fn foo(bar: *mut Bar);
+}
+
+fn main() {}
diff --git a/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr b/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr
index 235c89e200a..3cd59d6926e 100644
--- a/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr
+++ b/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr
@@ -1,8 +1,8 @@
 error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
-  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:6
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:17
    |
 LL | impl Marker for &'_ () {}
-   |      ^^^^^^
+   |                 ^^^^^^
    |
 note: multiple `impl`s satisfying `&(): Marker` found
   --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
@@ -13,10 +13,10 @@ LL | impl Marker for &'_ () {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
-  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:6
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:17
    |
 LL | impl Marker for &'_ () {}
-   |      ^^^^^^
+   |                 ^^^^^^
    |
 note: multiple `impl`s satisfying `&(): Marker` found
   --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
diff --git a/tests/ui/marker_trait_attr/region-overlap.stderr b/tests/ui/marker_trait_attr/region-overlap.stderr
index 6631fe987e2..c6497b4669d 100644
--- a/tests/ui/marker_trait_attr/region-overlap.stderr
+++ b/tests/ui/marker_trait_attr/region-overlap.stderr
@@ -1,8 +1,8 @@
 error[E0283]: type annotations needed: cannot satisfy `(&'static (), &'a ()): A`
-  --> $DIR/region-overlap.rs:5:10
+  --> $DIR/region-overlap.rs:5:16
    |
 LL | impl<'a> A for (&'static (), &'a ()) {}
-   |          ^
+   |                ^^^^^^^^^^^^^^^^^^^^^
    |
 note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found
   --> $DIR/region-overlap.rs:5:1
@@ -13,10 +13,10 @@ LL | impl<'a> A for (&'a (), &'static ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed: cannot satisfy `(&'a (), &'static ()): A`
-  --> $DIR/region-overlap.rs:6:10
+  --> $DIR/region-overlap.rs:6:16
    |
 LL | impl<'a> A for (&'a (), &'static ()) {}
-   |          ^
+   |                ^^^^^^^^^^^^^^^^^^^^^
    |
 note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found
   --> $DIR/region-overlap.rs:5:1
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index de5c9c56016..33b7a9185d0 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -47,6 +47,7 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constants
   --> $DIR/issue-52443.rs:9:21
@@ -64,6 +65,7 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr
index 9218ae9d5da..0cae01bd1e3 100644
--- a/tests/ui/parser/dyn-trait-compatibility.stderr
+++ b/tests/ui/parser/dyn-trait-compatibility.stderr
@@ -26,17 +26,13 @@ error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:5:15
    |
 LL | type A2 = dyn<dyn, dyn>;
-   |        -      ^^^ not found in this scope
-   |        |
-   |        help: you might be missing a type parameter: `<dyn>`
+   |               ^^^ not found in this scope
 
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:5:20
    |
 LL | type A2 = dyn<dyn, dyn>;
-   |        -           ^^^ not found in this scope
-   |        |
-   |        help: you might be missing a type parameter: `<dyn>`
+   |                    ^^^ not found in this scope
 
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:9:11
@@ -48,9 +44,7 @@ error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:9:16
    |
 LL | type A3 = dyn<<dyn as dyn>::dyn>;
-   |        -       ^^^ not found in this scope
-   |        |
-   |        help: you might be missing a type parameter: `<dyn>`
+   |                ^^^ not found in this scope
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/parser/recover-quantified-closure.rs b/tests/ui/parser/recover-quantified-closure.rs
index 10af39b7007..df22f5e065c 100644
--- a/tests/ui/parser/recover-quantified-closure.rs
+++ b/tests/ui/parser/recover-quantified-closure.rs
@@ -7,6 +7,6 @@ fn main() {
 enum Foo { Bar }
 fn foo(x: impl Iterator<Item = Foo>) {
     for <Foo>::Bar in x {}
-    //~^ ERROR expected one of `move`, `static`, `|`
+    //~^ ERROR expected one of `const`, `move`, `static`, `|`
     //~^^ ERROR `for<...>` binders for closures are experimental
 }
diff --git a/tests/ui/parser/recover-quantified-closure.stderr b/tests/ui/parser/recover-quantified-closure.stderr
index 39eec80f658..9ec4d2c034d 100644
--- a/tests/ui/parser/recover-quantified-closure.stderr
+++ b/tests/ui/parser/recover-quantified-closure.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `static`, `|`, or `||`, found `::`
+error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::`
   --> $DIR/recover-quantified-closure.rs:9:14
    |
 LL |     for <Foo>::Bar in x {}
-   |              ^^ expected one of `move`, `static`, `|`, or `||`
+   |              ^^ expected one of `const`, `move`, `static`, `|`, or `||`
 
 error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5
diff --git a/tests/ui/privacy/issue-75906.stderr b/tests/ui/privacy/issue-75906.stderr
index 4c6a68646ad..600dc7c876f 100644
--- a/tests/ui/privacy/issue-75906.stderr
+++ b/tests/ui/privacy/issue-75906.stderr
@@ -9,6 +9,10 @@ note: constructor is not visible here due to private fields
    |
 LL |     pub struct Bar(u8);
    |                    ^^ private field
+help: consider making the field publicly accessible
+   |
+LL |     pub struct Bar(pub u8);
+   |                    +++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/privacy/issue-75907.rs b/tests/ui/privacy/issue-75907.rs
index 6da99cf6435..3bed841d13e 100644
--- a/tests/ui/privacy/issue-75907.rs
+++ b/tests/ui/privacy/issue-75907.rs
@@ -2,7 +2,7 @@
 
 mod foo {
     pub(crate) struct Foo(u8);
-    pub(crate) struct Bar(pub u8, u8, Foo);
+    pub(crate) struct Bar(pub u8, pub(in crate::foo) u8, Foo);
 
     pub(crate) fn make_bar() -> Bar {
         Bar(1, 12, Foo(10))
diff --git a/tests/ui/privacy/issue-75907.stderr b/tests/ui/privacy/issue-75907.stderr
index 2f89e31a31a..f7cb874c2cc 100644
--- a/tests/ui/privacy/issue-75907.stderr
+++ b/tests/ui/privacy/issue-75907.stderr
@@ -11,6 +11,10 @@ LL |     let Bar(x, y, Foo(z)) = make_bar();
    |                ^  ^^^^^^ private field
    |                |
    |                private field
+help: consider making the fields publicly accessible
+   |
+LL |     pub(crate) struct Bar(pub u8, pub u8, pub Foo);
+   |                           ~~~     ~~~     +++
 
 error[E0532]: cannot match against a tuple struct which contains private fields
   --> $DIR/issue-75907.rs:15:19
@@ -23,6 +27,10 @@ note: constructor is not visible here due to private fields
    |
 LL |     let Bar(x, y, Foo(z)) = make_bar();
    |                       ^ private field
+help: consider making the field publicly accessible
+   |
+LL |     pub(crate) struct Foo(pub u8);
+   |                           +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/privacy/privacy5.stderr b/tests/ui/privacy/privacy5.stderr
index 680161272ce..615b0af2762 100644
--- a/tests/ui/privacy/privacy5.stderr
+++ b/tests/ui/privacy/privacy5.stderr
@@ -12,6 +12,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:52:16
@@ -27,6 +31,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:53:16
@@ -42,6 +50,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:56:12
@@ -57,6 +69,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:57:12
@@ -72,6 +88,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:58:18
@@ -87,6 +107,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:59:18
@@ -102,6 +126,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:61:12
@@ -117,6 +145,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:62:12
@@ -132,6 +164,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:63:18
@@ -147,6 +183,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:64:18
@@ -162,6 +202,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:65:18
@@ -177,6 +221,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:65:32
@@ -192,6 +240,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:68:12
@@ -207,6 +259,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:69:12
@@ -222,6 +278,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:70:12
@@ -237,6 +297,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:71:12
@@ -252,6 +316,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:72:18
@@ -267,6 +335,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:73:18
@@ -282,6 +354,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:74:18
@@ -297,6 +373,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:75:18
@@ -312,6 +392,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:83:17
@@ -327,6 +411,10 @@ note: the tuple struct constructor `A` is defined here
    |
 LL |     pub struct A(());
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub ());
+   |                  +++
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:84:17
@@ -342,6 +430,10 @@ note: the tuple struct constructor `B` is defined here
    |
 LL |     pub struct B(isize);
    |     ^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct B(pub isize);
+   |                  +++
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:85:17
@@ -357,6 +449,10 @@ note: the tuple struct constructor `C` is defined here
    |
 LL |     pub struct C(pub isize, isize);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the fields publicly accessible
+   |
+LL |     pub struct C(pub isize, pub isize);
+   |                  ~~~        +++
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:90:20
diff --git a/tests/ui/privacy/suggest-making-field-public.fixed b/tests/ui/privacy/suggest-making-field-public.fixed
new file mode 100644
index 00000000000..78e335b3db1
--- /dev/null
+++ b/tests/ui/privacy/suggest-making-field-public.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+mod a {
+    pub struct A(pub String);
+}
+
+mod b {
+    use crate::a::A;
+    pub fn x() {
+        A("".into()); //~ ERROR cannot initialize a tuple struct which contains private fields
+    }
+}
+fn main() {
+    a::A("a".into()); //~ ERROR tuple struct constructor `A` is private
+    b::x();
+}
diff --git a/tests/ui/privacy/suggest-making-field-public.rs b/tests/ui/privacy/suggest-making-field-public.rs
new file mode 100644
index 00000000000..b65c801d10e
--- /dev/null
+++ b/tests/ui/privacy/suggest-making-field-public.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+mod a {
+    pub struct A(pub(self)String);
+}
+
+mod b {
+    use crate::a::A;
+    pub fn x() {
+        A("".into()); //~ ERROR cannot initialize a tuple struct which contains private fields
+    }
+}
+fn main() {
+    a::A("a".into()); //~ ERROR tuple struct constructor `A` is private
+    b::x();
+}
diff --git a/tests/ui/privacy/suggest-making-field-public.stderr b/tests/ui/privacy/suggest-making-field-public.stderr
new file mode 100644
index 00000000000..e92e9aae310
--- /dev/null
+++ b/tests/ui/privacy/suggest-making-field-public.stderr
@@ -0,0 +1,39 @@
+error[E0603]: tuple struct constructor `A` is private
+  --> $DIR/suggest-making-field-public.rs:13:8
+   |
+LL |     pub struct A(pub(self)String);
+   |                  --------------- a constructor is private if any of the fields is private
+...
+LL |     a::A("a".into());
+   |        ^ private tuple struct constructor
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/suggest-making-field-public.rs:3:5
+   |
+LL |     pub struct A(pub(self)String);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub String);
+   |                  ~~~
+
+error[E0423]: cannot initialize a tuple struct which contains private fields
+  --> $DIR/suggest-making-field-public.rs:9:9
+   |
+LL |         A("".into());
+   |         ^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/suggest-making-field-public.rs:3:18
+   |
+LL |     pub struct A(pub(self)String);
+   |                  ^^^^^^^^^^^^^^^ private field
+help: consider making the field publicly accessible
+   |
+LL |     pub struct A(pub String);
+   |                  ~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0423, E0603.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs
new file mode 100644
index 00000000000..ad312a875e3
--- /dev/null
+++ b/tests/ui/proc-macro/panic-abort.rs
@@ -0,0 +1,4 @@
+// error-pattern: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+// compile-flags: --crate-type proc-macro -Cpanic=abort
+// force-host
+// check-pass
diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr
new file mode 100644
index 00000000000..a6e18614f8f
--- /dev/null
+++ b/tests/ui/proc-macro/panic-abort.stderr
@@ -0,0 +1,4 @@
+warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr
index 948f21fce4b..b6cf19b8286 100644
--- a/tests/ui/qualified/qualified-path-params-2.stderr
+++ b/tests/ui/qualified/qualified-path-params-2.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/qualified-path-params-2.rs:18:10
    |
 LL | type A = <S as Tr>::A::f<u8>;
-   |          ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<S as Tr>::A as Trait>::f`
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path
+   |
+LL | type A = <<S as Tr>::A as Example>::f;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/issue-103202.stderr b/tests/ui/resolve/issue-103202.stderr
index 880389371ef..d4d141fb06f 100644
--- a/tests/ui/resolve/issue-103202.stderr
+++ b/tests/ui/resolve/issue-103202.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-103202.rs:4:17
    |
 LL |     fn f(self: &S::x) {}
-   |                 ^^^^ help: use fully-qualified syntax: `<S as Trait>::x`
+   |                 ^^^^
+   |
+help: if there were a trait named `Example` with associated type `x` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     fn f(self: &<S as Example>::x) {}
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr
index ea27e7bd250..e9d8eb0835b 100644
--- a/tests/ui/resolve/issue-39559-2.stderr
+++ b/tests/ui/resolve/issue-39559-2.stderr
@@ -5,6 +5,7 @@ LL |     let array: [usize; Dim3::dim()]
    |                        ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:16:15
@@ -13,6 +14,7 @@ LL |         = [0; Dim3::dim()];
    |               ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/issue-42944.rs b/tests/ui/resolve/issue-42944.rs
index a4404857a56..7e439c10b7b 100644
--- a/tests/ui/resolve/issue-42944.rs
+++ b/tests/ui/resolve/issue-42944.rs
@@ -1,5 +1,5 @@
 mod foo {
-    pub struct Bx(());
+    pub struct Bx(pub(in crate::foo) ());
 }
 
 mod bar {
diff --git a/tests/ui/resolve/issue-42944.stderr b/tests/ui/resolve/issue-42944.stderr
index 0ee9fd391fe..4ffa9402c66 100644
--- a/tests/ui/resolve/issue-42944.stderr
+++ b/tests/ui/resolve/issue-42944.stderr
@@ -7,8 +7,8 @@ LL |         Bx(());
 note: tuple struct `foo::Bx` exists but is inaccessible
   --> $DIR/issue-42944.rs:2:5
    |
-LL |     pub struct Bx(());
-   |     ^^^^^^^^^^^^^^^^^^ not accessible
+LL |     pub struct Bx(pub(in crate::foo) ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0423]: cannot initialize a tuple struct which contains private fields
   --> $DIR/issue-42944.rs:9:9
@@ -19,8 +19,12 @@ LL |         Bx(());
 note: constructor is not visible here due to private fields
   --> $DIR/issue-42944.rs:2:19
    |
-LL |     pub struct Bx(());
-   |                   ^^ private field
+LL |     pub struct Bx(pub(in crate::foo) ());
+   |                   ^^^^^^^^^^^^^^^^^^^^^ private field
+help: consider making the field publicly accessible
+   |
+LL |     pub struct Bx(pub ());
+   |                   ~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr
index 17a666a401c..c1fcaaf0573 100644
--- a/tests/ui/resolve/privacy-struct-ctor.stderr
+++ b/tests/ui/resolve/privacy-struct-ctor.stderr
@@ -53,6 +53,10 @@ note: the tuple struct constructor `Z` is defined here
    |
 LL |         pub(in m) struct Z(pub(in m::n) u8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |         pub(in m) struct Z(pub u8);
+   |                            ~~~
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:29:8
@@ -68,6 +72,10 @@ note: the tuple struct constructor `S` is defined here
    |
 LL |     pub struct S(u8);
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct S(pub u8);
+   |                  +++
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:31:19
@@ -83,6 +91,10 @@ note: the tuple struct constructor `S` is defined here
    |
 LL |     pub struct S(u8);
    |     ^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |     pub struct S(pub u8);
+   |                  +++
 
 error[E0603]: tuple struct constructor `Z` is private
   --> $DIR/privacy-struct-ctor.rs:35:11
@@ -98,6 +110,10 @@ note: the tuple struct constructor `Z` is defined here
    |
 LL |         pub(in m) struct Z(pub(in m::n) u8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider making the field publicly accessible
+   |
+LL |         pub(in m) struct Z(pub u8);
+   |                            ~~~
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:41:16
diff --git a/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs
new file mode 100644
index 00000000000..91863f5e497
--- /dev/null
+++ b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs
@@ -0,0 +1,45 @@
+#![feature(do_not_recommend)]
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+const CONST: () = ();
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+static Static: () = ();
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+type Type = ();
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+enum Enum {
+}
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+extern {
+}
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+fn fun() {
+}
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+struct Struct {
+}
+
+#[do_not_recommend]
+//~^ `#[do_not_recommend]` can only be placed
+trait Trait {
+}
+
+#[do_not_recommend]
+impl Trait for i32 {
+}
+
+fn main() {
+}
diff --git a/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr
new file mode 100644
index 00000000000..01ebc23c86e
--- /dev/null
+++ b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr
@@ -0,0 +1,50 @@
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:3:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:7:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:11:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:15:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:20:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:25:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:30:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: `#[do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:35:1
+   |
+LL | #[do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs
index b816c4a19da..f0c5c222e78 100644
--- a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs
+++ b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs
@@ -1,6 +1,9 @@
+trait Foo {
+}
+
 #[do_not_recommend]
 //~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature
-trait Foo {
+impl Foo for i32 {
 }
 
 fn main() {
diff --git a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr
index 425d7e4bca0..1597e5be45f 100644
--- a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr
+++ b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature
-  --> $DIR/unstable-feature.rs:1:1
+  --> $DIR/unstable-feature.rs:4:1
    |
 LL | #[do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2632-const-trait-impl/call.rs b/tests/ui/rfc-2632-const-trait-impl/call.rs
new file mode 100644
index 00000000000..5f48c235373
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/call.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(const_closures, const_trait_impl)]
+#![allow(incomplete_features)]
+
+pub const _: () = {
+    assert!((const || true)());
+};
+
+fn main() {}
diff --git a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
index d463c774e28..96e0c78b9c7 100644
--- a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
@@ -7,6 +7,7 @@ LL | pub struct S(A);
    |              ^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
index 086547542bb..22f13a7416e 100644
--- a/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
+++ b/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
@@ -5,6 +5,7 @@ LL |     Const.func();
    |           ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfc-2632-const-trait-impl/gate.rs b/tests/ui/rfc-2632-const-trait-impl/gate.rs
new file mode 100644
index 00000000000..f2cd26c91b6
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/gate.rs
@@ -0,0 +1,5 @@
+// gate-test-const_closures
+fn main() {
+    (const || {})();
+    //~^ ERROR: const closures are experimental
+}
diff --git a/tests/ui/rfc-2632-const-trait-impl/gate.stderr b/tests/ui/rfc-2632-const-trait-impl/gate.stderr
new file mode 100644
index 00000000000..30edc4127e1
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/gate.stderr
@@ -0,0 +1,12 @@
+error[E0658]: const closures are experimental
+  --> $DIR/gate.rs:3:6
+   |
+LL |     (const || {})();
+   |      ^^^^^^^^^^^
+   |
+   = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information
+   = help: add `#![feature(const_closures)]` 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/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs
new file mode 100644
index 00000000000..cd8bb5963ad
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs
@@ -0,0 +1,15 @@
+#![feature(const_closures, const_trait_impl)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn foo(&self);
+}
+
+impl Foo for () {
+    fn foo(&self) {}
+}
+
+fn main() {
+    (const || { (()).foo() })();
+    //~^ ERROR: cannot call non-const fn
+}
diff --git a/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
new file mode 100644
index 00000000000..979d7febbca
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions
+  --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22
+   |
+LL |     (const || { (()).foo() })();
+   |                      ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
index 61f9840e0d0..d7aa0d95cfc 100644
--- a/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
+++ b/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
@@ -5,6 +5,7 @@ LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
index 0b450a94742..6a3396401d2 100644
--- a/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
+++ b/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
@@ -5,6 +5,7 @@ LL |     Default::default()
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
index 1f8f312df01..bf12ef1ca77 100644
--- a/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
+++ b/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `S: ~const Foo` is not satisfied
-  --> $DIR/super-traits-fail.rs:15:12
+  --> $DIR/super-traits-fail.rs:15:20
    |
 LL | impl const Bar for S {}
-   |            ^^^ the trait `~const Foo` is not implemented for `S`
+   |                    ^ the trait `~const Foo` is not implemented for `S`
    |
 note: the trait `Foo` is implemented for `S`, but that implementation is not `const`
-  --> $DIR/super-traits-fail.rs:15:12
+  --> $DIR/super-traits-fail.rs:15:20
    |
 LL | impl const Bar for S {}
-   |            ^^^
+   |                    ^
 note: required by a bound in `Bar`
   --> $DIR/super-traits-fail.rs:8:12
    |
diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr
index fb47f27e022..36372b644d6 100644
--- a/tests/ui/self/self-impl.stderr
+++ b/tests/ui/self/self-impl.stderr
@@ -2,13 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:23:16
    |
 LL |         let _: <Self>::Baz = true;
-   |                ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
 
 error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:25:16
    |
 LL |         let _: Self::Baz = true;
-   |                ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr
index 6c7ea007ee0..cb5cc320276 100644
--- a/tests/ui/span/issue-71363.stderr
+++ b/tests/ui/span/issue-71363.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `MyError` doesn't implement `std::fmt::Display`
- --> $DIR/issue-71363.rs:4:6
+ --> $DIR/issue-71363.rs:4:28
   |
 4 | impl std::error::Error for MyError {}
-  |      ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter
+  |                            ^^^^^^^ `MyError` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `MyError`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
@@ -10,10 +10,10 @@ note: required by a bound in `std::error::Error`
  --> $SRC_DIR/core/src/error.rs:LL:COL
 
 error[E0277]: `MyError` doesn't implement `Debug`
- --> $DIR/issue-71363.rs:4:6
+ --> $DIR/issue-71363.rs:4:28
   |
 4 | impl std::error::Error for MyError {}
-  |      ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted using `{:?}`
+  |                            ^^^^^^^ `MyError` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `MyError`
   = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError`
diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr
index be6f04ae62a..505baa23ca3 100644
--- a/tests/ui/specialization/min_specialization/issue-79224.stderr
+++ b/tests/ui/specialization/min_specialization/issue-79224.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `B: Clone` is not satisfied
-  --> $DIR/issue-79224.rs:18:17
+  --> $DIR/issue-79224.rs:18:29
    |
 LL | impl<B: ?Sized> Display for Cow<'_, B> {
-   |                 ^^^^^^^ the trait `Clone` is not implemented for `B`
+   |                             ^^^^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr
index abb445214f3..ca5f0b7e21e 100644
--- a/tests/ui/structs/struct-path-associated-type.stderr
+++ b/tests/ui/structs/struct-path-associated-type.stderr
@@ -48,19 +48,19 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
    |
 LL |     let s = S::A {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |             ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:33:13
    |
 LL |     let z = S::A::<u8> {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |             ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:35:9
    |
 LL |         S::A {} => {}
-   |         ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |         ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed
new file mode 100644
index 00000000000..78e48364bba
--- /dev/null
+++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed
@@ -0,0 +1,28 @@
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+    fn foo(&mut self) {
+        let x = |this: &Self, v: i32| {
+            this.bar();
+            this.hel();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        x(self, 1);
+        x(self, 3);
+    }
+    fn bar(&self) {}
+    fn hel(&self) {}
+    fn qux(&mut self) {}
+
+    fn hello(&mut self) {
+        let y = |this: &Self| {
+            this.bar();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        y(self);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs
new file mode 100644
index 00000000000..6d8a9ffc12d
--- /dev/null
+++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs
@@ -0,0 +1,28 @@
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+    fn foo(&mut self) {
+        let x = |v: i32| {
+            self.bar();
+            self.hel();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        x(1);
+        x(3);
+    }
+    fn bar(&self) {}
+    fn hel(&self) {}
+    fn qux(&mut self) {}
+
+    fn hello(&mut self) {
+        let y = || {
+            self.bar();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        y();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr
new file mode 100644
index 00000000000..bc97d32ebb6
--- /dev/null
+++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr
@@ -0,0 +1,49 @@
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-105761-suggest-self-for-closure.rs:11:9
+   |
+LL |         let x = |v: i32| {
+   |                 -------- immutable borrow occurs here
+LL |             self.bar();
+   |             ---- first borrow occurs due to use of `self` in closure
+...
+LL |         self.qux();
+   |         ^^^^^^^^^^ mutable borrow occurs here
+LL |         x(1);
+   |         - immutable borrow later used here
+   |
+help: try explicitly pass `&Self` into the Closure as an argument
+   |
+LL ~         let x = |this: &Self, v: i32| {
+LL ~             this.bar();
+LL ~             this.hel();
+LL |         };
+LL |         self.qux();
+LL ~         x(self, 1);
+LL ~         x(self, 3);
+   |
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-105761-suggest-self-for-closure.rs:23:9
+   |
+LL |         let y = || {
+   |                 -- immutable borrow occurs here
+LL |             self.bar();
+   |             ---- first borrow occurs due to use of `self` in closure
+LL |         };
+LL |         self.qux();
+   |         ^^^^^^^^^^ mutable borrow occurs here
+LL |         y();
+   |         - immutable borrow later used here
+   |
+help: try explicitly pass `&Self` into the Closure as an argument
+   |
+LL ~         let y = |this: &Self| {
+LL ~             this.bar();
+LL |         };
+LL |         self.qux();
+LL ~         y(self);
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr
index 2bf072ef521..b90ae051fb7 100644
--- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr
+++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr
@@ -21,7 +21,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/let-binding-init-expr-as-ty.rs:2:14
    |
 LL |     let foo: i32::from_be(num);
-   |              ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<i32 as Trait>::from_be`
+   |              ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path
+   |
+LL |     let foo: <i32 as Example>::from_be;
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/suggestions/type-not-found-in-adt-field.stderr b/tests/ui/suggestions/type-not-found-in-adt-field.stderr
index e990fb5ba12..934ba87bbaa 100644
--- a/tests/ui/suggestions/type-not-found-in-adt-field.stderr
+++ b/tests/ui/suggestions/type-not-found-in-adt-field.stderr
@@ -7,10 +7,13 @@ LL |     m: Vec<Someunknownname<String, ()>>,
 error[E0412]: cannot find type `K` in this scope
   --> $DIR/type-not-found-in-adt-field.rs:6:8
    |
-LL | struct OtherStruct {
-   |                   - help: you might be missing a type parameter: `<K>`
 LL |     m: K,
    |        ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | struct OtherStruct<K> {
+   |                   +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/trait-bounds/unsized-bound.stderr b/tests/ui/trait-bounds/unsized-bound.stderr
index ec85ada7a8d..da27ba1c58d 100644
--- a/tests/ui/trait-bounds/unsized-bound.stderr
+++ b/tests/ui/trait-bounds/unsized-bound.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the size for values of type `B` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:2:12
+  --> $DIR/unsized-bound.rs:2:30
    |
 LL | impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {}
-   |         -  ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         -                    ^^^^^^ doesn't have a size known at compile-time
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
@@ -38,10 +38,10 @@ LL + impl<A, B> Trait<(A, B)> for (A, B) where B: ?Sized, {}
    |
 
 error[E0277]: the size for values of type `C` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:5:31
+  --> $DIR/unsized-bound.rs:5:52
    |
 LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
-   |                    -          ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                    -                               ^^^^^^^^^ doesn't have a size known at compile-time
    |                    |
    |                    this type parameter needs to be `std::marker::Sized`
    |
@@ -92,10 +92,10 @@ LL + impl<A, B, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
    |
 
 error[E0277]: the size for values of type `B` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:10:28
+  --> $DIR/unsized-bound.rs:10:47
    |
 LL | impl<A: ?Sized, B: ?Sized> Trait2<(A, B)> for (A, B) {}
-   |                 -          ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                 -                             ^^^^^^ doesn't have a size known at compile-time
    |                 |
    |                 this type parameter needs to be `std::marker::Sized`
    |
@@ -131,10 +131,10 @@ LL + impl<A, B: ?Sized> Trait2<(A, B)> for (A, B) {}
    |
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:14:9
+  --> $DIR/unsized-bound.rs:14:23
    |
 LL | impl<A> Trait3<A> for A where A: ?Sized {}
-   |      -  ^^^^^^^^^ doesn't have a size known at compile-time
+   |      -                ^ doesn't have a size known at compile-time
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
@@ -154,10 +154,10 @@ LL | trait Trait3<A: ?Sized> {}
    |               ++++++++
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:17:17
+  --> $DIR/unsized-bound.rs:17:31
    |
 LL | impl<A: ?Sized> Trait4<A> for A {}
-   |      -          ^^^^^^^^^ doesn't have a size known at compile-time
+   |      -                        ^ doesn't have a size known at compile-time
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
@@ -177,10 +177,10 @@ LL | trait Trait4<A: ?Sized> {}
    |               ++++++++
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:20:12
+  --> $DIR/unsized-bound.rs:20:29
    |
 LL | impl<X, Y> Trait5<X, Y> for X where X: ?Sized {}
-   |      -     ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |      -                      ^ doesn't have a size known at compile-time
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
@@ -200,10 +200,10 @@ LL | trait Trait5<A: ?Sized, B> {}
    |               ++++++++
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized-bound.rs:23:20
+  --> $DIR/unsized-bound.rs:23:37
    |
 LL | impl<X: ?Sized, Y> Trait6<X, Y> for X {}
-   |      -             ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |      -                              ^ doesn't have a size known at compile-time
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr
index 1390106a291..45bd533b5c6 100644
--- a/tests/ui/traits/ignore-err-impls.stderr
+++ b/tests/ui/traits/ignore-err-impls.stderr
@@ -2,9 +2,12 @@ error[E0412]: cannot find type `Type` in this scope
   --> $DIR/ignore-err-impls.rs:6:14
    |
 LL | impl Generic<Type> for S {}
-   |     -        ^^^^ not found in this scope
-   |     |
-   |     help: you might be missing a type parameter: `<Type>`
+   |              ^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<Type> Generic<Type> for S {}
+   |     ++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/impl-bounds-checking.stderr b/tests/ui/traits/impl-bounds-checking.stderr
index b01bacdb87d..1f969efe114 100644
--- a/tests/ui/traits/impl-bounds-checking.stderr
+++ b/tests/ui/traits/impl-bounds-checking.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `isize: Clone2` is not satisfied
-  --> $DIR/impl-bounds-checking.rs:10:6
+  --> $DIR/impl-bounds-checking.rs:10:24
    |
 LL | impl Getter<isize> for isize {
-   |      ^^^^^^^^^^^^^ the trait `Clone2` is not implemented for `isize`
+   |                        ^^^^^ the trait `Clone2` is not implemented for `isize`
    |
 note: required by a bound in `Getter`
   --> $DIR/impl-bounds-checking.rs:6:17
diff --git a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 5572c6515ff..1bace8ab286 100644
--- a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -1,8 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
-  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13
+  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
-   |             ^^^^^^^^^^
+   |                            ^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
   --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6
@@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'b` as defined he
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |         ^^
 note: ...so that the types are compatible
-  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13
+  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
-   |             ^^^^^^^^^^
+   |                            ^^^^^^^^^
    = note: expected `T1<'a>`
               found `T1<'_>`
 
diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr
index bb890cb99ee..4fe12731475 100644
--- a/tests/ui/traits/issue-43784-supertrait.stderr
+++ b/tests/ui/traits/issue-43784-supertrait.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-43784-supertrait.rs:8:9
+  --> $DIR/issue-43784-supertrait.rs:8:22
    |
 LL | impl<T> Complete for T {}
-   |         ^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |                      ^ the trait `Copy` is not implemented for `T`
    |
 note: required by a bound in `Complete`
   --> $DIR/issue-43784-supertrait.rs:4:21
diff --git a/tests/ui/traits/issue-50480.stderr b/tests/ui/traits/issue-50480.stderr
index 0bb1f9ae035..aa8384e9805 100644
--- a/tests/ui/traits/issue-50480.stderr
+++ b/tests/ui/traits/issue-50480.stderr
@@ -2,9 +2,12 @@ error[E0412]: cannot find type `N` in this scope
   --> $DIR/issue-50480.rs:3:12
    |
 LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |           -^ not found in this scope
-   |           |
-   |           help: you might be missing a type parameter: `<N>`
+   |            ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | struct Foo<N>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           +++
 
 error[E0412]: cannot find type `NotDefined` in this scope
   --> $DIR/issue-50480.rs:3:15
@@ -16,17 +19,23 @@ error[E0412]: cannot find type `N` in this scope
   --> $DIR/issue-50480.rs:3:12
    |
 LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |           -^ not found in this scope
-   |           |
-   |           help: you might be missing a type parameter: `<N>`
+   |            ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | struct Foo<N>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           +++
 
 error[E0412]: cannot find type `NotDefined` in this scope
   --> $DIR/issue-50480.rs:3:15
    |
 LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |           -   ^^^^^^^^^^ not found in this scope
-   |           |
-   |           help: you might be missing a type parameter: `<NotDefined>`
+   |               ^^^^^^^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | struct Foo<NotDefined>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           ++++++++++++
 
 error[E0412]: cannot find type `N` in this scope
   --> $DIR/issue-50480.rs:12:18
diff --git a/tests/ui/traits/issue-75627.stderr b/tests/ui/traits/issue-75627.stderr
index 432ddf2dcdb..1675edc9ff0 100644
--- a/tests/ui/traits/issue-75627.stderr
+++ b/tests/ui/traits/issue-75627.stderr
@@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope
   --> $DIR/issue-75627.rs:3:26
    |
 LL | unsafe impl Send for Foo<T> {}
-   |            -             ^ not found in this scope
-   |            |
-   |            help: you might be missing a type parameter: `<T>`
+   |                          ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | unsafe impl<T> Send for Foo<T> {}
+   |            +++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr
index 7e781016e1f..8e7fd5f2557 100644
--- a/tests/ui/traits/issue-78372.stderr
+++ b/tests/ui/traits/issue-78372.stderr
@@ -30,9 +30,12 @@ error[E0412]: cannot find type `MISC` in this scope
   --> $DIR/issue-78372.rs:3:34
    |
 LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
-   |       -                          ^^^^ not found in this scope
-   |       |
-   |       help: you might be missing a type parameter: `, MISC`
+   |                                  ^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | impl<T, MISC> DispatchFromDyn<Smaht<U, MISC>> for T {}
+   |       ++++++
 
 error[E0658]: use of unstable library feature 'dispatch_from_dyn'
   --> $DIR/issue-78372.rs:1:5
diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr
index 6b314fa586d..85d903fadd1 100644
--- a/tests/ui/traits/issue-91594.stderr
+++ b/tests/ui/traits/issue-91594.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
-  --> $DIR/issue-91594.rs:10:6
+  --> $DIR/issue-91594.rs:10:19
    |
 LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
    |
    = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo`
 note: required for `Foo` to implement `Component<Foo>`
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index f137a298a7f..293cfbda86c 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -148,19 +148,24 @@ error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:115:12
    |
 LL |     let _: S::A;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |            ^^^^
+   |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     let _: <S as Example>::A;
+   |            ~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:116:12
    |
 LL |     let _: S::B;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
+   |            ^^^^ help: use the fully-qualified path: `<S as assoc_ty::B>::B`
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:117:12
    |
 LL |     let _: S::C;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
+   |            ^^^^ help: use the fully-qualified path: `<S as assoc_ty::C>::C`
 
 error[E0624]: associated type `A` is private
   --> $DIR/item-privacy.rs:119:12
diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
index 85087282d3a..b4591778f8e 100644
--- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
+++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
@@ -1,11 +1,13 @@
 error[E0412]: cannot find type `Dst` in this scope
   --> $DIR/unknown_dst.rs:20:36
    |
-LL | fn should_gracefully_handle_unknown_dst() {
-   |                                        - help: you might be missing a type parameter: `<Dst>`
-...
 LL |     assert::is_transmutable::<Src, Dst, Context>();
    |                                    ^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn should_gracefully_handle_unknown_dst<Dst>() {
+   |                                        +++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
index 9bedbe87c3f..a55d71d8068 100644
--- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
+++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
@@ -1,11 +1,13 @@
 error[E0412]: cannot find type `Src` in this scope
   --> $DIR/unknown_src.rs:20:31
    |
-LL | fn should_gracefully_handle_unknown_src() {
-   |                                        - help: you might be missing a type parameter: `<Src>`
-...
 LL |     assert::is_transmutable::<Src, Dst, Context>();
    |                               ^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn should_gracefully_handle_unknown_src<Src>() {
+   |                                        +++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/typeck/autoderef-with-param-env-error.stderr b/tests/ui/typeck/autoderef-with-param-env-error.stderr
index cde800336dd..182612d5ee7 100644
--- a/tests/ui/typeck/autoderef-with-param-env-error.stderr
+++ b/tests/ui/typeck/autoderef-with-param-env-error.stderr
@@ -1,11 +1,13 @@
 error[E0412]: cannot find type `T` in this scope
   --> $DIR/autoderef-with-param-env-error.rs:3:5
    |
-LL | fn foo()
-   |       - help: you might be missing a type parameter: `<T>`
-LL | where
 LL |     T: Send,
    |     ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn foo<T>()
+   |       +++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr
index 2b3b1b9efdf..5561673f3c6 100644
--- a/tests/ui/typeck/issue-104513-ice.stderr
+++ b/tests/ui/typeck/issue-104513-ice.stderr
@@ -1,10 +1,13 @@
 error[E0405]: cannot find trait `Oops` in this scope
   --> $DIR/issue-104513-ice.rs:3:19
    |
-LL | fn f() {
-   |     - help: you might be missing a type parameter: `<Oops>`
 LL |     let _: S<impl Oops> = S;
    |                   ^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn f<Oops>() {
+   |     ++++++
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
   --> $DIR/issue-104513-ice.rs:3:14
diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr
index 5f7f6aa9f6e..72fccea8ae3 100644
--- a/tests/ui/ufcs/ufcs-partially-resolved.stderr
+++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr
@@ -205,7 +205,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/ufcs-partially-resolved.rs:36:12
    |
 LL |     let _: <u8 as Tr>::Y::NN;
-   |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
+   |            ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `NN` implemented for `<u8 as Tr>::Y`, you could use the fully-qualified path
+   |
+LL |     let _: <<u8 as Tr>::Y as Example>::NN;
+   |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0599]: no associated item named `NN` found for type `u16` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:38:20
diff --git a/triagebot.toml b/triagebot.toml
index 1f1b1f1110d..914b52cf041 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -471,6 +471,7 @@ compiler-team = [
     "@lcnr",
     "@nagisa",
     "@wesleywiser",
+    "@michaelwoerister",
 ]
 compiler-team-contributors = [
     "@compiler-errors",
@@ -478,6 +479,7 @@ compiler-team-contributors = [
     "@jackh726",
     "@TaKO8Ki",
     "@Nilstrieb",
+    "@WaffleLapkin",
 ]
 compiler = [
     "compiler-team",