about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap4
-rw-r--r--Cargo.lock42
-rw-r--r--compiler/rustc_abi/src/lib.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs3
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs2
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs4
-rw-r--r--compiler/rustc_attr/src/lib.rs3
-rw-r--r--compiler/rustc_baked_icu_data/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_const_eval/src/lib.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_driver/src/lib.rs4
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml54
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs7
-rw-r--r--compiler/rustc_error_codes/src/lib.rs3
-rw-r--r--compiler/rustc_error_messages/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs50
-rw-r--r--compiler/rustc_expand/src/lib.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs19
-rw-r--r--compiler/rustc_feature/src/lib.rs49
-rw-r--r--compiler/rustc_feature/src/removed.rs21
-rw-r--r--compiler/rustc_feature/src/unstable.rs (renamed from compiler/rustc_feature/src/active.rs)374
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs154
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs34
-rw-r--r--compiler/rustc_lint/src/levels.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs257
-rw-r--r--compiler/rustc_passes/src/check_const.rs4
-rw-r--r--compiler/rustc_passes/src/loops.rs2
-rw-r--r--compiler/rustc_session/src/config.rs11
-rw-r--r--compiler/rustc_session/src/options.rs5
-rw-r--r--compiler/rustc_session/src/parse.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs28
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs125
-rw-r--r--compiler/rustc_span/src/span_encoding.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/abi.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs129
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/stable_mir/src/error.rs69
-rw-r--r--compiler/stable_mir/src/lib.rs43
-rw-r--r--compiler/stable_mir/src/mir.rs1
-rw-r--r--compiler/stable_mir/src/mir/mono.rs89
-rw-r--r--library/alloc/src/vec/mod.rs1
-rw-r--r--library/core/src/convert/mod.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs8
-rw-r--r--library/core/src/marker.rs28
-rw-r--r--library/core/src/ops/index.rs2
-rw-r--r--library/core/src/ops/try_trait.rs45
-rw-r--r--library/core/src/slice/index.rs5
-rw-r--r--library/core/src/sync/atomic.rs34
-rw-r--r--library/std/src/os/fd/owned.rs6
-rw-r--r--library/std/src/sys/unix/net.rs4
-rw-r--r--src/bootstrap/Cargo.toml10
-rw-r--r--src/bootstrap/job.rs143
-rw-r--r--src/bootstrap/src/bin/main.rs (renamed from src/bootstrap/bin/main.rs)0
-rw-r--r--src/bootstrap/src/bin/rustc.rs (renamed from src/bootstrap/bin/rustc.rs)15
-rw-r--r--src/bootstrap/src/bin/rustdoc.rs (renamed from src/bootstrap/bin/rustdoc.rs)14
-rw-r--r--src/bootstrap/src/bin/sccache-plus-cl.rs (renamed from src/bootstrap/bin/sccache-plus-cl.rs)0
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs (renamed from src/bootstrap/check.rs)22
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs (renamed from src/bootstrap/clean.rs)6
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs (renamed from src/bootstrap/compile.rs)28
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs (renamed from src/bootstrap/dist.rs)44
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs (renamed from src/bootstrap/doc.rs)14
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs (renamed from src/bootstrap/format.rs)4
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs (renamed from src/bootstrap/install.rs)12
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs (renamed from src/bootstrap/llvm.rs)27
-rw-r--r--src/bootstrap/src/core/build_steps/mod.rs15
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs (renamed from src/bootstrap/run.rs)14
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs (renamed from src/bootstrap/setup.rs)5
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs (renamed from src/bootstrap/suggest.rs)11
-rw-r--r--src/bootstrap/src/core/build_steps/synthetic_targets.rs (renamed from src/bootstrap/synthetic_targets.rs)6
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs (renamed from src/bootstrap/test.rs)106
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs (renamed from src/bootstrap/tool.rs)12
-rw-r--r--src/bootstrap/src/core/build_steps/toolstate.rs (renamed from src/bootstrap/toolstate.rs)4
-rw-r--r--src/bootstrap/src/core/builder.rs (renamed from src/bootstrap/builder.rs)38
-rw-r--r--src/bootstrap/src/core/config/config.rs (renamed from src/bootstrap/config.rs)29
-rw-r--r--src/bootstrap/src/core/config/flags.rs (renamed from src/bootstrap/flags.rs)6
-rw-r--r--src/bootstrap/src/core/config/mod.rs4
-rw-r--r--src/bootstrap/src/core/download.rs (renamed from src/bootstrap/download.rs)11
-rw-r--r--src/bootstrap/src/core/metadata.rs (renamed from src/bootstrap/metadata.rs)4
-rw-r--r--src/bootstrap/src/core/mod.rs6
-rw-r--r--src/bootstrap/src/core/sanity.rs (renamed from src/bootstrap/sanity.rs)6
-rw-r--r--src/bootstrap/src/lib.rs (renamed from src/bootstrap/lib.rs)150
-rw-r--r--src/bootstrap/src/tests/builder.rs (renamed from src/bootstrap/builder/tests.rs)11
-rw-r--r--src/bootstrap/src/tests/config.rs (renamed from src/bootstrap/config/tests.rs)10
-rw-r--r--src/bootstrap/src/tests/setup.rs (renamed from src/bootstrap/setup/tests.rs)0
-rw-r--r--src/bootstrap/src/utils/bin_helpers.rs (renamed from src/bootstrap/bin/_helper.rs)10
-rw-r--r--src/bootstrap/src/utils/cache.rs (renamed from src/bootstrap/cache.rs)2
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs (renamed from src/bootstrap/cc_detect.rs)4
-rw-r--r--src/bootstrap/src/utils/channel.rs (renamed from src/bootstrap/channel.rs)3
-rw-r--r--src/bootstrap/src/utils/dylib.rs (renamed from src/bootstrap/dylib_util.rs)11
-rw-r--r--src/bootstrap/src/utils/helpers.rs (renamed from src/bootstrap/util.rs)36
-rw-r--r--src/bootstrap/src/utils/job.rs161
-rw-r--r--src/bootstrap/src/utils/metrics.rs (renamed from src/bootstrap/metrics.rs)4
-rw-r--r--src/bootstrap/src/utils/mod.rs14
-rw-r--r--src/bootstrap/src/utils/render_tests.rs (renamed from src/bootstrap/render_tests.rs)2
-rw-r--r--src/bootstrap/src/utils/tarball.rs (renamed from src/bootstrap/tarball.rs)19
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md137
-rw-r--r--src/doc/rustdoc/src/unstable-features.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/check-cfg.md216
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/core.rs1
-rw-r--r--src/librustdoc/doctest.rs1
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs2
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/rustdoc-gui/tester.js9
-rw-r--r--src/tools/tidy/src/alphabetical.rs4
-rw-r--r--src/tools/tidy/src/features.rs16
-rw-r--r--tests/codegen/vec_pop_push_noop.rs24
-rw-r--r--tests/pretty/format-args-str-escape.pp21
-rw-r--r--tests/pretty/format-args-str-escape.rs10
-rw-r--r--tests/run-make-fulldeps/issue-19371/foo.rs1
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs2
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg.rs2
-rw-r--r--tests/rustdoc-ui/doctest/check-cfg-test.rs2
-rw-r--r--tests/rustdoc-ui/ice-assoc-const-for-primitive-31808.rs (renamed from tests/rustdoc/issue-31808.rs)5
-rw-r--r--tests/rustdoc-ui/issues/issue-96287.stderr7
-rw-r--r--tests/rustdoc/blanket-impl-29503.rs (renamed from tests/rustdoc/issue-29503.rs)3
-rw-r--r--tests/rustdoc/const-rendering-macros-33302.rs (renamed from tests/rustdoc/issue-33302.rs)3
-rw-r--r--tests/rustdoc/disambiguate-anchors-32890.rs (renamed from tests/rustdoc/issue-32890.rs)3
-rw-r--r--tests/rustdoc/disambiguate-anchors-header-29449.rs (renamed from tests/rustdoc/issue-29449.rs)3
-rw-r--r--tests/rustdoc/doc-hidden-trait-implementors-33069.rs (renamed from tests/rustdoc/issue-33069.rs)3
-rw-r--r--tests/rustdoc/doctest-cfg-feature-30252.rs (renamed from tests/rustdoc/issue-30252.rs)3
-rw-r--r--tests/rustdoc/doctest-ignore-32556.rs (renamed from tests/rustdoc/issue-32556.rs)3
-rw-r--r--tests/rustdoc/hidden-extern-34025.rs (renamed from tests/rustdoc/issue-34025.rs)1
-rw-r--r--tests/rustdoc/impl-type-parameter-33592.rs (renamed from tests/rustdoc/issue-33592.rs)1
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/issue-29584.rs (renamed from tests/rustdoc/auxiliary/issue-29584.rs)0
-rw-r--r--tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs (renamed from tests/rustdoc/issue-29584.rs)3
-rw-r--r--tests/rustdoc/link-extern-crate-33178.rs (renamed from tests/rustdoc/issue-33178.rs)3
-rw-r--r--tests/rustdoc/link-extern-crate-item-30109.rs (renamed from tests/rustdoc/issue-30109.rs)3
-rw-r--r--tests/rustdoc/link-extern-crate-title-33178.rs (renamed from tests/rustdoc/issue-33178-1.rs)3
-rw-r--r--tests/rustdoc/render-enum-variant-structlike-32395.rs (renamed from tests/rustdoc/issue-32395.rs)3
-rw-r--r--tests/rustdoc/src-links-inlined-34274.rs (renamed from tests/rustdoc/issue-34274.rs)1
-rw-r--r--tests/rustdoc/staged-api-deprecated-unstable-32374.rs (renamed from tests/rustdoc/issue-32374.rs)2
-rw-r--r--tests/rustdoc/summary-codeblock-31899.rs (renamed from tests/rustdoc/issue-31899.rs)3
-rw-r--r--tests/rustdoc/summary-reference-link-30366.rs (renamed from tests/rustdoc/issue-30366.rs)3
-rw-r--r--tests/rustdoc/type-alias-impls-32077.rs (renamed from tests/rustdoc/issue-32077-type-alias-impls.rs)1
-rw-r--r--tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs13
-rw-r--r--tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr14
-rw-r--r--tests/ui-fulldeps/stable-mir/instance.rs91
-rw-r--r--tests/ui/check-cfg/allow-at-crate-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-macro-cfg.rs2
-rw-r--r--tests/ui/check-cfg/allow-same-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-top-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-upper-level.rs2
-rw-r--r--tests/ui/check-cfg/compact-names.rs2
-rw-r--r--tests/ui/check-cfg/compact-values.rs2
-rw-r--r--tests/ui/check-cfg/concat-values.rs13
-rw-r--r--tests/ui/check-cfg/concat-values.stderr19
-rw-r--r--tests/ui/check-cfg/diagnotics.rs2
-rw-r--r--tests/ui/check-cfg/empty-names.rs10
-rw-r--r--tests/ui/check-cfg/empty-values.rs10
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr25
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr25
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.feature.stderr33
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.full.stderr33
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.rs34
-rw-r--r--tests/ui/check-cfg/exhaustive-names.empty_names.stderr (renamed from tests/ui/check-cfg/empty-names.stderr)8
-rw-r--r--tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr15
-rw-r--r--tests/ui/check-cfg/exhaustive-names.rs12
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr17
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_values.stderr (renamed from tests/ui/check-cfg/empty-values.stderr)2
-rw-r--r--tests/ui/check-cfg/exhaustive-values.rs13
-rw-r--r--tests/ui/check-cfg/exhaustive-values.without_names.stderr13
-rw-r--r--tests/ui/check-cfg/invalid-arguments.anything_else.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.giberich.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.mixed_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_values.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.rs32
-rw-r--r--tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-cfg-name.rs14
-rw-r--r--tests/ui/check-cfg/invalid-cfg-value.rs18
-rw-r--r--tests/ui/check-cfg/mix.cfg.stderr (renamed from tests/ui/check-cfg/mix.stderr)54
-rw-r--r--tests/ui/check-cfg/mix.names_values.stderr192
-rw-r--r--tests/ui/check-cfg/mix.rs6
-rw-r--r--tests/ui/check-cfg/no-expected-values.empty.stderr (renamed from tests/ui/check-cfg/no-values.stderr)4
-rw-r--r--tests/ui/check-cfg/no-expected-values.mixed.stderr23
-rw-r--r--tests/ui/check-cfg/no-expected-values.rs20
-rw-r--r--tests/ui/check-cfg/no-expected-values.simple.stderr23
-rw-r--r--tests/ui/check-cfg/no-expected-values.values.stderr23
-rw-r--r--tests/ui/check-cfg/no-values.rs14
-rw-r--r--tests/ui/check-cfg/stmt-no-ice.rs2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr (renamed from tests/ui/check-cfg/invalid-cfg-name.stderr)2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.names.stderr10
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.rs16
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr (renamed from tests/ui/check-cfg/invalid-cfg-value.stderr)4
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.rs22
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.values.stderr25
-rw-r--r--tests/ui/check-cfg/unknown-values.rs17
-rw-r--r--tests/ui/check-cfg/well-known-names.rs2
-rw-r--r--tests/ui/check-cfg/well-known-names.stderr8
-rw-r--r--tests/ui/check-cfg/well-known-values.rs2
-rw-r--r--tests/ui/impl-trait/async_scope_creep.rs4
-rw-r--r--tests/ui/impl-trait/async_scope_creep.tait.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/gat-outlives.rs17
-rw-r--r--tests/ui/impl-trait/in-trait/gat-outlives.stderr24
-rw-r--r--tests/ui/impl-trait/nested-return-type2-tait2.rs4
-rw-r--r--tests/ui/impl-trait/nested-return-type2-tait2.stderr23
-rw-r--r--tests/ui/impl-trait/nested-return-type2-tait3.rs4
-rw-r--r--tests/ui/impl-trait/nested-return-type2-tait3.stderr25
-rw-r--r--tests/ui/iterators/invalid-iterator-chain-fixable.fixed42
-rw-r--r--tests/ui/iterators/invalid-iterator-chain-fixable.rs42
-rw-r--r--tests/ui/iterators/invalid-iterator-chain-fixable.stderr157
-rw-r--r--tests/ui/iterators/invalid-iterator-chain.stderr26
-rw-r--r--tests/ui/resolve/issue-55673.fixed21
-rw-r--r--tests/ui/resolve/issue-55673.rs9
-rw-r--r--tests/ui/resolve/issue-55673.stderr24
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr14
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs504
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr32
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr34
-rw-r--r--tests/ui/traits/issue-59029-1.stderr4
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.fixed19
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.stderr9
-rw-r--r--triagebot.toml6
269 files changed, 4098 insertions, 1622 deletions
diff --git a/.mailmap b/.mailmap
index dea660a8fe9..c109074021d 100644
--- a/.mailmap
+++ b/.mailmap
@@ -346,7 +346,9 @@ Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
 Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
 Liu Dingming <liudingming@bytedance.com>
 Loo Maclin <loo.maclin@protonmail.com>
-Loïc BRANSTETT <lolo.branstett@numericable.fr>
+Urgau <urgau@numericable.fr>
+Urgau <urgau@numericable.fr> <lolo.branstett@numericable.fr>
+Urgau <urgau@numericable.fr> <3616612+Urgau@users.noreply.github.com>
 Lucy <luxx4x@protonmail.com>
 Lukas H. <lukaramu@users.noreply.github.com>
 Lukas Lueg <lukas.lueg@gmail.com>
diff --git a/Cargo.lock b/Cargo.lock
index 4ba9977cc90..c8e7665337f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2419,9 +2419,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eb022374af2f446981254e6bf9efb6e2c9e1a53176d395fca02792fd4435729"
+checksum = "5394aa376422b4b2b6c02fd9cfcb657e4ec544ae98e43d7d5d785fd0d042fd6d"
 
 [[package]]
 name = "minimal-lexical"
@@ -2972,30 +2972,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
 name = "proc-macro-hack"
 version = "0.5.20+deprecated"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5253,24 +5229,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4d38d39c754ae037a9bc3ca1580a985db7371cd14f1229172d1db9093feb6739"
 dependencies = [
  "papergrid",
- "tabled_derive",
  "unicode-width",
 ]
 
 [[package]]
-name = "tabled_derive"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4"
-dependencies = [
- "heck",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
 name = "tar"
 version = "0.4.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 494ab451560..3722a0774ba 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,5 +1,7 @@
 #![cfg_attr(feature = "nightly", feature(step_trait))]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
+#![cfg_attr(all(not(bootstrap), feature = "nightly"), doc(rust_logo))]
+#![cfg_attr(all(not(bootstrap), feature = "nightly"), feature(rustdoc_internals))]
 
 use std::fmt;
 use std::num::{NonZeroUsize, ParseIntError};
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 3d6619dcff3..68567f97eab 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -30,6 +30,9 @@
 //! get confused if the spans from leaf AST nodes occur in multiple places
 //! in the HIR, especially for multiple identifiers.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![feature(box_patterns)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 5d279943f1e..9328b83e8f3 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -658,7 +658,7 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
 
     for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
         .iter()
-        .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2))
+        .filter(|&&(f1, f2)| features.active(f1) && features.active(f2))
     {
         if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
             if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 7db413c5bbd..5147e672f5f 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,6 +4,9 @@
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(iter_is_partitioned)]
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index bf094af5f7b..475bdb02378 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,3 +1,6 @@
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(associated_type_bounds)]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 1142d492160..269cb8f2380 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -684,8 +684,8 @@ pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> St
     for piece in pieces {
         match piece {
             FormatArgsPiece::Literal(s) => {
-                for c in s.as_str().escape_debug() {
-                    template.push(c);
+                for c in s.as_str().chars() {
+                    template.extend(c.escape_debug());
                     if let '{' | '}' = c {
                         template.push(c);
                     }
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index cfed2acfb3a..53e3eaaab37 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -4,6 +4,9 @@
 //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
 //! to this crate.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![feature(let_chains)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs
index 4651e03f771..ae8c062d25d 100644
--- a/compiler/rustc_baked_icu_data/src/lib.rs
+++ b/compiler/rustc_baked_icu_data/src/lib.rs
@@ -19,6 +19,10 @@
 //! -k list/and@1 fallback/likelysubtags@1 fallback/parents@1 fallback/supplement/co@1 \
 //! --cldr-tag latest --icuexport-tag latest -o src/data
 //! ```
+
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![allow(elided_lifetimes_in_paths)]
 
 mod data {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 811355bc635..d274a3eea6c 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,5 +1,8 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
+#![allow(internal_features)]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
@@ -11,7 +14,6 @@
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
-#![allow(internal_features)]
 
 #[macro_use]
 extern crate rustc_middle;
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index ff04b0237c2..ee554370305 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::InferCtxt;
@@ -308,20 +309,19 @@ fn check_opaque_type_well_formed<'tcx>(
         return Ok(definition_ty);
     };
     let param_env = tcx.param_env(def_id);
-    // HACK This bubble is required for this tests to pass:
-    // nested-return-type2-tait2.rs
-    // nested-return-type2-tait3.rs
+
+    let mut parent_def_id = def_id;
+    while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy {
+        parent_def_id = tcx.local_parent(parent_def_id);
+    }
+
     // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error`
     // and prepopulate this `InferCtxt` with known opaque values, rather than
     // using the `Bind` anchor here. For now it's fine.
     let infcx = tcx
         .infer_ctxt()
         .with_next_trait_solver(next_trait_solver)
-        .with_opaque_type_inference(if next_trait_solver {
-            DefiningAnchor::Bind(def_id)
-        } else {
-            DefiningAnchor::Bubble
-        })
+        .with_opaque_type_inference(DefiningAnchor::Bind(parent_def_id))
         .build();
     let ocx = ObligationCtxt::new(&infcx);
     let identity_args = GenericArgs::identity_for_item(tcx, def_id);
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 35b615697f7..d84742c9b82 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -1,6 +1,9 @@
 //! This crate contains implementations of built-in macros and other code generating facilities
 //! injecting code into the crate before it is lowered to HIR.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 522fe7e425b..8992de5a923 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,3 +1,6 @@
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![feature(rustc_private)]
 // Note: please avoid adding other feature gates where possible
 #![warn(rust_2018_idioms)]
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 9c18fc4a0dc..6aa5b6bd1ff 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -12,6 +12,8 @@
  * TODO(antoyo): remove the patches.
  */
 
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(
     rustc_private,
     decl_macro,
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 59d1ea05d8a..7a390d35a2b 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -4,6 +4,9 @@
 //!
 //! This API is completely unstable and subject to change.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(extern_types)]
 #![feature(hash_raw_entry)]
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 8bb409cea08..1fd5723f277 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -4,6 +4,9 @@ Rust MIR: a lowered representation of Rust.
 
 */
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
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 d476805c0b2..92e7922ad3b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -323,7 +323,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         let gate = match op.status_in_item(self.ccx) {
             Status::Allowed => return,
 
-            Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
+            Status::Unstable(gate) if self.tcx.features().active(gate) => {
                 let unstable_in_stable = self.ccx.is_const_stable_const_fn()
                     && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
                 if unstable_in_stable {
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 461ec3a90ed..420f7c4f17f 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -6,6 +6,8 @@
 //!
 //! This API is completely unstable and subject to change.
 
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 0cd0b51b6ad..27f08fe7eef 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1,4 +1,8 @@
 // This crate is intentionally empty and a re-export of `rustc_driver_impl` to allow the code in
 // `rustc_driver_impl` to be compiled in parallel with other crates.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+
 pub use rustc_driver_impl::*;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index a7b01618ade..4894312b0d2 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -6,53 +6,55 @@ edition = "2021"
 [lib]
 
 [dependencies]
-time = { version = "0.3", default-features = false, features = ["formatting", ] }
-tracing = { version = "0.1.35" }
-serde_json = "1.0.59"
-rustc_log = { path = "../rustc_log" }
+# tidy-alphabetical-start
+rustc_ast = { path = "../rustc_ast" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
+rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
 rustc_const_eval = { path = "../rustc_const_eval" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_error_messages = { path = "../rustc_error_messages" }
+rustc_errors = { path = "../rustc_errors" }
 rustc_expand = { path = "../rustc_expand" }
-rustc_hir_typeck = { path = "../rustc_hir_typeck" }
+rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_hir_typeck = { path = "../rustc_hir_typeck" }
 rustc_incremental = { path = "../rustc_incremental" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_interface = { path = "../rustc_interface" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_log = { path = "../rustc_log" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_metadata = { path = "../rustc_metadata" }
+rustc_middle = { path = "../rustc_middle" }
 rustc_mir_build = { path = "../rustc_mir_build" }
 rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
+rustc_mir_transform = { path = "../rustc_mir_transform" }
 rustc_monomorphize = { path = "../rustc_monomorphize" }
+rustc_parse = { path = "../rustc_parse" }
 rustc_passes = { path = "../rustc_passes" }
+rustc_plugin_impl = { path = "../rustc_plugin_impl" }
 rustc_privacy = { path = "../rustc_privacy" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_resolve = { path = "../rustc_resolve" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
+rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
-rustc_middle = { path = "../rustc_middle" }
-rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_target = { path = "../rustc_target" }
-rustc_lint = { path = "../rustc_lint" }
-rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_feature = { path = "../rustc_feature" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_hir_pretty = { path = "../rustc_hir_pretty" }
-rustc_macros = { path = "../rustc_macros" }
-rustc_metadata = { path = "../rustc_metadata" }
-rustc_parse = { path = "../rustc_parse" }
-rustc_plugin_impl = { path = "../rustc_plugin_impl" }
-rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
-rustc_session = { path = "../rustc_session" }
-rustc_error_codes = { path = "../rustc_error_codes" }
-rustc_interface = { path = "../rustc_interface" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_span = { path = "../rustc_span" }
-rustc_hir_analysis = { path = "../rustc_hir_analysis" }
-rustc_mir_transform = { path = "../rustc_mir_transform" }
+serde_json = "1.0.59"
+time = { version = "0.3", default-features = false, features = ["formatting", ] }
+tracing = { version = "0.1.35" }
+# tidy-alphabetical-end
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 5bb7c41677c..ab18cc32d9b 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -312,6 +312,7 @@ fn run_compiler(
         locale_resources: DEFAULT_LOCALE_RESOURCES,
         lint_caps: Default::default(),
         parse_sess_created: None,
+        hash_untracked_state: None,
         register_lints: None,
         override_queries: None,
         make_codegen_backend,
@@ -1184,7 +1185,11 @@ fn print_flag_list<T>(
 ///
 /// So with all that in mind, the comments below have some more detail about the
 /// contortions done here to get things to work out correctly.
-fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
+///
+/// This does not need to be `pub` for rustc itself, but @chaosite needs it to
+/// be public when using rustc as a library, see
+/// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
+pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index d6b120e4dfc..81ad661286e 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -1,3 +1,6 @@
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![deny(rustdoc::invalid_codeblock_attributes)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 6c29144569d..6249c1e7961 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -1,3 +1,5 @@
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(let_chains)]
 #![feature(lazy_cell)]
 #![feature(rustc_attrs)]
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 4b213ff1922..b73c7593381 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -14,12 +14,12 @@ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_feature::{Feature, Features, State as FeatureState};
-use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES};
+use rustc_feature::Features;
+use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
 use rustc_parse::validate_attr;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::edition::{Edition, ALL_EDITIONS};
+use rustc_span::edition::ALL_EDITIONS;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use thin_vec::ThinVec;
@@ -36,16 +36,6 @@ pub struct StripUnconfigured<'a> {
 }
 
 pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
-    fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
-        ACTIVE_FEATURES.iter().filter(move |feature| {
-            if let Some(feature_edition) = feature.edition {
-                feature_edition <= edition
-            } else {
-                false
-            }
-        })
-    }
-
     fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
         if attr.has_name(sym::feature)
             && let Some(list) = attr.meta_item_list()
@@ -83,11 +73,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
     // Enable edition-dependent features based on `features_edition`.
     // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
     let mut edition_enabled_features = FxHashSet::default();
-    for feature in active_features_up_to(features_edition) {
-        // FIXME(Manishearth) there is currently no way to set lib features by
-        // edition.
-        edition_enabled_features.insert(feature.name);
-        feature.set(&mut features);
+    for f in UNSTABLE_FEATURES {
+        if let Some(edition) = f.feature.edition && edition <= features_edition {
+            // FIXME(Manishearth) there is currently no way to set lib features by
+            // edition.
+            edition_enabled_features.insert(f.feature.name);
+            (f.set_enabled)(&mut features);
+        }
     }
 
     // Process all features declared in the code.
@@ -147,19 +139,17 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
             }
 
             // If the declared feature has been removed, issue an error.
-            if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) {
-                if let FeatureState::Removed { reason } = state {
-                    sess.emit_err(FeatureRemoved {
-                        span: mi.span(),
-                        reason: reason.map(|reason| FeatureRemovedReason { reason }),
-                    });
-                    continue;
-                }
+            if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
+                sess.emit_err(FeatureRemoved {
+                    span: mi.span(),
+                    reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
+                });
+                continue;
             }
 
             // If the declared feature is stable, record it.
-            if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
-                let since = Some(Symbol::intern(since));
+            if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
+                let since = Some(Symbol::intern(f.since));
                 features.set_declared_lang_feature(name, mi.span(), since);
                 continue;
             }
@@ -175,8 +165,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
             }
 
             // If the declared feature is unstable, record it.
-            if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
-                f.set(&mut features);
+            if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
+                (f.set_enabled)(&mut features);
                 features.set_declared_lang_feature(name, mi.span(), None);
                 continue;
             }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 8b1fc5b90b4..5a774164a4b 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,3 +1,5 @@
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index b198876b05c..f07022733d4 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -1,23 +1,20 @@
 //! List of the accepted feature gates.
 
-use super::{to_nonzero, Feature, State};
+use super::{to_nonzero, Feature};
 use rustc_span::symbol::sym;
 
 macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None),
     )+) => {
-        /// Those language feature has since been Accepted (it was once Active)
+        /// Formerly unstable features that have now been accepted (stabilized).
         pub const ACCEPTED_FEATURES: &[Feature] = &[
-            $(
-                Feature {
-                    state: State::Accepted,
-                    name: sym::$feature,
-                    since: $ver,
-                    issue: to_nonzero($issue),
-                    edition: None,
-                }
-            ),+
+            $(Feature {
+                name: sym::$feature,
+                since: $ver,
+                issue: to_nonzero($issue),
+                edition: None,
+            }),+
         ];
     }
 }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 4721bff0ec7..070234df94c 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,42 +11,26 @@
 //! even if it is stabilized or removed, *do not remove it*. Instead, move the
 //! symbol to the `accepted` or `removed` modules respectively.
 
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![feature(lazy_cell)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
 mod accepted;
-mod active;
 mod builtin_attrs;
 mod removed;
+mod unstable;
 
 #[cfg(test)]
 mod tests;
 
 use rustc_span::{edition::Edition, symbol::Symbol};
-use std::fmt;
 use std::num::NonZeroU32;
 
-#[derive(Clone, Copy)]
-pub enum State {
-    Accepted,
-    Active { set: fn(&mut Features) },
-    Removed { reason: Option<&'static str> },
-}
-
-impl fmt::Debug for State {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            State::Accepted { .. } => write!(f, "accepted"),
-            State::Active { .. } => write!(f, "active"),
-            State::Removed { .. } => write!(f, "removed"),
-        }
-    }
-}
-
 #[derive(Debug, Clone)]
 pub struct Feature {
-    pub state: State,
     pub name: Symbol,
     pub since: &'static str,
     issue: Option<NonZeroU32>,
@@ -63,9 +47,9 @@ pub enum Stability {
 
 #[derive(Clone, Copy, Debug, Hash)]
 pub enum UnstableFeatures {
-    /// Hard errors for unstable features are active, as on beta/stable channels.
+    /// Disallow use of unstable features, as on beta/stable channels.
     Disallow,
-    /// Allow features to be activated, as on nightly.
+    /// Allow use of unstable features, as on nightly.
     Allow,
     /// Errors are bypassed for bootstrapping. This is required any time
     /// during the build that feature-related lints are set to warn or above
@@ -106,17 +90,16 @@ impl UnstableFeatures {
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     // Search in all the feature lists.
-    let found = []
-        .iter()
-        .chain(ACTIVE_FEATURES)
-        .chain(ACCEPTED_FEATURES)
-        .chain(REMOVED_FEATURES)
-        .find(|t| t.name == feature);
-
-    match found {
-        Some(found) => found.issue,
-        None => panic!("feature `{feature}` is not declared anywhere"),
+    if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) {
+        return f.feature.issue;
+    }
+    if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) {
+        return f.issue;
+    }
+    if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) {
+        return f.feature.issue;
     }
+    panic!("feature `{feature}` is not declared anywhere");
 }
 
 const fn to_nonzero(n: Option<u32>) -> Option<NonZeroU32> {
@@ -141,7 +124,6 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU3
 }
 
 pub use accepted::ACCEPTED_FEATURES;
-pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
 pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
@@ -149,3 +131,4 @@ pub use builtin_attrs::{
     GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::REMOVED_FEATURES;
+pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 1697e929eda..339f596144c 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -1,23 +1,28 @@
 //! List of the removed feature gates.
 
-use super::{to_nonzero, Feature, State};
+use super::{to_nonzero, Feature};
 use rustc_span::symbol::sym;
 
+pub struct RemovedFeature {
+    pub feature: Feature,
+    pub reason: Option<&'static str>,
+}
+
 macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr),
     )+) => {
-        /// Represents unstable features which have since been removed (it was once Active)
-        pub const REMOVED_FEATURES: &[Feature] = &[
-            $(
-                Feature {
-                    state: State::Removed { reason: $reason },
+        /// Formerly unstable features that have now been removed.
+        pub const REMOVED_FEATURES: &[RemovedFeature] = &[
+            $(RemovedFeature {
+                feature: Feature {
                     name: sym::$feature,
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: None,
-                }
-            ),+
+                },
+                reason: $reason
+            }),+
         ];
     };
 }
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/unstable.rs
index ef672487b98..27cdf1ba831 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -1,12 +1,17 @@
-//! List of the active feature gates.
+//! List of the unstable feature gates.
 
-use super::{to_nonzero, Feature, State};
+use super::{to_nonzero, Feature};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
+pub struct UnstableFeature {
+    pub feature: Feature,
+    pub set_enabled: fn(&mut Features),
+}
+
 #[derive(PartialEq)]
 enum FeatureStatus {
     Default,
@@ -15,7 +20,7 @@ enum FeatureStatus {
 }
 
 macro_rules! status_to_enum {
-    (active) => {
+    (unstable) => {
         FeatureStatus::Default
     };
     (incomplete) => {
@@ -30,23 +35,20 @@ macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr),
     )+) => {
-        /// Represents active features that are currently being implemented or
-        /// currently being considered for addition/removal.
-        pub const ACTIVE_FEATURES:
-            &[Feature] =
-            &[$(
-                // (sym::$feature, $ver, $issue, $edition, set!($feature))
-                Feature {
-                    state: State::Active {
-                        // Sets this feature's corresponding bool within `features`.
-                        set: |features| features.$feature = true,
-                    },
+        /// Unstable language features that are being implemented or being
+        /// considered for acceptance (stabilization) or removal.
+        pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[
+            $(UnstableFeature {
+                feature: Feature {
                     name: sym::$feature,
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: $edition,
-                }
-            ),+];
+                },
+                // Sets this feature's corresponding bool within `features`.
+                set_enabled: |features| features.$feature = true,
+            }),+
+        ];
 
         /// A set of features to be used by later passes.
         #[derive(Clone, Default, Debug)]
@@ -57,7 +59,7 @@ macro_rules! declare_features {
             pub declared_lib_features: Vec<(Symbol, Span)>,
             /// `declared_lang_features` + `declared_lib_features`.
             pub declared_features: FxHashSet<Symbol>,
-            /// Individual features (unstable only).
+            /// Active state of individual features (unstable only).
             $(
                 $(#[doc = $doc])*
                 pub $feature: bool
@@ -90,11 +92,11 @@ macro_rules! declare_features {
                 self.declared_features.contains(&feature)
             }
 
-            /// Is the given feature enabled, i.e. declared or automatically
+            /// Is the given feature active, i.e. declared or automatically
             /// enabled due to the edition?
             ///
             /// Panics if the symbol doesn't correspond to a declared feature.
-            pub fn enabled(&self, feature: Symbol) -> bool {
+            pub fn active(&self, feature: Symbol) -> bool {
                 match feature {
                     $( sym::$feature => self.$feature, )*
 
@@ -110,22 +112,21 @@ macro_rules! declare_features {
                     $(
                         sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
                     )*
-                    // accepted and removed features aren't in this file but are never incomplete
+                    // Accepted/removed features aren't in this file but are never incomplete.
                     _ if self.declared_features.contains(&feature) => false,
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
             }
 
             /// Some features are internal to the compiler and standard library and should not
-            /// be used in normal projects. We warn the user about these
-            /// to alert them.
+            /// be used in normal projects. We warn the user about these to alert them.
             pub fn internal(&self, feature: Symbol) -> bool {
                 match feature {
                     $(
                         sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
                     )*
-                    // accepted and removed features aren't in this file but are never internal
-                    // (a removed feature might have been internal, but it doesn't matter anymore)
+                    // Accepted/removed features aren't in this file but are never internal
+                    // (a removed feature might have been internal, but that's now irrelevant).
                     _ if self.declared_features.contains(&feature) => false,
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
@@ -134,16 +135,6 @@ macro_rules! declare_features {
     };
 }
 
-impl Feature {
-    /// Sets this feature in `Features`. Panics if called on a non-active feature.
-    pub fn set(&self, features: &mut Features) {
-        match self.state {
-            State::Active { set } => set(features),
-            _ => panic!("called `set` on feature `{}` which is not `active`", self.name),
-        }
-    }
-}
-
 // See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more
 // documentation about handling feature gates.
 //
@@ -153,8 +144,7 @@ impl Feature {
 // accepted or `removed.rs` if removed.
 //
 // The version numbers here correspond to the version in which the current status
-// was set. This is most important for knowing when a particular feature became
-// stable (active).
+// was set.
 //
 // Note that the features are grouped into internal/user-facing and then
 // sorted by version inside those groups. This is enforced with tidy.
@@ -170,9 +160,9 @@ declare_features! (
     // no-tracking-issue-start
 
     /// Allows using the `unadjusted` ABI; perma-unstable.
-    (active, abi_unadjusted, "1.16.0", None, None),
+    (unstable, abi_unadjusted, "1.16.0", None, None),
     /// Allows using the `vectorcall` ABI.
-    (active, abi_vectorcall, "1.7.0", None, None),
+    (unstable, abi_vectorcall, "1.7.0", None, None),
     /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
     (internal, allocator_internals, "1.20.0", None, None),
     /// Allows using `#[allow_internal_unsafe]`. This is an
@@ -186,21 +176,21 @@ declare_features! (
     /// macros disappear).
     (internal, allow_internal_unstable, "1.0.0", None, None),
     /// Allows using anonymous lifetimes in argument-position impl-trait.
-    (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
+    (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (internal, compiler_builtins, "1.13.0", None, None),
     /// Allows writing custom MIR
     (internal, custom_mir, "1.65.0", None, None),
     /// Outputs useful `assert!` messages
-    (active, generic_assert, "1.63.0", None, None),
+    (unstable, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
     (internal, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (internal, lang_items, "1.0.0", None, None),
     /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
-    (active, link_cfg, "1.14.0", None, None),
+    (unstable, link_cfg, "1.14.0", None, None),
     /// Allows the `multiple_supertrait_upcastable` lint.
-    (active, multiple_supertrait_upcastable, "1.69.0", None, None),
+    (unstable, multiple_supertrait_upcastable, "1.69.0", None, None),
     /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
     (incomplete, negative_bounds, "1.71.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
@@ -222,7 +212,7 @@ declare_features! (
     (internal, unsafe_pin_internals, "1.60.0", None, None),
     /// Use for stable + negative coherence and strict coherence depending on trait's
     /// rustc_strict_coherence value.
-    (active, with_negative_coherence, "1.60.0", None, None),
+    (unstable, with_negative_coherence, "1.60.0", None, None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
@@ -238,20 +228,20 @@ declare_features! (
 
     /// Allows features specific to auto traits.
     /// Renamed from `optin_builtin_traits`.
-    (active, auto_traits, "1.50.0", Some(13231), None),
+    (unstable, auto_traits, "1.50.0", Some(13231), None),
     /// Allows using `box` in patterns (RFC 469).
-    (active, box_patterns, "1.0.0", Some(29641), None),
+    (unstable, box_patterns, "1.0.0", Some(29641), None),
     /// Allows `#[doc(notable_trait)]`.
     /// Renamed from `doc_spotlight`.
-    (active, doc_notable_trait, "1.52.0", Some(45040), None),
+    (unstable, doc_notable_trait, "1.52.0", Some(45040), None),
     /// Allows using the `may_dangle` attribute (RFC 1327).
-    (active, dropck_eyepatch, "1.10.0", Some(34761), None),
+    (unstable, dropck_eyepatch, "1.10.0", Some(34761), None),
     /// Allows using the `#[fundamental]` attribute.
-    (active, fundamental, "1.0.0", Some(29635), None),
+    (unstable, fundamental, "1.0.0", Some(29635), None),
     /// Allows using `#[link_name="llvm.*"]`.
     (internal, link_llvm_intrinsics, "1.0.0", Some(29602), None),
     /// Allows using the `#[linkage = ".."]` attribute.
-    (active, linkage, "1.0.0", Some(29603), None),
+    (unstable, linkage, "1.0.0", Some(29603), None),
     /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
     (internal, needs_panic_runtime, "1.10.0", Some(32837), None),
     /// Allows using the `#![panic_runtime]` attribute.
@@ -263,19 +253,19 @@ declare_features! (
     /// purpose as `#[allow_internal_unstable]`.
     (internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
     /// Allows using compiler's own crates.
-    (active, rustc_private, "1.0.0", Some(27812), None),
+    (unstable, rustc_private, "1.0.0", Some(27812), None),
     /// Allows using internal rustdoc features like `doc(keyword)`.
     (internal, rustdoc_internals, "1.58.0", Some(90418), None),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
-    (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
+    (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
     /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
-    (active, start, "1.0.0", Some(29633), None),
+    (unstable, start, "1.0.0", Some(29633), None),
     /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
     /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
     /// feature with the same name exists.
-    (active, structural_match, "1.8.0", Some(31434), None),
+    (unstable, structural_match, "1.8.0", Some(31434), None),
     /// Allows using the `rust-call` ABI.
-    (active, unboxed_closures, "1.0.0", Some(29625), None),
+    (unstable, unboxed_closures, "1.0.0", Some(29625), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
@@ -291,20 +281,20 @@ declare_features! (
     // FIXME: Document these and merge with the list below.
 
     // Unstable `#[target_feature]` directives.
-    (active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
-    (active, arm_target_feature, "1.27.0", Some(44839), None),
-    (active, avx512_target_feature, "1.27.0", Some(44839), None),
-    (active, bpf_target_feature, "1.54.0", Some(44839), None),
-    (active, csky_target_feature, "1.73.0", Some(44839), None),
-    (active, ermsb_target_feature, "1.49.0", Some(44839), None),
-    (active, hexagon_target_feature, "1.27.0", Some(44839), None),
-    (active, mips_target_feature, "1.27.0", Some(44839), None),
-    (active, powerpc_target_feature, "1.27.0", Some(44839), None),
-    (active, riscv_target_feature, "1.45.0", Some(44839), None),
-    (active, rtm_target_feature, "1.35.0", Some(44839), None),
-    (active, sse4a_target_feature, "1.27.0", Some(44839), None),
-    (active, tbm_target_feature, "1.27.0", Some(44839), None),
-    (active, wasm_target_feature, "1.30.0", Some(44839), None),
+    (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
+    (unstable, arm_target_feature, "1.27.0", Some(44839), None),
+    (unstable, avx512_target_feature, "1.27.0", Some(44839), None),
+    (unstable, bpf_target_feature, "1.54.0", Some(44839), None),
+    (unstable, csky_target_feature, "1.73.0", Some(44839), None),
+    (unstable, ermsb_target_feature, "1.49.0", Some(44839), None),
+    (unstable, hexagon_target_feature, "1.27.0", Some(44839), None),
+    (unstable, mips_target_feature, "1.27.0", Some(44839), None),
+    (unstable, powerpc_target_feature, "1.27.0", Some(44839), None),
+    (unstable, riscv_target_feature, "1.45.0", Some(44839), None),
+    (unstable, rtm_target_feature, "1.35.0", Some(44839), None),
+    (unstable, sse4a_target_feature, "1.27.0", Some(44839), None),
+    (unstable, tbm_target_feature, "1.27.0", Some(44839), None),
+    (unstable, wasm_target_feature, "1.30.0", Some(44839), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
@@ -318,155 +308,155 @@ declare_features! (
     // -------------------------------------------------------------------------
 
     /// Allows using the `amdgpu-kernel` ABI.
-    (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
+    (unstable, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
     /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
-    (active, abi_avr_interrupt, "1.45.0", Some(69664), None),
+    (unstable, 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),
+    (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
     /// Allows `extern "msp430-interrupt" fn()`.
-    (active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
+    (unstable, abi_msp430_interrupt, "1.16.0", Some(38487), None),
     /// Allows `extern "ptx-*" fn()`.
-    (active, abi_ptx, "1.15.0", Some(38788), None),
+    (unstable, abi_ptx, "1.15.0", Some(38788), None),
     /// Allows `extern "riscv-interrupt-m" fn()` and `extern "riscv-interrupt-s" fn()`.
-    (active, abi_riscv_interrupt, "1.73.0", Some(111889), None),
+    (unstable, abi_riscv_interrupt, "1.73.0", Some(111889), None),
     /// Allows `extern "x86-interrupt" fn()`.
-    (active, abi_x86_interrupt, "1.17.0", Some(40180), None),
+    (unstable, abi_x86_interrupt, "1.17.0", Some(40180), None),
     /// Allows additional const parameter types, such as `&'static str` or user defined types
     (incomplete, adt_const_params, "1.56.0", Some(95174), None),
     /// Allows defining an `#[alloc_error_handler]`.
-    (active, alloc_error_handler, "1.29.0", Some(51540), None),
+    (unstable, alloc_error_handler, "1.29.0", Some(51540), None),
     /// Allows trait methods with arbitrary self types.
-    (active, arbitrary_self_types, "1.23.0", Some(44874), None),
+    (unstable, arbitrary_self_types, "1.23.0", Some(44874), None),
     /// Allows using `const` operands in inline assembly.
-    (active, asm_const, "1.58.0", Some(93332), None),
+    (unstable, asm_const, "1.58.0", Some(93332), None),
     /// Enables experimental inline assembly support for additional architectures.
-    (active, asm_experimental_arch, "1.58.0", Some(93335), None),
+    (unstable, asm_experimental_arch, "1.58.0", Some(93335), None),
     /// Allows the `may_unwind` option in inline assembly.
-    (active, asm_unwind, "1.58.0", Some(93334), None),
+    (unstable, asm_unwind, "1.58.0", Some(93334), None),
     /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
-    (active, associated_const_equality, "1.58.0", Some(92827), None),
+    (unstable, associated_const_equality, "1.58.0", Some(92827), None),
     /// Allows the user of associated type bounds.
-    (active, associated_type_bounds, "1.34.0", Some(52662), None),
+    (unstable, associated_type_bounds, "1.34.0", Some(52662), None),
     /// Allows associated type defaults.
-    (active, associated_type_defaults, "1.2.0", Some(29661), None),
+    (unstable, associated_type_defaults, "1.2.0", Some(29661), None),
     /// Allows `async || body` closures.
-    (active, async_closure, "1.37.0", Some(62290), None),
+    (unstable, async_closure, "1.37.0", Some(62290), None),
     /// Allows `#[track_caller]` on async functions.
-    (active, async_fn_track_caller, "1.73.0", Some(110011), None),
+    (unstable, async_fn_track_caller, "1.73.0", Some(110011), None),
     /// Allows builtin # foo() syntax
-    (active, builtin_syntax, "1.71.0", Some(110680), None),
+    (unstable, builtin_syntax, "1.71.0", Some(110680), None),
     /// Allows `c"foo"` literals.
-    (active, c_str_literals, "1.71.0", Some(105723), None),
+    (unstable, c_str_literals, "1.71.0", Some(105723), None),
     /// Treat `extern "C"` function as nounwind.
-    (active, c_unwind, "1.52.0", Some(74990), None),
+    (unstable, c_unwind, "1.52.0", Some(74990), None),
     /// Allows using C-variadics.
-    (active, c_variadic, "1.34.0", Some(44930), None),
+    (unstable, c_variadic, "1.34.0", Some(44930), None),
     /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
-    (active, cfg_overflow_checks, "1.71.0", Some(111466), None),
+    (unstable, cfg_overflow_checks, "1.71.0", Some(111466), None),
     /// Provides the relocation model information as cfg entry
-    (active, cfg_relocation_model, "1.73.0", Some(114929), None),
+    (unstable, cfg_relocation_model, "1.73.0", Some(114929), None),
     /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
-    (active, cfg_sanitize, "1.41.0", Some(39699), None),
+    (unstable, cfg_sanitize, "1.41.0", Some(39699), None),
     /// Allows `cfg(target_abi = "...")`.
-    (active, cfg_target_abi, "1.55.0", Some(80970), None),
+    (unstable, cfg_target_abi, "1.55.0", Some(80970), None),
     /// Allows `cfg(target(abi = "..."))`.
-    (active, cfg_target_compact, "1.63.0", Some(96901), None),
+    (unstable, cfg_target_compact, "1.63.0", Some(96901), None),
     /// Allows `cfg(target_has_atomic_load_store = "...")`.
-    (active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
+    (unstable, cfg_target_has_atomic, "1.60.0", Some(94039), None),
     /// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
-    (active, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None),
+    (unstable, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None),
     /// Allows `cfg(target_thread_local)`.
-    (active, cfg_target_thread_local, "1.7.0", Some(29594), None),
+    (unstable, cfg_target_thread_local, "1.7.0", Some(29594), None),
     /// Allow conditional compilation depending on rust version
-    (active, cfg_version, "1.45.0", Some(64796), None),
+    (unstable, cfg_version, "1.45.0", Some(64796), None),
     /// Allows to use the `#[cfi_encoding = ""]` attribute.
-    (active, cfi_encoding, "1.71.0", Some(89653), None),
+    (unstable, cfi_encoding, "1.71.0", Some(89653), None),
     /// Allows `for<...>` on closures and generators.
-    (active, closure_lifetime_binder, "1.64.0", Some(97362), None),
+    (unstable, closure_lifetime_binder, "1.64.0", Some(97362), None),
     /// Allows `#[track_caller]` on closures and generators.
-    (active, closure_track_caller, "1.57.0", Some(87417), None),
+    (unstable, closure_track_caller, "1.57.0", Some(87417), None),
     /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
-    (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
+    (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
     /// Allows use of the `#[collapse_debuginfo]` attribute.
-    (active, collapse_debuginfo, "1.65.0", Some(100758), None),
+    (unstable, collapse_debuginfo, "1.65.0", Some(100758), None),
     /// Allows `async {}` expressions in const contexts.
-    (active, const_async_blocks, "1.53.0", Some(85368), None),
+    (unstable, const_async_blocks, "1.53.0", Some(85368), None),
     /// Allows `const || {}` closures in const contexts.
     (incomplete, const_closures, "1.68.0", Some(106003), None),
     /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
-    (active, const_extern_fn, "1.40.0", Some(64926), None),
+    (unstable, const_extern_fn, "1.40.0", Some(64926), None),
     /// Allows basic arithmetic on floating point types in a `const fn`.
-    (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
+    (unstable, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
     /// Allows `for _ in _` loops in const contexts.
-    (active, const_for, "1.56.0", Some(87575), None),
+    (unstable, const_for, "1.56.0", Some(87575), None),
     /// Allows using `&mut` in constant functions.
-    (active, const_mut_refs, "1.41.0", Some(57349), None),
+    (unstable, const_mut_refs, "1.41.0", Some(57349), None),
     /// Be more precise when looking for live drops in a const context.
-    (active, const_precise_live_drops, "1.46.0", Some(73255), None),
+    (unstable, const_precise_live_drops, "1.46.0", Some(73255), None),
     /// Allows references to types with interior mutability within constants
-    (active, const_refs_to_cell, "1.51.0", Some(80384), None),
+    (unstable, const_refs_to_cell, "1.51.0", Some(80384), None),
     /// Allows `impl const Trait for T` syntax.
-    (active, const_trait_impl, "1.42.0", Some(67792), None),
+    (unstable, const_trait_impl, "1.42.0", Some(67792), None),
     /// Allows the `?` operator in const contexts.
-    (active, const_try, "1.56.0", Some(74935), None),
+    (unstable, const_try, "1.56.0", Some(74935), None),
     /// Allows function attribute `#[coverage(on/off)]`, to control coverage
     /// instrumentation of that function.
-    (active, coverage_attribute, "1.74.0", Some(84605), None),
+    (unstable, coverage_attribute, "1.74.0", Some(84605), None),
     /// Allows users to provide classes for fenced code block using `class:classname`.
-    (active, custom_code_classes_in_docs, "1.74.0", Some(79483), None),
+    (unstable, custom_code_classes_in_docs, "1.74.0", Some(79483), None),
     /// Allows non-builtin attributes in inner attribute position.
-    (active, custom_inner_attributes, "1.30.0", Some(54726), None),
+    (unstable, custom_inner_attributes, "1.30.0", Some(54726), None),
     /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
-    (active, custom_test_frameworks, "1.30.0", Some(50297), None),
+    (unstable, custom_test_frameworks, "1.30.0", Some(50297), None),
     /// Allows declarative macros 2.0 (`macro`).
-    (active, decl_macro, "1.17.0", Some(39412), None),
+    (unstable, decl_macro, "1.17.0", Some(39412), None),
     /// Allows default type parameters to influence type inference.
-    (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
+    (unstable, default_type_parameter_fallback, "1.3.0", Some(27336), None),
     /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
-    (active, deprecated_safe, "1.61.0", Some(94978), None),
+    (unstable, deprecated_safe, "1.61.0", Some(94978), None),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
-    (active, deprecated_suggestion, "1.61.0", Some(94785), None),
+    (unstable, deprecated_suggestion, "1.61.0", Some(94785), None),
     /// Allows using the `#[diagnostic]` attribute tool namespace
-    (active, diagnostic_namespace, "1.73.0", Some(111996), None),
+    (unstable, diagnostic_namespace, "1.73.0", Some(111996), None),
     /// Controls errors in trait implementations.
-    (active, do_not_recommend, "1.67.0", Some(51992), None),
+    (unstable, do_not_recommend, "1.67.0", Some(51992), None),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
-    (active, doc_auto_cfg, "1.58.0", Some(43781), None),
+    (unstable, doc_auto_cfg, "1.58.0", Some(43781), None),
     /// Allows `#[doc(cfg(...))]`.
-    (active, doc_cfg, "1.21.0", Some(43781), None),
+    (unstable, doc_cfg, "1.21.0", Some(43781), None),
     /// Allows `#[doc(cfg_hide(...))]`.
-    (active, doc_cfg_hide, "1.57.0", Some(43781), None),
+    (unstable, doc_cfg_hide, "1.57.0", Some(43781), None),
     /// Allows `#[doc(masked)]`.
-    (active, doc_masked, "1.21.0", Some(44027), None),
+    (unstable, doc_masked, "1.21.0", Some(44027), None),
     /// Allows `dyn* Trait` objects.
     (incomplete, dyn_star, "1.65.0", Some(102425), None),
     // Uses generic effect parameters for ~const bounds
-    (active, effects, "1.72.0", Some(102090), None),
+    (unstable, effects, "1.72.0", Some(102090), None),
     /// Allows `X..Y` patterns.
-    (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
+    (unstable, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
-    (active, exhaustive_patterns, "1.13.0", Some(51085), None),
+    (unstable, exhaustive_patterns, "1.13.0", Some(51085), None),
     /// Allows explicit tail calls via `become` expression.
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788), None),
     /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
     /// for functions with varargs.
-    (active, extended_varargs_abi_support, "1.65.0", Some(100189), None),
+    (unstable, extended_varargs_abi_support, "1.65.0", Some(100189), None),
     /// Allows defining `extern type`s.
-    (active, extern_types, "1.23.0", Some(43467), None),
+    (unstable, extern_types, "1.23.0", Some(43467), None),
     /// Allows the use of `#[ffi_const]` on foreign functions.
-    (active, ffi_const, "1.45.0", Some(58328), None),
+    (unstable, ffi_const, "1.45.0", Some(58328), None),
     /// Allows the use of `#[ffi_pure]` on foreign functions.
-    (active, ffi_pure, "1.45.0", Some(58329), None),
+    (unstable, ffi_pure, "1.45.0", Some(58329), None),
     /// Allows using `#[ffi_returns_twice]` on foreign functions.
-    (active, ffi_returns_twice, "1.34.0", Some(58314), None),
+    (unstable, ffi_returns_twice, "1.34.0", Some(58314), None),
     /// Allows using `#[repr(align(...))]` on function items
-    (active, fn_align, "1.53.0", Some(82232), None),
+    (unstable, fn_align, "1.53.0", Some(82232), None),
     /// Allows generators to be cloned.
-    (active, generator_clone, "1.65.0", Some(95360), None),
+    (unstable, generator_clone, "1.65.0", Some(95360), None),
     /// Allows defining generators.
-    (active, generators, "1.21.0", Some(43122), None),
+    (unstable, generators, "1.21.0", Some(43122), None),
     /// Infer generic args for both consts and types.
-    (active, generic_arg_infer, "1.55.0", Some(85077), None),
+    (unstable, generic_arg_infer, "1.55.0", Some(85077), None),
     /// An extension to the `generic_associated_types` feature, allowing incomplete features.
     (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
     /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
@@ -474,137 +464,137 @@ declare_features! (
     /// Allows generic parameters and where-clauses on free & associated const items.
     (incomplete, generic_const_items, "1.73.0", Some(113521), None),
     /// Allows using `..=X` as a patterns in slices.
-    (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
+    (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
     /// Allows `if let` guard in match arms.
-    (active, if_let_guard, "1.47.0", Some(51114), None),
+    (unstable, if_let_guard, "1.47.0", Some(51114), None),
     /// Allows `impl Trait` to be used inside associated types (RFC 2515).
-    (active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None),
+    (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063), None),
     /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
-    (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
+    (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
     /// Allows using imported `main` function
-    (active, imported_main, "1.53.0", Some(28937), None),
+    (unstable, imported_main, "1.53.0", Some(28937), None),
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
     /// Allow anonymous constants from an inline `const` block
-    (active, inline_const, "1.49.0", Some(76001), None),
+    (unstable, inline_const, "1.49.0", Some(76001), None),
     /// Allow anonymous constants from an inline `const` block in pattern position
     (incomplete, inline_const_pat, "1.58.0", Some(76001), None),
     /// Allows using `pointer` and `reference` in intra-doc links
-    (active, intra_doc_pointers, "1.51.0", Some(80896), None),
+    (unstable, intra_doc_pointers, "1.51.0", Some(80896), None),
     // Allows setting the threshold for the `large_assignments` lint.
-    (active, large_assignments, "1.52.0", Some(83518), None),
+    (unstable, large_assignments, "1.52.0", Some(83518), None),
     /// Allow to have type alias types for inter-crate use.
     (incomplete, lazy_type_alias, "1.72.0", Some(112792), None),
     /// Allows `if/while p && let q = r && ...` chains.
-    (active, let_chains, "1.37.0", Some(53667), None),
+    (unstable, let_chains, "1.37.0", Some(53667), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
-    (active, lint_reasons, "1.31.0", Some(54503), None),
+    (unstable, lint_reasons, "1.31.0", Some(54503), None),
     /// Give access to additional metadata about declarative macro meta-variables.
-    (active, macro_metavar_expr, "1.61.0", Some(83527), None),
+    (unstable, macro_metavar_expr, "1.61.0", Some(83527), None),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
-    (active, marker_trait_attr, "1.30.0", Some(29864), None),
+    (unstable, marker_trait_attr, "1.30.0", Some(29864), None),
     /// A minimal, sound subset of specialization intended to be used by the
     /// standard library until the soundness issues with specialization
     /// are fixed.
-    (active, min_specialization, "1.7.0", Some(31844), None),
+    (unstable, min_specialization, "1.7.0", Some(31844), None),
     /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
-    (active, more_qualified_paths, "1.54.0", Some(86935), None),
+    (unstable, more_qualified_paths, "1.54.0", Some(86935), None),
     /// Allows the `#[must_not_suspend]` attribute.
-    (active, must_not_suspend, "1.57.0", Some(83310), None),
+    (unstable, must_not_suspend, "1.57.0", Some(83310), None),
     /// Allows using `#[naked]` on functions.
-    (active, naked_functions, "1.9.0", Some(32408), None),
+    (unstable, naked_functions, "1.9.0", Some(32408), None),
     /// Allows specifying the as-needed link modifier
-    (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
+    (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
     /// Allow negative trait implementations.
-    (active, negative_impls, "1.44.0", Some(68318), None),
+    (unstable, negative_impls, "1.44.0", Some(68318), None),
     /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
-    (active, never_type, "1.13.0", Some(35121), None),
+    (unstable, never_type, "1.13.0", Some(35121), None),
     /// Allows diverging expressions to fall back to `!` rather than `()`.
-    (active, never_type_fallback, "1.41.0", Some(65992), None),
+    (unstable, never_type_fallback, "1.41.0", Some(65992), None),
     /// Allows `#![no_core]`.
-    (active, no_core, "1.3.0", Some(29639), None),
+    (unstable, no_core, "1.3.0", Some(29639), None),
     /// Allows the use of `no_sanitize` attribute.
-    (active, no_sanitize, "1.42.0", Some(39699), None),
+    (unstable, no_sanitize, "1.42.0", Some(39699), None),
     /// Allows using the `non_exhaustive_omitted_patterns` lint.
-    (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
+    (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
     /// Allows `for<T>` binders in where-clauses
     (incomplete, non_lifetime_binders, "1.69.0", Some(108185), None),
     /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
     /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
-    (active, object_safe_for_dispatch, "1.40.0", Some(43561), None),
+    (unstable, object_safe_for_dispatch, "1.40.0", Some(43561), None),
     /// Allows using `#[optimize(X)]`.
-    (active, optimize_attribute, "1.34.0", Some(54882), None),
+    (unstable, optimize_attribute, "1.34.0", Some(54882), None),
     /// Allows using `#![plugin(myplugin)]`.
-    (active, plugin, "1.0.0", Some(29597), None),
+    (unstable, plugin, "1.0.0", Some(29597), None),
     /// Allows exhaustive integer pattern matching on `usize` and `isize`.
-    (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
+    (unstable, precise_pointer_size_matching, "1.32.0", Some(56354), None),
     /// Allows macro attributes on expressions, statements and non-inline modules.
-    (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
+    (unstable, proc_macro_hygiene, "1.30.0", Some(54727), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
-    (active, raw_ref_op, "1.41.0", Some(64490), None),
+    (unstable, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
-    (active, register_tool, "1.41.0", Some(66079), None),
+    (unstable, register_tool, "1.41.0", Some(66079), None),
     /// Allows the `#[repr(i128)]` attribute for enums.
     (incomplete, repr128, "1.16.0", Some(56071), None),
     /// Allows `repr(simd)` and importing the various simd intrinsics.
-    (active, repr_simd, "1.4.0", Some(27731), None),
+    (unstable, repr_simd, "1.4.0", Some(27731), None),
     /// Allows bounding the return type of AFIT/RPITIT.
     (incomplete, return_type_notation, "1.70.0", Some(109417), None),
     /// Allows `extern "rust-cold"`.
-    (active, rust_cold_cc, "1.63.0", Some(97544), None),
+    (unstable, rust_cold_cc, "1.63.0", Some(97544), None),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
-    (active, simd_ffi, "1.0.0", Some(27731), None),
+    (unstable, simd_ffi, "1.0.0", Some(27731), None),
     /// Allows specialization of implementations (RFC 1210).
     (incomplete, specialization, "1.7.0", Some(31844), None),
     /// Allows attributes on expressions and non-item statements.
-    (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
+    (unstable, stmt_expr_attributes, "1.6.0", Some(15701), None),
     /// Allows lints part of the strict provenance effort.
-    (active, strict_provenance, "1.61.0", Some(95228), None),
+    (unstable, strict_provenance, "1.61.0", Some(95228), None),
     /// Allows string patterns to dereference values to match them.
-    (active, string_deref_patterns, "1.67.0", Some(87121), None),
+    (unstable, string_deref_patterns, "1.67.0", Some(87121), None),
     /// Allows the use of `#[target_feature]` on safe functions.
-    (active, target_feature_11, "1.45.0", Some(69098), None),
+    (unstable, target_feature_11, "1.45.0", Some(69098), None),
     /// Allows using `#[thread_local]` on `static` items.
-    (active, thread_local, "1.0.0", Some(29594), None),
+    (unstable, thread_local, "1.0.0", Some(29594), None),
     /// Allows defining `trait X = A + B;` alias items.
-    (active, trait_alias, "1.24.0", Some(41517), None),
+    (unstable, trait_alias, "1.24.0", Some(41517), None),
     /// Allows dyn upcasting trait objects via supertraits.
     /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
-    (active, trait_upcasting, "1.56.0", Some(65991), None),
+    (unstable, trait_upcasting, "1.56.0", Some(65991), None),
     /// Allows for transmuting between arrays with sizes that contain generic consts.
-    (active, transmute_generic_consts, "1.70.0", Some(109929), None),
+    (unstable, transmute_generic_consts, "1.70.0", Some(109929), None),
     /// Allows #[repr(transparent)] on unions (RFC 2645).
-    (active, transparent_unions, "1.37.0", Some(60405), None),
+    (unstable, transparent_unions, "1.37.0", Some(60405), None),
     /// Allows inconsistent bounds in where clauses.
-    (active, trivial_bounds, "1.28.0", Some(48214), None),
+    (unstable, trivial_bounds, "1.28.0", Some(48214), None),
     /// Allows using `try {...}` expressions.
-    (active, try_blocks, "1.29.0", Some(31436), None),
+    (unstable, try_blocks, "1.29.0", Some(31436), None),
     /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
-    (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
+    (unstable, type_alias_impl_trait, "1.38.0", Some(63063), None),
     /// Allows the use of type ascription in expressions.
-    (active, type_ascription, "1.6.0", Some(23416), None),
+    (unstable, type_ascription, "1.6.0", Some(23416), None),
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
-    (active, type_changing_struct_update, "1.58.0", Some(86555), None),
+    (unstable, type_changing_struct_update, "1.58.0", Some(86555), None),
     /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`).
-    (active, type_privacy_lints, "1.72.0", Some(48054), None),
+    (unstable, type_privacy_lints, "1.72.0", Some(48054), None),
     /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
-    (active, unix_sigpipe, "1.65.0", Some(97889), None),
+    (unstable, unix_sigpipe, "1.65.0", Some(97889), None),
     /// Allows unnamed fields of struct and union type
     (incomplete, unnamed_fields, "1.74.0", Some(49804), None),
     /// Allows unsized fn parameters.
-    (active, unsized_fn_params, "1.49.0", Some(48055), None),
+    (unstable, unsized_fn_params, "1.49.0", Some(48055), None),
     /// Allows unsized rvalues at arguments and parameters.
     (incomplete, unsized_locals, "1.30.0", Some(48055), None),
     /// Allows unsized tuple coercion.
-    (active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
+    (unstable, unsized_tuple_coercion, "1.20.0", Some(42877), None),
     /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
-    (active, used_with_arg, "1.60.0", Some(93798), None),
+    (unstable, used_with_arg, "1.60.0", Some(93798), None),
     /// Allows `extern "wasm" fn`
-    (active, wasm_abi, "1.53.0", Some(83788), None),
+    (unstable, wasm_abi, "1.53.0", Some(83788), None),
     /// Allows `do yeet` expressions
-    (active, yeet_expr, "1.62.0", Some(96373), None),
+    (unstable, yeet_expr, "1.62.0", Some(96373), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 45d174cbbbb..059dfc60450 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -284,6 +284,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             self.one_bound_for_assoc_type(
                 || traits::supertraits(tcx, trait_ref),
                 trait_ref.skip_binder().print_only_trait_name(),
+                None,
                 binding.item_name,
                 path_span,
                 match binding.kind {
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index ed4dde419c4..9e18767a7c3 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -6,10 +6,9 @@ use crate::errors::{
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{sym, Ident};
@@ -102,6 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         &self,
         all_candidates: impl Fn() -> I,
         ty_param_name: &str,
+        ty_param_def_id: Option<LocalDefId>,
         assoc_name: Ident,
         span: Span,
     ) -> ErrorGuaranteed
@@ -190,13 +190,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 })
                 .collect::<Vec<_>>()[..]
             {
+                let trait_name = self.tcx().def_path_str(*best_trait);
+                let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
                 err.span_label(
                     assoc_name.span,
                     format!(
-                        "there is a similarly named associated type `{suggested_name}` in the trait `{}`",
-                        self.tcx().def_path_str(*best_trait)
+                        "there is {an} associated type `{suggested_name}` in the \
+                         trait `{trait_name}`",
                     ),
                 );
+                let hir = self.tcx().hir();
+                if let Some(def_id) = ty_param_def_id
+                    && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id))
+                    && let Some(generics) = hir.get_generics(parent.def_id)
+                {
+                    if generics.bounds_for_param(def_id)
+                        .flat_map(|pred| pred.bounds.iter())
+                        .any(|b| match b {
+                            hir::GenericBound::Trait(t, ..) => {
+                                t.trait_ref.trait_def_id().as_ref() == Some(best_trait)
+                            }
+                            _ => false,
+                        })
+                    {
+                        // The type param already has a bound for `trait_name`, we just need to
+                        // change the associated type.
+                        err.span_suggestion_verbose(
+                            assoc_name.span,
+                            format!(
+                                "change the associated type name to use `{suggested_name}` from \
+                                 `{trait_name}`",
+                            ),
+                            suggested_name.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else if suggest_constraining_type_param(
+                            self.tcx(),
+                            generics,
+                            &mut err,
+                            &ty_param_name,
+                            &trait_name,
+                            None,
+                            None,
+                        )
+                        && suggested_name != assoc_name.name
+                    {
+                        // We suggested constraining a type parameter, but the associated type on it
+                        // was also not an exact match, so we also suggest changing it.
+                        err.span_suggestion_verbose(
+                            assoc_name.span,
+                            "and also change the associated type name",
+                            suggested_name.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
                 return err.emit();
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index ac97df0c087..960a1bfdd2d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1062,6 +1062,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 )
             },
             param_name,
+            Some(ty_param_def_id),
             assoc_name,
             span,
             None,
@@ -1075,6 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         &self,
         all_candidates: impl Fn() -> I,
         ty_param_name: impl Display,
+        ty_param_def_id: Option<LocalDefId>,
         assoc_name: Ident,
         span: Span,
         is_equality: Option<ty::Term<'tcx>>,
@@ -1089,13 +1091,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
         });
 
-        let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
+        let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
+        {
             (Some(bound), _) => (bound, matching_candidates.next()),
             (None, Some(bound)) => (bound, const_candidates.next()),
             (None, None) => {
                 let reported = self.complain_about_assoc_type_not_found(
                     all_candidates,
                     &ty_param_name.to_string(),
+                    ty_param_def_id,
                     assoc_name,
                     span,
                 );
@@ -1104,6 +1108,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         };
         debug!(?bound);
 
+        // look for a candidate that is not the same as our first bound, disregarding
+        // whether the bound is const.
+        while let Some(mut bound2) = next_cand {
+            debug!(?bound2);
+            let tcx = self.tcx();
+            if bound2.bound_vars() != bound.bound_vars() {
+                break;
+            }
+
+            let generics = tcx.generics_of(bound.def_id());
+            let Some(host_index) = generics.host_effect_index else { break };
+
+            // always return the bound that contains the host param.
+            if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() {
+                (bound, bound2) = (bound2, bound);
+            }
+
+            let unconsted_args = bound
+                .skip_binder()
+                .args
+                .iter()
+                .enumerate()
+                .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
+
+            if unconsted_args.eq(bound2.skip_binder().args.iter()) {
+                next_cand = matching_candidates.next().or_else(|| const_candidates.next());
+            } else {
+                break;
+            }
+        }
+
         if let Some(bound2) = next_cand {
             debug!(?bound2);
 
@@ -1143,30 +1178,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     err.span_label(
                         bound_span,
                         format!(
-                            "ambiguous `{}` from `{}`",
-                            assoc_name,
+                            "ambiguous `{assoc_name}` from `{}`",
                             bound.print_only_trait_path(),
                         ),
                     );
                     if let Some(constraint) = &is_equality {
                         where_bounds.push(format!(
-                            "        T: {trait}::{assoc} = {constraint}",
+                            "        T: {trait}::{assoc_name} = {constraint}",
                             trait=bound.print_only_trait_path(),
-                            assoc=assoc_name,
-                            constraint=constraint,
                         ));
                     } else {
                         err.span_suggestion_verbose(
                             span.with_hi(assoc_name.span.lo()),
                             "use fully qualified syntax to disambiguate",
-                            format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()),
+                            format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
                             Applicability::MaybeIncorrect,
                         );
                     }
                 } else {
                     err.note(format!(
-                        "associated type `{}` could derive from `{}`",
-                        ty_param_name,
+                        "associated type `{ty_param_name}` could derive from `{}`",
                         bound.print_only_trait_path(),
                     ));
                 }
@@ -1174,8 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             if !where_bounds.is_empty() {
                 err.help(format!(
                     "consider introducing a new type parameter `T` and adding `where` constraints:\
-                     \n    where\n        T: {},\n{}",
-                    ty_param_name,
+                     \n    where\n        T: {ty_param_name},\n{}",
                     where_bounds.join(",\n"),
                 ));
             }
@@ -1397,6 +1427,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         )
                     },
                     kw::SelfUpper,
+                    None,
                     assoc_ident,
                     span,
                     None,
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 1d9ae2b9cb7..af1a4e5d99e 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -44,6 +44,33 @@ impl<'tcx> Bounds<'tcx> {
         span: Span,
         polarity: ty::ImplPolarity,
     ) {
+        self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
+
+        // if we have a host param, we push an unconst trait bound in addition
+        // to the const one.
+        // FIXME(effects) we should find a better way than name matching
+        if tcx.features().effects && trait_ref.skip_binder().args.host_effect_param().is_some() {
+            let generics = tcx.generics_of(trait_ref.def_id());
+            let Some(host_index) = generics.host_effect_index else { return };
+            let trait_ref = trait_ref.map_bound(|mut trait_ref| {
+                trait_ref.args =
+                    tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| {
+                        if host_index == n { tcx.consts.true_.into() } else { arg }
+                    }));
+                trait_ref
+            });
+
+            self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
+        }
+    }
+
+    fn push_trait_bound_inner(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        span: Span,
+        polarity: ty::ImplPolarity,
+    ) {
         self.clauses.push((
             trait_ref
                 .map_bound(|trait_ref| {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 97ebd42d077..34c28bce5d8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -314,9 +314,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
 ///     fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
 /// }
 /// ```
-fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
+fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
     // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
     let mut required_bounds_by_item = FxHashMap::default();
+    let associated_items = tcx.associated_items(trait_def_id);
 
     // Loop over all GATs together, because if this lint suggests adding a where-clause bound
     // to one GAT, it might then require us to an additional bound on another GAT.
@@ -325,8 +326,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
     // those GATs.
     loop {
         let mut should_continue = false;
-        for gat_item in associated_items {
-            let gat_def_id = gat_item.id.owner_id;
+        for gat_item in associated_items.in_definition_order() {
+            let gat_def_id = gat_item.def_id.expect_local();
             let gat_item = tcx.associated_item(gat_def_id);
             // If this item is not an assoc ty, or has no args, then it's not a GAT
             if gat_item.kind != ty::AssocKind::Type {
@@ -342,8 +343,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
             // This is calculated by taking the intersection of the bounds that each item
             // constrains the GAT with individually.
             let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
-            for item in associated_items {
-                let item_def_id = item.id.owner_id;
+            for item in associated_items.in_definition_order() {
+                let item_def_id = item.def_id.expect_local();
                 // Skip our own GAT, since it does not constrain itself at all.
                 if item_def_id == gat_def_id {
                     continue;
@@ -351,9 +352,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
 
                 let param_env = tcx.param_env(item_def_id);
 
-                let item_required_bounds = match item.kind {
+                let item_required_bounds = match tcx.associated_item(item_def_id).kind {
                     // In our example, this corresponds to `into_iter` method
-                    hir::AssocItemKind::Fn { .. } => {
+                    ty::AssocKind::Fn => {
                         // For methods, we check the function signature's return type for any GATs
                         // to constrain. In the `into_iter` case, we see that the return type
                         // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@@ -369,12 +370,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                             // We also assume that all of the function signature's parameter types
                             // are well formed.
                             &sig.inputs().iter().copied().collect(),
-                            gat_def_id.def_id,
+                            gat_def_id,
                             gat_generics,
                         )
                     }
                     // In our example, this corresponds to the `Iter` and `Item` associated types
-                    hir::AssocItemKind::Type => {
+                    ty::AssocKind::Type => {
                         // If our associated item is a GAT with missing bounds, add them to
                         // the param-env here. This allows this GAT to propagate missing bounds
                         // to other GATs.
@@ -391,11 +392,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                                 .instantiate_identity_iter_copied()
                                 .collect::<Vec<_>>(),
                             &FxIndexSet::default(),
-                            gat_def_id.def_id,
+                            gat_def_id,
                             gat_generics,
                         )
                     }
-                    hir::AssocItemKind::Const => None,
+                    ty::AssocKind::Const => None,
                 };
 
                 if let Some(item_required_bounds) = item_required_bounds {
@@ -431,7 +432,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
     }
 
     for (gat_def_id, required_bounds) in required_bounds_by_item {
-        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
+        // Don't suggest adding `Self: 'a` to a GAT that can't be named
+        if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) {
+            continue;
+        }
+
+        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
         debug!(?required_bounds);
         let param_env = tcx.param_env(gat_def_id);
 
@@ -441,21 +447,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
                     !region_known_to_outlive(
                         tcx,
-                        gat_def_id.def_id,
+                        gat_def_id,
                         param_env,
                         &FxIndexSet::default(),
                         a,
                         b,
                     )
                 }
-                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive(
-                    tcx,
-                    gat_def_id.def_id,
-                    param_env,
-                    &FxIndexSet::default(),
-                    a,
-                    b,
-                ),
+                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+                    !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b)
+                }
                 _ => bug!("Unexpected ClauseKind"),
             })
             .map(|clause| clause.to_string())
@@ -534,7 +535,7 @@ fn augment_param_env<'tcx>(
 fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    item_def_id: hir::OwnerId,
+    item_def_id: LocalDefId,
     to_check: T,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
@@ -567,7 +568,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
         // reflected in a where clause on the GAT itself.
         for (ty, ty_idx) in &types {
             // In our example, requires that `Self: 'a`
-            if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) {
+            if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) {
                 debug!(?ty_idx, ?region_a_idx);
                 debug!("required clause: {ty} must outlive {region_a}");
                 // Translate into the generic parameters of the GAT. In
@@ -606,14 +607,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
             if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b {
                 continue;
             }
-            if region_known_to_outlive(
-                tcx,
-                item_def_id.def_id,
-                param_env,
-                &wf_tys,
-                *region_a,
-                *region_b,
-            ) {
+            if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) {
                 debug!(?region_a_idx, ?region_b_idx);
                 debug!("required clause: {region_a} must outlive {region_b}");
                 // Translate into the generic parameters of the GAT.
@@ -1114,8 +1108,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     });
 
     // Only check traits, don't check trait aliases
-    if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind {
-        check_gat_where_clauses(tcx, items);
+    if let hir::ItemKind::Trait(..) = item.kind {
+        check_gat_where_clauses(tcx, item.owner_id.def_id);
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 1b38f77654c..104da581e01 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
 /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
@@ -38,11 +38,38 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
         // an obligation and instead be skipped. Otherwise we'd use
         // `tcx.def_span(def_id);`
         let span = rustc_span::DUMMY_SP;
-        result.predicates =
-            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
+        let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) {
+            // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound,
+            // because only implementing `Self: Trait<.., false>` is currently not possible.
+            Some((
+                ty::TraitRef::new(
+                    tcx,
+                    def_id,
+                    ty::GenericArgs::for_item(tcx, def_id, |param, _| {
+                        if param.is_host_effect() {
+                            tcx.consts.true_.into()
+                        } else {
+                            tcx.mk_param_from_def(param)
+                        }
+                    }),
+                )
+                .to_predicate(tcx),
                 span,
-            ))));
+            ))
+        } else {
+            None
+        };
+        result.predicates = tcx.arena.alloc_from_iter(
+            result
+                .predicates
+                .iter()
+                .copied()
+                .chain(std::iter::once((
+                    ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
+                    span,
+                )))
+                .chain(non_const_bound),
+        );
     }
     debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 512d73fc103..1c23ccd1579 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -650,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .sess
                 .source_map()
                 .is_multiline(call_expr.span.with_lo(callee_expr.span.hi()))
-                && call_expr.span.ctxt() == callee_expr.span.ctxt();
+                && call_expr.span.eq_ctxt(callee_expr.span);
             if call_is_multiline {
                 err.span_suggestion(
                     callee_expr.span.shrink_to_hi(),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 4a245d30c8e..7677d6f953b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         let item_def_id = tcx.hir().ty_param_owner(def_id);
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+        // HACK(eddyb) should get the original `Span`.
+        let span = tcx.def_span(def_id);
         ty::GenericPredicates {
             parent: None,
             predicates: tcx.arena.alloc_from_iter(
                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
                     match predicate.kind().skip_binder() {
                         ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
-                            // HACK(eddyb) should get the original `Span`.
-                            let span = tcx.def_span(def_id);
                             Some((predicate, span))
                         }
                         _ => None,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1c330c064ab..d2ce77ad535 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -5,6 +5,7 @@ use rustc_ast::{self as ast, LitKind, MetaItemKind};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::defer;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorGuaranteed, Handler};
@@ -124,8 +125,13 @@ pub fn parse_cfgspecs(
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
 pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
-        let mut check_cfg = CheckCfg::default();
+        // If any --check-cfg is passed then exhaustive_values and exhaustive_names
+        // are enabled by default.
+        let exhaustive_names = !specs.is_empty();
+        let exhaustive_values = !specs.is_empty();
+        let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
 
+        let mut old_syntax = None;
         for s in specs {
             let sess = ParseSess::with_silent_emitter(Some(format!(
                 "this error occurred on the command line: `--check-cfg={s}`"
@@ -141,18 +147,21 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                 };
             }
 
-            let expected_error = || {
-                error!(
-                    "expected `names(name1, name2, ... nameN)` or \
-                        `values(name, \"value1\", \"value2\", ... \"valueN\")`"
-                )
-            };
+            let expected_error =
+                || error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`");
 
             match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item() {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if let Some(args) = meta_item.meta_item_list() {
                             if meta_item.has_name(sym::names) {
+                                // defaults are flipped for the old syntax
+                                if old_syntax == None {
+                                    check_cfg.exhaustive_names = false;
+                                    check_cfg.exhaustive_values = false;
+                                }
+                                old_syntax = Some(true);
+
                                 check_cfg.exhaustive_names = true;
                                 for arg in args {
                                     if arg.is_word() && arg.ident().is_some() {
@@ -166,6 +175,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                                     }
                                 }
                             } else if meta_item.has_name(sym::values) {
+                                // defaults are flipped for the old syntax
+                                if old_syntax == None {
+                                    check_cfg.exhaustive_names = false;
+                                    check_cfg.exhaustive_values = false;
+                                }
+                                old_syntax = Some(true);
+
                                 if let Some((name, values)) = args.split_first() {
                                     if name.is_word() && name.ident().is_some() {
                                         let ident = name.ident().expect("multi-segment cfg key");
@@ -215,6 +231,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                                 } else {
                                     expected_error();
                                 }
+                            } else if meta_item.has_name(sym::cfg) {
+                                old_syntax = Some(false);
+
+                                let mut names = Vec::new();
+                                let mut values: FxHashSet<_> = Default::default();
+
+                                let mut any_specified = false;
+                                let mut values_specified = false;
+                                let mut values_any_specified = false;
+
+                                for arg in args {
+                                    if arg.is_word() && let Some(ident) = arg.ident() {
+                                        if values_specified {
+                                            error!("`cfg()` names cannot be after values");
+                                        }
+                                        names.push(ident);
+                                    } else if arg.has_name(sym::any)
+                                        && let Some(args) = arg.meta_item_list()
+                                    {
+                                        if any_specified {
+                                            error!("`any()` cannot be specified multiple times");
+                                        }
+                                        any_specified = true;
+                                        if !args.is_empty() {
+                                            error!("`any()` must be empty");
+                                        }
+                                    } else if arg.has_name(sym::values)
+                                        && let Some(args) = arg.meta_item_list()
+                                    {
+                                        if names.is_empty() {
+                                            error!(
+                                                "`values()` cannot be specified before the names"
+                                            );
+                                        } else if values_specified {
+                                            error!(
+                                                "`values()` cannot be specified multiple times"
+                                            );
+                                        }
+                                        values_specified = true;
+
+                                        for arg in args {
+                                            if let Some(LitKind::Str(s, _)) =
+                                                arg.lit().map(|lit| &lit.kind)
+                                            {
+                                                values.insert(Some(s.to_string()));
+                                            } else if arg.has_name(sym::any)
+                                                && let Some(args) = arg.meta_item_list()
+                                            {
+                                                if values_any_specified {
+                                                    error!(
+                                                        "`any()` in `values()` cannot be specified multiple times"
+                                                    );
+                                                }
+                                                values_any_specified = true;
+                                                if !args.is_empty() {
+                                                    error!("`any()` must be empty");
+                                                }
+                                            } else {
+                                                error!(
+                                                    "`values()` arguments must be string literals or `any()`"
+                                                );
+                                            }
+                                        }
+                                    } else {
+                                        error!(
+                                            "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
+                                        );
+                                    }
+                                }
+
+                                if values.is_empty() && !values_any_specified && !any_specified {
+                                    values.insert(None);
+                                } else if !values.is_empty() && values_any_specified {
+                                    error!(
+                                        "`values()` arguments cannot specify string literals and `any()` at the same time"
+                                    );
+                                }
+
+                                if any_specified {
+                                    if !names.is_empty()
+                                        || !values.is_empty()
+                                        || values_any_specified
+                                    {
+                                        error!("`cfg(any())` can only be provided in isolation");
+                                    }
+
+                                    check_cfg.exhaustive_names = false;
+                                } else {
+                                    for name in names {
+                                        check_cfg
+                                            .expecteds
+                                            .entry(name.to_string())
+                                            .and_modify(|v| match v {
+                                                ExpectedValues::Some(v)
+                                                    if !values_any_specified =>
+                                                {
+                                                    v.extend(values.clone())
+                                                }
+                                                ExpectedValues::Some(_) => *v = ExpectedValues::Any,
+                                                ExpectedValues::Any => {}
+                                            })
+                                            .or_insert_with(|| {
+                                                if values_any_specified {
+                                                    ExpectedValues::Any
+                                                } else {
+                                                    ExpectedValues::Some(values.clone())
+                                                }
+                                            });
+                                    }
+                                }
                             } else {
                                 expected_error();
                             }
@@ -260,6 +386,12 @@ pub struct Config {
     /// This is a callback from the driver that is called when [`ParseSess`] is created.
     pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,
 
+    /// This is a callback to hash otherwise untracked state used by the caller, if the
+    /// hash changes between runs the incremental cache will be cleared.
+    ///
+    /// e.g. used by Clippy to hash its config file
+    pub hash_untracked_state: Option<Box<dyn FnOnce(&Session, &mut StableHasher) + Send>>,
+
     /// This is a callback from the driver that is called when we're registering lints;
     /// it is called during plugin registration when we have the LintStore in a non-shared state.
     ///
@@ -269,8 +401,6 @@ pub struct Config {
 
     /// This is a callback from the driver that is called just after we have populated
     /// the list of queries.
-    ///
-    /// The second parameter is local providers and the third parameter is external providers.
     pub override_queries: Option<fn(&Session, &mut Providers)>,
 
     /// This is a callback from the driver that is called to create a codegen backend.
@@ -330,6 +460,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 parse_sess_created(&mut sess.parse_sess);
             }
 
+            if let Some(hash_untracked_state) = config.hash_untracked_state {
+                let mut hasher = StableHasher::new();
+                hash_untracked_state(&sess, &mut hasher);
+                sess.opts.untracked_state_hash = hasher.finish()
+            }
+
             let compiler = Compiler {
                 sess: Lrc::new(sess),
                 codegen_backend: Lrc::from(codegen_backend),
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 76131c1ad69..ffa2667a351 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -3,6 +3,7 @@
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(lazy_cell)]
+#![feature(let_chains)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 197fe6552d7..4c4d2933bf4 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -494,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
 
 lint_requested_level = requested on the command line with `{$level} {$lint_name}`
 
+lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
+
 lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
     .label = target type is set here
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index bf177690ce5..3e44e168786 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2249,7 +2249,7 @@ declare_lint! {
 }
 
 declare_lint_pass!(
-    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
+    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
     IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
 );
 
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index b1266b58a61..740c90757e6 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) {
 }
 
 fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
-    if !tcx.features().enabled(sym::lint_reasons) {
+    if !tcx.features().active(sym::lint_reasons) {
         return;
     }
 
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index fc2d3d0a254..2d86129c480 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -3,14 +3,14 @@
 
 use crate::lints::{
     BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
-    QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+    QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
     UntranslatableDiagnosticTrivial,
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 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};
+use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -537,3 +537,33 @@ impl LateLintPass<'_> for BadOptAccess {
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::SPAN_USE_EQ_CTXT,
+    Allow,
+    "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
+
+impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
+            if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
+                cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
+            }
+        }
+    }
+}
+
+fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match &expr.kind {
+        ExprKind::MethodCall(..) => cx
+            .typeck_results()
+            .type_dependent_def_id(expr.hir_id)
+            .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
+
+        _ => false,
+    }
+}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 7a4fcb08363..0d20f6232db 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1062,7 +1062,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
     #[track_caller]
     fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
-            if !self.features.enabled(feature) {
+            if !self.features.active(feature) {
                 let lint = builtin::UNKNOWN_LINTS;
                 let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
                 struct_lint_level(
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b9e455e6c2a..d61c59af1e0 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -531,6 +531,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_late_mod_pass(|_| Box::new(BadOptAccess));
     store.register_lints(&PassByValue::get_lints());
     store.register_late_mod_pass(|_| Box::new(PassByValue));
+    store.register_lints(&SpanUseEqCtxt::get_lints());
+    store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
     // these lints will trigger all of the time - change this once migration to diagnostic structs
@@ -548,6 +550,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(USAGE_OF_QUALIFIED_TY),
             LintId::of(EXISTING_DOC_KEYWORD),
             LintId::of(BAD_OPT_ACCESS),
+            LintId::of(SPAN_USE_EQ_CTXT),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 594ef97b3ff..4eaf8bbf5de 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -901,6 +901,10 @@ pub struct QueryInstability {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_span_use_eq_ctxt)]
+pub struct SpanUseEqCtxtDiag;
+
+#[derive(LintDiagnostic)]
 #[diag(lint_tykind_kind)]
 pub struct TykindKind {
     #[suggestion(code = "ty", applicability = "maybe-incorrect")]
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 8e6c1cd4bbb..44e88d3e230 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -79,6 +79,10 @@ impl GenericParamDef {
         }
     }
 
+    pub fn is_host_effect(&self) -> bool {
+        matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
+    }
+
     pub fn default_value<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 506bcea0e39..f1a0f762041 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -3,7 +3,7 @@ use std::cell::OnceCell;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_index::IndexVec;
 use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind};
-use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
+use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
 
 use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
 
@@ -215,9 +215,6 @@ struct CoverageSpansGenerator<'a> {
     /// is mutated.
     prev_original_span: Span,
 
-    /// A copy of the expn_span from the prior iteration.
-    prev_expn_span: Option<Span>,
-
     /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
     /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
     /// If a new `curr` span also fits this criteria (compared to an existing list of
@@ -272,13 +269,12 @@ impl<'a> CoverageSpansGenerator<'a> {
             body_span,
             basic_coverage_blocks,
             sorted_spans_iter: sorted_spans.into_iter(),
-            refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
             some_curr: None,
-            curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
+            curr_original_span: DUMMY_SP,
             some_prev: None,
-            prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
-            prev_expn_span: None,
+            prev_original_span: DUMMY_SP,
             pending_dups: Vec::new(),
+            refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
         };
 
         coverage_spans.to_refined_spans()
@@ -288,43 +284,48 @@ impl<'a> CoverageSpansGenerator<'a> {
     /// de-duplicated `CoverageSpan`s.
     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
         while self.next_coverage_span() {
+            // For the first span we don't have `prev` set, so most of the
+            // span-processing steps don't make sense yet.
             if self.some_prev.is_none() {
                 debug!("  initial span");
-                self.check_invoked_macro_name_span();
-            } else if self.curr().is_mergeable(self.prev()) {
-                debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
+                self.maybe_push_macro_name_span();
+                continue;
+            }
+
+            // The remaining cases assume that `prev` and `curr` are set.
+            let prev = self.prev();
+            let curr = self.curr();
+
+            if curr.is_mergeable(prev) {
+                debug!("  same bcb (and neither is a closure), merge with prev={prev:?}");
                 let prev = self.take_prev();
                 self.curr_mut().merge_from(prev);
-                self.check_invoked_macro_name_span();
+                self.maybe_push_macro_name_span();
             // Note that curr.span may now differ from curr_original_span
-            } else if self.prev_ends_before_curr() {
+            } else if prev.span.hi() <= curr.span.lo() {
                 debug!(
-                    "  different bcbs and disjoint spans, so keep curr for next iter, and add \
-                    prev={:?}",
-                    self.prev()
+                    "  different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
                 );
                 let prev = self.take_prev();
                 self.push_refined_span(prev);
-                self.check_invoked_macro_name_span();
-            } else if self.prev().is_closure {
+                self.maybe_push_macro_name_span();
+            } else if prev.is_closure {
                 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
                 // next iter
                 debug!(
-                    "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
-                    prev={:?}",
-                    self.prev()
+                    "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. prev={prev:?}",
                 );
-                self.take_curr();
-            } else if self.curr().is_closure {
+                self.take_curr(); // Discards curr.
+            } else if curr.is_closure {
                 self.carve_out_span_for_closure();
-            } else if self.prev_original_span == self.curr().span {
+            } else if self.prev_original_span == curr.span {
                 // Note that this compares the new (`curr`) span to `prev_original_span`.
                 // In this branch, the actual span byte range of `prev_original_span` is not
                 // important. What is important is knowing whether the new `curr` span was
                 // **originally** the same as the original span of `prev()`. The original spans
                 // reflect their original sort order, and for equal spans, conveys a partial
                 // ordering based on CFG dominator priority.
-                if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
+                if prev.is_macro_expansion() && curr.is_macro_expansion() {
                     // Macros that expand to include branching (such as
                     // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
                     // `trace!()`) typically generate callee spans with identical
@@ -338,23 +339,24 @@ impl<'a> CoverageSpansGenerator<'a> {
                     debug!(
                         "  curr and prev are part of a macro expansion, and curr has the same span \
                         as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
-                        prev={:?}",
-                        self.prev()
+                        prev={prev:?}",
                     );
-                    self.take_curr();
+                    self.take_curr(); // Discards curr.
                 } else {
-                    self.hold_pending_dups_unless_dominated();
+                    self.update_pending_dups();
                 }
             } else {
                 self.cutoff_prev_at_overlapping_curr();
-                self.check_invoked_macro_name_span();
+                self.maybe_push_macro_name_span();
             }
         }
 
-        debug!("    AT END, adding last prev={:?}", self.prev());
         let prev = self.take_prev();
-        let pending_dups = self.pending_dups.split_off(0);
-        for dup in pending_dups {
+        debug!("    AT END, adding last prev={prev:?}");
+
+        // Take `pending_dups` so that we can drain it while calling self methods.
+        // It is never used as a field after this point.
+        for dup in std::mem::take(&mut self.pending_dups) {
             debug!("    ...adding at least one pending dup={:?}", dup);
             self.push_refined_span(dup);
         }
@@ -384,43 +386,40 @@ impl<'a> CoverageSpansGenerator<'a> {
     }
 
     fn push_refined_span(&mut self, covspan: CoverageSpan) {
-        let len = self.refined_spans.len();
-        if len > 0 {
-            let last = &mut self.refined_spans[len - 1];
-            if last.is_mergeable(&covspan) {
-                debug!(
-                    "merging new refined span with last refined span, last={:?}, covspan={:?}",
-                    last, covspan
-                );
-                last.merge_from(covspan);
-                return;
-            }
+        if let Some(last) = self.refined_spans.last_mut()
+            && last.is_mergeable(&covspan)
+        {
+            // Instead of pushing the new span, merge it with the last refined span.
+            debug!(?last, ?covspan, "merging new refined span with last refined span");
+            last.merge_from(covspan);
+        } else {
+            self.refined_spans.push(covspan);
         }
-        self.refined_spans.push(covspan)
     }
 
-    fn check_invoked_macro_name_span(&mut self) {
-        if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
-            if !self
-                .prev_expn_span
-                .is_some_and(|prev_expn_span| self.curr().expn_span.ctxt() == prev_expn_span.ctxt())
-            {
-                let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
-                let after_macro_bang =
-                    merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
-                let mut macro_name_cov = self.curr().clone();
-                self.curr_mut().span =
-                    self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
-                macro_name_cov.span =
-                    macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
-                debug!(
-                    "  and curr starts a new macro expansion, so add a new span just for \
-                            the macro `{}!`, new span={:?}",
-                    visible_macro, macro_name_cov
-                );
-                self.push_refined_span(macro_name_cov);
-            }
+    /// If `curr` is part of a new macro expansion, carve out and push a separate
+    /// span that ends just after the macro name and its subsequent `!`.
+    fn maybe_push_macro_name_span(&mut self) {
+        let curr = self.curr();
+
+        let Some(visible_macro) = curr.visible_macro(self.body_span) else { return };
+        if let Some(prev) = &self.some_prev
+            && prev.expn_span.eq_ctxt(curr.expn_span)
+        {
+            return;
         }
+
+        let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo();
+        let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
+        let mut macro_name_cov = curr.clone();
+        self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang);
+        macro_name_cov.span =
+            macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
+        debug!(
+            "  and curr starts a new macro expansion, so add a new span just for \
+            the macro `{visible_macro}!`, new span={macro_name_cov:?}",
+        );
+        self.push_refined_span(macro_name_cov);
     }
 
     fn curr(&self) -> &CoverageSpan {
@@ -435,6 +434,12 @@ impl<'a> CoverageSpansGenerator<'a> {
             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
     }
 
+    /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
+    /// `curr` coverage span.
+    fn take_curr(&mut self) -> CoverageSpan {
+        self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
+    }
+
     fn prev(&self) -> &CoverageSpan {
         self.some_prev
             .as_ref()
@@ -460,84 +465,78 @@ impl<'a> CoverageSpansGenerator<'a> {
     ///     `pending_dups` could have as few as one span)
     /// In either case, no more spans will match the span of `pending_dups`, so
     /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
-    fn check_pending_dups(&mut self) {
-        if let Some(dup) = self.pending_dups.last()
-            && dup.span != self.prev().span
-        {
-            debug!(
-                "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
-                previous iteration, or prev started a new disjoint span"
-            );
-            if dup.span.hi() <= self.curr().span.lo() {
-                let pending_dups = self.pending_dups.split_off(0);
-                for dup in pending_dups.into_iter() {
-                    debug!("    ...adding at least one pending={:?}", dup);
-                    self.push_refined_span(dup);
-                }
-            } else {
-                self.pending_dups.clear();
+    fn maybe_flush_pending_dups(&mut self) {
+        let Some(last_dup) = self.pending_dups.last() else { return };
+        if last_dup.span == self.prev().span {
+            return;
+        }
+
+        debug!(
+            "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
+            previous iteration, or prev started a new disjoint span"
+        );
+        if last_dup.span.hi() <= self.curr().span.lo() {
+            // Temporarily steal `pending_dups` into a local, so that we can
+            // drain it while calling other self methods.
+            let mut pending_dups = std::mem::take(&mut self.pending_dups);
+            for dup in pending_dups.drain(..) {
+                debug!("    ...adding at least one pending={:?}", dup);
+                self.push_refined_span(dup);
             }
+            // The list of dups is now empty, but we can recycle its capacity.
+            assert!(pending_dups.is_empty() && self.pending_dups.is_empty());
+            self.pending_dups = pending_dups;
+        } else {
+            self.pending_dups.clear();
         }
     }
 
     /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
     fn next_coverage_span(&mut self) -> bool {
         if let Some(curr) = self.some_curr.take() {
-            self.prev_expn_span = Some(curr.expn_span);
             self.some_prev = Some(curr);
             self.prev_original_span = self.curr_original_span;
         }
         while let Some(curr) = self.sorted_spans_iter.next() {
             debug!("FOR curr={:?}", curr);
-            if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
+            if let Some(prev) = &self.some_prev && prev.span.lo() > curr.span.lo() {
+                // Skip curr because prev has already advanced beyond the end of curr.
+                // This can only happen if a prior iteration updated `prev` to skip past
+                // a region of code, such as skipping past a closure.
                 debug!(
                     "  prev.span starts after curr.span, so curr will be dropped (skipping past \
-                    closure?); prev={:?}",
-                    self.prev()
+                    closure?); prev={prev:?}",
                 );
             } else {
                 // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
                 // by `self.curr_mut().merge_from(prev)`.
                 self.curr_original_span = curr.span;
                 self.some_curr.replace(curr);
-                self.check_pending_dups();
+                self.maybe_flush_pending_dups();
                 return true;
             }
         }
         false
     }
 
-    /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
-    /// `curr` coverage span.
-    fn take_curr(&mut self) -> CoverageSpan {
-        self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
-    }
-
-    /// Returns true if the curr span should be skipped because prev has already advanced beyond the
-    /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
-    /// of code, such as skipping past a closure.
-    fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
-        self.prev().span.lo() > next_curr.span.lo()
-    }
-
-    /// Returns true if the curr span starts past the end of the prev span, which means they don't
-    /// overlap, so we now know the prev can be added to the refined coverage spans.
-    fn prev_ends_before_curr(&self) -> bool {
-        self.prev().span.hi() <= self.curr().span.lo()
-    }
-
     /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
     /// `prev`'s span. (The closure's coverage counters will be injected when processing the
     /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
     /// extends to the right of the closure, update `prev` to that portion of the span. For any
     /// `pending_dups`, repeat the same process.
     fn carve_out_span_for_closure(&mut self) {
-        let curr_span = self.curr().span;
-        let left_cutoff = curr_span.lo();
-        let right_cutoff = curr_span.hi();
-        let has_pre_closure_span = self.prev().span.lo() < right_cutoff;
-        let has_post_closure_span = self.prev().span.hi() > right_cutoff;
-        let mut pending_dups = self.pending_dups.split_off(0);
+        let prev = self.prev();
+        let curr = self.curr();
+
+        let left_cutoff = curr.span.lo();
+        let right_cutoff = curr.span.hi();
+        let has_pre_closure_span = prev.span.lo() < right_cutoff;
+        let has_post_closure_span = prev.span.hi() > right_cutoff;
+
+        // Temporarily steal `pending_dups` into a local, so that we can
+        // mutate and/or drain it while calling other self methods.
+        let mut pending_dups = std::mem::take(&mut self.pending_dups);
+
         if has_pre_closure_span {
             let mut pre_closure = self.prev().clone();
             pre_closure.span = pre_closure.span.with_hi(left_cutoff);
@@ -551,6 +550,7 @@ impl<'a> CoverageSpansGenerator<'a> {
             }
             self.push_refined_span(pre_closure);
         }
+
         if has_post_closure_span {
             // Mutate `prev.span()` to start after the closure (and discard curr).
             // (**NEVER** update `prev_original_span` because it affects the assumptions
@@ -561,12 +561,15 @@ impl<'a> CoverageSpansGenerator<'a> {
                 debug!("    ...and at least one overlapping dup={:?}", dup);
                 dup.span = dup.span.with_lo(right_cutoff);
             }
-            self.pending_dups.append(&mut pending_dups);
-            let closure_covspan = self.take_curr();
+            let closure_covspan = self.take_curr(); // Prevent this curr from becoming prev.
             self.push_refined_span(closure_covspan); // since self.prev() was already updated
         } else {
             pending_dups.clear();
         }
+
+        // Restore the modified post-closure spans, or the empty vector's capacity.
+        assert!(self.pending_dups.is_empty());
+        self.pending_dups = pending_dups;
     }
 
     /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
@@ -583,26 +586,28 @@ impl<'a> CoverageSpansGenerator<'a> {
     /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
     /// until their disposition is determined. In this latter case, the `prev` dup is moved into
     /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
-    fn hold_pending_dups_unless_dominated(&mut self) {
+    fn update_pending_dups(&mut self) {
+        let prev_bcb = self.prev().bcb;
+        let curr_bcb = self.curr().bcb;
+
         // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
         // impossible for `curr` to dominate any previous `CoverageSpan`.
-        debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev()));
+        debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb));
 
         let initial_pending_count = self.pending_dups.len();
         if initial_pending_count > 0 {
-            let mut pending_dups = self.pending_dups.split_off(0);
-            pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr()));
-            self.pending_dups.append(&mut pending_dups);
-            if self.pending_dups.len() < initial_pending_count {
+            self.pending_dups
+                .retain(|dup| !self.basic_coverage_blocks.dominates(dup.bcb, curr_bcb));
+
+            let n_discarded = initial_pending_count - self.pending_dups.len();
+            if n_discarded > 0 {
                 debug!(
-                    "  discarded {} of {} pending_dups that dominated curr",
-                    initial_pending_count - self.pending_dups.len(),
-                    initial_pending_count
+                    "  discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr",
                 );
             }
         }
 
-        if self.span_bcb_dominates(self.prev(), self.curr()) {
+        if self.basic_coverage_blocks.dominates(prev_bcb, curr_bcb) {
             debug!(
                 "  different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
                 self.prev()
@@ -667,8 +672,4 @@ impl<'a> CoverageSpansGenerator<'a> {
             self.pending_dups.clear();
         }
     }
-
-    fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool {
-        self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb)
-    }
 }
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 6d176af8098..7188c177feb 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -86,7 +86,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
         let is_feature_allowed = |feature_gate| {
             // All features require that the corresponding gate be enabled,
             // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
-            if !tcx.features().enabled(feature_gate) {
+            if !tcx.features().active(feature_gate) {
                 return false;
             }
 
@@ -134,7 +134,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
-            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
+            required_gates.iter().copied().filter(|&g| !features.active(g)).collect();
 
         match missing_gates.as_slice() {
             [] => {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 4590ab9e4f5..25e131d7477 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -231,7 +231,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             AsyncClosure(closure_span) => {
                 self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
             }
-            UnlabeledBlock(block_span) if is_break && block_span.ctxt() == break_span.ctxt() => {
+            UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
                 let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
                 self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
             }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 2a6f5994c49..bbba800e840 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1047,6 +1047,7 @@ impl Default for Options {
             target_triple: TargetTriple::from_triple(host_triple()),
             test: false,
             incremental: None,
+            untracked_state_hash: Default::default(),
             unstable_opts: Default::default(),
             prints: Vec::new(),
             cg: Default::default(),
@@ -2889,6 +2890,7 @@ pub fn build_session_options(
         target_triple,
         test,
         incremental,
+        untracked_state_hash: Default::default(),
         unstable_opts,
         prints,
         cg,
@@ -3167,17 +3169,17 @@ impl PpMode {
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
-    use super::Polonius;
     use super::{
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
         ErrorOutputType, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
-        LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes,
+        LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
         ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
         SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
-    use crate::utils::{NativeLib, NativeLibKind};
+    use crate::utils::NativeLib;
+    use rustc_data_structures::stable_hasher::Hash64;
     use rustc_errors::LanguageIdentifier;
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
@@ -3233,6 +3235,7 @@ pub(crate) mod dep_tracking {
         usize,
         NonZeroUsize,
         u64,
+        Hash64,
         String,
         PathBuf,
         lint::Level,
@@ -3247,14 +3250,12 @@ pub(crate) mod dep_tracking {
         MergeFunctions,
         PanicStrategy,
         RelroLevel,
-        Passes,
         OptLevel,
         LtoCli,
         DebugInfo,
         DebugInfoCompression,
         UnstableFeatures,
         NativeLib,
-        NativeLibKind,
         SanitizerSet,
         CFGuard,
         CFProtection,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index eb1aa6d6c88..f33139c5c4b 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,6 +4,7 @@ use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
 use crate::{lint, EarlyErrorHandler};
 use rustc_data_structures::profiling::TimePassesFormat;
+use rustc_data_structures::stable_hasher::Hash64;
 use rustc_errors::ColorConfig;
 use rustc_errors::{LanguageIdentifier, TerminalUrl};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
@@ -158,6 +159,10 @@ top_level_options!(
         /// directory to store intermediate results.
         incremental: Option<PathBuf> [UNTRACKED],
         assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED],
+        /// Set by the `Config::hash_untracked_state` callback for custom
+        /// drivers to invalidate the incremental cache
+        #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")]
+        untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH],
 
         unstable_opts: UnstableOptions [SUBSTRUCT],
         prints: Vec<PrintRequest> [UNTRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 671204c0d8e..abb0ab5630c 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -39,7 +39,7 @@ pub struct GatedSpans {
 
 impl GatedSpans {
     /// Feature gate the given `span` under the given `feature`
-    /// which is same `Symbol` used in `active.rs`.
+    /// which is same `Symbol` used in `unstable.rs`.
     pub fn gate(&self, feature: Symbol, span: Span) {
         self.spans.borrow_mut().entry(feature).or_default().push(span);
     }
@@ -78,7 +78,7 @@ impl SymbolGallery {
 }
 
 /// Construct a diagnostic for a language feature error due to the given `span`.
-/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
+/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbols`.
 #[track_caller]
 pub fn feature_err(
     sess: &ParseSess,
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index e3c84f06543..5ea805e5739 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -6,9 +6,11 @@
 use crate::rustc_internal;
 use crate::rustc_smir::Tables;
 use rustc_data_structures::fx;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_interface::{interface, Queries};
 use rustc_middle::mir::interpret::AllocId;
+use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
@@ -97,7 +99,7 @@ impl<'tcx> Tables<'tcx> {
         stable_mir::ty::Prov(self.create_alloc_id(aid))
     }
 
-    fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
+    pub(crate) fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
         self.def_ids.create_or_fetch(did)
     }
 
@@ -108,6 +110,17 @@ impl<'tcx> Tables<'tcx> {
     pub(crate) fn create_span(&mut self, span: Span) -> stable_mir::ty::Span {
         self.spans.create_or_fetch(span)
     }
+
+    pub(crate) fn instance_def(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+    ) -> stable_mir::mir::mono::InstanceDef {
+        self.instances.create_or_fetch(instance)
+    }
+
+    pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
+        stable_mir::mir::mono::StaticDef(self.create_def_id(did))
+    }
 }
 
 pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -118,10 +131,11 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
     stable_mir::run(
         Tables {
             tcx,
-            def_ids: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
-            alloc_ids: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
-            spans: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
+            def_ids: IndexMap::default(),
+            alloc_ids: IndexMap::default(),
+            spans: IndexMap::default(),
             types: vec![],
+            instances: IndexMap::default(),
         },
         f,
     );
@@ -192,6 +206,12 @@ pub struct IndexMap<K, V> {
     index_map: fx::FxIndexMap<K, V>,
 }
 
+impl<K, V> Default for IndexMap<K, V> {
+    fn default() -> Self {
+        Self { index_map: FxIndexMap::default() }
+    }
+}
+
 impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> {
     pub fn create_or_fetch(&mut self, key: K) -> V {
         let len = self.index_map.len();
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index f26d18ad38f..94dc15b4767 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -13,10 +13,12 @@ use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region};
 use rustc_hir as hir;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{alloc_range, AllocId};
-use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
+use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_target::abi::FieldIdx;
-use stable_mir::mir::{CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
+use stable_mir::mir::mono::InstanceDef;
+use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
 use stable_mir::ty::{
     FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
 };
@@ -119,29 +121,7 @@ impl<'tcx> Context for Tables<'tcx> {
 
     fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
         let def_id = self[item];
-        let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id));
-        stable_mir::mir::Body {
-            blocks: mir
-                .basic_blocks
-                .iter()
-                .map(|block| stable_mir::mir::BasicBlock {
-                    terminator: block.terminator().stable(self),
-                    statements: block
-                        .statements
-                        .iter()
-                        .map(|statement| statement.stable(self))
-                        .collect(),
-                })
-                .collect(),
-            locals: mir
-                .local_decls
-                .iter()
-                .map(|decl| stable_mir::mir::LocalDecl {
-                    ty: self.intern_ty(decl.ty),
-                    span: decl.source_info.span.stable(self),
-                })
-                .collect(),
-        }
+        self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self)
     }
 
     fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind {
@@ -190,6 +170,34 @@ impl<'tcx> Context for Tables<'tcx> {
                 .collect(),
         }
     }
+
+    fn instance_body(&mut self, _def: InstanceDef) -> Body {
+        todo!("Monomorphize the body")
+    }
+
+    fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
+        let instance = self.instances[def];
+        let ty = instance.ty(self.tcx, ParamEnv::empty());
+        self.intern_ty(ty)
+    }
+
+    fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId {
+        let def_id = self.instances[def].def_id();
+        self.create_def_id(def_id)
+    }
+
+    fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
+        let def_id = self[item.0];
+        Instance::mono(self.tcx, def_id).stable(self)
+    }
+
+    fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
+        let def_id = self[def_id];
+        let generics = self.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(self.tcx);
+        println!("req {result}: {def_id:?}");
+        result
+    }
 }
 
 #[derive(Clone)]
@@ -224,7 +232,8 @@ pub struct Tables<'tcx> {
     pub def_ids: IndexMap<DefId, stable_mir::DefId>,
     pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
     pub spans: IndexMap<rustc_span::Span, Span>,
-    pub types: Vec<MaybeStable<stable_mir::ty::TyKind, Ty<'tcx>>>,
+    pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
+    pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
 }
 
 impl<'tcx> Tables<'tcx> {
@@ -254,6 +263,35 @@ pub(crate) trait Stable<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T;
 }
 
+impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
+    type T = stable_mir::mir::Body;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::Body {
+            blocks: self
+                .basic_blocks
+                .iter()
+                .map(|block| stable_mir::mir::BasicBlock {
+                    terminator: block.terminator().stable(tables),
+                    statements: block
+                        .statements
+                        .iter()
+                        .map(|statement| statement.stable(tables))
+                        .collect(),
+                })
+                .collect(),
+            locals: self
+                .local_decls
+                .iter()
+                .map(|decl| stable_mir::mir::LocalDecl {
+                    ty: tables.intern_ty(decl.ty),
+                    span: decl.source_info.span.stable(tables),
+                })
+                .collect(),
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
     type T = stable_mir::mir::Statement;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
@@ -1637,3 +1675,38 @@ impl<'tcx> Stable<'tcx> for DefKind {
         opaque(self)
     }
 }
+
+impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
+    type T = stable_mir::mir::mono::Instance;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let def = tables.instance_def(*self);
+        let kind = match self.def {
+            ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item,
+            ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic,
+            ty::InstanceDef::Virtual(..) => stable_mir::mir::mono::InstanceKind::Virtual,
+            ty::InstanceDef::VTableShim(..)
+            | ty::InstanceDef::ReifyShim(..)
+            | ty::InstanceDef::FnPtrAddrShim(..)
+            | ty::InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ThreadLocalShim(..)
+            | ty::InstanceDef::DropGlue(..)
+            | ty::InstanceDef::CloneShim(..)
+            | ty::InstanceDef::FnPtrShim(..) => stable_mir::mir::mono::InstanceKind::Shim,
+        };
+        stable_mir::mir::mono::Instance { def, kind }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
+    type T = stable_mir::mir::mono::MonoItem;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::mir::mono::MonoItem as StableMonoItem;
+        match self {
+            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)),
+            MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)),
+            MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)),
+        }
+    }
+}
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index bfc9e125362..f7d17a267d6 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -212,6 +212,7 @@ impl Span {
 
     /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
     /// It's a cut-down version of `data_untracked`.
+    #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
     #[inline]
     pub fn ctxt(self) -> SyntaxContext {
         if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ea261923c65..be8c65862dc 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -303,6 +303,7 @@ symbols! {
         SliceIndex,
         SliceIter,
         Some,
+        SpanCtxt,
         String,
         StructuralEq,
         StructuralPartialEq,
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index a99cccd42c4..4c1f0c01a04 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -182,7 +182,7 @@ pub fn is_enabled(
 ) -> Result<(), AbiDisabled> {
     let s = is_stable(name);
     if let Err(AbiDisabled::Unstable { feature, .. }) = s {
-        if features.enabled(feature) || span.allows_unstable(feature) {
+        if features.active(feature) || span.allows_unstable(feature) {
             return Ok(());
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index cbfb06eac7b..9c9b78f4152 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -180,8 +180,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             flags.push((sym::cause, Some("MainFunctionType".to_string())));
         }
 
-        // Add all types without trimmed paths.
-        ty::print::with_no_trimmed_paths!({
+        // Add all types without trimmed paths or visible paths, ensuring they end up with
+        // their "canonical" def path.
+        ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
             let generics = self.tcx.generics_of(def_id);
             let self_ty = trait_ref.self_ty();
             // This is also included through the generics list as `Self`,
@@ -296,7 +297,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             {
                 flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
             }
-        });
+        }));
 
         if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
             command.evaluate(self.tcx, trait_ref, &flags)
@@ -578,7 +579,9 @@ impl<'tcx> OnUnimplementedDirective {
                     Some(tcx.features()),
                     &mut |cfg| {
                         let value = cfg.value.map(|v| {
-                            OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
+                            // `with_no_visible_paths` is also used when generating the options,
+                            // so we need to match it here.
+                            ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map))
                         });
 
                         options.contains(&(cfg.name, value))
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index ea8ceda87be..4329460b1b7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -313,6 +313,18 @@ pub trait TypeErrCtxtExt<'tcx> {
         predicate: ty::Predicate<'tcx>,
         call_hir_id: HirId,
     );
+
+    fn look_for_iterator_item_mistakes(
+        &self,
+        assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
+        typeck_results: &TypeckResults<'tcx>,
+        type_diffs: &[TypeError<'tcx>],
+        param_env: ty::ParamEnv<'tcx>,
+        path_segment: &hir::PathSegment<'_>,
+        args: &[hir::Expr<'_>],
+        err: &mut Diagnostic,
+    );
+
     fn point_at_chain(
         &self,
         expr: &hir::Expr<'_>,
@@ -321,6 +333,7 @@ pub trait TypeErrCtxtExt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         err: &mut Diagnostic,
     );
+
     fn probe_assoc_types_at_expr(
         &self,
         type_diffs: &[TypeError<'tcx>],
@@ -364,7 +377,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -
 /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but
 /// it can also be an `impl Trait` param that needs to be decomposed to a type
 /// param for cleaner code.
-fn suggest_restriction<'tcx>(
+pub fn suggest_restriction<'tcx>(
     tcx: TyCtxt<'tcx>,
     item_id: LocalDefId,
     hir_generics: &hir::Generics<'tcx>,
@@ -3612,6 +3625,109 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         }
     }
 
+    fn look_for_iterator_item_mistakes(
+        &self,
+        assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
+        typeck_results: &TypeckResults<'tcx>,
+        type_diffs: &[TypeError<'tcx>],
+        param_env: ty::ParamEnv<'tcx>,
+        path_segment: &hir::PathSegment<'_>,
+        args: &[hir::Expr<'_>],
+        err: &mut Diagnostic,
+    ) {
+        let tcx = self.tcx;
+        // Special case for iterator chains, we look at potential failures of `Iterator::Item`
+        // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`.
+        for entry in assocs_in_this_method {
+            let Some((_span, (def_id, ty))) = entry else {
+                continue;
+            };
+            for diff in type_diffs {
+                let Sorts(expected_found) = diff else {
+                    continue;
+                };
+                if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
+                    && path_segment.ident.name == sym::map
+                    && self.can_eq(param_env, expected_found.found, *ty)
+                    && let [arg] = args
+                    && let hir::ExprKind::Closure(closure) = arg.kind
+                {
+                    let body = tcx.hir().body(closure.body);
+                    if let hir::ExprKind::Block(block, None) = body.value.kind
+                        && let None = block.expr
+                        && let [.., stmt] = block.stmts
+                        && let hir::StmtKind::Semi(expr) = stmt.kind
+                        // FIXME: actually check the expected vs found types, but right now
+                        // the expected is a projection that we need to resolve.
+                        // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
+                        && expected_found.found.is_unit()
+                    {
+                        err.span_suggestion_verbose(
+                            expr.span.shrink_to_hi().with_hi(stmt.span.hi()),
+                            "consider removing this semicolon",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    let expr = if let hir::ExprKind::Block(block, None) = body.value.kind
+                        && let Some(expr) = block.expr
+                    {
+                        expr
+                    } else {
+                        body.value
+                    };
+                    if let hir::ExprKind::MethodCall(path_segment, rcvr, [], span) = expr.kind
+                        && path_segment.ident.name == sym::clone
+                        && let Some(expr_ty) = typeck_results.expr_ty_opt(expr)
+                        && let Some(rcvr_ty) = typeck_results.expr_ty_opt(rcvr)
+                        && self.can_eq(param_env, expr_ty, rcvr_ty)
+                        && let ty::Ref(_, ty, _) = expr_ty.kind()
+                    {
+                        err.span_label(
+                            span,
+                            format!(
+                                "this method call is cloning the reference `{expr_ty}`, not \
+                                 `{ty}` which doesn't implement `Clone`",
+                            ),
+                        );
+                        let ty::Param(..) = ty.kind() else {
+                            continue;
+                        };
+                        let hir = tcx.hir();
+                        let node = hir.get_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
+
+                        let pred = ty::Binder::dummy(ty::TraitPredicate {
+                            trait_ref: ty::TraitRef::from_lang_item(
+                                tcx,
+                                LangItem::Clone,
+                                span,
+                                [*ty],
+                            ),
+                            polarity: ty::ImplPolarity::Positive,
+                        });
+                        let Some(generics) = node.generics() else {
+                            continue;
+                        };
+                        let Some(body_id) = node.body_id() else {
+                            continue;
+                        };
+                        suggest_restriction(
+                            tcx,
+                            hir.body_owner_def_id(body_id),
+                            &generics,
+                            &format!("type parameter `{ty}`"),
+                            err,
+                            node.fn_sig(),
+                            None,
+                            pred,
+                            None,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     fn point_at_chain(
         &self,
         expr: &hir::Expr<'_>,
@@ -3631,13 +3747,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let mut prev_ty = self.resolve_vars_if_possible(
             typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
         );
-        while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
+        while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
             // Point at every method call in the chain with the resulting type.
             // vec![1, 2, 3].iter().map(mapper).sum<i32>()
             //               ^^^^^^ ^^^^^^^^^^^
             expr = rcvr_expr;
             let assocs_in_this_method =
                 self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
+            self.look_for_iterator_item_mistakes(
+                &assocs_in_this_method,
+                typeck_results,
+                &type_diffs,
+                param_env,
+                path_segment,
+                args,
+                err,
+            );
             assocs.push(assocs_in_this_method);
             prev_ty = self.resolve_vars_if_possible(
                 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 73c2ff3c536..175cc2b116b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1233,7 +1233,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 
             let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
 
-            let result = if projected_term.has_projections() {
+            let mut result = if projected_term.has_projections() {
                 let mut normalizer = AssocTypeNormalizer::new(
                     selcx,
                     param_env,
@@ -1243,14 +1243,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 );
                 let normalized_ty = normalizer.fold(projected_term);
 
-                let mut deduped = SsoHashSet::with_capacity(projected_obligations.len());
-                projected_obligations.retain(|obligation| deduped.insert(obligation.clone()));
-
                 Normalized { value: normalized_ty, obligations: projected_obligations }
             } else {
                 Normalized { value: projected_term, obligations: projected_obligations }
             };
 
+            let mut deduped = SsoHashSet::with_capacity(result.obligations.len());
+            result.obligations.retain(|obligation| deduped.insert(obligation.clone()));
+
             if use_cache {
                 infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             }
diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs
new file mode 100644
index 00000000000..12ac8f1ca65
--- /dev/null
+++ b/compiler/stable_mir/src/error.rs
@@ -0,0 +1,69 @@
+//! When things go wrong, we need some error handling.
+//! There are a few different types of errors in StableMIR:
+//!
+//! - [CompilerError]: This represents errors that can be raised when invoking the compiler.
+//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
+
+use std::fmt::{Debug, Display, Formatter};
+use std::{error, fmt};
+
+/// An error type used to represent an error that has already been reported by the compiler.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum CompilerError<T> {
+    /// Internal compiler error (I.e.: Compiler crashed).
+    ICE,
+    /// Compilation failed.
+    CompilationFailed,
+    /// Compilation was interrupted.
+    Interrupted(T),
+    /// Compilation skipped. This happens when users invoke rustc to retrieve information such as
+    /// --version.
+    Skipped,
+}
+
+/// A generic error to represent an API request that cannot be fulfilled.
+#[derive(Debug)]
+pub struct Error(String);
+
+impl Error {
+    pub(crate) fn new(msg: String) -> Self {
+        Self(msg)
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        Display::fmt(&self.0, f)
+    }
+}
+
+impl<T> Display for CompilerError<T>
+where
+    T: Display,
+{
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            CompilerError::ICE => write!(f, "Internal Compiler Error"),
+            CompilerError::CompilationFailed => write!(f, "Compilation Failed"),
+            CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"),
+            CompilerError::Skipped => write!(f, "Compilation Skipped"),
+        }
+    }
+}
+
+impl<T> Debug for CompilerError<T>
+where
+    T: Debug,
+{
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            CompilerError::ICE => write!(f, "Internal Compiler Error"),
+            CompilerError::CompilationFailed => write!(f, "Compilation Failed"),
+            CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"),
+            CompilerError::Skipped => write!(f, "Compilation Skipped"),
+        }
+    }
+}
+
+impl error::Error for Error {}
+impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index a3b05f2435e..59af3f64ad3 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -17,6 +17,8 @@
 //! The goal is to eventually be published on
 //! [crates.io](https://crates.io).
 
+use crate::mir::mono::InstanceDef;
+use crate::mir::Body;
 use std::cell::Cell;
 use std::fmt;
 use std::fmt::Debug;
@@ -29,11 +31,15 @@ use self::ty::{
 #[macro_use]
 extern crate scoped_tls;
 
+pub mod error;
 pub mod fold;
 pub mod mir;
 pub mod ty;
 pub mod visitor;
 
+pub use error::*;
+use mir::mono::Instance;
+
 /// Use String for now but we should replace it.
 pub type Symbol = String;
 
@@ -85,20 +91,6 @@ pub type TraitDecls = Vec<TraitDef>;
 /// A list of impl trait decls.
 pub type ImplTraitDecls = Vec<ImplDef>;
 
-/// An error type used to represent an error that has already been reported by the compiler.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum CompilerError<T> {
-    /// Internal compiler error (I.e.: Compiler crashed).
-    ICE,
-    /// Compilation failed.
-    CompilationFailed,
-    /// Compilation was interrupted.
-    Interrupted(T),
-    /// Compilation skipped. This happens when users invoke rustc to retrieve information such as
-    /// --version.
-    Skipped,
-}
-
 /// Holds information about a crate.
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct Crate {
@@ -113,7 +105,7 @@ pub type Filename = Opaque;
 /// Holds information about an item in the crate.
 /// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to
 /// use this item.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct CrateItem(pub DefId);
 
 impl CrateItem {
@@ -132,6 +124,10 @@ impl CrateItem {
     pub fn kind(&self) -> DefKind {
         with(|cx| cx.def_kind(self.0))
     }
+
+    pub fn requires_monomorphization(&self) -> bool {
+        with(|cx| cx.requires_monomorphization(self.0))
+    }
 }
 
 /// Return the function where execution starts if the current
@@ -220,6 +216,23 @@ pub trait Context {
 
     /// Create a new `Ty` from scratch without information from rustc.
     fn mk_ty(&mut self, kind: TyKind) -> Ty;
+
+    /// Get the body of an Instance.
+    /// FIXME: Monomorphize the body.
+    fn instance_body(&mut self, instance: InstanceDef) -> Body;
+
+    /// Get the instance type with generic substitutions applied and lifetimes erased.
+    fn instance_ty(&mut self, instance: InstanceDef) -> Ty;
+
+    /// Get the instance.
+    fn instance_def_id(&mut self, instance: InstanceDef) -> DefId;
+
+    /// Convert a non-generic crate item into an instance.
+    /// This function will panic if the item is generic.
+    fn mono_instance(&mut self, item: CrateItem) -> Instance;
+
+    /// Item requires monomorphization.
+    fn requires_monomorphization(&self, def_id: DefId) -> bool;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs
index a9dbc3463f8..3138bb1ec83 100644
--- a/compiler/stable_mir/src/mir.rs
+++ b/compiler/stable_mir/src/mir.rs
@@ -1,3 +1,4 @@
 mod body;
+pub mod mono;
 
 pub use body::*;
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
new file mode 100644
index 00000000000..d8e8ccb0454
--- /dev/null
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -0,0 +1,89 @@
+use crate::mir::Body;
+use crate::ty::{IndexedVal, Ty};
+use crate::{with, CrateItem, DefId, Error, Opaque};
+use std::fmt::Debug;
+
+#[derive(Clone, Debug)]
+pub enum MonoItem {
+    Fn(Instance),
+    Static(StaticDef),
+    GlobalAsm(Opaque),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct Instance {
+    /// The type of instance.
+    pub kind: InstanceKind,
+    /// An ID used to get the instance definition from the compiler.
+    /// Do not use this field directly.
+    pub def: InstanceDef,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum InstanceKind {
+    /// A user defined item.
+    Item,
+    /// A compiler intrinsic function.
+    Intrinsic,
+    /// A virtual function definition stored in a VTable.
+    Virtual,
+    /// A compiler generated shim.
+    Shim,
+}
+
+impl Instance {
+    /// Get the body of an Instance. The body will be eagerly monomorphized.
+    pub fn body(&self) -> Body {
+        with(|context| context.instance_body(self.def))
+    }
+
+    /// Get the instance type with generic substitutions applied and lifetimes erased.
+    pub fn ty(&self) -> Ty {
+        with(|context| context.instance_ty(self.def))
+    }
+}
+
+/// Try to convert a crate item into an instance.
+/// The item cannot be generic in order to be converted into an instance.
+impl TryFrom<CrateItem> for Instance {
+    type Error = crate::Error;
+
+    fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
+        with(|context| {
+            if !context.requires_monomorphization(item.0) {
+                Ok(context.mono_instance(item))
+            } else {
+                Err(Error::new("Item requires monomorphization".to_string()))
+            }
+        })
+    }
+}
+
+/// Try to convert an instance into a crate item.
+/// Only user defined instances can be converted.
+impl TryFrom<Instance> for CrateItem {
+    type Error = crate::Error;
+
+    fn try_from(value: Instance) -> Result<Self, Self::Error> {
+        if value.kind == InstanceKind::Item {
+            Ok(CrateItem(with(|context| context.instance_def_id(value.def))))
+        } else {
+            Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct InstanceDef(usize);
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct StaticDef(pub DefId);
+
+impl IndexedVal for InstanceDef {
+    fn to_val(index: usize) -> Self {
+        InstanceDef(index)
+    }
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 35015238e6e..3b12c1bee0b 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1956,6 +1956,7 @@ impl<T, A: Allocator> Vec<T, A> {
         } else {
             unsafe {
                 self.len -= 1;
+                core::intrinsics::assume(self.len < self.capacity());
                 Some(ptr::read(self.as_ptr().add(self.len())))
             }
         }
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 9407c1609c2..89125b7955e 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -573,7 +573,7 @@ pub trait Into<T>: Sized {
 #[rustc_diagnostic_item = "From"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(on(
-    all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")),
+    all(_Self = "&str", T = "alloc::string::String"),
     note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
 ))]
 pub trait From<T>: Sized {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index ac1fc26a1ef..c7ace58afa8 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -27,13 +27,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"),
+        _Self = "core::ops::range::RangeTo<Idx>",
         label = "if you meant to iterate until a value, add a starting value",
         note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
               bounded `Range`: `0..end`"
     ),
     on(
-        any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"),
+        _Self = "core::ops::range::RangeToInclusive<Idx>",
         label = "if you meant to iterate until a value (including it), add a starting value",
         note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
               to have a bounded `RangeInclusive`: `0..=end`"
@@ -44,7 +44,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     ),
     on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
     on(
-        any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"),
+        _Self = "alloc::vec::Vec<T, A>",
         label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
     ),
     on(
@@ -52,7 +52,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
-        any(_Self = "alloc::string::String", _Self = "std::string::String"),
+        _Self = "alloc::string::String",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 5ed82e26a0a..f1594501d40 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -573,59 +573,59 @@ impl<T: ?Sized> Copy for &T {}
 #[lang = "sync"]
 #[rustc_on_unimplemented(
     on(
-        any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"),
+        _Self = "core::cell::once::OnceCell<T>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
     ),
     on(
-        any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"),
+        _Self = "core::cell::Cell<u8>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"),
+        _Self = "core::cell::Cell<u16>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"),
+        _Self = "core::cell::Cell<u32>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"),
+        _Self = "core::cell::Cell<u64>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"),
+        _Self = "core::cell::Cell<usize>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"),
+        _Self = "core::cell::Cell<i8>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"),
+        _Self = "core::cell::Cell<i16>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"),
+        _Self = "core::cell::Cell<i32>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"),
+        _Self = "core::cell::Cell<i64>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"),
+        _Self = "core::cell::Cell<isize>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"),
+        _Self = "core::cell::Cell<bool>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
     ),
     on(
-        any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"),
+        _Self = "core::cell::Cell<T>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
     ),
     on(
-        any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"),
+        _Self = "core::cell::RefCell<T>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
     ),
     message = "`{Self}` cannot be shared between threads safely",
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index f4649be54d5..6ceee463729 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -153,7 +153,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
     on(
-        any(_Self = "alloc::string::String", _Self = "std::string::String"),
+        _Self = "alloc::string::String",
         note = "you can use `.chars().nth()` or `.bytes().nth()`
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 17625daccbc..3f8c8efd416 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -226,14 +226,8 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::result::Result<T, E>",
-                _Self = "std::result::Result<T, E>",
-            ),
-            any(
-                R = "core::option::Option<core::convert::Infallible>",
-                R = "std::option::Option<std::convert::Infallible>",
-            )
+            _Self = "core::result::Result<T, E>",
+            R = "core::option::Option<core::convert::Infallible>",
         ),
         message = "the `?` operator can only be used on `Result`s, not `Option`s, \
             in {ItemContext} that returns `Result`",
@@ -243,10 +237,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::result::Result<T, E>",
-                _Self = "std::result::Result<T, E>",
-            )
+            _Self = "core::result::Result<T, E>",
         ),
         // There's a special error message in the trait selection code for
         // `From` in `?`, so this is not shown for result-in-result errors,
@@ -259,14 +250,8 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::option::Option<T>",
-                _Self = "std::option::Option<T>",
-            ),
-            any(
-                R = "core::result::Result<T, E>",
-                R = "std::result::Result<T, E>",
-            )
+            _Self = "core::option::Option<T>",
+            R = "core::result::Result<T, E>",
         ),
         message = "the `?` operator can only be used on `Option`s, not `Result`s, \
             in {ItemContext} that returns `Option`",
@@ -276,10 +261,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::option::Option<T>",
-                _Self = "std::option::Option<T>",
-            )
+            _Self = "core::option::Option<T>",
         ),
         // `Option`-in-`Option` always works, as there's only one possible
         // residual, so this can also be phrased strongly.
@@ -291,14 +273,8 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::ops::ControlFlow<B, C>",
-                _Self = "std::ops::ControlFlow<B, C>",
-            ),
-            any(
-                R = "core::ops::ControlFlow<B, C>",
-                R = "std::ops::ControlFlow<B, C>",
-            )
+            _Self = "core::ops::control_flow::ControlFlow<B, C>",
+            R = "core::ops::control_flow::ControlFlow<B, C>",
         ),
         message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
             can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
@@ -309,10 +285,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            any(
-                _Self = "core::ops::ControlFlow<B, C>",
-                _Self = "std::ops::ControlFlow<B, C>",
-            )
+            _Self = "core::ops::control_flow::ControlFlow<B, C>",
             // `R` is not a `ControlFlow`, as that case was matched previously
         ),
         message = "the `?` operator can only be used on `ControlFlow`s \
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index d313e8e012f..1da3a87e117 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -152,10 +152,7 @@ mod private_slice_index {
 #[rustc_on_unimplemented(
     on(T = "str", label = "string indices are ranges of `usize`",),
     on(
-        all(
-            any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"),
-            _Self = "{integer}"
-        ),
+        all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"),
         note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
                 for more information, see chapter 8 in The Book: \
                 <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index de41bd1a116..073488817c4 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -79,6 +79,40 @@
 //!
 //! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm
 //!
+//! # Atomic accesses to read-only memory
+//!
+//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting
+//! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only
+//! operation) can still cause a page fault if the underlying memory page is mapped read-only. Since
+//! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault
+//! on read-only memory.
+//!
+//! For the purpose of this section, "read-only memory" is defined as memory that is read-only in
+//! the underlying target, i.e., the pages are mapped with a read-only flag and any attempt to write
+//! will cause a page fault. In particular, an `&u128` reference that points to memory that is
+//! read-write mapped is *not* considered to point to "read-only memory". In Rust, almost all memory
+//! is read-write; the only exceptions are memory created by `const` items or `static` items without
+//! interior mutability, and memory that was specifically marked as read-only by the operating
+//! system via platform-specific APIs.
+//!
+//! As an exception from the general rule stated above, "sufficiently small" atomic loads with
+//! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not
+//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies
+//! depending on the target:
+//!
+//! | `target_arch` | Size limit |
+//! |---------------|---------|
+//! | `x86`, `arm`, `mips`, `mips32r6, `powerpc`, `riscv32`, `sparc`, `hexagon` | 4 bytes |
+//! | `x86_64`, `aarch64`, `loongarch64`, `mips64`, `mips64r6`, `powerpc64`, `riscv64`, `sparc64`, `s390x` | 8 bytes |
+//!
+//! Atomics loads that are larger than this limit as well as atomic loads with ordering other
+//! than `Relaxed`, as well as *all* atomic loads on targets not listed in the table, might still be
+//! read-only under certain conditions, but that is not a stable guarantee and should not be relied
+//! upon.
+//!
+//! If you need to do an acquire load on read-only memory, you can do a relaxed load followed by an
+//! acquire fence instead.
+//!
 //! # Examples
 //!
 //! A simple spinlock:
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 81106d6c62c..24f2bdcf421 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -97,14 +97,14 @@ impl BorrowedFd<'_> {
         // We want to atomically duplicate this file descriptor and set the
         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
         // is a POSIX flag that was added to Linux in 2.6.24.
-        #[cfg(not(target_os = "espidf"))]
+        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
         let cmd = libc::F_DUPFD_CLOEXEC;
 
         // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
         // will never be supported, as this is a bare metal framework with
         // no capabilities for multi-process execution. While F_DUPFD is also
         // not supported yet, it might be (currently it returns ENOSYS).
-        #[cfg(target_os = "espidf")]
+        #[cfg(any(target_os = "espidf", target_os = "vita"))]
         let cmd = libc::F_DUPFD;
 
         // Avoid using file descriptors below 3 as they are used for stdio
@@ -119,7 +119,7 @@ impl BorrowedFd<'_> {
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
         Err(crate::io::const_io_error!(
             crate::io::ErrorKind::Unsupported,
-            "operation not supported on WASI yet",
+            "operation not supported on this platform",
         ))
     }
 }
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index f450d708dae..7e2016c410e 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -103,7 +103,7 @@ impl Socket {
         }
     }
 
-    #[cfg(not(any(target_os = "vxworks", target_os = "vita")))]
+    #[cfg(not(target_os = "vxworks"))]
     pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
         unsafe {
             let mut fds = [0, 0];
@@ -135,7 +135,7 @@ impl Socket {
         }
     }
 
-    #[cfg(any(target_os = "vxworks", target_os = "vita"))]
+    #[cfg(target_os = "vxworks")]
     pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
         unimplemented!()
     }
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 006a992eb3c..e236421b7f5 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -9,27 +9,27 @@ default-run = "bootstrap"
 build-metrics = ["sysinfo"]
 
 [lib]
-path = "lib.rs"
+path = "src/lib.rs"
 doctest = false
 
 [[bin]]
 name = "bootstrap"
-path = "bin/main.rs"
+path = "src/bin/main.rs"
 test = false
 
 [[bin]]
 name = "rustc"
-path = "bin/rustc.rs"
+path = "src/bin/rustc.rs"
 test = false
 
 [[bin]]
 name = "rustdoc"
-path = "bin/rustdoc.rs"
+path = "src/bin/rustdoc.rs"
 test = false
 
 [[bin]]
 name = "sccache-plus-cl"
-path = "bin/sccache-plus-cl.rs"
+path = "src/bin/sccache-plus-cl.rs"
 test = false
 
 [dependencies]
diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs
deleted file mode 100644
index b0a97b540ec..00000000000
--- a/src/bootstrap/job.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-//! Job management on Windows for bootstrapping
-//!
-//! Most of the time when you're running a build system (e.g., make) you expect
-//! Ctrl-C or abnormal termination to actually terminate the entire tree of
-//! process in play, not just the one at the top. This currently works "by
-//! default" on Unix platforms because Ctrl-C actually sends a signal to the
-//! *process group* rather than the parent process, so everything will get torn
-//! down. On Windows, however, this does not happen and Ctrl-C just kills the
-//! parent process.
-//!
-//! To achieve the same semantics on Windows we use Job Objects to ensure that
-//! all processes die at the same time. Job objects have a mode of operation
-//! where when all handles to the object are closed it causes all child
-//! processes associated with the object to be terminated immediately.
-//! Conveniently whenever a process in the job object spawns a new process the
-//! child will be associated with the job object as well. This means if we add
-//! ourselves to the job object we create then everything will get torn down!
-//!
-//! Unfortunately most of the time the build system is actually called from a
-//! python wrapper (which manages things like building the build system) so this
-//! all doesn't quite cut it so far. To go the last mile we duplicate the job
-//! object handle into our parent process (a python process probably) and then
-//! close our own handle. This means that the only handle to the job object
-//! resides in the parent python process, so when python dies the whole build
-//! system dies (as one would probably expect!).
-//!
-//! Note that this module has a #[cfg(windows)] above it as none of this logic
-//! is required on Unix.
-
-use crate::Build;
-use std::env;
-use std::ffi::c_void;
-use std::io;
-use std::mem;
-
-use windows::{
-    core::PCWSTR,
-    Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
-    Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE},
-    Win32::System::JobObjects::{
-        AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
-        SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
-        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
-    },
-    Win32::System::Threading::{
-        GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
-    },
-};
-
-pub unsafe fn setup(build: &mut Build) {
-    // Enable the Windows Error Reporting dialog which msys disables,
-    // so we can JIT debug rustc
-    let mode = SetErrorMode(THREAD_ERROR_MODE::default());
-    let mode = THREAD_ERROR_MODE(mode);
-    SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
-
-    // Create a new job object for us to use
-    let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
-
-    // Indicate that when all handles to the job object are gone that all
-    // process in the object should be killed. Note that this includes our
-    // entire process tree by default because we've added ourselves and our
-    // children will reside in the job by default.
-    let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
-    info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
-    if build.config.low_priority {
-        info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
-        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
-    }
-    let r = SetInformationJobObject(
-        job,
-        JobObjectExtendedLimitInformation,
-        &info as *const _ as *const c_void,
-        mem::size_of_val(&info) as u32,
-    )
-    .ok();
-    assert!(r.is_ok(), "{}", io::Error::last_os_error());
-
-    // Assign our process to this job object. Note that if this fails, one very
-    // likely reason is that we are ourselves already in a job object! This can
-    // happen on the build bots that we've got for Windows, or if just anyone
-    // else is instrumenting the build. In this case we just bail out
-    // immediately and assume that they take care of it.
-    //
-    // Also note that nested jobs (why this might fail) are supported in recent
-    // versions of Windows, but the version of Windows that our bots are running
-    // at least don't support nested job objects.
-    let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
-    if r.is_err() {
-        CloseHandle(job);
-        return;
-    }
-
-    // If we've got a parent process (e.g., the python script that called us)
-    // then move ownership of this job object up to them. That way if the python
-    // script is killed (e.g., via ctrl-c) then we'll all be torn down.
-    //
-    // If we don't have a parent (e.g., this was run directly) then we
-    // intentionally leak the job object handle. When our process exits
-    // (normally or abnormally) it will close the handle implicitly, causing all
-    // processes in the job to be cleaned up.
-    let pid = match env::var("BOOTSTRAP_PARENT_ID") {
-        Ok(s) => s,
-        Err(..) => return,
-    };
-
-    let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
-        Some(parent) => parent,
-        _ => {
-            // If we get a null parent pointer here, it is possible that either
-            // we have an invalid pid or the parent process has been closed.
-            // Since the first case rarely happens
-            // (only when wrongly setting the environmental variable),
-            // it might be better to improve the experience of the second case
-            // when users have interrupted the parent process and we haven't finish
-            // duplicating the handle yet. We just need close the job object if that occurs.
-            CloseHandle(job);
-            return;
-        }
-    };
-
-    let mut parent_handle = HANDLE::default();
-    let r = DuplicateHandle(
-        GetCurrentProcess(),
-        job,
-        parent,
-        &mut parent_handle,
-        0,
-        false,
-        DUPLICATE_SAME_ACCESS,
-    )
-    .ok();
-
-    // If this failed, well at least we tried! An example of DuplicateHandle
-    // failing in the past has been when the wrong python2 package spawned this
-    // build system (e.g., the `python2` package in MSYS instead of
-    // `mingw-w64-x86_64-python2`). Not sure why it failed, but the "failure
-    // mode" here is that we only clean everything up when the build system
-    // dies, not when the python parent does, so not too bad.
-    if r.is_err() {
-        CloseHandle(job);
-    }
-}
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/src/bin/main.rs
index d87fb6a9cef..d87fb6a9cef 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 6cc5162120a..241ae16e595 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -15,19 +15,24 @@
 //! switching compilers for the bootstrap and for build scripts will probably
 //! never get replaced.
 
-include!("../dylib_util.rs");
-include!("./_helper.rs");
-
 use std::env;
 use std::path::PathBuf;
-use std::process::{exit, Child, Command};
+use std::process::{Child, Command};
 use std::time::Instant;
 
+use dylib_util::{dylib_path, dylib_path_var};
+
+#[path = "../utils/bin_helpers.rs"]
+mod bin_helpers;
+
+#[path = "../utils/dylib.rs"]
+mod dylib_util;
+
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str());
 
-    let verbose = parse_rustc_verbose();
+    let verbose = bin_helpers::parse_rustc_verbose();
 
     // Detect whether or not we're a build script depending on whether --target
     // is passed (a bit janky...)
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs
index 6561c1c1933..f5f80ba2a0b 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/src/bin/rustdoc.rs
@@ -5,17 +5,21 @@
 use std::env;
 use std::ffi::OsString;
 use std::path::PathBuf;
-use std::process::{exit, Command};
+use std::process::Command;
 
-include!("../dylib_util.rs");
+use dylib_util::{dylib_path, dylib_path_var};
 
-include!("./_helper.rs");
+#[path = "../utils/bin_helpers.rs"]
+mod bin_helpers;
+
+#[path = "../utils/dylib.rs"]
+mod dylib_util;
 
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
 
-    let stage = parse_rustc_stage();
-    let verbose = parse_rustc_verbose();
+    let stage = bin_helpers::parse_rustc_stage();
+    let verbose = bin_helpers::parse_rustc_verbose();
 
     let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
     let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set");
diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs
index 554c2dd4d81..554c2dd4d81 100644
--- a/src/bootstrap/bin/sccache-plus-cl.rs
+++ b/src/bootstrap/src/bin/sccache-plus-cl.rs
diff --git a/src/bootstrap/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index b417abc00f5..121925b56a0 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -1,10 +1,12 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
-use crate::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
-use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
-use crate::config::TargetSelection;
-use crate::tool::{prepare_tool_cargo, SourceType};
+use crate::core::build_steps::compile::{
+    add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
+};
+use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType};
+use crate::core::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step};
+use crate::core::config::TargetSelection;
+use crate::utils::cache::Interned;
 use crate::INTERNER;
 use crate::{Compiler, Mode, Subcommand};
 use std::path::{Path, PathBuf};
@@ -16,7 +18,7 @@ pub struct Std {
     ///
     /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
     ///
-    /// [`compile::Rustc`]: crate::compile::Rustc
+    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
     crates: Interned<Vec<String>>,
 }
 
@@ -193,7 +195,7 @@ pub struct Rustc {
     ///
     /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
     ///
-    /// [`compile::Rustc`]: crate::compile::Rustc
+    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
     crates: Interned<Vec<String>>,
 }
 
@@ -237,8 +239,8 @@ impl Step for Rustc {
             // the sysroot for the compiler to find. Otherwise, we're going to
             // fail when building crates that need to generate code (e.g., build
             // scripts and their dependencies).
-            builder.ensure(crate::compile::Std::new(compiler, compiler.host));
-            builder.ensure(crate::compile::Std::new(compiler, target));
+            builder.ensure(crate::core::build_steps::compile::Std::new(compiler, compiler.host));
+            builder.ensure(crate::core::build_steps::compile::Std::new(compiler, target));
         } else {
             builder.ensure(Std::new(target));
         }
@@ -387,7 +389,7 @@ impl Step for RustAnalyzer {
             &["rust-analyzer/in-rust-tree".to_owned()],
         );
 
-        cargo.allow_features(crate::tool::RustAnalyzer::ALLOW_FEATURES);
+        cargo.allow_features(crate::core::build_steps::tool::RustAnalyzer::ALLOW_FEATURES);
 
         // For ./x.py clippy, don't check those targets because
         // linting tests and benchmarks can produce very noisy results
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 7389816b44c..679770ce0ec 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -9,9 +9,9 @@ use std::fs;
 use std::io::{self, ErrorKind};
 use std::path::Path;
 
-use crate::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
-use crate::util::t;
+use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
+use crate::utils::cache::Interned;
+use crate::utils::helpers::t;
 use crate::{Build, Compiler, Mode, Subcommand};
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 623fa5fa111..441931e415c 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -19,16 +19,17 @@ use std::str;
 
 use serde_derive::Deserialize;
 
-use crate::builder::crate_description;
-use crate::builder::Cargo;
-use crate::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
-use crate::cache::{Interned, INTERNER};
-use crate::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
-use crate::dist;
-use crate::llvm;
-use crate::tool::SourceType;
-use crate::util::get_clang_cl_resource_dir;
-use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date};
+use crate::core::build_steps::dist;
+use crate::core::build_steps::llvm;
+use crate::core::build_steps::tool::SourceType;
+use crate::core::builder::crate_description;
+use crate::core::builder::Cargo;
+use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
+use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::helpers::{
+    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date,
+};
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
 use filetime::FileTime;
@@ -510,7 +511,7 @@ impl Step for StdLink {
         let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() {
             // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too
             let lib = builder.sysroot_libdir_relative(self.compiler);
-            let sysroot = builder.ensure(crate::compile::Sysroot {
+            let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {
                 compiler: self.compiler,
                 force_recompile: self.force_recompile,
             });
@@ -1016,7 +1017,8 @@ pub fn rustc_cargo_env(
     // detected that LLVM is already built and good to go which helps prevent
     // busting caches (e.g. like #71152).
     if builder.config.llvm_enabled() {
-        let building_is_expensive = crate::llvm::prebuilt_llvm_config(builder, target).is_err();
+        let building_is_expensive =
+            crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).is_err();
         // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
         let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage;
         let should_skip_build = building_is_expensive && can_skip_build;
@@ -1684,7 +1686,7 @@ impl Step for Assemble {
             builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe));
             let self_contained_lld_dir = libdir_bin.join("gcc-ld");
             t!(fs::create_dir(&self_contained_lld_dir));
-            let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper {
+            let lld_wrapper_exe = builder.ensure(crate::core::build_steps::tool::LldWrapper {
                 compiler: build_compiler,
                 target: target_compiler.host,
             });
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 05556d2f679..47f41ab288d 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -19,16 +19,16 @@ use std::process::Command;
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
 
-use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::{Interned, INTERNER};
-use crate::channel;
-use crate::compile;
-use crate::config::TargetSelection;
-use crate::doc::DocumentationFormat;
-use crate::llvm;
-use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
-use crate::tool::{self, Tool};
-use crate::util::{exe, is_dylib, output, t, timeit};
+use crate::core::build_steps::compile;
+use crate::core::build_steps::doc::DocumentationFormat;
+use crate::core::build_steps::llvm;
+use crate::core::build_steps::tool::{self, Tool};
+use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
+use crate::core::config::TargetSelection;
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::channel;
+use crate::utils::helpers::{exe, is_dylib, output, t, timeit};
+use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
@@ -104,7 +104,7 @@ impl Step for JsonDocs {
     /// Builds the `rust-docs-json` installer component.
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let host = self.host;
-        builder.ensure(crate::doc::Std::new(
+        builder.ensure(crate::core::build_steps::doc::Std::new(
             builder.top_stage,
             host,
             builder,
@@ -488,7 +488,7 @@ impl Step for Rustc {
             let man_src = builder.src.join("src/doc/man");
             let man_dst = image.join("share/man/man1");
 
-            // don't use our `bootstrap::util::{copy, cp_r}`, because those try
+            // don't use our `bootstrap::{copy, cp_r}`, because those try
             // to hardlink, and we don't want to edit the source templates
             for file_entry in builder.read_dir(&man_src) {
                 let page_src = file_entry.path();
@@ -1002,11 +1002,15 @@ impl Step for PlainSourceTarball {
             channel::write_commit_info_file(&plain_dst_src, info);
         }
 
-        // If we're building from git sources, we need to vendor a complete distribution.
-        if builder.rust_info().is_managed_git_subrepository() {
-            // Ensure we have the submodules checked out.
-            builder.update_submodule(Path::new("src/tools/cargo"));
-            builder.update_submodule(Path::new("src/tools/rust-analyzer"));
+        // If we're building from git or tarball sources, we need to vendor
+        // a complete distribution.
+        if builder.rust_info().is_managed_git_subrepository()
+            || builder.rust_info().is_from_tarball()
+        {
+            if builder.rust_info().is_managed_git_subrepository() {
+                // Ensure we have the submodules checked out.
+                builder.update_submodule(Path::new("src/tools/cargo"));
+            }
 
             // Vendor all Cargo dependencies
             let mut cmd = Command::new(&builder.initial_cargo);
@@ -2056,7 +2060,7 @@ impl Step for LlvmTools {
             }
         }
 
-        builder.ensure(crate::llvm::Llvm { target });
+        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
 
         let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
         tarball.set_overlay(OverlayKind::LLVM);
@@ -2115,10 +2119,10 @@ impl Step for RustDev {
         let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
         tarball.set_overlay(OverlayKind::LLVM);
 
-        builder.ensure(crate::llvm::Llvm { target });
+        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
 
         // We want to package `lld` to use it with `download-ci-llvm`.
-        builder.ensure(crate::llvm::Lld { target });
+        builder.ensure(crate::core::build_steps::llvm::Lld { target });
 
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this list, you likely want to change
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 505f06ed12d..628a4ece8e9 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -10,13 +10,13 @@
 use std::fs;
 use std::path::{Path, PathBuf};
 
-use crate::builder::crate_description;
-use crate::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::{Interned, INTERNER};
-use crate::compile;
-use crate::config::{Config, TargetSelection};
-use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
-use crate::util::{dir_is_empty, symlink_dir, t, up_to_date};
+use crate::core::build_steps::compile;
+use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool};
+use crate::core::builder::crate_description;
+use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
+use crate::core::config::{Config, TargetSelection};
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::helpers::{dir_is_empty, symlink_dir, t, up_to_date};
 use crate::Mode;
 
 macro_rules! submodule_helper {
diff --git a/src/bootstrap/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 11f2762f766..0e260e69c85 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -1,7 +1,7 @@
 //! Runs rustfmt on the repository.
 
-use crate::builder::Builder;
-use crate::util::{output, program_out_of_date, t};
+use crate::core::builder::Builder;
+use crate::utils::helpers::{output, program_out_of_date, t};
 use build_helper::ci::CiEnv;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
diff --git a/src/bootstrap/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 885b3a78236..391995b7c3b 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -8,15 +8,13 @@ use std::fs;
 use std::path::{Component, Path, PathBuf};
 use std::process::Command;
 
-use crate::util::t;
-
-use crate::dist;
-use crate::tarball::GeneratedTarball;
+use crate::core::build_steps::dist;
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::core::config::{Config, TargetSelection};
+use crate::utils::helpers::t;
+use crate::utils::tarball::GeneratedTarball;
 use crate::{Compiler, Kind};
 
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::config::{Config, TargetSelection};
-
 #[cfg(target_os = "illumos")]
 const SHELL: &str = "bash";
 #[cfg(not(target_os = "illumos"))]
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 4556831589b..24351118a5a 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -16,11 +16,10 @@ use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::channel;
-use crate::config::{Config, TargetSelection};
-use crate::util::get_clang_cl_resource_dir;
-use crate::util::{self, exe, output, t, up_to_date};
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::core::config::{Config, TargetSelection};
+use crate::utils::channel;
+use crate::utils::helpers::{self, exe, get_clang_cl_resource_dir, output, t, up_to_date};
 use crate::{CLang, GitRepo, Kind};
 
 use build_helper::ci::CiEnv;
@@ -281,7 +280,7 @@ impl Step for Llvm {
 
         let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target);
         t!(stamp.remove());
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         t!(fs::create_dir_all(&out_dir));
 
         // https://llvm.org/docs/CMake.html
@@ -410,7 +409,7 @@ impl Step for Llvm {
 
         let mut enabled_llvm_projects = Vec::new();
 
-        if util::forcing_clang_based_tests() {
+        if helpers::forcing_clang_based_tests() {
             enabled_llvm_projects.push("clang");
             enabled_llvm_projects.push("compiler-rt");
         }
@@ -528,8 +527,12 @@ impl Step for Llvm {
 
             // If the shared library exists in LLVM's `/build/lib/` or `/lib/` folders, strip its
             // debuginfo.
-            crate::compile::strip_debug(builder, target, &out_dir.join("lib").join(&lib_name));
-            crate::compile::strip_debug(
+            crate::core::build_steps::compile::strip_debug(
+                builder,
+                target,
+                &out_dir.join("lib").join(&lib_name),
+            );
+            crate::core::build_steps::compile::strip_debug(
                 builder,
                 target,
                 &out_dir.join("build").join("lib").join(&lib_name),
@@ -846,7 +849,7 @@ impl Step for Lld {
         }
 
         let _guard = builder.msg_unstaged(Kind::Build, "LLD", target);
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         t!(fs::create_dir_all(&out_dir));
 
         let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld"));
@@ -877,7 +880,7 @@ impl Step for Lld {
         // `LD_LIBRARY_PATH` overrides)
         //
         if builder.config.rpath_enabled(target)
-            && util::use_host_linker(target)
+            && helpers::use_host_linker(target)
             && builder.config.llvm_link_shared()
             && target.contains("linux")
         {
@@ -970,7 +973,7 @@ impl Step for Sanitizers {
 
         let _guard = builder.msg_unstaged(Kind::Build, "sanitizers", self.target);
         t!(stamp.remove());
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
 
         let mut cfg = cmake::Config::new(&compiler_rt_dir);
         cfg.profile("Release");
diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs
new file mode 100644
index 00000000000..50d83789be8
--- /dev/null
+++ b/src/bootstrap/src/core/build_steps/mod.rs
@@ -0,0 +1,15 @@
+pub(crate) mod check;
+pub(crate) mod clean;
+pub(crate) mod compile;
+pub(crate) mod dist;
+pub(crate) mod doc;
+pub(crate) mod format;
+pub(crate) mod install;
+pub(crate) mod llvm;
+pub(crate) mod run;
+pub(crate) mod setup;
+pub(crate) mod suggest;
+pub(crate) mod synthetic_targets;
+pub(crate) mod test;
+pub(crate) mod tool;
+pub(crate) mod toolstate;
diff --git a/src/bootstrap/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index f253f5225a1..d1d6b7e869e 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -1,13 +1,13 @@
 use std::path::PathBuf;
 use std::process::Command;
 
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::config::TargetSelection;
-use crate::dist::distdir;
-use crate::flags::get_completion;
-use crate::test;
-use crate::tool::{self, SourceType, Tool};
-use crate::util::output;
+use crate::core::build_steps::dist::distdir;
+use crate::core::build_steps::test;
+use crate::core::build_steps::tool::{self, SourceType, Tool};
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::core::config::flags::get_completion;
+use crate::core::config::TargetSelection;
+use crate::utils::helpers::output;
 use crate::Mode;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 14ec33147fb..ebe093674fc 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -1,4 +1,4 @@
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::Config;
 use crate::{t, CONFIG_CHANGE_HISTORY};
 use sha2::Digest;
@@ -12,6 +12,7 @@ use std::str::FromStr;
 use std::{fmt, fs, io};
 
 #[cfg(test)]
+#[path = "../../tests/setup.rs"]
 mod tests;
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
@@ -35,7 +36,7 @@ static SETTINGS_HASHES: &[&str] = &[
     "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
     "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
 ];
-static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
+static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json");
 
 impl Profile {
     fn include_path(&self, src_path: &Path) -> PathBuf {
diff --git a/src/bootstrap/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index f225104bda9..82fb10cebe0 100644
--- a/src/bootstrap/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -1,12 +1,11 @@
 #![cfg_attr(feature = "build-metrics", allow(unused))]
 
-use std::str::FromStr;
-
-use std::path::PathBuf;
-
 use clap::Parser;
+use std::path::PathBuf;
+use std::str::FromStr;
 
-use crate::{builder::Builder, tool::Tool};
+use crate::core::build_steps::tool::Tool;
+use crate::core::builder::Builder;
 
 /// Suggests a list of possible `x.py` commands to run based on modified files in branch.
 pub fn suggest(builder: &Builder<'_>, run: bool) {
@@ -62,7 +61,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
         for sug in suggestions {
             let mut build: crate::Build = builder.build.clone();
             build.config.paths = sug.2;
-            build.config.cmd = crate::flags::Flags::parse_from(["x.py", sug.0]).cmd;
+            build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd;
             if let Some(stage) = sug.1 {
                 build.config.stage = stage;
             }
diff --git a/src/bootstrap/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
index 7eeac9025c9..d2c65b740da 100644
--- a/src/bootstrap/synthetic_targets.rs
+++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
@@ -7,8 +7,8 @@
 //! one of the target specs already defined in this module, or create new ones by adding a new step
 //! that calls create_synthetic_target.
 
-use crate::builder::{Builder, ShouldRun, Step};
-use crate::config::TargetSelection;
+use crate::core::builder::{Builder, ShouldRun, Step};
+use crate::core::config::TargetSelection;
 use crate::Compiler;
 use std::process::{Command, Stdio};
 
@@ -76,7 +76,7 @@ fn create_synthetic_target(
 
     std::fs::write(&path, &serde_json::to_vec_pretty(&spec).unwrap()).unwrap();
     let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap());
-    crate::cc_detect::find_target(builder, target);
+    crate::utils::cc_detect::find_target(builder, target);
 
     target
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index fb8ec0355c2..831a86940fb 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -13,21 +13,24 @@ use std::process::{Command, Stdio};
 
 use clap_complete::shells;
 
-use crate::builder::crate_description;
-use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
-use crate::cache::INTERNER;
-use crate::compile;
-use crate::config::TargetSelection;
-use crate::dist;
-use crate::doc::DocumentationFormat;
-use crate::flags::Subcommand;
-use crate::llvm;
-use crate::render_tests::add_flags_and_try_run_tests;
-use crate::synthetic_targets::MirOptPanicAbortSyntheticTarget;
-use crate::tool::{self, SourceType, Tool};
-use crate::toolstate::ToolState;
-use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date};
+use crate::core::build_steps::compile;
+use crate::core::build_steps::dist;
+use crate::core::build_steps::doc::DocumentationFormat;
+use crate::core::build_steps::llvm;
+use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
+use crate::core::build_steps::tool::{self, SourceType, Tool};
+use crate::core::build_steps::toolstate::ToolState;
+use crate::core::builder::crate_description;
+use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
+use crate::core::config::flags::get_completion;
+use crate::core::config::flags::Subcommand;
+use crate::core::config::TargetSelection;
+use crate::utils;
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::helpers::{
+    self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date,
+};
+use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
 const ADB_TEST_DIR: &str = "/data/local/tmp/work";
@@ -167,7 +170,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         // Run the linkchecker.
         let _guard =
             builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc")));
     }
 
@@ -219,7 +222,11 @@ impl Step for HtmlCheck {
         }
         // Ensure that a few different kinds of documentation are available.
         builder.default_doc(&[]);
-        builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder));
+        builder.ensure(crate::core::build_steps::doc::Rustc::new(
+            builder.top_stage,
+            self.target,
+            builder,
+        ));
 
         builder.run_delaying_failure(
             builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)),
@@ -260,7 +267,7 @@ impl Step for Cargotest {
         let out_dir = builder.out.join("ct");
         t!(fs::create_dir_all(&out_dir));
 
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         let mut cmd = builder.tool_cmd(Tool::CargoTest);
         builder.run_delaying_failure(
             cmd.arg(&cargo)
@@ -328,7 +335,7 @@ impl Step for Cargo {
             builder,
         );
 
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         add_flags_and_try_run_tests(builder, &mut cargo);
     }
 }
@@ -642,7 +649,7 @@ impl Step for Miri {
         // does not understand the flags added by `add_flags_and_try_run_test`.
         let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
         {
-            let _time = util::timeit(&builder);
+            let _time = helpers::timeit(&builder);
             builder.run(&mut cargo);
         }
 
@@ -658,7 +665,7 @@ impl Step for Miri {
 
             let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
             {
-                let _time = util::timeit(&builder);
+                let _time = helpers::timeit(&builder);
                 builder.run(&mut cargo);
             }
         }
@@ -698,7 +705,7 @@ impl Step for Miri {
 
         let mut cargo = Command::from(cargo);
         {
-            let _time = util::timeit(&builder);
+            let _time = helpers::timeit(&builder);
             builder.run(&mut cargo);
         }
     }
@@ -859,7 +866,7 @@ impl Step for RustdocTheme {
         if builder.is_fuse_ld_lld(self.compiler.host) {
             cmd.env(
                 "RUSTDOC_LLD_NO_THREADS",
-                util::lld_flag_no_threads(self.compiler.host.contains("windows")),
+                helpers::lld_flag_no_threads(self.compiler.host.contains("windows")),
             );
         }
         builder.run_delaying_failure(&mut cmd);
@@ -900,7 +907,8 @@ impl Step for RustdocJSStd {
             .arg("--test-folder")
             .arg(builder.src.join("tests/rustdoc-js-std"));
         for path in &builder.paths {
-            if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder) {
+            if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)
+            {
                 if !p.ends_with(".js") {
                     eprintln!("A non-js file was given: `{}`", path.display());
                     panic!("Cannot run rustdoc-js-std tests");
@@ -908,7 +916,7 @@ impl Step for RustdocJSStd {
                 command.arg("--test-file").arg(path);
             }
         }
-        builder.ensure(crate::doc::Std::new(
+        builder.ensure(crate::core::build_steps::doc::Std::new(
             builder.top_stage,
             self.target,
             builder,
@@ -1035,7 +1043,7 @@ impl Step for RustdocGUI {
             .env("RUSTC", builder.rustc(self.compiler));
 
         for path in &builder.paths {
-            if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
+            if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
                 if !p.ends_with(".goml") {
                     eprintln!("A non-goml file was given: `{}`", path.display());
                     panic!("Cannot run rustdoc-gui tests");
@@ -1058,7 +1066,7 @@ impl Step for RustdocGUI {
             cmd.arg("--npm").arg(npm);
         }
 
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         let _guard = builder.msg_sysroot_tool(
             Kind::Test,
             self.compiler.stage,
@@ -1066,7 +1074,7 @@ impl Step for RustdocGUI {
             self.compiler.host,
             self.target,
         );
-        crate::render_tests::try_run_tests(builder, &mut cmd, true);
+        try_run_tests(builder, &mut cmd, true);
     }
 }
 
@@ -1126,7 +1134,7 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
                 );
                 crate::exit!(1);
             }
-            crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
+            crate::core::build_steps::format::format(&builder, !builder.config.cmd.bless(), &[]);
         }
 
         builder.info("tidy check");
@@ -1138,10 +1146,10 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
         let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"]
             .map(|filename| builder.src.join("src/etc/completions").join(filename));
         if builder.config.cmd.bless() {
-            builder.ensure(crate::run::GenerateCompletions);
-        } else if crate::flags::get_completion(shells::Bash, &bash).is_some()
-            || crate::flags::get_completion(shells::Fish, &fish).is_some()
-            || crate::flags::get_completion(shells::PowerShell, &powershell).is_some()
+            builder.ensure(crate::core::build_steps::run::GenerateCompletions);
+        } else if get_completion(shells::Bash, &bash).is_some()
+            || get_completion(shells::Fish, &fish).is_some()
+            || get_completion(shells::PowerShell, &powershell).is_some()
             || crate::flags::get_completion(shells::Zsh, &zsh).is_some()
         {
             eprintln!(
@@ -1403,10 +1411,10 @@ impl Step for MirOpt {
                     // have been detected by bootstrap if the target we're testing wasn't in the
                     // --target flags.
                     if !builder.cc.borrow().contains_key(&target_32bit) {
-                        crate::cc_detect::find_target(builder, target_32bit);
+                        utils::cc_detect::find_target(builder, target_32bit);
                     }
                     if !builder.cc.borrow().contains_key(&target_64bit) {
-                        crate::cc_detect::find_target(builder, target_64bit);
+                        utils::cc_detect::find_target(builder, target_64bit);
                     }
 
                     vec![target_32bit, target_64bit]
@@ -1679,7 +1687,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             }
         }
 
-        if util::forcing_clang_based_tests() {
+        if helpers::forcing_clang_based_tests() {
             let clang_exe = builder.llvm_out(target).join("bin").join("clang");
             cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
         }
@@ -1698,7 +1706,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         // Get test-args by striping suite path
         let mut test_args: Vec<&str> = paths
             .iter()
-            .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
+            .filter_map(|p| helpers::is_valid_test_suite_arg(p, suite_path, builder))
             .collect();
 
         test_args.append(&mut builder.config.test_args());
@@ -1887,7 +1895,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             compiler.host,
             target,
         );
-        crate::render_tests::try_run_tests(builder, &mut cmd, false);
+        try_run_tests(builder, &mut cmd, false);
 
         if let Some(compare_mode) = compare_mode {
             cmd.arg("--compare-mode").arg(compare_mode);
@@ -1909,8 +1917,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the
                 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                 suite, mode, compare_mode, &compiler.host, target
             ));
-            let _time = util::timeit(&builder);
-            crate::render_tests::try_run_tests(builder, &mut cmd, false);
+            let _time = helpers::timeit(&builder);
+            try_run_tests(builder, &mut cmd, false);
         }
     }
 }
@@ -1981,7 +1989,7 @@ impl BookTest {
             compiler.host,
             compiler.host,
         );
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) {
             ToolState::TestPass
         } else {
@@ -2003,7 +2011,7 @@ impl BookTest {
         // Do a breadth-first traversal of the `src/doc` directory and just run
         // tests for all files that end in `*.md`
         let mut stack = vec![builder.src.join(self.path)];
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         let mut files = Vec::new();
         while let Some(p) = stack.pop() {
             if p.is_dir() {
@@ -2114,7 +2122,7 @@ impl Step for ErrorIndex {
 
         let guard =
             builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
         builder.run_quiet(&mut tool);
         drop(guard);
         // The tests themselves need to link to std, so make sure it is
@@ -2236,7 +2244,7 @@ fn run_cargo_test<'a>(
 ) -> bool {
     let mut cargo =
         prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
-    let _time = util::timeit(&builder);
+    let _time = helpers::timeit(&builder);
     let _group = description.into().and_then(|what| {
         builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target)
     });
@@ -2631,7 +2639,7 @@ impl Step for RemoteCopyLibs {
         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
             let f = t!(f);
             let name = f.file_name().into_string().unwrap();
-            if util::is_dylib(&name) {
+            if helpers::is_dylib(&name) {
                 builder.run(Command::new(&tool).arg("push").arg(f.path()));
             }
         }
@@ -2676,7 +2684,9 @@ impl Step for Distcheck {
                 .current_dir(&dir),
         );
         builder.run(
-            Command::new(util::make(&builder.config.build.triple)).arg("check").current_dir(&dir),
+            Command::new(helpers::make(&builder.config.build.triple))
+                .arg("check")
+                .current_dir(&dir),
         );
 
         // Now make sure that rust-src has all of libstd's dependencies
@@ -2833,7 +2843,7 @@ impl Step for LintDocs {
     /// Tests that the lint examples in the rustc book generate the correct
     /// lints and have the expected format.
     fn run(self, builder: &Builder<'_>) {
-        builder.ensure(crate::doc::RustcBook {
+        builder.ensure(crate::core::build_steps::doc::RustcBook {
             compiler: self.compiler,
             target: self.target,
             validate: true,
@@ -3052,7 +3062,7 @@ impl Step for CodegenCranelift {
             &compiler.host,
             target
         ));
-        let _time = util::timeit(&builder);
+        let _time = helpers::timeit(&builder);
 
         // FIXME handle vendoring for source tarballs before removing the --skip-test below
         let download_dir = builder.out.join("cg_clif_download");
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index f094dd9d7c9..5702fa62d7c 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -3,12 +3,12 @@ use std::fs;
 use std::path::PathBuf;
 use std::process::Command;
 
-use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
-use crate::channel::GitInfo;
-use crate::compile;
-use crate::config::TargetSelection;
-use crate::toolstate::ToolState;
-use crate::util::{add_dylib_path, exe, t};
+use crate::core::build_steps::compile;
+use crate::core::build_steps::toolstate::ToolState;
+use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
+use crate::core::config::TargetSelection;
+use crate::utils::channel::GitInfo;
+use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::Compiler;
 use crate::Mode;
 use crate::{gha, Kind};
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs
index 308023537d5..f892577ccbf 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/src/core/build_steps/toolstate.rs
@@ -1,5 +1,5 @@
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::util::t;
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::utils::helpers::t;
 use serde_derive::{Deserialize, Serialize};
 use std::collections::HashMap;
 use std::env;
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/src/core/builder.rs
index c714b09ec3c..039a87e760d 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -12,20 +12,15 @@ use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::time::{Duration, Instant};
 
-use crate::cache::{Cache, Interned, INTERNER};
-use crate::config::{DryRun, SplitDebuginfo, TargetSelection};
-use crate::doc;
-use crate::flags::{Color, Subcommand};
-use crate::install;
-use crate::llvm;
-use crate::run;
-use crate::setup;
-use crate::test;
-use crate::tool::{self, SourceType};
-use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
+use crate::core::build_steps::llvm;
+use crate::core::build_steps::tool::{self, SourceType};
+use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, setup, test};
+use crate::core::config::flags::{Color, Subcommand};
+use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection};
+use crate::utils::cache::{Cache, Interned, INTERNER};
+use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
+use crate::Crate;
 use crate::EXTRA_CHECK_CFGS;
-use crate::{check, compile, Crate};
-use crate::{clean, dist};
 use crate::{Build, CLang, DocTests, GitRepo, Mode};
 
 pub use crate::Compiler;
@@ -36,6 +31,10 @@ pub use crate::Compiler;
 use clap::ValueEnum;
 use once_cell::sync::{Lazy, OnceCell};
 
+#[cfg(test)]
+#[path = "../tests/builder.rs"]
+mod tests;
+
 pub struct Builder<'a> {
     pub build: &'a Build,
     pub top_stage: u32,
@@ -723,7 +722,7 @@ impl<'a> Builder<'a> {
                 check::Bootstrap
             ),
             Kind::Test => describe!(
-                crate::toolstate::ToolStateCheck,
+                crate::core::build_steps::toolstate::ToolStateCheck,
                 test::ExpandYamlAnchors,
                 test::Tidy,
                 test::Ui,
@@ -1297,8 +1296,8 @@ impl<'a> Builder<'a> {
 
         // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
         // needs to not accidentally link to libLLVM in stage0/lib.
-        cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
-        if let Some(e) = env::var_os(util::dylib_path_var()) {
+        cargo.env("REAL_LIBRARY_PATH_VAR", &helpers::dylib_path_var());
+        if let Some(e) = env::var_os(helpers::dylib_path_var()) {
             cargo.env("REAL_LIBRARY_PATH", e);
         }
 
@@ -1311,7 +1310,7 @@ impl<'a> Builder<'a> {
             // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
             // of work comparatively, and we'd likely need to rebuild it anyway,
             // so that's okay.
-            if crate::llvm::prebuilt_llvm_config(self, target).is_err() {
+            if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target).is_err() {
                 cargo.env("RUST_CHECK", "1");
             }
         }
@@ -1643,7 +1642,7 @@ impl<'a> Builder<'a> {
         // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
         // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
         // to change a flag in a binary?
-        if self.config.rpath_enabled(target) && util::use_host_linker(target) {
+        if self.config.rpath_enabled(target) && helpers::use_host_linker(target) {
             let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap();
             let rpath = if target.contains("apple") {
                 // Note that we need to take one extra step on macOS to also pass
@@ -2197,9 +2196,6 @@ impl<'a> Builder<'a> {
     }
 }
 
-#[cfg(test)]
-mod tests;
-
 /// Represents flag values in `String` form with whitespace delimiter to pass it to the compiler later.
 ///
 /// `-Z crate-attr` flags will be applied recursively on the target code using the `rustc_parse::parser::Parser`.
diff --git a/src/bootstrap/config.rs b/src/bootstrap/src/core/config/config.rs
index 759d874a089..7ca1bbad968 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -4,6 +4,7 @@
 //! how the build runs.
 
 #[cfg(test)]
+#[path = "../../tests/config.rs"]
 mod tests;
 
 use std::cell::{Cell, RefCell};
@@ -17,19 +18,20 @@ use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str::FromStr;
 
-use crate::cache::{Interned, INTERNER};
-use crate::cc_detect::{ndk_compiler, Language};
-use crate::channel::{self, GitInfo};
-use crate::compile::CODEGEN_BACKEND_PREFIX;
-pub use crate::flags::Subcommand;
-use crate::flags::{Color, Flags, Warnings};
-use crate::util::{exe, output, t};
+use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
+use crate::core::config::flags::{Color, Flags, Warnings};
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::cc_detect::{ndk_compiler, Language};
+use crate::utils::channel::{self, GitInfo};
+use crate::utils::helpers::{exe, output, t};
 use build_helper::exit;
 use once_cell::sync::OnceCell;
 use semver::Version;
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
 
+pub use crate::core::config::flags::Subcommand;
+
 macro_rules! check_ci_llvm {
     ($name:expr) => {
         assert!(
@@ -547,7 +549,7 @@ impl Target {
 /// `Config` structure.
 #[derive(Deserialize, Default)]
 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct TomlConfig {
+pub(crate) struct TomlConfig {
     changelog_seen: Option<usize>, // FIXME: Deprecated field. Remove it at 2024.
     change_id: Option<usize>,
     build: Option<Build>,
@@ -1269,7 +1271,7 @@ impl Config {
         // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
         if !config.out.is_absolute() {
             // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
-            config.out = crate::util::absolute(&config.out);
+            config.out = crate::utils::helpers::absolute(&config.out);
         }
 
         config.initial_rustc = if let Some(rustc) = build.rustc {
@@ -1527,11 +1529,12 @@ impl Config {
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert_eq!(s, "if-available", "unknown option `{s}` for download-ci-llvm");
-                    crate::llvm::is_ci_llvm_available(&config, asserts)
+                    crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts)
                 }
                 Some(StringOrBool::Bool(b)) => b,
                 None => {
-                    config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts)
+                    config.channel == "dev"
+                        && crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts)
                 }
             };
 
@@ -1573,8 +1576,8 @@ impl Config {
                 config.llvm_link_shared.set(Some(true));
             }
         } else {
-            config.llvm_from_ci =
-                config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, false);
+            config.llvm_from_ci = config.channel == "dev"
+                && crate::core::build_steps::llvm::is_ci_llvm_available(&config, false);
         }
 
         if let Some(t) = toml.target {
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 5a6a5f37fc6..dea55303544 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -7,9 +7,9 @@ use std::path::{Path, PathBuf};
 
 use clap::{CommandFactory, Parser, ValueEnum};
 
-use crate::builder::{Builder, Kind};
-use crate::config::{target_selection_list, Config, TargetSelectionList};
-use crate::setup::Profile;
+use crate::core::build_steps::setup::Profile;
+use crate::core::builder::{Builder, Kind};
+use crate::core::config::{target_selection_list, Config, TargetSelectionList};
 use crate::{Build, DocTests};
 
 #[derive(Copy, Clone, Default, Debug, ValueEnum)]
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
new file mode 100644
index 00000000000..9c6861826d6
--- /dev/null
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -0,0 +1,4 @@
+pub(crate) mod config;
+pub(crate) mod flags;
+
+pub use config::*;
diff --git a/src/bootstrap/download.rs b/src/bootstrap/src/core/download.rs
index 2a0dec75599..5541a2f3e35 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -11,13 +11,10 @@ use build_helper::ci::CiEnv;
 use once_cell::sync::OnceCell;
 use xz2::bufread::XzDecoder;
 
-use crate::{
-    config::RustfmtMetadata,
-    llvm::detect_llvm_sha,
-    t,
-    util::{check_run, exe, program_out_of_date},
-    Config,
-};
+use crate::core::build_steps::llvm::detect_llvm_sha;
+use crate::core::config::RustfmtMetadata;
+use crate::utils::helpers::{check_run, exe, program_out_of_date};
+use crate::{t, Config};
 
 static SHOULD_FIX_BINS_AND_DYLIBS: OnceCell<bool> = OnceCell::new();
 
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/src/core/metadata.rs
index 3b20ceac875..5802082326a 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/src/core/metadata.rs
@@ -3,8 +3,8 @@ use std::process::Command;
 
 use serde_derive::Deserialize;
 
-use crate::cache::INTERNER;
-use crate::util::output;
+use crate::utils::cache::INTERNER;
+use crate::utils::helpers::output;
 use crate::{t, Build, Crate};
 
 /// For more information, see the output of
diff --git a/src/bootstrap/src/core/mod.rs b/src/bootstrap/src/core/mod.rs
new file mode 100644
index 00000000000..9e18d6704d4
--- /dev/null
+++ b/src/bootstrap/src/core/mod.rs
@@ -0,0 +1,6 @@
+pub(crate) mod build_steps;
+pub(crate) mod builder;
+pub(crate) mod config;
+pub(crate) mod download;
+pub(crate) mod metadata;
+pub(crate) mod sanity;
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 0febdf250d3..eec3be66a12 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -15,9 +15,9 @@ use std::fs;
 use std::path::PathBuf;
 use std::process::Command;
 
-use crate::cache::INTERNER;
-use crate::config::Target;
-use crate::util::output;
+use crate::core::config::Target;
+use crate::utils::cache::INTERNER;
+use crate::utils::helpers::output;
 use crate::Build;
 
 pub struct Finder {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/src/lib.rs
index a9a81cb25f6..97c743074af 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -28,70 +28,28 @@ use std::str;
 
 use build_helper::ci::{gha, CiEnv};
 use build_helper::exit;
-use channel::GitInfo;
-use config::{DryRun, Target};
 use filetime::FileTime;
 use once_cell::sync::OnceCell;
-
-use crate::builder::Kind;
-use crate::config::{LlvmLibunwind, TargetSelection};
-use crate::util::{
-    dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
+use termcolor::{ColorChoice, StandardStream, WriteColor};
+use utils::channel::GitInfo;
+
+use crate::core::builder;
+use crate::core::builder::Kind;
+use crate::core::config::flags;
+use crate::core::config::{DryRun, Target};
+use crate::core::config::{LlvmLibunwind, TargetSelection};
+use crate::utils::cache::{Interned, INTERNER};
+use crate::utils::helpers::{
+    self, dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir,
+    try_run_suppressed,
 };
 
-mod builder;
-mod cache;
-mod cc_detect;
-mod channel;
-mod check;
-mod clean;
-mod compile;
-mod config;
-mod dist;
-mod doc;
-mod download;
-mod flags;
-mod format;
-mod install;
-mod llvm;
-mod metadata;
-mod render_tests;
-mod run;
-mod sanity;
-mod setup;
-mod suggest;
-mod synthetic_targets;
-mod tarball;
-mod test;
-mod tool;
-mod toolstate;
-pub mod util;
-
-#[cfg(feature = "build-metrics")]
-mod metrics;
-
-#[cfg(windows)]
-mod job;
-
-#[cfg(all(unix, not(target_os = "haiku")))]
-mod job {
-    pub unsafe fn setup(build: &mut crate::Build) {
-        if build.config.low_priority {
-            libc::setpriority(libc::PRIO_PGRP as _, 0, 10);
-        }
-    }
-}
-
-#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))]
-mod job {
-    pub unsafe fn setup(_build: &mut crate::Build) {}
-}
+mod core;
+mod utils;
 
-pub use crate::builder::PathSet;
-use crate::cache::{Interned, INTERNER};
-pub use crate::config::Config;
-pub use crate::flags::Subcommand;
-use termcolor::{ColorChoice, StandardStream, WriteColor};
+pub use crate::core::builder::PathSet;
+pub use crate::core::config::flags::Subcommand;
+pub use crate::core::config::Config;
 
 const LLVM_TOOLS: &[&str] = &[
     "llvm-cov",      // used to generate coverage report
@@ -210,12 +168,12 @@ pub struct Build {
     src: PathBuf,
     out: PathBuf,
     bootstrap_out: PathBuf,
-    cargo_info: channel::GitInfo,
-    rust_analyzer_info: channel::GitInfo,
-    clippy_info: channel::GitInfo,
-    miri_info: channel::GitInfo,
-    rustfmt_info: channel::GitInfo,
-    in_tree_llvm_info: channel::GitInfo,
+    cargo_info: GitInfo,
+    rust_analyzer_info: GitInfo,
+    clippy_info: GitInfo,
+    miri_info: GitInfo,
+    rustfmt_info: GitInfo,
+    in_tree_llvm_info: GitInfo,
     local_rebuild: bool,
     fail_fast: bool,
     doc_tests: DocTests,
@@ -248,7 +206,7 @@ pub struct Build {
     prerelease_version: Cell<Option<u32>>,
 
     #[cfg(feature = "build-metrics")]
-    metrics: metrics::BuildMetrics,
+    metrics: crate::utils::metrics::BuildMetrics,
 }
 
 #[derive(Debug, Clone)]
@@ -372,16 +330,15 @@ impl Build {
         let is_sudo = false;
 
         let omit_git_hash = config.omit_git_hash;
-        let rust_info = channel::GitInfo::new(omit_git_hash, &src);
-        let cargo_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/cargo"));
-        let rust_analyzer_info =
-            channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer"));
-        let clippy_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/clippy"));
-        let miri_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/miri"));
-        let rustfmt_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt"));
+        let rust_info = GitInfo::new(omit_git_hash, &src);
+        let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo"));
+        let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer"));
+        let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy"));
+        let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri"));
+        let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt"));
 
         // we always try to use git for LLVM builds
-        let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project"));
+        let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project"));
 
         let initial_target_libdir_str = if config.dry_run() {
             "/dummy/lib/path/to/lib/".to_string()
@@ -474,7 +431,7 @@ impl Build {
             prerelease_version: Cell::new(None),
 
             #[cfg(feature = "build-metrics")]
-            metrics: metrics::BuildMetrics::init(),
+            metrics: crate::utils::metrics::BuildMetrics::init(),
         };
 
         // If local-rust is the same major.minor as the current version, then force a
@@ -493,7 +450,7 @@ impl Build {
         }
 
         build.verbose("finding compilers");
-        cc_detect::find(&build);
+        utils::cc_detect::find(&build);
         // When running `setup`, the profile is about to change, so any requirements we have now may
         // be different on the next invocation. Don't check for them until the next time x.py is
         // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
@@ -501,7 +458,7 @@ impl Build {
         // Similarly, for `setup` we don't actually need submodules or cargo metadata.
         if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
             build.verbose("running sanity check");
-            sanity::check(&mut build);
+            crate::core::sanity::check(&mut build);
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
             // Cargo.toml files.
@@ -513,7 +470,7 @@ impl Build {
             build.update_existing_submodules();
 
             build.verbose("learning about cargo");
-            metadata::build(&mut build);
+            crate::core::metadata::build(&mut build);
         }
 
         // Make a symbolic link so we can use a consistent directory in the documentation.
@@ -549,7 +506,7 @@ impl Build {
 
         // NOTE: The check for the empty directory is here because when running x.py the first time,
         // the submodule won't be checked out. Check it out now so we can build it.
-        if !channel::GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
+        if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
             && !dir_is_empty(&absolute_path)
         {
             return;
@@ -663,7 +620,7 @@ impl Build {
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
             let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
             // Don't update the submodule unless it's already been cloned.
-            if channel::GitInfo::new(false, submodule).is_managed_git_subrepository() {
+            if GitInfo::new(false, submodule).is_managed_git_subrepository() {
                 self.update_submodule(submodule);
             }
         }
@@ -672,7 +629,7 @@ impl Build {
     /// Executes the entire build, as configured by the flags and configuration.
     pub fn build(&mut self) {
         unsafe {
-            job::setup(self);
+            crate::utils::job::setup(self);
         }
 
         // Download rustfmt early so that it can be used in rust-analyzer configs.
@@ -681,10 +638,14 @@ impl Build {
         // hardcoded subcommands
         match &self.config.cmd {
             Subcommand::Format { check } => {
-                return format::format(&builder::Builder::new(&self), *check, &self.config.paths);
+                return core::build_steps::format::format(
+                    &builder::Builder::new(&self),
+                    *check,
+                    &self.config.paths,
+                );
             }
             Subcommand::Suggest { run } => {
-                return suggest::suggest(&builder::Builder::new(&self), *run);
+                return core::build_steps::suggest::suggest(&builder::Builder::new(&self), *run);
             }
             _ => (),
         }
@@ -1065,7 +1026,7 @@ impl Build {
 
     /// Return a `Group` guard for a [`Step`] that is built for each `--stage`.
     ///
-    /// [`Step`]: crate::builder::Step
+    /// [`Step`]: crate::core::builder::Step
     #[must_use = "Groups should not be dropped until the Step finishes running"]
     #[track_caller]
     fn msg(
@@ -1093,7 +1054,7 @@ impl Build {
 
     /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`.
     ///
-    /// [`Step`]: crate::builder::Step
+    /// [`Step`]: crate::core::builder::Step
     #[must_use = "Groups should not be dropped until the Step finishes running"]
     #[track_caller]
     fn msg_unstaged(
@@ -1253,7 +1214,7 @@ impl Build {
             // that are only existed in CXX libraries
             Some(self.cxx.borrow()[&target].path().into())
         } else if target != self.config.build
-            && util::use_host_linker(target)
+            && helpers::use_host_linker(target)
             && !target.contains("msvc")
         {
             Some(self.cc(target))
@@ -1278,7 +1239,7 @@ impl Build {
                 options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string());
             }
 
-            let no_threads = util::lld_flag_no_threads(target.contains("windows"));
+            let no_threads = helpers::lld_flag_no_threads(target.contains("windows"));
             options[1] = Some(format!("-Clink-arg=-Wl,{no_threads}"));
         }
 
@@ -1418,7 +1379,7 @@ impl Build {
         fn extract_beta_rev_from_file<P: AsRef<Path>>(version_file: P) -> Option<String> {
             let version = fs::read_to_string(version_file).ok()?;
 
-            extract_beta_rev(&version)
+            helpers::extract_beta_rev(&version)
         }
 
         if let Some(s) = self.prerelease_version.get() {
@@ -1732,7 +1693,7 @@ impl Build {
     /// Returns if config.ninja is enabled, and checks for ninja existence,
     /// exiting with a nicer error message if not.
     fn ninja(&self) -> bool {
-        let mut cmd_finder = crate::sanity::Finder::new();
+        let mut cmd_finder = crate::core::sanity::Finder::new();
 
         if self.config.ninja_in_file {
             // Some Linux distros rename `ninja` to `ninja-build`.
@@ -1798,17 +1759,6 @@ to download LLVM rather than building it.
     }
 }
 
-/// Extract the beta revision from the full version string.
-///
-/// The full version string looks like "a.b.c-beta.y". And we need to extract
-/// the "y" part from the string.
-pub fn extract_beta_rev(version: &str) -> Option<String> {
-    let parts = version.splitn(2, "-beta.").collect::<Vec<_>>();
-    let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string()));
-
-    count
-}
-
 #[cfg(unix)]
 fn chmod(path: &Path, perms: u32) {
     use std::os::unix::fs::*;
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/src/tests/builder.rs
index 80e66622e8b..96139f7b099 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/src/tests/builder.rs
@@ -1,6 +1,6 @@
 use super::*;
-use crate::config::{Config, DryRun, TargetSelection};
-use crate::doc::DocumentationFormat;
+use crate::core::config::{Config, DryRun, TargetSelection};
+use crate::core::build_steps::doc::DocumentationFormat;
 use std::thread;
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
@@ -22,7 +22,6 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config
         ..Config::parse(&["check".to_owned()])
     });
     submodule_build.update_submodule(Path::new("src/doc/book"));
-    submodule_build.update_submodule(Path::new("src/tools/rust-analyzer"));
     config.submodules = Some(false);
 
     config.ninja_in_file = false;
@@ -159,7 +158,7 @@ fn alias_and_path_for_library() {
 
 #[test]
 fn test_beta_rev_parsing() {
-    use crate::extract_beta_rev;
+    use crate::utils::helpers::extract_beta_rev;
 
     // single digit revision
     assert_eq!(extract_beta_rev("1.99.9-beta.7 (xxxxxx)"), Some("7".to_string()));
@@ -175,7 +174,7 @@ fn test_beta_rev_parsing() {
 
 mod defaults {
     use super::{configure, first, run_build};
-    use crate::builder::*;
+    use crate::core::builder::*;
     use crate::Config;
     use pretty_assertions::assert_eq;
 
@@ -286,7 +285,7 @@ mod defaults {
 
 mod dist {
     use super::{first, run_build, Config};
-    use crate::builder::*;
+    use crate::core::builder::*;
     use pretty_assertions::assert_eq;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/src/tests/config.rs
index ae8363b6de9..59bd52a94dc 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/src/tests/config.rs
@@ -1,6 +1,6 @@
-use crate::config::TomlConfig;
-
+use crate::core::config::TomlConfig;
 use super::{Config, Flags};
+
 use clap::CommandFactory;
 use serde::Deserialize;
 use std::{
@@ -18,7 +18,7 @@ fn parse(config: &str) -> Config {
 
 #[test]
 fn download_ci_llvm() {
-    if crate::llvm::is_ci_llvm_modified(&parse("")) {
+    if crate::core::build_steps::llvm::is_ci_llvm_modified(&parse("")) {
         eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change");
         return;
     }
@@ -137,7 +137,7 @@ build-config = {}
     assert_eq!(config.change_id, Some(1), "setting top-level value");
     assert_eq!(
         config.rust_lto,
-        crate::config::RustcLto::Fat,
+        crate::core::config::RustcLto::Fat,
         "setting string value without quotes"
     );
     assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes");
@@ -175,7 +175,7 @@ fn profile_user_dist() {
             "profile = \"user\"".to_owned()
         } else {
             assert!(file.ends_with("config.dist.toml"));
-            std::fs::read_to_string(dbg!(file)).unwrap()
+            std::fs::read_to_string(file).unwrap()
         };
         toml::from_str(&contents)
             .and_then(|table: toml::Value| TomlConfig::deserialize(table))
diff --git a/src/bootstrap/setup/tests.rs b/src/bootstrap/src/tests/setup.rs
index 0fe6e4a4644..0fe6e4a4644 100644
--- a/src/bootstrap/setup/tests.rs
+++ b/src/bootstrap/src/tests/setup.rs
diff --git a/src/bootstrap/bin/_helper.rs b/src/bootstrap/src/utils/bin_helpers.rs
index 46c574c5bf4..b9177c490ac 100644
--- a/src/bootstrap/bin/_helper.rs
+++ b/src/bootstrap/src/utils/bin_helpers.rs
@@ -1,8 +1,12 @@
+//! This file is meant to be included directly from bootstrap shims to avoid a
+//! dependency on the bootstrap library. This reduces the binary size and
+//! improves compilation time by reducing the linking time.
+
 /// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`.
 /// If it was not defined, returns 0 by default.
 ///
 /// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer.
-fn parse_rustc_verbose() -> usize {
+pub(crate) fn parse_rustc_verbose() -> usize {
     use std::str::FromStr;
 
     match std::env::var("RUSTC_VERBOSE") {
@@ -15,11 +19,11 @@ fn parse_rustc_verbose() -> usize {
 ///
 /// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
 #[allow(unused)]
-fn parse_rustc_stage() -> String {
+pub(crate) fn parse_rustc_stage() -> String {
     std::env::var("RUSTC_STAGE").unwrap_or_else(|_| {
         // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
         eprintln!("rustc shim: fatal: RUSTC_STAGE was not set");
         eprintln!("rustc shim: note: use `x.py build -vvv` to see all environment variables set by bootstrap");
-        exit(101);
+        std::process::exit(101);
     })
 }
diff --git a/src/bootstrap/cache.rs b/src/bootstrap/src/utils/cache.rs
index 53e4ff03431..1b2aa9c234b 100644
--- a/src/bootstrap/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -14,7 +14,7 @@ use std::sync::Mutex;
 // FIXME: replace with std::lazy after it gets stabilized and reaches beta
 use once_cell::sync::Lazy;
 
-use crate::builder::Step;
+use crate::core::builder::Step;
 
 pub struct Interned<T>(usize, PhantomData<*const T>);
 
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 2496c2a9db5..3d3f93f7720 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -26,8 +26,8 @@ use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::{env, iter};
 
-use crate::config::{Target, TargetSelection};
-use crate::util::output;
+use crate::core::config::{Target, TargetSelection};
+use crate::utils::helpers::output;
 use crate::{Build, CLang, GitRepo};
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/src/utils/channel.rs
index 87018574048..e59d7f22aaa 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -9,8 +9,7 @@ use std::fs;
 use std::path::Path;
 use std::process::Command;
 
-use crate::util::output;
-use crate::util::t;
+use crate::utils::helpers::{output, t};
 use crate::Build;
 
 #[derive(Clone, Default)]
diff --git a/src/bootstrap/dylib_util.rs b/src/bootstrap/src/utils/dylib.rs
index b14c0bed66c..279a6a010f1 100644
--- a/src/bootstrap/dylib_util.rs
+++ b/src/bootstrap/src/utils/dylib.rs
@@ -1,7 +1,4 @@
-// Various utilities for working with dylib paths.
-//
-// This file is meant to be included directly to avoid a dependency on the bootstrap library from
-// the rustc and rustdoc wrappers. This improves compilation time by reducing the linking time.
+//! Various utilities for working with dylib paths.
 
 /// Returns the environment variable which the dynamic library lookup path
 /// resides in for this platform.
@@ -21,10 +18,10 @@ pub fn dylib_path_var() -> &'static str {
 
 /// Parses the `dylib_path_var()` environment variable, returning a list of
 /// paths that are members of this lookup path.
-pub fn dylib_path() -> Vec<PathBuf> {
-    let var = match env::var_os(dylib_path_var()) {
+pub fn dylib_path() -> Vec<std::path::PathBuf> {
+    let var = match std::env::var_os(dylib_path_var()) {
         Some(v) => v,
         None => return vec![],
     };
-    env::split_paths(&var).collect()
+    std::env::split_paths(&var).collect()
 }
diff --git a/src/bootstrap/util.rs b/src/bootstrap/src/utils/helpers.rs
index 3c4a21434c0..bb84b70d987 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -12,10 +12,12 @@ use std::process::{Command, Stdio};
 use std::str;
 use std::time::{Instant, SystemTime, UNIX_EPOCH};
 
-use crate::builder::Builder;
-use crate::config::{Config, TargetSelection};
+use crate::core::builder::Builder;
+use crate::core::config::{Config, TargetSelection};
 use crate::OnceCell;
 
+pub use crate::utils::dylib::{dylib_path, dylib_path_var};
+
 /// A helper macro to `unwrap` a result except also print out details like:
 ///
 /// * The file/line of the panic
@@ -81,8 +83,6 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
     cmd.env(dylib_path_var(), t!(env::join_paths(list)));
 }
 
-include!("dylib_util.rs");
-
 /// Adds a list of lookup paths to `cmd`'s link library lookup path.
 pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
     let mut list = link_lib_path();
@@ -293,23 +293,6 @@ pub fn output(cmd: &mut Command) -> String {
     String::from_utf8(output.stdout).unwrap()
 }
 
-pub fn output_result(cmd: &mut Command) -> Result<String, String> {
-    let output = match cmd.stderr(Stdio::inherit()).output() {
-        Ok(status) => status,
-        Err(e) => return Err(format!("failed to run command: {cmd:?}: {e}")),
-    };
-    if !output.status.success() {
-        return Err(format!(
-            "command did not execute successfully: {:?}\n\
-             expected success, got: {}\n{}",
-            cmd,
-            output.status,
-            String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
-        ));
-    }
-    Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?)
-}
-
 /// Returns the last-modified time for `path`, or zero if it doesn't exist.
 pub fn mtime(path: &Path) -> SystemTime {
     fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
@@ -495,3 +478,14 @@ pub fn lld_flag_no_threads(is_windows: bool) -> &'static str {
 pub fn dir_is_empty(dir: &Path) -> bool {
     t!(std::fs::read_dir(dir)).next().is_none()
 }
+
+/// Extract the beta revision from the full version string.
+///
+/// The full version string looks like "a.b.c-beta.y". And we need to extract
+/// the "y" part from the string.
+pub fn extract_beta_rev(version: &str) -> Option<String> {
+    let parts = version.splitn(2, "-beta.").collect::<Vec<_>>();
+    let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string()));
+
+    count
+}
diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs
new file mode 100644
index 00000000000..37235134a28
--- /dev/null
+++ b/src/bootstrap/src/utils/job.rs
@@ -0,0 +1,161 @@
+#[cfg(windows)]
+pub use for_windows::*;
+
+#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))]
+pub unsafe fn setup(_build: &mut crate::Build) {}
+
+#[cfg(all(unix, not(target_os = "haiku")))]
+pub unsafe fn setup(build: &mut crate::Build) {
+    if build.config.low_priority {
+        libc::setpriority(libc::PRIO_PGRP as _, 0, 10);
+    }
+}
+
+#[cfg(windows)]
+mod for_windows {
+    //! Job management on Windows for bootstrapping
+    //!
+    //! Most of the time when you're running a build system (e.g., make) you expect
+    //! Ctrl-C or abnormal termination to actually terminate the entire tree of
+    //! process in play, not just the one at the top. This currently works "by
+    //! default" on Unix platforms because Ctrl-C actually sends a signal to the
+    //! *process group* rather than the parent process, so everything will get torn
+    //! down. On Windows, however, this does not happen and Ctrl-C just kills the
+    //! parent process.
+    //!
+    //! To achieve the same semantics on Windows we use Job Objects to ensure that
+    //! all processes die at the same time. Job objects have a mode of operation
+    //! where when all handles to the object are closed it causes all child
+    //! processes associated with the object to be terminated immediately.
+    //! Conveniently whenever a process in the job object spawns a new process the
+    //! child will be associated with the job object as well. This means if we add
+    //! ourselves to the job object we create then everything will get torn down!
+    //!
+    //! Unfortunately most of the time the build system is actually called from a
+    //! python wrapper (which manages things like building the build system) so this
+    //! all doesn't quite cut it so far. To go the last mile we duplicate the job
+    //! object handle into our parent process (a python process probably) and then
+    //! close our own handle. This means that the only handle to the job object
+    //! resides in the parent python process, so when python dies the whole build
+    //! system dies (as one would probably expect!).
+    //!
+    //! Note that this module has a #[cfg(windows)] above it as none of this logic
+    //! is required on Unix.
+
+    use crate::Build;
+    use std::env;
+    use std::ffi::c_void;
+    use std::io;
+    use std::mem;
+
+    use windows::{
+        core::PCWSTR,
+        Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
+        Win32::System::Diagnostics::Debug::{
+            SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE,
+        },
+        Win32::System::JobObjects::{
+            AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
+            SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
+            JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
+        },
+        Win32::System::Threading::{
+            GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+        },
+    };
+
+    pub unsafe fn setup(build: &mut Build) {
+        // Enable the Windows Error Reporting dialog which msys disables,
+        // so we can JIT debug rustc
+        let mode = SetErrorMode(THREAD_ERROR_MODE::default());
+        let mode = THREAD_ERROR_MODE(mode);
+        SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
+
+        // Create a new job object for us to use
+        let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
+
+        // Indicate that when all handles to the job object are gone that all
+        // process in the object should be killed. Note that this includes our
+        // entire process tree by default because we've added ourselves and our
+        // children will reside in the job by default.
+        let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
+        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+        if build.config.low_priority {
+            info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
+            info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
+        }
+        let r = SetInformationJobObject(
+            job,
+            JobObjectExtendedLimitInformation,
+            &info as *const _ as *const c_void,
+            mem::size_of_val(&info) as u32,
+        )
+        .ok();
+        assert!(r.is_ok(), "{}", io::Error::last_os_error());
+
+        // Assign our process to this job object. Note that if this fails, one very
+        // likely reason is that we are ourselves already in a job object! This can
+        // happen on the build bots that we've got for Windows, or if just anyone
+        // else is instrumenting the build. In this case we just bail out
+        // immediately and assume that they take care of it.
+        //
+        // Also note that nested jobs (why this might fail) are supported in recent
+        // versions of Windows, but the version of Windows that our bots are running
+        // at least don't support nested job objects.
+        let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
+        if r.is_err() {
+            CloseHandle(job);
+            return;
+        }
+
+        // If we've got a parent process (e.g., the python script that called us)
+        // then move ownership of this job object up to them. That way if the python
+        // script is killed (e.g., via ctrl-c) then we'll all be torn down.
+        //
+        // If we don't have a parent (e.g., this was run directly) then we
+        // intentionally leak the job object handle. When our process exits
+        // (normally or abnormally) it will close the handle implicitly, causing all
+        // processes in the job to be cleaned up.
+        let pid = match env::var("BOOTSTRAP_PARENT_ID") {
+            Ok(s) => s,
+            Err(..) => return,
+        };
+
+        let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
+            Some(parent) => parent,
+            _ => {
+                // If we get a null parent pointer here, it is possible that either
+                // we have an invalid pid or the parent process has been closed.
+                // Since the first case rarely happens
+                // (only when wrongly setting the environmental variable),
+                // it might be better to improve the experience of the second case
+                // when users have interrupted the parent process and we haven't finish
+                // duplicating the handle yet. We just need close the job object if that occurs.
+                CloseHandle(job);
+                return;
+            }
+        };
+
+        let mut parent_handle = HANDLE::default();
+        let r = DuplicateHandle(
+            GetCurrentProcess(),
+            job,
+            parent,
+            &mut parent_handle,
+            0,
+            false,
+            DUPLICATE_SAME_ACCESS,
+        )
+        .ok();
+
+        // If this failed, well at least we tried! An example of DuplicateHandle
+        // failing in the past has been when the wrong python2 package spawned this
+        // build system (e.g., the `python2` package in MSYS instead of
+        // `mingw-w64-x86_64-python2`). Not sure why it failed, but the "failure
+        // mode" here is that we only clean everything up when the build system
+        // dies, not when the python parent does, so not too bad.
+        if r.is_err() {
+            CloseHandle(job);
+        }
+    }
+}
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/src/utils/metrics.rs
index cf8d33dfcb0..65794f05d2d 100644
--- a/src/bootstrap/metrics.rs
+++ b/src/bootstrap/src/utils/metrics.rs
@@ -4,8 +4,8 @@
 //! As this module requires additional dependencies not present during local builds, it's cfg'd
 //! away whenever the `build.metrics` config option is not set to `true`.
 
-use crate::builder::{Builder, Step};
-use crate::util::t;
+use crate::core::builder::{Builder, Step};
+use crate::utils::helpers::t;
 use crate::Build;
 use build_helper::metrics::{
     JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test,
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
new file mode 100644
index 00000000000..7dcb6a82862
--- /dev/null
+++ b/src/bootstrap/src/utils/mod.rs
@@ -0,0 +1,14 @@
+//! This module contains integral components of the build and configuration process, providing
+//! support for a wide range of tasks and operations such as caching, tarballs, release
+//! channels, job management, etc.
+
+pub(crate) mod cache;
+pub(crate) mod cc_detect;
+pub(crate) mod channel;
+pub(crate) mod dylib;
+pub(crate) mod helpers;
+pub(crate) mod job;
+#[cfg(feature = "build-metrics")]
+pub(crate) mod metrics;
+pub(crate) mod render_tests;
+pub(crate) mod tarball;
diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 6802bf4511b..f97aa958513 100644
--- a/src/bootstrap/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -6,7 +6,7 @@
 //! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had
 //! to reimplement all the rendering logic in this module because of that.
 
-use crate::builder::Builder;
+use crate::core::builder::Builder;
 use std::io::{BufRead, BufReader, Read, Write};
 use std::process::{ChildStdout, Command, Stdio};
 use std::time::Duration;
diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 95d909c5730..b437456f8a1 100644
--- a/src/bootstrap/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -3,9 +3,10 @@ use std::{
     process::Command,
 };
 
-use crate::builder::Builder;
-use crate::channel;
-use crate::util::t;
+use crate::core::build_steps::dist::distdir;
+use crate::core::builder::Builder;
+use crate::utils::channel;
+use crate::utils::helpers::t;
 
 #[derive(Copy, Clone)]
 pub(crate) enum OverlayKind {
@@ -112,7 +113,7 @@ impl<'a> Tarball<'a> {
     }
 
     fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option<String>) -> Self {
-        let pkgname = crate::dist::pkgname(builder, component);
+        let pkgname = crate::core::build_steps::dist::pkgname(builder, component);
 
         let mut temp_dir = builder.out.join("tmp").join("tarball").join(component);
         if let Some(target) = &target {
@@ -265,7 +266,7 @@ impl<'a> Tarball<'a> {
         t!(std::fs::rename(&self.image_dir, &dest));
 
         self.run(|this, cmd| {
-            let distdir = crate::dist::distdir(this.builder);
+            let distdir = distdir(this.builder);
             t!(std::fs::create_dir_all(&distdir));
             cmd.arg("tarball")
                 .arg("--input")
@@ -292,7 +293,7 @@ impl<'a> Tarball<'a> {
             .arg("--non-installed-overlay")
             .arg(&self.overlay_dir)
             .arg("--output-dir")
-            .arg(crate::dist::distdir(self.builder));
+            .arg(distdir(self.builder));
     }
 
     fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball {
@@ -306,11 +307,11 @@ impl<'a> Tarball<'a> {
             self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
         }
 
-        let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller);
+        let mut cmd = self.builder.tool_cmd(crate::core::build_steps::tool::Tool::RustInstaller);
 
         let package_name = self.package_name();
         self.builder.info(&format!("Dist {package_name}"));
-        let _time = crate::util::timeit(self.builder);
+        let _time = crate::utils::helpers::timeit(self.builder);
 
         build_cli(&self, &mut cmd);
         cmd.arg("--work-dir").arg(&self.temp_dir);
@@ -344,7 +345,7 @@ impl<'a> Tarball<'a> {
             .unwrap_or("gz");
 
         GeneratedTarball {
-            path: crate::dist::distdir(self.builder).join(format!("{package_name}.tar.{ext}")),
+            path: distdir(self.builder).join(format!("{package_name}.tar.{ext}")),
             decompressed_output,
             work: self.temp_dir,
         }
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 1fb5e56db5d..db834600b9c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -244,7 +244,7 @@ target | std | host | notes
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
-[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? |  | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
+[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ |  | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
 [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |  | ARMv7-A OpenHarmony |
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7-A Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7-A Linux with uClibc, hardfloat
diff --git a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
index 49eed366dac..e1473bd966c 100644
--- a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
@@ -2,15 +2,16 @@
 
 **Tier: 3**
 
-This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console. `armv7-vita-newlibeabihf` aims to have support for `std` crate using `newlib` as a bridge.
+This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console.
 
 Rust support for this target is not affiliated with Sony, and is not derived
 from nor used with any official Sony SDK.
 
 ## Target maintainers
 
-* [@amg98](https://github.com/amg98)
 * [@nikarh](https://github.com/nikarh)
+* [@pheki](https://github.com/pheki)
+* [@ZetaNumbers](https://github.com/ZetaNumbers)
 
 ## Requirements
 
@@ -20,18 +21,16 @@ This target is cross-compiled, and requires installing [VITASDK](https://vitasdk
 `alloc`, and `panic_abort`.
 
 `std` is partially supported, but mostly works. Some APIs are unimplemented
-and will simply return an error, such as `std::process`. An allocator is provided
-by default.
+and will simply return an error, such as `std::process`.
 
-In order to support some APIs, binaries must be linked against `libc` written
-for the target, using a linker for the target. These are provided by the
-VITASDK toolchain.
+This target generates binaries in the ELF format with thumb ISA by default.
+
+Binaries are linked with `arm-vita-eabi-gcc` provided by VITASDK toolchain.
 
-This target generates binaries in the ELF format with thumb ISA.
 
 ## Building the target
 
-Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build binaries with `std`:
+Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build ELF binaries with `std`:
 
 ```sh
 cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf --release
@@ -39,113 +38,45 @@ cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf -
 
 ## Building Rust programs
 
-To test your developed rust programs on PlayStation Vita, first you must correctly package your elf. These steps can be preformed using tools available in VITASDK, and can be automated using a tool like `cargo-make`.
+The recommended way to build artifacts that can be installed and run on PlayStation Vita is by using the [cargo-vita](https://github.com/vita-rust/cargo-vita) tool. This tool uses `build-std` and VITASDK toolchain to build artifacts runnable on Vita.
+
+To install the tool run:
+
+```sh
+cargo install cargo-vita
+```
 
-First, set up environment variables for `VITASDK`, and it's binaries:
+[VITASDK](https://vitasdk.org/) toolchain must be installed, and the `VITASDK` environment variable must be set to its location, e.g.:
 
 ```sh
 export VITASDK=/opt/vitasdk
-export PATH=$PATH:$VITASDK/bin
 ```
 
-Use the example below as a template for your project:
+Add the following section to your project's `Cargo.toml`:
+
 
 ```toml
-[env]
-TITLE = "Rust Hello World"
-TITLEID = "RUST00001"
-
-# At least a "sce_sys" folder should be place there for app metadata (title, icons, description...)
-# You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/
-STATIC_DIR = "static"   # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys)
-CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] }
-CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release"
-
-[tasks.build]
-description = "Build the project using `cargo`."
-command = "cargo"
-args = ["build", "-Z", "build-std=std,panic_abort", "--target=armv7-sony-vita-newlibeabihf", "--release"]
-
-[tasks.strip]
-description = "Strip the produced ELF executable."
-dependencies = ["build"]
-command = "arm-vita-eabi-strip"
-args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf']
-
-[tasks.velf]
-description = "Build an VELF executable from the obtained ELF file."
-dependencies = ["strip"]
-command = "vita-elf-create"
-args = ['${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf', '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf']
-
-[tasks.eboot-bin]
-description = "Build an `eboot.bin` file from the obtained VELF file."
-dependencies = ["velf"]
-command = "vita-make-fself"
-args = ["-s", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf', '${CARGO_OUT_DIR}/eboot.bin']
-
-[tasks.param-sfo]
-description = "Build the `param.sfo` manifest using with given TITLE and TITLEID."
-command = "vita-mksfoex"
-args = ["-s", 'TITLE_ID=${TITLEID}', '${TITLE}', '${CARGO_OUT_DIR}/param.sfo']
-
-[tasks.manifest]
-description = "List all static resources into a manifest file."
-script = [
-  'mkdir -p "${CARGO_OUT_DIR}"',
-  '''
-  if [ -d "${STATIC_DIR}" ]; then
-    find "${STATIC_DIR}" -type f > "${CARGO_OUT_DIR}/MANIFEST"
-  else
-    touch "${CARGO_OUT_DIR}/MANIFEST"
-  fi
-  '''
-]
-
-[tasks.vpk]
-description = "Build a VPK distribution of the project executable and resources."
-dependencies = ["eboot-bin", "param-sfo", "manifest"]
-script_runner = "@rust"
-script = [
-    '''
-    use std::io::BufRead;
-    use std::fs::File;
-
-    fn main() {
-
-      let crate_name = env!("CARGO_MAKE_CRATE_NAME");
-      let static_dir = env!("STATIC_DIR");
-      let out_dir = std::path::PathBuf::from(env!("CARGO_OUT_DIR"));
-
-      let mut cmd = ::std::process::Command::new("vita-pack-vpk");
-      cmd.arg("-s").arg(out_dir.join("param.sfo"));
-      cmd.arg("-b").arg(out_dir.join("eboot.bin"));
-
-      // Add files from MANIFEST
-      if let Ok(file) = File::open(out_dir.join("MANIFEST")) {
-          let mut reader = ::std::io::BufReader::new(file);
-          let mut lines = reader.lines();
-          while let Some(Ok(line)) = lines.next() {
-              let p1 = ::std::path::PathBuf::from(line);            // path on FS
-              let p2 = p1.strip_prefix(static_dir).unwrap();        // path in VPK
-              cmd.arg("--add").arg(format!("{}={}", p1.display(), p2.display()));
-          }
-      }
-
-      cmd.arg(out_dir.join(format!("{}.vpk", crate_name)))
-        .output()
-        .expect("command failed.");
-    }
-    '''
-]
+[package.metadata.vita]
+# A unique 9 character alphanumeric identifier of the app.
+title_id = "RUSTAPP01"
+# A title that will be used for the app. Optional, name will be used if not defined
+title_name = "My application"
 ```
 
-After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, or you can use an [Vita3K](https://vita3k.org/) emulator.
+To build a VPK with ELF in the release profile, run:
+
+```sh
+cargo vita build vpk --release
+```
+
+After building a *.vpk file it can be uploaded to a PlayStation Vita and installed, or used with a [Vita3K](https://vita3k.org/) emulator.
 
 ## Testing
 
-Currently there is no support to run the rustc test suite for this target.
+The default Rust test runner is supported, and tests can be compiled to an elf and packed to a *.vpk file using `cargo-vita` tool. Filtering tests is not currently supported since passing command-line arguments to the executable is not supported on Vita, so the runner will always execute all tests.
+
+The Rust test suite for `library/std` is not yet supported.
 
 ## Cross-compilation
 
-This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
+This target can be cross-compiled from `x86_64` on Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 199b5d69a1c..41602dec44c 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -628,10 +628,10 @@ Using this flag looks like this:
 
 ```bash
 $ rustdoc src/lib.rs -Z unstable-options \
-    --check-cfg='names()' --check-cfg='values(feature, "foo", "bar")'
+    --check-cfg='cfg(feature, values("foo", "bar"))'
 ```
 
-The example above check every well known names (`target_os`, `doc`, `test`, ... via `names()`)
+The example above check every well known names and values (`target_os`, `doc`, `test`, ...)
 and check the values of `feature`: `foo` and `bar`.
 
 ### `--generate-link-to-definition`: Generate links on types in source code
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index 10f0fbc5062..ca18ec567a4 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -10,97 +10,80 @@ This feature allows you to enable complete or partial checking of configuration.
 check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The
 check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is.
 
-`--check-cfg` option can take one of two forms:
+`--check-cfg` option take one form:
 
-1. `--check-cfg names(...)` enables checking condition names.
-2. `--check-cfg values(...)` enables checking the values within list-valued conditions.
-
-These two options are independent. `names` checks only the namespace of condition names
-while `values` checks only the namespace of the values of list-valued conditions.
+1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions.
 
 NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to
-pass all expected names and values using `names(...)` and `values(...)`.
+pass all expected names and values using `cfg(...)`.
 
-## The `names(...)` form
+## The `cfg(...)` form
 
-The `names(...)` form enables checking the names. This form uses a named list:
+The `cfg(...)` form enables checking the values within list-valued conditions. It has this
+basic form:
 
 ```bash
-rustc --check-cfg 'names(name1, name2, ... nameN)'
+rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'
 ```
 
-where each `name` is a bare identifier (has no quotes). The order of the names is not significant.
+where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal
+string. `name` specifies the name of the condition, such as `feature` or `my_cfg`.
 
-If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to
-condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause
-inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition
-names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint
-diagnostic. The default diagnostic level for this lint is `Warn`.
+When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]`
+attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]`
+and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the
+list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs`
+lint diagnostic. The default diagnostic level for this lint is `Warn`.
 
-If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition
-names.
+To enable checking of values, but to provide an empty set of expected values, use these forms:
 
-`--check-cfg names(...)` may be specified more than once. The result is that the list of valid
-condition names is merged across all options. It is legal for a condition name to be specified
-more than once; redundantly specifying a condition name has no effect.
+```bash
+rustc --check-cfg 'cfg(name1, ..., nameN)'
+rustc --check-cfg 'cfg(name1, ..., nameN, values())'
+```
 
-To enable checking condition names with an empty set of valid condition names, use the following
-form. The parentheses are required.
+To enable checking of name but not values (i.e. unknown expected values), use this form:
 
 ```bash
-rustc --check-cfg 'names()'
+rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))'
 ```
 
-Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely.
-The first form enables checking condition names, while specifying that there are no valid
-condition names (outside of the set of well-known names defined by `rustc`). Omitting the
-`--check-cfg 'names(...)'` option does not enable checking condition names.
-
-## The `values(...)` form
+The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for
+different names. If it is repeated for the same condition name, then the sets of values for that
+condition are merged together (presedence is given to `any()`).
 
-The `values(...)` form enables checking the values within list-valued conditions. It has this
-form:
+## Well known names and values
 
-```bash
-rustc --check-cfg `values(name, "value1", "value2", ... "valueN")'
-```
+`rustc` has a internal list of well known names and their corresponding values.
+Those well known names and values follows the same stability as what they refer to.
 
-where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal
-string. `name` specifies the name of the condition, such as `feature` or `target_os`.
+Well known values checking is always enabled as long as a `--check-cfg` argument is present.
 
-When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]`
-attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]`
-and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the
-list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs`
-lint diagnostic. The default diagnostic level for this lint is `Warn`.
+Well known names checking is always enable as long as a `--check-cfg` argument is present
+**unless** any `cfg(any())` argument is passed.
 
-To enable checking of values, but to provide an empty set of valid values, use this form:
+To disable checking of well known names, use this form:
 
 ```bash
-rustc --check-cfg `values(name)`
+rustc --check-cfg 'cfg(any())'
 ```
 
-The `--check-cfg values(...)` option can be repeated, both for the same condition name and for
-different names. If it is repeated for the same condition name, then the sets of values for that
-condition are merged together.
-
-If `values()` is specified, then `rustc` will enable the checking of well-known values defined
-by itself. Note that it's necessary to specify the `values()` form to enable the checking of
-well known values, specifying the other forms doesn't implicitly enable it.
+NOTE: If one want to enable values and names checking without having any cfg to declare, one
+can use an empty `cfg()` argument.
 
 ## Examples
 
 Consider this command line:
 
 ```bash
-rustc --check-cfg 'names(feature)' \
-      --check-cfg 'values(feature, "lion", "zebra")' \
+rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \
       --cfg 'feature="lion"' -Z unstable-options \
       example.rs
 ```
 
 This command line indicates that this crate has two features: `lion` and `zebra`. The `lion`
-feature is enabled, while the `zebra` feature is disabled. Consider compiling this code:
+feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and
+values are enabled by default. Consider compiling this code:
 
 ```rust
 // This is expected, and tame_lion() will be compiled
@@ -119,35 +102,36 @@ fn poke_platypus() {}
 // and will cause a compiler warning (by default).
 #[cfg(feechure = "lion")]
 fn tame_lion() {}
-```
 
-> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition
-> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so
-> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be
-> shortened to > `--check-cfg names()` in order to enable checking well-known condition names.
+// This is UNEXPECTED, because 'windows' is a well known condition name,
+// and because 'windows' doens't take any values,
+// and will cause a compiler warning (by default).
+#[cfg(windows = "unix")]
+fn tame_windows() {}
+```
 
 ### Example: Checking condition names, but not values
 
 ```bash
 # This turns on checking for condition names, but not values, such as 'feature' values.
-rustc --check-cfg 'names(is_embedded, has_feathers)' \
+rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
       --cfg has_feathers -Z unstable-options
 ```
 
 ```rust
-#[cfg(is_embedded)]         // This is expected as "is_embedded" was provided in names()
-fn do_embedded() {}
+#[cfg(is_embedded)]         // This is expected as "is_embedded" was provided in cfg()
+fn do_embedded() {}         // and because names exhaustiveness was not disabled
 
-#[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in names()
-fn do_features() {}
+#[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in cfg()
+fn do_features() {}         // and because names exhaustiveness was not disbaled
 
-#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names()
+#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg()
                                  // and because no value checking was enable for "has_feathers"
                                  // no warning is emitted for the value "zapping"
 fn do_zapping() {}
 
 #[cfg(has_mumble_frotz)]    // This is UNEXPECTED because names checking is enable and
-                            // "has_mumble_frotz" was not provided in names()
+                            // "has_mumble_frotz" was not provided in cfg()
 fn do_mumble_frotz() {}
 ```
 
@@ -155,25 +139,25 @@ fn do_mumble_frotz() {}
 
 ```bash
 # This turns on checking for feature values, but not for condition names.
-rustc --check-cfg 'values(feature, "zapping", "lasers")' \
+rustc --check-cfg 'configure(feature, values("zapping", "lasers"))' \
+      --check-cfg 'cfg(any())' \
       --cfg 'feature="zapping"' -Z unstable-options
 ```
 
 ```rust
-#[cfg(is_embedded)]         // This is doesn't raise a warning, because names checking was not
-                            // enable (ie not names())
+#[cfg(is_embedded)]         // This is doesn't raise a warning, because names checking was
+                            // disabled by 'cfg(any())'
 fn do_embedded() {}
 
-#[cfg(has_feathers)]        // Same as above, --check-cfg names(...) was never used so no name
+#[cfg(has_feathers)]        // Same as above, 'cfg(any())' was provided so no name
                             // checking is performed
 fn do_features() {}
 
-
-#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the values(feature) list
+#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the cfg(feature) list
 fn shoot_lasers() {}
 
 #[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the
-                            // --check-cfg values(feature) list
+                            // cfg(feature) list
 fn write_shakespeare() {}
 ```
 
@@ -181,26 +165,92 @@ fn write_shakespeare() {}
 
 ```bash
 # This turns on checking for feature values and for condition names.
-rustc --check-cfg 'names(is_embedded, has_feathers)' \
-      --check-cfg 'values(feature, "zapping", "lasers")' \
+rustc --check-cfg 'cfg(is_embedded, has_feathers)' \
+      --check-cfg 'cfg(feature, values("zapping", "lasers"))' \
       --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options
 ```
 
 ```rust
-#[cfg(is_embedded)]         // This is expected because "is_embedded" was provided in names()
-fn do_embedded() {}
+#[cfg(is_embedded)]         // This is expected because "is_embedded" was provided in cfg()
+fn do_embedded() {}         // and doesn't take any value
 
-#[cfg(has_feathers)]        // This is expected because "has_feathers" was provided in names()
-fn do_features() {}
+#[cfg(has_feathers)]        // This is expected because "has_feathers" was provided in cfg()
+fn do_features() {}         // and deosn't take any value
 
-#[cfg(has_mumble_frotz)]    // This is UNEXPECTED, because has_mumble_frotz is not in the
-                            // --check-cfg names(...) list
+#[cfg(has_mumble_frotz)]    // This is UNEXPECTED, because "has_mumble_frotz" was never provided
 fn do_mumble_frotz() {}
 
-#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the values(feature) list
+#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the cfg(feature) list
 fn shoot_lasers() {}
 
 #[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in
-                            // the values(feature) list
+                            // the cfg(feature) list
 fn write_shakespeare() {}
 ```
+
+## The deprecated `names(...)` form
+
+The `names(...)` form enables checking the names. This form uses a named list:
+
+```bash
+rustc --check-cfg 'names(name1, name2, ... nameN)'
+```
+
+where each `name` is a bare identifier (has no quotes). The order of the names is not significant.
+
+If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to
+condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause
+inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition
+names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint
+diagnostic. The default diagnostic level for this lint is `Warn`.
+
+If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition
+names.
+
+`--check-cfg names(...)` may be specified more than once. The result is that the list of valid
+condition names is merged across all options. It is legal for a condition name to be specified
+more than once; redundantly specifying a condition name has no effect.
+
+To enable checking condition names with an empty set of valid condition names, use the following
+form. The parentheses are required.
+
+```bash
+rustc --check-cfg 'names()'
+```
+
+Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely.
+The first form enables checking condition names, while specifying that there are no valid
+condition names (outside of the set of well-known names defined by `rustc`). Omitting the
+`--check-cfg 'names(...)'` option does not enable checking condition names.
+
+## The deprecated `values(...)` form
+
+The `values(...)` form enables checking the values within list-valued conditions. It has this
+form:
+
+```bash
+rustc --check-cfg `values(name, "value1", "value2", ... "valueN")'
+```
+
+where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal
+string. `name` specifies the name of the condition, such as `feature` or `target_os`.
+
+When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]`
+attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]`
+and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the
+list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs`
+lint diagnostic. The default diagnostic level for this lint is `Warn`.
+
+To enable checking of values, but to provide an empty set of valid values, use this form:
+
+```bash
+rustc --check-cfg `values(name)`
+```
+
+The `--check-cfg values(...)` option can be repeated, both for the same condition name and for
+different names. If it is repeated for the same condition name, then the sets of values for that
+condition are merged together.
+
+If `values()` is specified, then `rustc` will enable the checking of well-known values defined
+by itself. Note that it's necessary to specify the `values()` form to enable the checking of
+well known values, specifying the other forms doesn't implicitly enable it.
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 29912b95703..38935b7d1bb 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -10,7 +10,7 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.12", default-features = false, features = ["config"] }
 itertools = "0.10.1"
-minifier = "0.2.2"
+minifier = "0.2.3"
 once_cell = "1.10.0"
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3e6066c78fb..9066061f1a2 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -262,6 +262,7 @@ pub(crate) fn create_config(
         locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
         lint_caps,
         parse_sess_created: None,
+        hash_untracked_state: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
         override_queries: Some(|_sess, providers| {
             // We do not register late module lints, so this only runs `MissingDoc`.
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 741d329fb19..db69cf5752d 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -104,6 +104,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
         lint_caps,
         parse_sess_created: None,
+        hash_untracked_state: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
         override_queries: None,
         make_codegen_backend: None,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 6fa6fdc7606cfa664f9bee2fb33ee2ed904f4e8
+Subproject 8eb8acbb116e7923ea2ce33a50109933ed5ab37
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 14877385646..5134cf66050 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -701,7 +701,7 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
 
 fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
     if let Some(parent) = get_parent_expr(cx, e)
-        && parent.span.ctxt() == e.span.ctxt()
+        && parent.span.eq_ctxt(e.span)
     {
         match parent.kind {
             ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 6197b5b19eb..70a467dde61 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
                 },
             ],
             _,
-        ) if key_span.ctxt() == expr.span.ctxt() => {
+        ) if key_span.eq_ctxt(expr.span) => {
             let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
             let expr = ContainsExpr {
                 negated,
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index d03480c2108..4ebf0e9667d 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
         for element in array {
             if_chain! {
                 if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
-                if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt();
+                if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span);
                 let space_span = lhs.span.between(op.span);
                 if let Some(space_snippet) = snippet_opt(cx, space_span);
                 let lint_span = lhs.span.with_lo(lhs.span.hi());
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 4e9d77ea156..79d728a021c 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped {
             if !in_external_macro(cx.tcx.sess, local.span);
             if let Some(ty) = local.ty; // Ensure that it has a type defined
             if let TyKind::Infer = &ty.kind; // that type is '_'
-            if local.span.ctxt() == ty.span.ctxt();
+            if local.span.eq_ctxt(ty.span);
             then {
                 // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
                 // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 2117308cd40..86bbdb4ea19 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -59,7 +59,7 @@ impl<'tcx> QuestionMark {
             let Some(init) = local.init &&
             local.els.is_none() &&
             local.ty.is_none() &&
-            init.span.ctxt() == stmt.span.ctxt() &&
+            init.span.eq_ctxt(stmt.span) &&
             let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
         {
             match if_let_or_match {
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 33a052c41a3..29b935fb61a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -57,7 +57,7 @@ fn check_arm<'tcx>(
                 }
             },
         };
-        if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt();
+        if outer_pat.span.eq_ctxt(inner_scrutinee.span);
         // match expression must be a local binding
         // match <local> { .. }
         if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee));
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 6b611f567ae..781ee138c76 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -119,7 +119,7 @@ where
     // it's being passed by value.
     let scrutinee = peel_hir_expr_refs(scrutinee).0;
     let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
-    let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
+    let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX {
         format!("({scrutinee_str})")
     } else {
         scrutinee_str.into()
@@ -130,7 +130,7 @@ where
         if_chain! {
             if !some_expr.needs_unsafe_block;
             if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
-            if func.span.ctxt() == some_expr.expr.span.ctxt();
+            if func.span.eq_ctxt(some_expr.expr.span);
             then {
                 snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index 5464e455dea..e70a1bc9879 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
         // lint, with note if neither arg is > 1 line and both map() and
         // unwrap_or_else() have the same span
         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
-        let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt();
+        let same_span = map_arg.span.eq_ctxt(unwrap_arg.span);
         if same_span && !multiline {
             let var_snippet = snippet(cx, recv.span, "..");
             span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 7b0f7eaf1f0..0e834fb3ac7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind;
         if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
         if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind;
-        if expr.span.ctxt() == inner_expr.span.ctxt();
+        if expr.span.eq_ctxt(inner_expr.span);
         let expr_ty = cx.typeck_results().expr_ty(expr);
         let inner_ty = cx.typeck_results().expr_ty(inner_expr);
         if expr_ty == inner_ty;
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index d47728f190a..e94e4589966 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                         || (path.ident.name == sym!(set_mode)
                             && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()));
                     if let ExprKind::Lit(_) = param.kind;
-                    if param.span.ctxt() == expr.span.ctxt();
+                    if param.span.eq_ctxt(expr.span);
 
                     then {
                         let Some(snip) = snippet_opt(cx, param.span) else {
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                     if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
                     if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
                     if let ExprKind::Lit(_) = param.kind;
-                    if param.span.ctxt() == expr.span.ctxt();
+                    if param.span.eq_ctxt(expr.span);
                     if let Some(snip) = snippet_opt(cx, param.span);
                     if !snip.starts_with("0o");
                     then {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 534b2762ba7..8193057a6eb 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
             let Some(body_expr) = desugar_async_block(cx, expr) &&
             let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
             // The await prefix must not come from a macro as its content could change in the future.
-            expr.span.ctxt() == body_expr.span.ctxt() &&
+            expr.span.eq_ctxt(body_expr.span) &&
             // An async block does not have immediate side-effects from a `.await` point-of-view.
             (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
             let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index db870ec4c5b..12da29f1108 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf {
         if_chain! {
             if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
             if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
-            if deref_target.span.ctxt() == e.span.ctxt();
+            if deref_target.span.eq_ctxt(e.span);
             if !addrof_target.span.from_expansion();
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 8e156b8829b..39cd289b67a 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -33,7 +33,7 @@ impl LateLintPass<'_> for ConfusingXorAndPow {
         if !in_external_macro(cx.sess(), expr.span)
             && let ExprKind::Binary(op, left, right) = &expr.kind
             && op.node == BinOpKind::BitXor
-            && left.span.ctxt() == right.span.ctxt()
+            && left.span.eq_ctxt(right.span)
             && let ExprKind::Lit(lit_left) = &left.kind
             && let ExprKind::Lit(lit_right) = &right.kind
             && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..))
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index eaf590f6ad7..46ce4ffdce5 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -245,7 +245,7 @@ impl<'a> PanicExpn<'a> {
             return None;
         };
         let result = match name {
-            "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
+            "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty,
             "panic" | "panic_str" => Self::Str(arg),
             "panic_display" | "panic_cold_display" => {
                 let ExprKind::AddrOf(_, _, e) = &arg.kind else {
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index c212e8aafe1..9e852b0645a 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -23,4 +23,4 @@ glob = "0.3"
 tempfile = "3.5"
 derive_builder = "0.12"
 clap = { version = "4", features = ["derive"] }
-tabled = "0.13"
+tabled = { version = "0.13", default-features = false, features = ["std"] }
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index af1bc05ddb2..8f6626f6296 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -249,12 +249,17 @@ async function main(argv) {
         console.log("`--no-headless` option is active, disabling concurrency for running tests.");
     }
 
-    console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
-
     if (opts["jobs"] < 1) {
+        const len = files.length;
+        console.log(
+            `Running ${len} rustdoc-gui (UNBOUNDED concurrency; use "-j#" for a limit) ...`,
+        );
         process.setMaxListeners(files.length + 1);
     } else if (headless) {
+        console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
         process.setMaxListeners(opts["jobs"] + 1);
+    } else {
+        console.log(`Running ${files.length} rustdoc-gui ...`);
     }
 
     // We catch this "event" to display a nicer message in case of unexpected exit (because of a
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index fdc411c8925..3e60915c224 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -30,8 +30,8 @@ fn is_close_bracket(c: char) -> bool {
 }
 
 // Don't let tidy check this here :D
-const START_COMMENT: &str = concat!("// tidy-alphabetical", "-start");
-const END_COMMENT: &str = "// tidy-alphabetical-end";
+const START_COMMENT: &str = concat!("tidy-alphabetical", "-start");
+const END_COMMENT: &str = "tidy-alphabetical-end";
 
 fn check_section<'a>(
     file: impl Display,
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index d900c04c124..8e791a7dc69 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -30,7 +30,7 @@ const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end";
 
 #[derive(Debug, PartialEq, Clone)]
 pub enum Status {
-    Stable,
+    Accepted,
     Removed,
     Unstable,
 }
@@ -38,7 +38,7 @@ pub enum Status {
 impl fmt::Display for Status {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let as_str = match *self {
-            Status::Stable => "stable",
+            Status::Accepted => "accepted",
             Status::Unstable => "unstable",
             Status::Removed => "removed",
         };
@@ -279,9 +279,9 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
 
 pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features {
     let mut features = Features::new();
-    collect_lang_features_in(&mut features, base_compiler_path, "active.rs", bad);
     collect_lang_features_in(&mut features, base_compiler_path, "accepted.rs", bad);
     collect_lang_features_in(&mut features, base_compiler_path, "removed.rs", bad);
+    collect_lang_features_in(&mut features, base_compiler_path, "unstable.rs", bad);
     features
 }
 
@@ -336,11 +336,11 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
 
         let mut parts = line.split(',');
         let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) {
-            Some("active") => Status::Unstable,
+            Some("unstable") => Status::Unstable,
             Some("incomplete") => Status::Unstable,
             Some("internal") => Status::Unstable,
             Some("removed") => Status::Removed,
-            Some("accepted") => Status::Stable,
+            Some("accepted") => Status::Accepted,
             _ => continue,
         };
         let name = parts.next().unwrap().trim();
@@ -449,7 +449,7 @@ fn get_and_check_lib_features(
         Ok((name, f)) => {
             let mut check_features = |f: &Feature, list: &Features, display: &str| {
                 if let Some(ref s) = list.get(name) {
-                    if f.tracking_issue != s.tracking_issue && f.level != Status::Stable {
+                    if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted {
                         tidy_error!(
                             bad,
                             "{}:{}: `issue` \"{}\" mismatches the {} `issue` of \"{}\"",
@@ -566,7 +566,7 @@ fn map_lib_features(
                 let level = if line.contains("[unstable(") {
                     Status::Unstable
                 } else if line.contains("[stable(") {
-                    Status::Stable
+                    Status::Accepted
                 } else {
                     continue;
                 };
@@ -581,7 +581,7 @@ fn map_lib_features(
                     Some(Err(_err)) => {
                         err!("malformed stability attribute: can't parse `since` key");
                     }
-                    None if level == Status::Stable => {
+                    None if level == Status::Accepted => {
                         err!("malformed stability attribute: missing the `since` key");
                     }
                     None => None,
diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs
new file mode 100644
index 00000000000..8bc7b68a816
--- /dev/null
+++ b/tests/codegen/vec_pop_push_noop.rs
@@ -0,0 +1,24 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// CHECK-LABEL: @noop(
+pub fn noop(v: &mut Vec<u8>) {
+    // CHECK-NOT: reserve_for_push
+    // CHECK-NOT: call
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: reserve_for_push
+    // CHECK-NOT: call
+    // CHECK: ret
+    if let Some(x) = v.pop() {
+        v.push(x)
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_byte(
+pub fn push_byte(v: &mut Vec<u8>) {
+    // CHECK: call {{.*}}reserve_for_push
+    v.push(3);
+}
diff --git a/tests/pretty/format-args-str-escape.pp b/tests/pretty/format-args-str-escape.pp
new file mode 100644
index 00000000000..b84bc2303b7
--- /dev/null
+++ b/tests/pretty/format-args-str-escape.pp
@@ -0,0 +1,21 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:format-args-str-escape.pp
+
+fn main() {
+    { ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); };
+    { ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); };
+    {
+        ::std::io::_print(format_args!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m\n"));
+    };
+    {
+        ::std::io::_print(format_args!("{0}\n",
+                "\x1B[1mHello, world!\x1B[0m"));
+    };
+}
diff --git a/tests/pretty/format-args-str-escape.rs b/tests/pretty/format-args-str-escape.rs
new file mode 100644
index 00000000000..e596fcfd8bc
--- /dev/null
+++ b/tests/pretty/format-args-str-escape.rs
@@ -0,0 +1,10 @@
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:format-args-str-escape.pp
+
+fn main() {
+    println!("\x1B[1mHello, world!\x1B[0m");
+    println!("\u{1B}[1mHello, world!\u{1B}[0m");
+    println!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m");
+    println!("{}", "\x1B[1mHello, world!\x1B[0m");
+}
diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs
index 1c9d33dcc8e..7ee46e1520a 100644
--- a/tests/run-make-fulldeps/issue-19371/foo.rs
+++ b/tests/run-make-fulldeps/issue-19371/foo.rs
@@ -57,6 +57,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         locale_resources: &[],
         lint_caps: Default::default(),
         parse_sess_created: None,
+        hash_untracked_state: None,
         register_lints: None,
         override_queries: None,
         make_codegen_backend: None,
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
index 5c500ce6ce0..806b6d1253d 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
+++ b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
@@ -1,2 +1,2 @@
 // check-fail
-// compile-flags: --check-cfg=names()
+// compile-flags: --check-cfg=cfg()
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.rs b/tests/rustdoc-ui/check-cfg/check-cfg.rs
index fa8789ad3ed..96fa9e08dde 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg.rs
+++ b/tests/rustdoc-ui/check-cfg/check-cfg.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 /// uniz is nor a builtin nor pass as arguments so is unexpected
 #[cfg(uniz)]
diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.rs b/tests/rustdoc-ui/doctest/check-cfg-test.rs
index 49a801c3fb3..38cd59aa790 100644
--- a/tests/rustdoc-ui/doctest/check-cfg-test.rs
+++ b/tests/rustdoc-ui/doctest/check-cfg-test.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --test --nocapture --check-cfg=values(feature,"test") -Z unstable-options
+// compile-flags: --test --nocapture --check-cfg=cfg(feature,values("test")) -Z unstable-options
 // normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 // normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
diff --git a/tests/rustdoc/issue-31808.rs b/tests/rustdoc-ui/ice-assoc-const-for-primitive-31808.rs
index e55c5bd4f7c..6e4709403a4 100644
--- a/tests/rustdoc/issue-31808.rs
+++ b/tests/rustdoc-ui/ice-assoc-const-for-primitive-31808.rs
@@ -1,5 +1,10 @@
+// check-pass
+
 // Test that associated item impls on primitive types don't crash rustdoc
 
+// https://github.com/rust-lang/rust/issues/31808
+#![crate_name="issue_31808"]
+
 pub trait Foo {
     const BAR: usize;
     type BAZ;
diff --git a/tests/rustdoc-ui/issues/issue-96287.stderr b/tests/rustdoc-ui/issues/issue-96287.stderr
index 7722eb96028..c4809a311fc 100644
--- a/tests/rustdoc-ui/issues/issue-96287.stderr
+++ b/tests/rustdoc-ui/issues/issue-96287.stderr
@@ -2,7 +2,12 @@ error[E0220]: associated type `Assoc` not found for `V`
   --> $DIR/issue-96287.rs:7:33
    |
 LL | pub type Foo<V> = impl Trait<V::Assoc>;
-   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+   |                                 ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
+   |
+help: consider restricting type parameter `V`
+   |
+LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
+   |               ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/rustdoc/issue-29503.rs b/tests/rustdoc/blanket-impl-29503.rs
index 01ae4438500..d6a132e1c26 100644
--- a/tests/rustdoc/issue-29503.rs
+++ b/tests/rustdoc/blanket-impl-29503.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/29503
+#![crate_name="issue_29503"]
+
 use std::fmt;
 
 // @has issue_29503/trait.MyTrait.html
diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/const-rendering-macros-33302.rs
index a316f3ad99b..0f5cb921411 100644
--- a/tests/rustdoc/issue-33302.rs
+++ b/tests/rustdoc/const-rendering-macros-33302.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/33302
+#![crate_name="issue_33302"]
+
 // Ensure constant and array length values are not taken from source
 // code, which wreaks havoc with macros.
 
diff --git a/tests/rustdoc/issue-32890.rs b/tests/rustdoc/disambiguate-anchors-32890.rs
index 970954433ec..d88601d65d3 100644
--- a/tests/rustdoc/issue-32890.rs
+++ b/tests/rustdoc/disambiguate-anchors-32890.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/32890
+#![crate_name="issue_32890"]
+
 // @has issue_32890/struct.Foo.html
 pub struct Foo<T>(T);
 
diff --git a/tests/rustdoc/issue-29449.rs b/tests/rustdoc/disambiguate-anchors-header-29449.rs
index 0d829cf6fcf..38a4954fc13 100644
--- a/tests/rustdoc/issue-29449.rs
+++ b/tests/rustdoc/disambiguate-anchors-header-29449.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/29449
+#![crate_name="issue_29449"]
+
 // @has issue_29449/struct.Foo.html
 pub struct Foo;
 
diff --git a/tests/rustdoc/issue-33069.rs b/tests/rustdoc/doc-hidden-trait-implementors-33069.rs
index 0213a53cab5..35570668ea1 100644
--- a/tests/rustdoc/issue-33069.rs
+++ b/tests/rustdoc/doc-hidden-trait-implementors-33069.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/33069
+#![crate_name="issue_33069"]
+
 pub trait Bar {}
 
 #[doc(hidden)]
diff --git a/tests/rustdoc/issue-30252.rs b/tests/rustdoc/doctest-cfg-feature-30252.rs
index c3777362a66..ceb8076fe35 100644
--- a/tests/rustdoc/issue-30252.rs
+++ b/tests/rustdoc/doctest-cfg-feature-30252.rs
@@ -1,5 +1,8 @@
 // compile-flags:--test --cfg feature="bar"
 
+// https://github.com/rust-lang/rust/issues/30252
+#![crate_name="issue_30252"]
+
 /// ```rust
 /// assert_eq!(cfg!(feature = "bar"), true);
 /// ```
diff --git a/tests/rustdoc/issue-32556.rs b/tests/rustdoc/doctest-ignore-32556.rs
index e1cf1150997..99da9358bd6 100644
--- a/tests/rustdoc/issue-32556.rs
+++ b/tests/rustdoc/doctest-ignore-32556.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/32556
+#![crate_name="issue_32556"]
+
 /// Blah blah blah
 /// ```ignore (testing rustdoc's handling of ignore)
 /// bad_assert!();
diff --git a/tests/rustdoc/issue-34025.rs b/tests/rustdoc/hidden-extern-34025.rs
index 9b9f21cb316..81ccf2a0e5c 100644
--- a/tests/rustdoc/issue-34025.rs
+++ b/tests/rustdoc/hidden-extern-34025.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/34025
 #![crate_name = "foo"]
 
 // @!has 'foo/sys/index.html'
diff --git a/tests/rustdoc/issue-33592.rs b/tests/rustdoc/impl-type-parameter-33592.rs
index 7a128f0b897..77f53710e5e 100644
--- a/tests/rustdoc/issue-33592.rs
+++ b/tests/rustdoc/impl-type-parameter-33592.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/33592
 #![crate_name = "foo"]
 
 pub trait Foo<T> {}
diff --git a/tests/rustdoc/auxiliary/issue-29584.rs b/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs
index a9b8796c0fe..a9b8796c0fe 100644
--- a/tests/rustdoc/auxiliary/issue-29584.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs
diff --git a/tests/rustdoc/issue-29584.rs b/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs
index 4364a9649b5..b246e94e048 100644
--- a/tests/rustdoc/issue-29584.rs
+++ b/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs
@@ -1,6 +1,9 @@
 // aux-build:issue-29584.rs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/29584
+#![crate_name="issue_29584"]
+
 extern crate issue_29584;
 
 // @has issue_29584/struct.Foo.html
diff --git a/tests/rustdoc/issue-33178.rs b/tests/rustdoc/link-extern-crate-33178.rs
index ed643f5ae11..6a63712c4a7 100644
--- a/tests/rustdoc/issue-33178.rs
+++ b/tests/rustdoc/link-extern-crate-33178.rs
@@ -3,6 +3,9 @@
 // build-aux-docs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/33178
+#![crate_name="issue_33178"]
+
 // @has issue_33178/index.html
 // @has - '//a[@title="mod empty"][@href="../empty/index.html"]' empty
 pub extern crate empty;
diff --git a/tests/rustdoc/issue-30109.rs b/tests/rustdoc/link-extern-crate-item-30109.rs
index e9447538ad7..c83234352ad 100644
--- a/tests/rustdoc/issue-30109.rs
+++ b/tests/rustdoc/link-extern-crate-item-30109.rs
@@ -2,6 +2,9 @@
 // aux-build:issue-30109-1.rs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/30109
+#![crate_name="issue_30109"]
+
 pub mod quux {
     extern crate issue_30109_1 as bar;
     use self::bar::Bar;
diff --git a/tests/rustdoc/issue-33178-1.rs b/tests/rustdoc/link-extern-crate-title-33178.rs
index 4dc425346ab..d2f115a386e 100644
--- a/tests/rustdoc/issue-33178-1.rs
+++ b/tests/rustdoc/link-extern-crate-title-33178.rs
@@ -2,6 +2,9 @@
 // aux-build:variant-struct.rs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/33178
+#![crate_name="issue_33178_1"]
+
 // @has issue_33178_1/index.html
 // @!has - //a/@title empty
 pub extern crate empty;
diff --git a/tests/rustdoc/issue-32395.rs b/tests/rustdoc/render-enum-variant-structlike-32395.rs
index 5552300f9fe..2200d8ec637 100644
--- a/tests/rustdoc/issue-32395.rs
+++ b/tests/rustdoc/render-enum-variant-structlike-32395.rs
@@ -2,6 +2,9 @@
 // build-aux-docs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/32395
+#![crate_name="issue_32395"]
+
 // @has variant_struct/enum.Foo.html
 // @!hasraw - 'pub qux'
 // @!hasraw - 'pub(crate) qux'
diff --git a/tests/rustdoc/issue-34274.rs b/tests/rustdoc/src-links-inlined-34274.rs
index ce5be84a549..a3c9bf7e45c 100644
--- a/tests/rustdoc/issue-34274.rs
+++ b/tests/rustdoc/src-links-inlined-34274.rs
@@ -2,6 +2,7 @@
 // build-aux-docs
 // ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/34274
 #![crate_name = "foo"]
 
 extern crate issue_34274;
diff --git a/tests/rustdoc/issue-32374.rs b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs
index 985bf03a121..d282dea907e 100644
--- a/tests/rustdoc/issue-32374.rs
+++ b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs
@@ -1,6 +1,8 @@
+// https://github.com/rust-lang/rust/issues/32374
 #![feature(staged_api)]
 #![doc(issue_tracker_base_url = "https://issue_url/")]
 #![unstable(feature = "test", issue = "32374")]
+#![crate_name="issue_32374"]
 
 // @matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \
 //      'Deprecated'
diff --git a/tests/rustdoc/issue-31899.rs b/tests/rustdoc/summary-codeblock-31899.rs
index 3eee374465d..c1b33058c9e 100644
--- a/tests/rustdoc/issue-31899.rs
+++ b/tests/rustdoc/summary-codeblock-31899.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/31899
+#![crate_name="issue_31899"]
+
 // @has issue_31899/index.html
 // @hasraw - 'Make this line a bit longer.'
 // @!hasraw - 'rust rust-example-rendered'
diff --git a/tests/rustdoc/issue-30366.rs b/tests/rustdoc/summary-reference-link-30366.rs
index c6274a058b0..5b9854c5390 100644
--- a/tests/rustdoc/issue-30366.rs
+++ b/tests/rustdoc/summary-reference-link-30366.rs
@@ -1,5 +1,8 @@
 // @has issue_30366/index.html '//a/@href' 'http://www.rust-lang.org/'
 
+// https://github.com/rust-lang/rust/issues/30366
+#![crate_name="issue_30366"]
+
 /// Describe it. [Link somewhere][1].
 ///
 /// [1]: http://www.rust-lang.org/
diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/type-alias-impls-32077.rs
index 664b678093e..7bb763f86af 100644
--- a/tests/rustdoc/issue-32077-type-alias-impls.rs
+++ b/tests/rustdoc/type-alias-impls-32077.rs
@@ -1,5 +1,6 @@
 // Regression test for <https://github.com/rust-lang/rust/issues/32077>.
 
+// https://github.com/rust-lang/rust/issues/32077
 #![crate_name = "foo"]
 
 pub struct GenericStruct<T>(T);
diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
new file mode 100644
index 00000000000..39980ee7c67
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
@@ -0,0 +1,13 @@
+// Test the `rustc::span_use_eq_ctxt` internal lint
+// compile-flags: -Z unstable-options
+
+#![feature(rustc_private)]
+#![deny(rustc::span_use_eq_ctxt)]
+#![crate_type = "lib"]
+
+extern crate rustc_span;
+use rustc_span::Span;
+
+pub fn f(s: Span, t: Span) -> bool {
+    s.ctxt() == t.ctxt() //~ ERROR use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
+}
diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr
new file mode 100644
index 00000000000..b33f6212545
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr
@@ -0,0 +1,14 @@
+error: use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
+  --> $DIR/span_use_eq_ctxt.rs:12:5
+   |
+LL |     s.ctxt() == t.ctxt()
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/span_use_eq_ctxt.rs:5:9
+   |
+LL | #![deny(rustc::span_use_eq_ctxt)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/instance.rs
new file mode 100644
index 00000000000..fe06d9b5cc9
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/instance.rs
@@ -0,0 +1,91 @@
+// run-pass
+// Test that users are able to use stable mir APIs to retrieve monomorphized instances
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+
+extern crate rustc_middle;
+extern crate rustc_smir;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+
+use stable_mir::*;
+use rustc_smir::rustc_internal;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+    let items = stable_mir::all_local_items();
+
+    // Get all items and split generic vs monomorphic items.
+    let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| {
+        item.requires_monomorphization()
+    });
+    assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant");
+    assert_eq!(generic.len(), 2, "Expected 2 generic functions");
+
+    // For all monomorphic items, get the correspondent instances.
+    let instances = mono.iter().filter_map(|item| {
+        mir::mono::Instance::try_from(*item).ok()
+    }).collect::<Vec<mir::mono::Instance>>();
+    assert_eq!(instances.len(), mono.len());
+
+    // For all generic items, try_from should fail.
+    assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
+
+    ControlFlow::Continue(())
+}
+
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "instance_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    rustc_internal::StableMir::new(args, test_stable_mir).run().unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+    pub fn ty_param<T>(t: &T) -> T where T: Clone {{
+        t.clone()
+    }}
+
+    pub fn const_param<const LEN: usize>(a: [bool; LEN]) -> bool {{
+        LEN > 0 && a[0]
+    }}
+
+    pub fn monomorphic() {{
+    }}
+
+    pub mod foo {{
+        pub fn bar_mono(i: i32) -> i64 {{
+            i as i64
+        }}
+    }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/check-cfg/allow-at-crate-level.rs b/tests/ui/check-cfg/allow-at-crate-level.rs
index ce3383a2961..1629d2e0b67 100644
--- a/tests/ui/check-cfg/allow-at-crate-level.rs
+++ b/tests/ui/check-cfg/allow-at-crate-level.rs
@@ -1,7 +1,7 @@
 // This test check that #![allow(unexpected_cfgs)] works with --cfg
 //
 // check-pass
-// compile-flags: --cfg=unexpected --check-cfg=names() -Z unstable-options
+// compile-flags: --cfg=unexpected --check-cfg=cfg() -Z unstable-options
 
 #![allow(unexpected_cfgs)]
 
diff --git a/tests/ui/check-cfg/allow-macro-cfg.rs b/tests/ui/check-cfg/allow-macro-cfg.rs
index 8016a4d190c..ea26355aca8 100644
--- a/tests/ui/check-cfg/allow-macro-cfg.rs
+++ b/tests/ui/check-cfg/allow-macro-cfg.rs
@@ -1,7 +1,7 @@
 // This test check that local #[allow(unexpected_cfgs)] works
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 fn foo() {
diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs
index 6c869dc4202..29491e0b39e 100644
--- a/tests/ui/check-cfg/allow-same-level.rs
+++ b/tests/ui/check-cfg/allow-same-level.rs
@@ -1,7 +1,7 @@
 // This test check that #[allow(unexpected_cfgs)] doesn't work if put on the same level
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 #[cfg(FALSE)]
diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs
index d14b0eae5cc..df06f655d9a 100644
--- a/tests/ui/check-cfg/allow-top-level.rs
+++ b/tests/ui/check-cfg/allow-top-level.rs
@@ -1,7 +1,7 @@
 // This test check that a top-level #![allow(unexpected_cfgs)] works
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![allow(unexpected_cfgs)]
 
diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs
index 04340694d9c..bd5c97815f2 100644
--- a/tests/ui/check-cfg/allow-upper-level.rs
+++ b/tests/ui/check-cfg/allow-upper-level.rs
@@ -1,7 +1,7 @@
 // This test check that #[allow(unexpected_cfgs)] work if put on an upper level
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 mod aa {
diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs
index bff80740039..4f7168255cf 100644
--- a/tests/ui/check-cfg/compact-names.rs
+++ b/tests/ui/check-cfg/compact-names.rs
@@ -1,7 +1,7 @@
 // This test check that we correctly emit an warning for compact cfg
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![feature(cfg_target_compact)]
 
diff --git a/tests/ui/check-cfg/compact-values.rs b/tests/ui/check-cfg/compact-values.rs
index 1f17057840c..13c072fe920 100644
--- a/tests/ui/check-cfg/compact-values.rs
+++ b/tests/ui/check-cfg/compact-values.rs
@@ -1,7 +1,7 @@
 // This test check that we correctly emit an warning for compact cfg
 //
 // check-pass
-// compile-flags:--check-cfg=values() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![feature(cfg_target_compact)]
 
diff --git a/tests/ui/check-cfg/concat-values.rs b/tests/ui/check-cfg/concat-values.rs
new file mode 100644
index 00000000000..0f9178ce6a5
--- /dev/null
+++ b/tests/ui/check-cfg/concat-values.rs
@@ -0,0 +1,13 @@
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(my_cfg,values("foo")) --check-cfg=cfg(my_cfg,values("bar"))
+
+#[cfg(my_cfg)]
+//~^ WARNING unexpected `cfg` condition value
+fn my_cfg() {}
+
+#[cfg(my_cfg = "unk")]
+//~^ WARNING unexpected `cfg` condition value
+fn my_cfg() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr
new file mode 100644
index 00000000000..da2bd7d6ad9
--- /dev/null
+++ b/tests/ui/check-cfg/concat-values.stderr
@@ -0,0 +1,19 @@
+warning: unexpected `cfg` condition value: (none)
+  --> $DIR/concat-values.rs:5:7
+   |
+LL | #[cfg(my_cfg)]
+   |       ^^^^^^
+   |
+   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/concat-values.rs:9:7
+   |
+LL | #[cfg(my_cfg = "unk")]
+   |       ^^^^^^^^^^^^^^
+   |
+   = note: expected values for `my_cfg` are: `bar`, `foo`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
index 49e127d079a..45875bddc17 100644
--- a/tests/ui/check-cfg/diagnotics.rs
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options
+// compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values) -Z unstable-options
 
 #[cfg(featur)]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/empty-names.rs b/tests/ui/check-cfg/empty-names.rs
deleted file mode 100644
index 046ff0364e2..00000000000
--- a/tests/ui/check-cfg/empty-names.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check warning for unexpected cfg
-//
-// check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
-
-#[cfg(unknown_key = "value")]
-//~^ WARNING unexpected `cfg` condition name
-pub fn f() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/empty-values.rs b/tests/ui/check-cfg/empty-values.rs
deleted file mode 100644
index 9bda42e5d15..00000000000
--- a/tests/ui/check-cfg/empty-values.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check warning for unexpected cfg value
-//
-// check-pass
-// compile-flags: --check-cfg=values() -Z unstable-options
-
-#[cfg(test = "value")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn f() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
new file mode 100644
index 00000000000..53ccc0f4d31
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `empty_cfg` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr
new file mode 100644
index 00000000000..5e8b74054ce
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `empty_names_values` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
new file mode 100644
index 00000000000..7705a665eb7
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -0,0 +1,33 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/exhaustive-names-values.rs:20:7
+   |
+LL | #[cfg(feature = "unk")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `std`
+
+warning: unexpected condition value `` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
new file mode 100644
index 00000000000..f0224a2e33c
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -0,0 +1,33 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/exhaustive-names-values.rs:20:7
+   |
+LL | #[cfg(feature = "unk")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `std`
+
+warning: unexpected `full` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs
new file mode 100644
index 00000000000..f553d93cae2
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.rs
@@ -0,0 +1,34 @@
+// Check warning for unexpected cfg in the code and in the CLI
+// arguments (here the revision cfg).
+//
+// check-pass
+// revisions: empty_names_values empty_cfg feature full
+// compile-flags: -Z unstable-options
+// [empty_names_values]compile-flags: --check-cfg=names() --check-cfg=values()
+// [empty_cfg]compile-flags: --check-cfg=cfg()
+// [feature]compile-flags: --check-cfg=cfg(feature,values("std"))
+// [full]compile-flags: --check-cfg=cfg(feature,values("std")) --check-cfg=cfg()
+
+#[cfg(unknown_key = "value")]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+#[cfg(test = "value")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+#[cfg(feature = "unk")]
+//[feature]~^ WARNING unexpected `cfg` condition value
+//[full]~^^ WARNING unexpected `cfg` condition value
+pub fn feat() {}
+
+#[cfg(feature = "std")]
+pub fn feat() {}
+
+#[cfg(windows)]
+pub fn win() {}
+
+#[cfg(unix)]
+pub fn unix() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/empty-names.stderr b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr
index 9bba852c6de..6190ff71464 100644
--- a/tests/ui/check-cfg/empty-names.stderr
+++ b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/empty-names.rs:6:7
+  --> $DIR/exhaustive-names.rs:8:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,9 @@ LL | #[cfg(unknown_key = "value")]
    = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
-warning: 1 warning emitted
+warning: unexpected `empty_names` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
 
diff --git a/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr
new file mode 100644
index 00000000000..f338434cd29
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr
@@ -0,0 +1,15 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names.rs:8:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `exhaustive_names` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names.rs b/tests/ui/check-cfg/exhaustive-names.rs
new file mode 100644
index 00000000000..b86a7f84eb4
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names.rs
@@ -0,0 +1,12 @@
+// Check warning for unexpected cfg
+//
+// check-pass
+// revisions: empty_names exhaustive_names
+// [empty_names]compile-flags: --check-cfg=names() -Z unstable-options
+// [exhaustive_names]compile-flags: --check-cfg=cfg() -Z unstable-options
+
+#[cfg(unknown_key = "value")]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
new file mode 100644
index 00000000000..999b2702849
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
@@ -0,0 +1,17 @@
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-values.rs:9:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `empty_cfg` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
index 932651c5bfe..77ddc35100a 100644
--- a/tests/ui/check-cfg/empty-values.stderr
+++ b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/empty-values.rs:6:7
+  --> $DIR/exhaustive-values.rs:9:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
diff --git a/tests/ui/check-cfg/exhaustive-values.rs b/tests/ui/check-cfg/exhaustive-values.rs
new file mode 100644
index 00000000000..8a1689ba86b
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.rs
@@ -0,0 +1,13 @@
+// Check warning for unexpected cfg value
+//
+// check-pass
+// revisions: empty_values empty_cfg without_names
+// [empty_values]compile-flags: --check-cfg=values() -Z unstable-options
+// [empty_cfg]compile-flags: --check-cfg=cfg() -Z unstable-options
+// [without_names]compile-flags: --check-cfg=cfg(any()) -Z unstable-options
+
+#[cfg(test = "value")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-values.without_names.stderr b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
new file mode 100644
index 00000000000..77ddc35100a
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-values.rs:9:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
index 850924d993a..925664bb3fc 100644
--- a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
+++ b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
@@ -1,2 +1,2 @@
-error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
+error: invalid `--check-cfg` argument: `anything_else(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
 
diff --git a/tests/ui/check-cfg/invalid-arguments.giberich.stderr b/tests/ui/check-cfg/invalid-arguments.giberich.stderr
new file mode 100644
index 00000000000..d427033fcc2
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.giberich.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr
new file mode 100644
index 00000000000..0dc44d9ac76
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(bar))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr
new file mode 100644
index 00000000000..d0a1453e3c4
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values("bar",bar,"bar"))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr
new file mode 100644
index 00000000000..9239f8cce94
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(),values(any()))` (`values()` cannot be specified before the names)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr
new file mode 100644
index 00000000000..4c406143d08
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values("bar",any()))` (`values()` arguments cannot specify string literals and `any()` at the same time)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr
new file mode 100644
index 00000000000..6f1db1b13c3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(),any())` (`any()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr
new file mode 100644
index 00000000000..bce305b09c3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(),values())` (`values()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr
new file mode 100644
index 00000000000..748ce231af7
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(any(),any()))` (`any()` in `values()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr
new file mode 100644
index 00000000000..daf38147fe5
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(foo))` (`any()` must be empty)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr
new file mode 100644
index 00000000000..79f83e802ca
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(any(bar)))` (`any()` must be empty)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs
index 5090ce3e845..79bef89c957 100644
--- a/tests/ui/check-cfg/invalid-arguments.rs
+++ b/tests/ui/check-cfg/invalid-arguments.rs
@@ -2,9 +2,33 @@
 //
 // check-fail
 // revisions: anything_else names_simple_ident values_simple_ident values_string_literals
-// [anything_else]compile-flags: -Z unstable-options --check-cfg=anything_else(...)
-// [names_simple_ident]compile-flags: -Z unstable-options --check-cfg=names("NOT_IDENT")
-// [values_simple_ident]compile-flags: -Z unstable-options --check-cfg=values("NOT_IDENT")
-// [values_string_literals]compile-flags: -Z unstable-options --check-cfg=values(test,12)
+// revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values
+// revisions: multiple_values_any not_empty_any not_empty_values_any
+// revisions: values_any_missing_values values_any_before_ident ident_in_values_1
+// revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3
+// revisions: mixed_values_any mixed_any giberich
+//
+// compile-flags: -Z unstable-options
+// [anything_else]compile-flags: --check-cfg=anything_else(...)
+// [names_simple_ident]compile-flags: --check-cfg=names("NOT_IDENT")
+// [values_simple_ident]compile-flags: --check-cfg=values("NOT_IDENT")
+// [values_string_literals]compile-flags: --check-cfg=values(test,12)
+// [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT")
+// [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar)
+// [multiple_any]compile-flags: --check-cfg=cfg(any(),any())
+// [multiple_values]compile-flags: --check-cfg=cfg(foo,values(),values())
+// [multiple_values_any]compile-flags: --check-cfg=cfg(foo,values(any(),any()))
+// [not_empty_any]compile-flags: --check-cfg=cfg(any(foo))
+// [not_empty_values_any]compile-flags: --check-cfg=cfg(foo,values(any(bar)))
+// [values_any_missing_values]compile-flags: --check-cfg=cfg(foo,any())
+// [values_any_before_ident]compile-flags: --check-cfg=cfg(values(any()),foo)
+// [ident_in_values_1]compile-flags: --check-cfg=cfg(foo,values(bar))
+// [ident_in_values_2]compile-flags: --check-cfg=cfg(foo,values("bar",bar,"bar"))
+// [unknown_meta_item_1]compile-flags: --check-cfg=abc()
+// [unknown_meta_item_2]compile-flags: --check-cfg=cfg(foo,test())
+// [unknown_meta_item_3]compile-flags: --check-cfg=cfg(foo,values(test()))
+// [mixed_values_any]compile-flags: --check-cfg=cfg(foo,values("bar",any()))
+// [mixed_any]compile-flags: --check-cfg=cfg(any(),values(any()))
+// [giberich]compile-flags: --check-cfg=cfg(...)
 
 fn main() {}
diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr
new file mode 100644
index 00000000000..c6f6834ffd3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg("NOT_IDENT")` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr
new file mode 100644
index 00000000000..ab3dc86cd1a
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,"NOT_IDENT",bar)` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr
new file mode 100644
index 00000000000..c04b15ec265
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `abc()` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr
new file mode 100644
index 00000000000..cee65f9887b
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,test())` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr
new file mode 100644
index 00000000000..2441e2537b7
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(test()))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr
new file mode 100644
index 00000000000..fc93ec8fbdf
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(values(any()),foo)` (`values()` cannot be specified before the names)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr
new file mode 100644
index 00000000000..f41672fcbdb
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,any())` (`cfg(any())` can only be provided in isolation)
+
diff --git a/tests/ui/check-cfg/invalid-cfg-name.rs b/tests/ui/check-cfg/invalid-cfg-name.rs
deleted file mode 100644
index 8499d3d4448..00000000000
--- a/tests/ui/check-cfg/invalid-cfg-name.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Check warning for invalid configuration name
-//
-// edition:2018
-// check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
-
-#[cfg(widnows)]
-//~^ WARNING unexpected `cfg` condition name
-pub fn f() {}
-
-#[cfg(windows)]
-pub fn g() {}
-
-pub fn main() {}
diff --git a/tests/ui/check-cfg/invalid-cfg-value.rs b/tests/ui/check-cfg/invalid-cfg-value.rs
deleted file mode 100644
index 9e428d367fd..00000000000
--- a/tests/ui/check-cfg/invalid-cfg-value.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Check warning for invalid configuration value
-//
-// edition:2018
-// check-pass
-// compile-flags: --check-cfg=values(feature,"serde","full") --cfg=feature="rand" -Z unstable-options
-
-#[cfg(feature = "sedre")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn f() {}
-
-#[cfg(feature = "serde")]
-pub fn g() {}
-
-#[cfg(feature = "rand")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn h() {}
-
-pub fn main() {}
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.cfg.stderr
index 23da9f22a72..daa200440cc 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:11:7
+  --> $DIR/mix.rs:15:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
@@ -7,7 +7,7 @@ LL | #[cfg(widnows)]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
-  --> $DIR/mix.rs:15:7
+  --> $DIR/mix.rs:19:7
    |
 LL | #[cfg(feature)]
    |       ^^^^^^^- help: specify a config value: `= "foo"`
@@ -15,7 +15,7 @@ LL | #[cfg(feature)]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:22:7
+  --> $DIR/mix.rs:26:7
    |
 LL | #[cfg(feature = "bar")]
    |       ^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[cfg(feature = "bar")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:26:7
+  --> $DIR/mix.rs:30:7
    |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
@@ -31,12 +31,12 @@ LL | #[cfg(feature = "zebra")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `uu`
-  --> $DIR/mix.rs:30:12
+  --> $DIR/mix.rs:34:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
    |
-   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
 
 warning: unexpected condition value `bar` for condition name `feature`
    |
@@ -47,13 +47,13 @@ warning: unexpected `unknown_name` as condition name
    = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
 
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:39:10
+  --> $DIR/mix.rs:43:10
    |
 LL |     cfg!(widnows);
    |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:42:10
+  --> $DIR/mix.rs:46:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     cfg!(feature = "bar");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:44:10
+  --> $DIR/mix.rs:48:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
@@ -69,25 +69,25 @@ LL |     cfg!(feature = "zebra");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:46:10
+  --> $DIR/mix.rs:50:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:48:10
+  --> $DIR/mix.rs:52:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:50:14
+  --> $DIR/mix.rs:54:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `bad`
-  --> $DIR/mix.rs:52:14
+  --> $DIR/mix.rs:56:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
@@ -95,43 +95,43 @@ LL |     cfg!(any(feature = "bad", windows));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:54:23
+  --> $DIR/mix.rs:58:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:56:20
+  --> $DIR/mix.rs:60:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:58:14
+  --> $DIR/mix.rs:62:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:58:18
+  --> $DIR/mix.rs:62:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:61:14
+  --> $DIR/mix.rs:65:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:61:18
+  --> $DIR/mix.rs:65:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:64:20
+  --> $DIR/mix.rs:68:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     cfg!(any(unix, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:66:14
+  --> $DIR/mix.rs:70:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:66:19
+  --> $DIR/mix.rs:70:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
@@ -153,19 +153,19 @@ LL |     cfg!(any(xxx, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:69:14
+  --> $DIR/mix.rs:73:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:69:25
+  --> $DIR/mix.rs:73:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:14
+  --> $DIR/mix.rs:76:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:33
+  --> $DIR/mix.rs:76:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:52
+  --> $DIR/mix.rs:76:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/mix.names_values.stderr b/tests/ui/check-cfg/mix.names_values.stderr
new file mode 100644
index 00000000000..daa200440cc
--- /dev/null
+++ b/tests/ui/check-cfg/mix.names_values.stderr
@@ -0,0 +1,192 @@
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/mix.rs:15:7
+   |
+LL | #[cfg(widnows)]
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
+   |
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: (none)
+  --> $DIR/mix.rs:19:7
+   |
+LL | #[cfg(feature)]
+   |       ^^^^^^^- help: specify a config value: `= "foo"`
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/mix.rs:26:7
+   |
+LL | #[cfg(feature = "bar")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:30:7
+   |
+LL | #[cfg(feature = "zebra")]
+   |       ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `uu`
+  --> $DIR/mix.rs:34:12
+   |
+LL | #[cfg_attr(uu, test)]
+   |            ^^
+   |
+   = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+
+warning: unexpected condition value `bar` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: unexpected `unknown_name` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/mix.rs:43:10
+   |
+LL |     cfg!(widnows);
+   |          ^^^^^^^ help: there is a config with a similar name: `windows`
+
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/mix.rs:46:10
+   |
+LL |     cfg!(feature = "bar");
+   |          ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:48:10
+   |
+LL |     cfg!(feature = "zebra");
+   |          ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:50:10
+   |
+LL |     cfg!(xxx = "foo");
+   |          ^^^^^^^^^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:52:10
+   |
+LL |     cfg!(xxx);
+   |          ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:54:14
+   |
+LL |     cfg!(any(xxx, windows));
+   |              ^^^
+
+warning: unexpected `cfg` condition value: `bad`
+  --> $DIR/mix.rs:56:14
+   |
+LL |     cfg!(any(feature = "bad", windows));
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:58:23
+   |
+LL |     cfg!(any(windows, xxx));
+   |                       ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:60:20
+   |
+LL |     cfg!(all(unix, xxx));
+   |                    ^^^
+
+warning: unexpected `cfg` condition name: `aa`
+  --> $DIR/mix.rs:62:14
+   |
+LL |     cfg!(all(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name: `bb`
+  --> $DIR/mix.rs:62:18
+   |
+LL |     cfg!(all(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition name: `aa`
+  --> $DIR/mix.rs:65:14
+   |
+LL |     cfg!(any(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name: `bb`
+  --> $DIR/mix.rs:65:18
+   |
+LL |     cfg!(any(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:68:20
+   |
+LL |     cfg!(any(unix, feature = "zebra"));
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:70:14
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |              ^^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:70:19
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:73:14
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |              ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:73:25
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |                         ^^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:14
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |              ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:33
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                 ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:52
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: 28 warnings emitted
+
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index 9adf5c46e43..d7b3b4953b7 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -3,7 +3,11 @@
 // we correctly lint on the `cfg!` macro and `cfg_attr` attribute.
 //
 // check-pass
-// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" --cfg unknown_name -Z unstable-options
+// revisions: names_values cfg
+// compile-flags: --cfg feature="bar" --cfg unknown_name -Z unstable-options
+// compile-flags: --check-cfg=cfg(names_values,cfg)
+// [names_values]compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo")
+// [cfg]compile-flags: --check-cfg=cfg(feature,values("foo"))
 
 #[cfg(windows)]
 fn do_windows_stuff() {}
diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-expected-values.empty.stderr
index b05a569dd01..5d261b2a5e6 100644
--- a/tests/ui/check-cfg/no-values.stderr
+++ b/tests/ui/check-cfg/no-expected-values.empty.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-values.rs:6:7
+  --> $DIR/no-expected-values.rs:12:7
    |
 LL | #[cfg(feature = "foo")]
    |       ^^^^^^^--------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-values.rs:10:7
+  --> $DIR/no-expected-values.rs:16:7
    |
 LL | #[cfg(test = "foo")]
    |       ^^^^--------
diff --git a/tests/ui/check-cfg/no-expected-values.mixed.stderr b/tests/ui/check-cfg/no-expected-values.mixed.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.mixed.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-expected-values.rs b/tests/ui/check-cfg/no-expected-values.rs
new file mode 100644
index 00000000000..9e2a9f09aed
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.rs
@@ -0,0 +1,20 @@
+// Check that we detect unexpected value when none are allowed
+//
+// check-pass
+// revisions: values simple mixed empty
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(values,simple,mixed,empty)
+// [values]compile-flags: --check-cfg=values(test) --check-cfg=values(feature)
+// [simple]compile-flags: --check-cfg=cfg(test) --check-cfg=cfg(feature)
+// [mixed]compile-flags: --check-cfg=cfg(test,feature)
+// [empty]compile-flags: --check-cfg=cfg(test,feature,values())
+
+#[cfg(feature = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+#[cfg(test = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/no-expected-values.simple.stderr b/tests/ui/check-cfg/no-expected-values.simple.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.simple.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-expected-values.values.stderr b/tests/ui/check-cfg/no-expected-values.values.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.values.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-values.rs b/tests/ui/check-cfg/no-values.rs
deleted file mode 100644
index 8c80f56cb5a..00000000000
--- a/tests/ui/check-cfg/no-values.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Check that we detect unexpected value when none are allowed
-//
-// check-pass
-// compile-flags: --check-cfg=values(test) --check-cfg=values(feature) -Z unstable-options
-
-#[cfg(feature = "foo")]
-//~^ WARNING unexpected `cfg` condition value
-fn do_foo() {}
-
-#[cfg(test = "foo")]
-//~^ WARNING unexpected `cfg` condition value
-fn do_foo() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/stmt-no-ice.rs b/tests/ui/check-cfg/stmt-no-ice.rs
index cf76487ed46..383e830a1b2 100644
--- a/tests/ui/check-cfg/stmt-no-ice.rs
+++ b/tests/ui/check-cfg/stmt-no-ice.rs
@@ -1,7 +1,7 @@
 // This test checks that there is no ICE with this code
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags:--check-cfg=cfg() -Z unstable-options
 
 fn main() {
     #[cfg(crossbeam_loom)]
diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
index 8c3c72c9667..513f7ac7fd1 100644
--- a/tests/ui/check-cfg/invalid-cfg-name.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/invalid-cfg-name.rs:7:7
+  --> $DIR/unexpected-cfg-name.rs:9:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr
new file mode 100644
index 00000000000..513f7ac7fd1
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr
@@ -0,0 +1,10 @@
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/unexpected-cfg-name.rs:9:7
+   |
+LL | #[cfg(widnows)]
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
+   |
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.rs b/tests/ui/check-cfg/unexpected-cfg-name.rs
new file mode 100644
index 00000000000..15c3aa6e081
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-name.rs
@@ -0,0 +1,16 @@
+// Check warning for unexpected configuration name
+//
+// check-pass
+// revisions: names exhaustive
+// compile-flags: --check-cfg=cfg(names,exhaustive)
+// [names]compile-flags: --check-cfg=names() -Z unstable-options
+// [exhaustive]compile-flags: --check-cfg=cfg() -Z unstable-options
+
+#[cfg(widnows)]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+#[cfg(windows)]
+pub fn g() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr
index 947beac6ffd..2ed7f900557 100644
--- a/tests/ui/check-cfg/invalid-cfg-value.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `sedre`
-  --> $DIR/invalid-cfg-value.rs:7:7
+  --> $DIR/unexpected-cfg-value.rs:11:7
    |
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "sedre")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `rand`
-  --> $DIR/invalid-cfg-value.rs:14:7
+  --> $DIR/unexpected-cfg-value.rs:18:7
    |
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.rs b/tests/ui/check-cfg/unexpected-cfg-value.rs
new file mode 100644
index 00000000000..a84458071de
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-value.rs
@@ -0,0 +1,22 @@
+// Check warning for invalid configuration value in the code and
+// in the cli
+//
+// check-pass
+// revisions: values cfg
+// compile-flags: --cfg=feature="rand" -Z unstable-options
+// compile-flags: --check-cfg=cfg(values,cfg)
+// [values]compile-flags: --check-cfg=values(feature,"serde","full")
+// [cfg]compile-flags: --check-cfg=cfg(feature,values("serde","full"))
+
+#[cfg(feature = "sedre")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+#[cfg(feature = "serde")]
+pub fn g() {}
+
+#[cfg(feature = "rand")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn h() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr
new file mode 100644
index 00000000000..2ed7f900557
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition value: `sedre`
+  --> $DIR/unexpected-cfg-value.rs:11:7
+   |
+LL | #[cfg(feature = "sedre")]
+   |       ^^^^^^^^^^-------
+   |                 |
+   |                 help: there is a expected value with a similar name: `"serde"`
+   |
+   = note: expected values for `feature` are: `full`, `serde`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `rand`
+  --> $DIR/unexpected-cfg-value.rs:18:7
+   |
+LL | #[cfg(feature = "rand")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `full`, `serde`
+
+warning: unexpected condition value `rand` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/unknown-values.rs b/tests/ui/check-cfg/unknown-values.rs
new file mode 100644
index 00000000000..c082a2f25ac
--- /dev/null
+++ b/tests/ui/check-cfg/unknown-values.rs
@@ -0,0 +1,17 @@
+// Check that no warning is emitted for unknown cfg value
+//
+// check-pass
+// revisions: simple mixed with_values
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(simple,mixed,with_values)
+// [simple]compile-flags: --check-cfg=cfg(foo,values(any()))
+// [mixed]compile-flags: --check-cfg=cfg(foo) --check-cfg=cfg(foo,values(any()))
+// [with_values]compile-flags:--check-cfg=cfg(foo,values(any())) --check-cfg=cfg(foo,values("aa"))
+
+#[cfg(foo = "value")]
+pub fn f() {}
+
+#[cfg(foo)]
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/well-known-names.rs b/tests/ui/check-cfg/well-known-names.rs
index e57fb69a1e0..1dcb419b4a7 100644
--- a/tests/ui/check-cfg/well-known-names.rs
+++ b/tests/ui/check-cfg/well-known-names.rs
@@ -1,7 +1,7 @@
 // This test checks that we lint on non well known names and that we don't lint on well known names
 //
 // check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(target_oz = "linux")]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index a5d38a99eee..3001289b7e0 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -2,11 +2,13 @@ warning: unexpected `cfg` condition name: `target_oz`
   --> $DIR/well-known-names.rs:6:7
    |
 LL | #[cfg(target_oz = "linux")]
-   |       ---------^^^^^^^^^^
-   |       |
-   |       help: there is a config with a similar name: `target_os`
+   |       ^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
+help: there is a config with a similar name and value
+   |
+LL | #[cfg(target_os = "linux")]
+   |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `features`
   --> $DIR/well-known-names.rs:13:7
diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs
index 96375dc8d31..8b56c8729d8 100644
--- a/tests/ui/check-cfg/well-known-values.rs
+++ b/tests/ui/check-cfg/well-known-values.rs
@@ -2,7 +2,7 @@
 // values
 //
 // check-pass
-// compile-flags: --check-cfg=values() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(target_os = "linuz")]
 //~^ WARNING unexpected `cfg` condition value
diff --git a/tests/ui/impl-trait/async_scope_creep.rs b/tests/ui/impl-trait/async_scope_creep.rs
index 9a8831a299e..60975439a33 100644
--- a/tests/ui/impl-trait/async_scope_creep.rs
+++ b/tests/ui/impl-trait/async_scope_creep.rs
@@ -1,6 +1,6 @@
 #![feature(type_alias_impl_trait)]
 // edition:2021
-//[rpit] check-pass
+// check-pass
 // revisions: tait rpit
 
 struct Pending {}
@@ -23,7 +23,7 @@ impl Pending {
 
     #[cfg(tait)]
     fn read_fut(&mut self) -> OpeningReadFuture<'_> {
-        self.read() //[tait]~ ERROR: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+        self.read()
     }
 
     #[cfg(rpit)]
diff --git a/tests/ui/impl-trait/async_scope_creep.tait.stderr b/tests/ui/impl-trait/async_scope_creep.tait.stderr
deleted file mode 100644
index 165096a0574..00000000000
--- a/tests/ui/impl-trait/async_scope_creep.tait.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0284]: type annotations needed: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
-  --> $DIR/async_scope_creep.rs:26:9
-   |
-LL |         self.read()
-   |         ^^^^^^^^^^^ cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/impl-trait/in-trait/gat-outlives.rs b/tests/ui/impl-trait/in-trait/gat-outlives.rs
new file mode 100644
index 00000000000..83dd6cfce53
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/gat-outlives.rs
@@ -0,0 +1,17 @@
+// edition: 2021
+
+use std::future::Future;
+
+trait Trait {
+    type Gat<'a>;
+    //~^ ERROR missing required bound on `Gat`
+    async fn foo(&self) -> Self::Gat<'_>;
+}
+
+trait Trait2 {
+    type Gat<'a>;
+    //~^ ERROR missing required bound on `Gat`
+    async fn foo(&self) -> impl Future<Output = Self::Gat<'_>>;
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/gat-outlives.stderr b/tests/ui/impl-trait/in-trait/gat-outlives.stderr
new file mode 100644
index 00000000000..8ec4b0ab2ee
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/gat-outlives.stderr
@@ -0,0 +1,24 @@
+error: missing required bound on `Gat`
+  --> $DIR/gat-outlives.rs:6:5
+   |
+LL |     type Gat<'a>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: missing required bound on `Gat`
+  --> $DIR/gat-outlives.rs:12:5
+   |
+LL |     type Gat<'a>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.rs b/tests/ui/impl-trait/nested-return-type2-tait2.rs
index af8e0663054..b7fee1d91d1 100644
--- a/tests/ui/impl-trait/nested-return-type2-tait2.rs
+++ b/tests/ui/impl-trait/nested-return-type2-tait2.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Duh {}
@@ -17,6 +19,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 
 type Sendable = impl Send;
 type Traitable = impl Trait<Assoc = Sendable>;
+//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds
 
 // The `impl Send` here is then later compared against the inference var
 // created, causing the inference var to be set to `impl Send` instead of
@@ -25,7 +28,6 @@ type Traitable = impl Trait<Assoc = Sendable>;
 // type does not implement `Duh`, even if its hidden type does. So we error out.
 fn foo() -> Traitable {
     || 42
-    //~^ ERROR `Sendable: Duh` is not satisfied
 }
 
 fn main() {
diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.stderr b/tests/ui/impl-trait/nested-return-type2-tait2.stderr
index 125262b96e8..790e339c8b1 100644
--- a/tests/ui/impl-trait/nested-return-type2-tait2.stderr
+++ b/tests/ui/impl-trait/nested-return-type2-tait2.stderr
@@ -1,18 +1,13 @@
-error[E0277]: the trait bound `Sendable: Duh` is not satisfied
-  --> $DIR/nested-return-type2-tait2.rs:27:5
+warning: opaque type `Traitable` does not satisfy its associated type bounds
+  --> $DIR/nested-return-type2-tait2.rs:21:29
    |
-LL |     || 42
-   |     ^^^^^ the trait `Duh` is not implemented for `Sendable`
+LL |     type Assoc: Duh;
+   |                 --- this associated type bound is unsatisfied for `Sendable`
+...
+LL | type Traitable = impl Trait<Assoc = Sendable>;
+   |                             ^^^^^^^^^^^^^^^^
    |
-   = help: the trait `Duh` is implemented for `i32`
-note: required for `{closure@$DIR/nested-return-type2-tait2.rs:27:5: 27:7}` to implement `Trait`
-  --> $DIR/nested-return-type2-tait2.rs:14:31
-   |
-LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
-   |         ---                   ^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
+   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
 
-error: aborting due to previous error
+warning: 1 warning emitted
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.rs b/tests/ui/impl-trait/nested-return-type2-tait3.rs
index 74fd8a9dda0..eed5c271f88 100644
--- a/tests/ui/impl-trait/nested-return-type2-tait3.rs
+++ b/tests/ui/impl-trait/nested-return-type2-tait3.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Duh {}
@@ -16,6 +18,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 }
 
 type Traitable = impl Trait<Assoc = impl Send>;
+//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds
 
 // The `impl Send` here is then later compared against the inference var
 // created, causing the inference var to be set to `impl Send` instead of
@@ -24,7 +27,6 @@ type Traitable = impl Trait<Assoc = impl Send>;
 // type does not implement `Duh`, even if its hidden type does. So we error out.
 fn foo() -> Traitable {
     || 42
-    //~^ ERROR `impl Send: Duh` is not satisfied
 }
 
 fn main() {
diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.stderr b/tests/ui/impl-trait/nested-return-type2-tait3.stderr
index c2332b6e4bd..72aa51a23f4 100644
--- a/tests/ui/impl-trait/nested-return-type2-tait3.stderr
+++ b/tests/ui/impl-trait/nested-return-type2-tait3.stderr
@@ -1,18 +1,17 @@
-error[E0277]: the trait bound `impl Send: Duh` is not satisfied
-  --> $DIR/nested-return-type2-tait3.rs:26:5
+warning: opaque type `Traitable` does not satisfy its associated type bounds
+  --> $DIR/nested-return-type2-tait3.rs:20:29
    |
-LL |     || 42
-   |     ^^^^^ the trait `Duh` is not implemented for `impl Send`
+LL |     type Assoc: Duh;
+   |                 --- this associated type bound is unsatisfied for `impl Send`
+...
+LL | type Traitable = impl Trait<Assoc = impl Send>;
+   |                             ^^^^^^^^^^^^^^^^^
    |
-   = help: the trait `Duh` is implemented for `i32`
-note: required for `{closure@$DIR/nested-return-type2-tait3.rs:26:5: 26:7}` to implement `Trait`
-  --> $DIR/nested-return-type2-tait3.rs:14:31
+   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
+help: add this bound
    |
-LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
-   |         ---                   ^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
+LL | type Traitable = impl Trait<Assoc = impl Send + Duh>;
+   |                                               +++++
 
-error: aborting due to previous error
+warning: 1 warning emitted
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.fixed b/tests/ui/iterators/invalid-iterator-chain-fixable.fixed
new file mode 100644
index 00000000000..513b5bd13d8
--- /dev/null
+++ b/tests/ui/iterators/invalid-iterator-chain-fixable.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone {
+    let i = i.map(|x| x.clone());
+    i.collect() //~ ERROR E0277
+}
+
+fn main() {
+    let v = vec![(0, 0)];
+    let scores = v
+        .iter()
+        .map(|(a, b)| {
+            a + b
+        });
+    println!("{}", scores.sum::<i32>()); //~ ERROR E0277
+    println!(
+        "{}",
+        vec![0, 1]
+            .iter()
+            .map(|x| x * 2)
+            .map(|x| { x })
+            .map(|x| { x })
+            .sum::<i32>(), //~ ERROR E0277
+    );
+    println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>()); //~ ERROR E0277
+    let a = vec![0];
+    let b = a.into_iter();
+    let c = b.map(|x| x + 1);
+    let d = c.filter(|x| *x > 10 );
+    let e = d.map(|x| {
+        x + 1
+    });
+    let f = e.filter(|_| false);
+    let g: Vec<i32> = f.collect(); //~ ERROR E0277
+    println!("{g:?}");
+
+    let mut s = HashSet::new();
+    s.insert(1u8);
+    println!("{:?}", iter_to_vec(s.iter()));
+}
diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.rs b/tests/ui/iterators/invalid-iterator-chain-fixable.rs
new file mode 100644
index 00000000000..79b861702c7
--- /dev/null
+++ b/tests/ui/iterators/invalid-iterator-chain-fixable.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+    let i = i.map(|x| x.clone());
+    i.collect() //~ ERROR E0277
+}
+
+fn main() {
+    let v = vec![(0, 0)];
+    let scores = v
+        .iter()
+        .map(|(a, b)| {
+            a + b;
+        });
+    println!("{}", scores.sum::<i32>()); //~ ERROR E0277
+    println!(
+        "{}",
+        vec![0, 1]
+            .iter()
+            .map(|x| x * 2)
+            .map(|x| { x; })
+            .map(|x| { x })
+            .sum::<i32>(), //~ ERROR E0277
+    );
+    println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); //~ ERROR E0277
+    let a = vec![0];
+    let b = a.into_iter();
+    let c = b.map(|x| x + 1);
+    let d = c.filter(|x| *x > 10 );
+    let e = d.map(|x| {
+        x + 1;
+    });
+    let f = e.filter(|_| false);
+    let g: Vec<i32> = f.collect(); //~ ERROR E0277
+    println!("{g:?}");
+
+    let mut s = HashSet::new();
+    s.insert(1u8);
+    println!("{:?}", iter_to_vec(s.iter()));
+}
diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr
new file mode 100644
index 00000000000..1bfe765e78a
--- /dev/null
+++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr
@@ -0,0 +1,157 @@
+error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
+  --> $DIR/invalid-iterator-chain-fixable.rs:7:7
+   |
+LL |     let i = i.map(|x| x.clone());
+   |                         ------- this method call is cloning the reference `&X`, not `X` which doesn't implement `Clone`
+LL |     i.collect()
+   |       ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
+   |
+   = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
+   = help: the trait `FromIterator<X>` is implemented for `Vec<X>`
+   = help: for that trait implementation, expected `X`, found `&X`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-fixable.rs:5:26
+   |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+   |                          ^^^^^^^^^^^ `Iterator::Item` is `&X` here
+LL |     let i = i.map(|x| x.clone());
+   |               ------------------ `Iterator::Item` remains `&X` here
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider further restricting type parameter `X`
+   |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone {
+   |                                                 ++++++++++++++
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+  --> $DIR/invalid-iterator-chain-fixable.rs:17:33
+   |
+LL |     println!("{}", scores.sum::<i32>());
+   |                           ---   ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+   |                           |
+   |                           required by a bound introduced by this call
+   |
+   = help: the trait `Sum<()>` is not implemented for `i32`
+   = help: the following other types implement trait `Sum<A>`:
+             <i32 as Sum>
+             <i32 as Sum<&'a i32>>
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-fixable.rs:14:10
+   |
+LL |       let v = vec![(0, 0)];
+   |               ------------ this expression has type `Vec<({integer}, {integer})>`
+LL |       let scores = v
+LL |           .iter()
+   |            ------ `Iterator::Item` is `&({integer}, {integer})` here
+LL |           .map(|(a, b)| {
+   |  __________^
+LL | |             a + b;
+LL | |         });
+   | |__________^ `Iterator::Item` changed to `()` here
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -             a + b;
+LL +             a + b
+   |
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+  --> $DIR/invalid-iterator-chain-fixable.rs:25:20
+   |
+LL |             .sum::<i32>(),
+   |              ---   ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+   |              |
+   |              required by a bound introduced by this call
+   |
+   = help: the trait `Sum<()>` is not implemented for `i32`
+   = help: the following other types implement trait `Sum<A>`:
+             <i32 as Sum>
+             <i32 as Sum<&'a i32>>
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-fixable.rs:23:14
+   |
+LL |         vec![0, 1]
+   |         ---------- this expression has type `Vec<{integer}>`
+LL |             .iter()
+   |              ------ `Iterator::Item` is `&{integer}` here
+LL |             .map(|x| x * 2)
+   |              -------------- `Iterator::Item` changed to `{integer}` here
+LL |             .map(|x| { x; })
+   |              ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
+LL |             .map(|x| { x })
+   |              -------------- `Iterator::Item` remains `()` here
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -             .map(|x| { x; })
+LL +             .map(|x| { x })
+   |
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+  --> $DIR/invalid-iterator-chain-fixable.rs:27:60
+   |
+LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+   |                                                      ---   ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+   |                                                      |
+   |                                                      required by a bound introduced by this call
+   |
+   = help: the trait `Sum<()>` is not implemented for `i32`
+   = help: the following other types implement trait `Sum<A>`:
+             <i32 as Sum>
+             <i32 as Sum<&'a i32>>
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-fixable.rs:27:38
+   |
+LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+   |                    ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
+   |                    |          |
+   |                    |          `Iterator::Item` is `&{integer}` here
+   |                    this expression has type `Vec<{integer}>`
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+LL +     println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>());
+   |
+
+error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()`
+  --> $DIR/invalid-iterator-chain-fixable.rs:36:25
+   |
+LL |     let g: Vec<i32> = f.collect();
+   |                         ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
+   |
+   = help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
+   = help: the trait `FromIterator<i32>` is implemented for `Vec<i32>`
+   = help: for that trait implementation, expected `i32`, found `()`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain-fixable.rs:32:15
+   |
+LL |       let a = vec![0];
+   |               ------- this expression has type `Vec<{integer}>`
+LL |       let b = a.into_iter();
+   |                 ----------- `Iterator::Item` is `{integer}` here
+LL |       let c = b.map(|x| x + 1);
+   |                 -------------- `Iterator::Item` remains `{integer}` here
+LL |       let d = c.filter(|x| *x > 10 );
+   |                 -------------------- `Iterator::Item` remains `{integer}` here
+LL |       let e = d.map(|x| {
+   |  _______________^
+LL | |         x + 1;
+LL | |     });
+   | |______^ `Iterator::Item` changed to `()` here
+LL |       let f = e.filter(|_| false);
+   |                 ----------------- `Iterator::Item` remains `()` here
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -         x + 1;
+LL +         x + 1
+   |
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr
index 2601c9c0d69..4dc13086912 100644
--- a/tests/ui/iterators/invalid-iterator-chain.stderr
+++ b/tests/ui/iterators/invalid-iterator-chain.stderr
@@ -1,6 +1,8 @@
 error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
   --> $DIR/invalid-iterator-chain.rs:6:7
    |
+LL |     let i = i.map(|x| x.clone());
+   |                         ------- this method call is cloning the reference `&X`, not `X` which doesn't implement `Clone`
 LL |     i.collect()
    |       ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
    |
@@ -16,6 +18,10 @@ LL |     let i = i.map(|x| x.clone());
    |               ------------------ `Iterator::Item` remains `&X` here
 note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider further restricting type parameter `X`
+   |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone {
+   |                                                 ++++++++++++++
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
   --> $DIR/invalid-iterator-chain.rs:15:33
@@ -43,6 +49,11 @@ LL | |         });
    | |__________^ `Iterator::Item` changed to `()` here
 note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -             a + b;
+LL +             a + b
+   |
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
   --> $DIR/invalid-iterator-chain.rs:26:20
@@ -77,6 +88,11 @@ LL |             .map(|x| { x; })
    |              ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
 note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -             .map(|x| { x; })
+LL +             .map(|x| { x })
+   |
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64`
   --> $DIR/invalid-iterator-chain.rs:36:20
@@ -130,6 +146,11 @@ LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
    |                    this expression has type `Vec<{integer}>`
 note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+LL +     println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>());
+   |
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
   --> $DIR/invalid-iterator-chain.rs:39:46
@@ -182,6 +203,11 @@ LL |       let f = e.filter(|_| false);
    |                 ----------------- `Iterator::Item` remains `()` here
 note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider removing this semicolon
+   |
+LL -         x + 1;
+LL +         x + 1
+   |
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/resolve/issue-55673.fixed b/tests/ui/resolve/issue-55673.fixed
new file mode 100644
index 00000000000..261742a26cb
--- /dev/null
+++ b/tests/ui/resolve/issue-55673.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+#![allow(dead_code)]
+trait Foo {
+    type Bar;
+}
+
+fn foo<T: Foo>()
+where
+    T::Bar: std::fmt::Debug,
+    //~^ ERROR associated type `Baa` not found for `T`
+{
+}
+
+fn bar<T>()
+where
+    T::Bar: std::fmt::Debug, T: Foo
+    //~^ ERROR associated type `Baa` not found for `T`
+{
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-55673.rs b/tests/ui/resolve/issue-55673.rs
index 0436bd39742..6ac49be141c 100644
--- a/tests/ui/resolve/issue-55673.rs
+++ b/tests/ui/resolve/issue-55673.rs
@@ -1,3 +1,5 @@
+// run-rustfix
+#![allow(dead_code)]
 trait Foo {
     type Bar;
 }
@@ -9,4 +11,11 @@ where
 {
 }
 
+fn bar<T>()
+where
+    T::Baa: std::fmt::Debug,
+    //~^ ERROR associated type `Baa` not found for `T`
+{
+}
+
 fn main() {}
diff --git a/tests/ui/resolve/issue-55673.stderr b/tests/ui/resolve/issue-55673.stderr
index 39318f95905..ffc3252230a 100644
--- a/tests/ui/resolve/issue-55673.stderr
+++ b/tests/ui/resolve/issue-55673.stderr
@@ -1,9 +1,29 @@
 error[E0220]: associated type `Baa` not found for `T`
-  --> $DIR/issue-55673.rs:7:8
+  --> $DIR/issue-55673.rs:9:8
    |
 LL |     T::Baa: std::fmt::Debug,
    |        ^^^ there is a similarly named associated type `Bar` in the trait `Foo`
+   |
+help: change the associated type name to use `Bar` from `Foo`
+   |
+LL |     T::Bar: std::fmt::Debug,
+   |        ~~~
+
+error[E0220]: associated type `Baa` not found for `T`
+  --> $DIR/issue-55673.rs:16:8
+   |
+LL |     T::Baa: std::fmt::Debug,
+   |        ^^^ there is a similarly named associated type `Bar` in the trait `Foo`
+   |
+help: consider further restricting type parameter `T`
+   |
+LL |     T::Baa: std::fmt::Debug, T: Foo
+   |                            ~~~~~~~~
+help: and also change the associated type name
+   |
+LL |     T::Bar: std::fmt::Debug,
+   |        ~~~
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr
index ad11c090f12..6d436018bf4 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr
@@ -1,14 +1,12 @@
-error[E0277]: the trait bound `T: Foo` is not satisfied
-  --> $DIR/assoc-type-const-bound-usage.rs:12:6
+error[E0308]: mismatched types
+  --> $DIR/assoc-type-const-bound-usage.rs:12:5
    |
 LL |     <T as Foo>::Assoc::foo();
-   |      ^ the trait `Foo` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true`
    |
-help: consider further restricting this bound
-   |
-LL | const fn foo<T: ~const Foo + Foo>() {
-   |                            +++++
+   = note: expected constant `host`
+              found constant `true`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
new file mode 100644
index 00000000000..c38b4b3f1a2
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
@@ -0,0 +1,504 @@
+#![crate_type = "lib"]
+#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)]
+#![feature(fundamental)]
+#![feature(const_trait_impl, effects, const_mut_refs)]
+#![allow(internal_features)]
+#![no_std]
+#![no_core]
+
+// known-bug: #110395
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "add"]
+#[const_trait]
+trait Add<Rhs = Self> {
+    type Output;
+
+    fn add(self, rhs: Rhs) -> Self::Output;
+}
+
+// FIXME we shouldn't need to have to specify `Rhs`.
+impl const Add<i32> for i32 {
+    type Output = i32;
+    fn add(self, rhs: i32) -> i32 {
+        loop {}
+    }
+}
+
+fn foo() {
+    let x = 42_i32 + 43_i32;
+}
+
+const fn bar() {
+    let x = 42_i32 + 43_i32;
+}
+
+
+#[lang = "Try"]
+#[const_trait]
+trait Try: FromResidual {
+    type Output;
+    type Residual;
+
+    #[lang = "from_output"]
+    fn from_output(output: Self::Output) -> Self;
+
+    #[lang = "branch"]
+    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+// FIXME
+// #[const_trait]
+trait FromResidual<R = <Self as Try>::Residual> {
+    #[lang = "from_residual"]
+    fn from_residual(residual: R) -> Self;
+}
+
+enum ControlFlow<B, C = ()> {
+    #[lang = "Continue"]
+    Continue(C),
+    #[lang = "Break"]
+    Break(B),
+}
+
+#[const_trait]
+#[lang = "fn"]
+#[rustc_paren_sugar]
+trait Fn<Args: Tuple>: ~const FnMut<Args> {
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+#[const_trait]
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[const_trait]
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+trait FnOnce<Args: Tuple> {
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+struct ConstFnMutClosure<CapturedData, Function> {
+    data: CapturedData,
+    func: Function,
+}
+
+#[lang = "tuple_trait"]
+pub trait Tuple {}
+
+macro_rules! impl_fn_mut_tuple {
+    ($($var:ident)*) => {
+        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+            FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+        where
+            Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue,
+            Function: ~const Destruct,
+        {
+            type Output = ClosureReturnValue;
+
+            extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
+            self.call_mut(args)
+            }
+        }
+        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+            FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+        where
+            Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
+            Function: ~const Destruct,
+        {
+            extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
+                #[allow(non_snake_case)]
+                let ($($var),*) = &mut self.data;
+                (self.func)(($($var),*), args)
+            }
+        }
+    };
+}
+//impl_fn_mut_tuple!(A);
+//impl_fn_mut_tuple!(A B);
+//impl_fn_mut_tuple!(A B C);
+//impl_fn_mut_tuple!(A B C D);
+//impl_fn_mut_tuple!(A B C D E);
+
+#[lang = "receiver"]
+trait Receiver {}
+
+impl<T: ?Sized> Receiver for &T {}
+
+impl<T: ?Sized> Receiver for &mut T {}
+
+#[lang = "destruct"]
+#[const_trait]
+trait Destruct {}
+
+#[lang = "freeze"]
+unsafe auto trait Freeze {}
+
+#[lang = "drop"]
+#[const_trait]
+trait Drop {
+    fn drop(&mut self);
+}
+
+/*
+#[const_trait]
+trait Residual<O> {
+    type TryType: ~const Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>;
+}
+*/
+
+const fn size_of<T>() -> usize {
+    42
+}
+
+impl Copy for u8 {}
+
+impl usize {
+    #[rustc_allow_incoherent_impl]
+    const fn repeat_u8(x: u8) -> usize {
+        usize::from_ne_bytes([x; size_of::<usize>()])
+    }
+    #[rustc_allow_incoherent_impl]
+    const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
+        loop {}
+    }
+}
+
+#[rustc_do_not_const_check] // hooked by const-eval
+const fn panic_display() {
+    panic_fmt();
+}
+
+fn panic_fmt() {}
+
+#[lang = "index"]
+#[const_trait]
+trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+
+#[const_trait]
+unsafe trait SliceIndex<T: ?Sized> {
+    type Output: ?Sized;
+    fn index(self, slice: &T) -> &Self::Output;
+}
+
+impl<T, I> const Index<I> for [T]
+where
+    I: ~const SliceIndex<[T]>,
+{
+    type Output = I::Output;
+
+    #[inline]
+    fn index(&self, index: I) -> &I::Output {
+        index.index(self)
+    }
+}
+/* FIXME
+impl<T, I, const N: usize> const Index<I> for [T; N]
+where
+    [T]: ~const Index<I>,
+{
+    type Output = <[T] as Index<I>>::Output;
+
+    #[inline]
+    // FIXME: make `Self::Output` act like `<Self as ~const Index<I>>::Output`
+    fn index(&self, index: I) -> &<[T] as Index<I>>::Output {
+        Index::index(self as &[T], index)
+    }
+}
+*/
+
+#[lang = "unsize"]
+trait Unsize<T: ?Sized> {
+}
+
+#[lang = "coerce_unsized"]
+trait CoerceUnsized<T: ?Sized> {
+}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+
+
+#[lang = "deref"]
+// #[const_trait] FIXME
+trait Deref {
+    #[lang = "deref_target"]
+    type Target: ?Sized;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+
+impl<T: ?Sized> /* const */ Deref for &T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        *self
+    }
+}
+
+impl<T: ?Sized> /* const */ Deref for &mut T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        *self
+    }
+}
+
+enum Option<T> {
+    #[lang = "None"]
+    None,
+    #[lang = "Some"]
+    Some(T),
+}
+
+impl<T> Option<T> {
+    const fn as_ref(&self) -> Option<&T> {
+        match *self {
+            Some(ref x) => Some(x),
+            None => None,
+        }
+    }
+
+    const fn as_mut(&mut self) -> Option<&mut T> {
+        match *self {
+            Some(ref mut x) => Some(x),
+            None => None,
+        }
+    }
+}
+
+use Option::*;
+
+/*
+const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target>
+where
+    T: ~const Deref,
+{
+    match opt {
+        Option::Some(t) => Option::Some(t.deref()),
+        Option::None => Option::None,
+    }
+}
+*/
+
+#[const_trait]
+trait Into<T>: Sized {
+    fn into(self) -> T;
+}
+
+#[const_trait]
+trait From<T>: Sized {
+    fn from(value: T) -> Self;
+}
+
+impl<T, U> const Into<U> for T
+where
+    U: ~const From<T>,
+{
+    fn into(self) -> U {
+        U::from(self)
+    }
+}
+
+impl<T> const From<T> for T {
+    fn from(t: T) -> T {
+        t
+    }
+}
+
+enum Result<T, E> {
+    Ok(T),
+    Err(E),
+}
+use Result::*;
+
+fn from_str(s: &str) -> Result<bool, ()> {
+    match s {
+        "true" => Ok(true),
+        "false" => Ok(false),
+        _ => Err(()),
+    }
+}
+
+#[lang = "eq"]
+#[const_trait]
+trait PartialEq<Rhs: ?Sized = Self> {
+    fn eq(&self, other: &Rhs) -> bool;
+    fn ne(&self, other: &Rhs) -> bool {
+        !self.eq(other)
+    }
+}
+
+// FIXME(effects): again, this should not error without Rhs specified
+impl PartialEq<str> for str {
+    fn eq(&self, other: &str) -> bool {
+        loop {}
+    }
+}
+
+
+#[lang = "not"]
+#[const_trait]
+trait Not {
+    type Output;
+    fn not(self) -> Self::Output;
+}
+
+impl const Not for bool {
+    type Output = bool;
+    fn not(self) -> bool {
+        !self
+    }
+}
+
+impl Copy for bool {}
+impl<'a> Copy for &'a str {}
+
+#[lang = "pin"]
+#[fundamental]
+#[repr(transparent)]
+struct Pin<P> {
+    pointer: P,
+}
+
+impl<P> Pin<P> {
+    #[lang = "new_unchecked"]
+    const unsafe fn new_unchecked(pointer: P) -> Pin<P> {
+        Pin { pointer }
+    }
+}
+
+impl<'a, T: ?Sized> Pin<&'a T> {
+    const fn get_ref(self) -> &'a T {
+        self.pointer
+    }
+}
+
+
+impl<P: Deref> Pin<P> {
+    /* const */ fn as_ref(&self) -> Pin<&P::Target>
+    where
+        P: /* ~const */ Deref,
+    {
+        unsafe { Pin::new_unchecked(&*self.pointer) }
+    }
+}
+
+
+impl<'a, T: ?Sized> Pin<&'a mut T> {
+    const unsafe fn get_unchecked_mut(self) -> &'a mut T {
+        self.pointer
+    }
+}
+/* FIXME lol
+impl<T> Option<T> {
+    const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
+        match Pin::get_ref(self).as_ref() {
+            Some(x) => unsafe { Some(Pin::new_unchecked(x)) },
+            None => None,
+        }
+    }
+
+    const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
+        unsafe {
+            match Pin::get_unchecked_mut(self).as_mut() {
+                Some(x) => Some(Pin::new_unchecked(x)),
+                None => None,
+            }
+        }
+    }
+}
+*/
+
+impl<P: /* ~const */ Deref> /* const */ Deref for Pin<P> {
+    type Target = P::Target;
+    fn deref(&self) -> &P::Target {
+        Pin::get_ref(Pin::as_ref(self))
+    }
+}
+
+impl<T> /* const */ Deref for Option<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        loop {}
+    }
+}
+
+impl<P: Receiver> Receiver for Pin<P> {}
+
+impl<T: Clone> Clone for RefCell<T> {
+    fn clone(&self) -> RefCell<T> {
+        RefCell::new(self.borrow().clone())
+    }
+}
+
+struct RefCell<T: ?Sized> {
+    borrow: UnsafeCell<()>,
+    value: UnsafeCell<T>,
+}
+impl<T> RefCell<T> {
+    const fn new(value: T) -> RefCell<T> {
+        loop {}
+    }
+}
+impl<T: ?Sized> RefCell<T> {
+    fn borrow(&self) -> Ref<'_, T> {
+        loop {}
+    }
+}
+
+#[lang = "unsafe_cell"]
+#[repr(transparent)]
+struct UnsafeCell<T: ?Sized> {
+    value: T,
+}
+
+struct Ref<'b, T: ?Sized + 'b> {
+    value: *const T,
+    borrow: &'b UnsafeCell<()>,
+}
+
+impl<T: ?Sized> Deref for Ref<'_, T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        loop {}
+    }
+}
+
+#[lang = "clone"]
+#[rustc_trivial_field_reads]
+#[const_trait]
+trait Clone: Sized {
+    fn clone(&self) -> Self;
+    fn clone_from(&mut self, source: &Self)
+    where
+        Self: ~const Destruct,
+    {
+        *self = source.clone()
+    }
+}
+
+#[lang = "structural_peq"]
+trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+trait StructuralEq {}
+
+const fn drop<T: ~const Destruct>(_: T) {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
new file mode 100644
index 00000000000..02429374218
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
@@ -0,0 +1,32 @@
+error[E0369]: cannot add `i32` to `i32`
+  --> $DIR/minicore.rs:33:20
+   |
+LL |     let x = 42_i32 + 43_i32;
+   |             ------ ^ ------ i32
+   |             |
+   |             i32
+
+error[E0369]: cannot add `i32` to `i32`
+  --> $DIR/minicore.rs:37:20
+   |
+LL |     let x = 42_i32 + 43_i32;
+   |             ------ ^ ------ i32
+   |             |
+   |             i32
+
+error[E0600]: cannot apply unary operator `!` to type `bool`
+  --> $DIR/minicore.rs:343:9
+   |
+LL |         !self.eq(other)
+   |         ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
+
+error[E0600]: cannot apply unary operator `!` to type `bool`
+  --> $DIR/minicore.rs:365:9
+   |
+LL |         !self
+   |         ^^^^^ cannot apply unary operator `!`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0369, E0600.
+For more information about an error, try `rustc --explain E0369`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
new file mode 100644
index 00000000000..b30d7743edf
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
@@ -0,0 +1,11 @@
+// check-pass
+#![feature(const_trait_impl, effects)]
+
+pub trait Owo<X = <Self as Uwu>::T> {}
+
+#[const_trait]
+pub trait Uwu: Owo {
+    type T;
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
index c94563d3591..2a9647da782 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
@@ -1,35 +1,21 @@
-error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/trait-where-clause-const.rs:21:5
    |
 LL |     T::b();
-   |     ^ the trait `Bar` is not implemented for `T`
+   |     ^^^^^^ expected `host`, found `true`
    |
-note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause-const.rs:15:24
-   |
-LL |     fn b() where Self: ~const Bar;
-   |                        ^^^^^^^^^^ required by this bound in `Foo::b`
-help: consider further restricting this bound
-   |
-LL | const fn test1<T: ~const Foo + Bar + Bar>() {
-   |                                    +++++
+   = note: expected constant `host`
+              found constant `true`
 
-error[E0277]: the trait bound `T: ~const Bar` is not satisfied
-  --> $DIR/trait-where-clause-const.rs:23:12
+error[E0308]: mismatched types
+  --> $DIR/trait-where-clause-const.rs:23:5
    |
 LL |     T::c::<T>();
-   |            ^ the trait `Bar` is not implemented for `T`
-   |
-note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause-const.rs:16:13
-   |
-LL |     fn c<T: ~const Bar>();
-   |             ^^^^^^^^^^ required by this bound in `Foo::c`
-help: consider further restricting this bound
+   |     ^^^^^^^^^^^ expected `host`, found `true`
    |
-LL | const fn test1<T: ~const Foo + Bar + Bar>() {
-   |                                    +++++
+   = note: expected constant `host`
+              found constant `true`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/issue-59029-1.stderr b/tests/ui/traits/issue-59029-1.stderr
index 51354bcc545..5c47eefcd6c 100644
--- a/tests/ui/traits/issue-59029-1.stderr
+++ b/tests/ui/traits/issue-59029-1.stderr
@@ -2,13 +2,13 @@ error[E0220]: associated type `Res` not found for `Self`
   --> $DIR/issue-59029-1.rs:5:52
    |
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-   |                                                    ^^^ there is a similarly named associated type `Res` in the trait `Svc`
+   |                                                    ^^^ there is an associated type `Res` in the trait `Svc`
 
 error[E0220]: associated type `Res` not found for `Self`
   --> $DIR/issue-59029-1.rs:5:52
    |
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-   |                                                    ^^^ there is a similarly named associated type `Res` in the trait `Svc`
+   |                                                    ^^^ there is an associated type `Res` in the trait `Svc`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.fixed b/tests/ui/type-alias-impl-trait/not_well_formed.fixed
new file mode 100644
index 00000000000..d98e83ff6dd
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.fixed
@@ -0,0 +1,19 @@
+// run-rustfix
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+fn main() {}
+
+trait TraitWithAssoc {
+    type Assoc;
+}
+
+type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>; //~ associated type `Assoc` not found for `V`
+
+trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+    ()
+}
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.rs b/tests/ui/type-alias-impl-trait/not_well_formed.rs
index fbb7a4d58e4..18f173a693d 100644
--- a/tests/ui/type-alias-impl-trait/not_well_formed.rs
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 #![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
 
 fn main() {}
 
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.stderr b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
index c36b95f47e8..b267e6a7544 100644
--- a/tests/ui/type-alias-impl-trait/not_well_formed.stderr
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
@@ -1,8 +1,13 @@
 error[E0220]: associated type `Assoc` not found for `V`
-  --> $DIR/not_well_formed.rs:9:29
+  --> $DIR/not_well_formed.rs:11:29
    |
 LL | type Foo<V> = impl Trait<V::Assoc>;
-   |                             ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+   |                             ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
+   |
+help: consider restricting type parameter `V`
+   |
+LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
+   |           ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/triagebot.toml b/triagebot.toml
index 036a53b5e49..fbdc28787ff 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -414,6 +414,10 @@ message_on_add = """\
 Issue #{number} "{title}" has been added.
 """
 
+[no-merges]
+exclude_titles = ["Rollup of", "subtree update"]
+labels = ["has-merge-commits", "S-waiting-on-author"]
+
 [github-releases]
 format = "rustc"
 project-name = "Rust"
@@ -552,7 +556,7 @@ cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"]
 
 [mentions."compiler/rustc_smir"]
 message = "This PR changes Stable MIR"
-cc = ["@oli-obk", "@celinval", "@spastorino"]
+cc = ["@oli-obk", "@celinval", "@spastorino", "@ouz-a"]
 
 [mentions."compiler/stable_mir"]
 message = "This PR changes Stable MIR"