about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-07-17 05:06:45 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-07-17 05:06:45 +0000
commit52db0ce24fd71a9dbb9f7345a0685575b0aff652 (patch)
treefa3b3b1a2d1b775b7ace597a5b072305d66a0806
parent5946616c064330cb7418930dd20f317e5a4d5339 (diff)
parentfd2eb391d032181459773f3498c17b198513e0d0 (diff)
downloadrust-52db0ce24fd71a9dbb9f7345a0685575b0aff652.tar.gz
rust-52db0ce24fd71a9dbb9f7345a0685575b0aff652.zip
Merge from rustc
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/expand/mod.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs9
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs30
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs464
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg_old.rs247
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs102
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs8
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl6
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_select.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs77
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs20
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs261
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs6
-rw-r--r--compiler/rustc_const_eval/messages.ftl27
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs55
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs68
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0536.md16
-rw-r--r--compiler/rustc_expand/src/base.rs10
-rw-r--r--compiler/rustc_expand/src/config.rs52
-rw-r--r--compiler/rustc_expand/src/expand.rs38
-rw-r--r--compiler/rustc_hir/src/def.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_parse/src/parser/cfg_select.rs10
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs59
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs167
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs1
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs61
-rw-r--r--compiler/rustc_resolve/src/ident.rs19
-rw-r--r--compiler/rustc_resolve/src/imports.rs14
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/lib.rs113
-rw-r--r--compiler/rustc_resolve/src/macros.rs24
-rw-r--r--compiler/rustc_type_ir/src/walk.rs12
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec/mod.rs20
-rw-r--r--library/core/src/array/mod.rs10
-rw-r--r--library/core/src/macros/mod.rs16
-rw-r--r--library/core/src/num/wrapping.rs48
-rw-r--r--library/core/src/ops/index.rs6
-rw-r--r--library/core/src/ptr/const_ptr.rs5
-rw-r--r--library/core/src/ptr/mut_ptr.rs5
-rw-r--r--library/core/src/ptr/non_null.rs5
-rw-r--r--library/core/src/range.rs16
-rw-r--r--library/core/src/slice/index.rs45
-rw-r--r--library/core/src/slice/mod.rs20
-rw-r--r--library/core/src/str/mod.rs7
-rw-r--r--library/core/src/str/traits.rs37
-rw-r--r--library/coretests/tests/floats/f128.rs153
-rw-r--r--library/coretests/tests/floats/f16.rs143
-rw-r--r--library/coretests/tests/floats/f32.rs143
-rw-r--r--library/coretests/tests/floats/f64.rs142
-rw-r--r--library/coretests/tests/floats/mod.rs301
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/std/Cargo.toml3
-rw-r--r--library/std/src/sys/backtrace.rs100
-rw-r--r--library/std/src/thread/local.rs23
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--src/bootstrap/src/core/build_steps/mod.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs68
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs1
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs2
-rw-r--r--src/bootstrap/src/core/builder/mod.rs6
-rw-r--r--src/bootstrap/src/core/config/config.rs2
-rw-r--r--src/bootstrap/src/core/config/flags.rs8
-rw-r--r--src/bootstrap/src/core/sanity.rs1
-rw-r--r--src/bootstrap/src/lib.rs11
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs14
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/metrics.rs2
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md1
-rw-r--r--src/doc/rustc-dev-guide/src/building/quickstart.md3
-rw-r--r--src/doc/rustc-dev-guide/src/building/suggested.md17
-rw-r--r--src/doc/rustc-dev-guide/src/tests/suggest-tests.md59
-rw-r--r--src/doc/rustc/src/platform-support/netbsd.md3
-rw-r--r--src/etc/completions/x.fish37
-rw-r--r--src/etc/completions/x.ps144
-rw-r--r--src/etc/completions/x.py.fish37
-rw-r--r--src/etc/completions/x.py.ps144
-rw-r--r--src/etc/completions/x.py.sh191
-rw-r--r--src/etc/completions/x.py.zsh51
-rw-r--r--src/etc/completions/x.sh191
-rw-r--r--src/etc/completions/x.zsh51
-rw-r--r--src/librustdoc/clean/types.rs80
-rw-r--r--src/librustdoc/html/render/mod.rs6
-rw-r--r--src/librustdoc/html/render/print_item.rs3
-rw-r--r--src/librustdoc/json/conversions.rs99
-rw-r--r--src/rustdoc-json-types/lib.rs89
m---------src/tools/cargo0
-rw-r--r--src/tools/compiletest/src/directives.rs1
-rw-r--r--src/tools/miri/src/helpers.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs6
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr21
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr20
-rw-r--r--src/tools/remote-test-client/src/main.rs4
-rw-r--r--src/tools/run-make-support/src/symbols.rs184
-rw-r--r--src/tools/rustbook/Cargo.lock4
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/suggest-tests/Cargo.toml8
-rw-r--r--src/tools/suggest-tests/src/dynamic_suggestions.rs32
-rw-r--r--src/tools/suggest-tests/src/lib.rs96
-rw-r--r--src/tools/suggest-tests/src/main.rs40
-rw-r--r--src/tools/suggest-tests/src/static_suggestions.rs40
-rw-r--r--src/tools/suggest-tests/src/tests.rs21
-rw-r--r--src/tools/tidy/src/filenames.rs40
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs92
-rw-r--r--tests/run-make/compiletest-self-test/symbols-helpers/sample.rs13
-rw-r--r--tests/run-make/fmt-write-bloat/rmake.rs4
-rw-r--r--tests/run-make/used/rmake.rs4
-rw-r--r--tests/rustdoc-json/attrs/automatically_derived.rs2
-rw-r--r--tests/rustdoc-json/attrs/cold.rs2
-rw-r--r--tests/rustdoc-json/attrs/export_name_2021.rs2
-rw-r--r--tests/rustdoc-json/attrs/export_name_2024.rs4
-rw-r--r--tests/rustdoc-json/attrs/inline.rs6
-rw-r--r--tests/rustdoc-json/attrs/link_section_2021.rs3
-rw-r--r--tests/rustdoc-json/attrs/link_section_2024.rs3
-rw-r--r--tests/rustdoc-json/attrs/must_use.rs4
-rw-r--r--tests/rustdoc-json/attrs/no_mangle_2021.rs2
-rw-r--r--tests/rustdoc-json/attrs/no_mangle_2024.rs2
-rw-r--r--tests/rustdoc-json/attrs/non_exhaustive.rs6
-rw-r--r--tests/rustdoc-json/attrs/optimize.rs6
-rw-r--r--tests/rustdoc-json/attrs/repr_align.rs3
-rw-r--r--tests/rustdoc-json/attrs/repr_c.rs18
-rw-r--r--tests/rustdoc-json/attrs/repr_c_int_enum.rs11
-rw-r--r--tests/rustdoc-json/attrs/repr_combination.rs25
-rw-r--r--tests/rustdoc-json/attrs/repr_int_enum.rs15
-rw-r--r--tests/rustdoc-json/attrs/repr_packed.rs8
-rw-r--r--tests/rustdoc-json/attrs/target_feature.rs25
-rw-r--r--tests/rustdoc-json/enums/discriminant/struct.rs2
-rw-r--r--tests/rustdoc-json/enums/discriminant/tuple.rs2
-rw-r--r--tests/rustdoc-json/keyword_private.rs4
-rw-r--r--tests/rustdoc-json/visibility/doc_hidden_documented.rs6
-rw-r--r--tests/ui/attributes/malformed-attrs.rs2
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr7
-rw-r--r--tests/ui/cfg/cfg-target-compact-errors.rs12
-rw-r--r--tests/ui/cfg/cfg-target-compact-errors.stderr47
-rw-r--r--tests/ui/cfg/cfg-version/syntax.stderr4
-rw-r--r--tests/ui/cfg/diagnostics-cross-crate.stderr12
-rw-r--r--tests/ui/cfg/diagnostics-reexport-2.stderr20
-rw-r--r--tests/ui/cfg/diagnostics-reexport.stderr16
-rw-r--r--tests/ui/cfg/diagnostics-same-crate.stderr16
-rw-r--r--tests/ui/check-cfg/compact-names.rs4
-rw-r--r--tests/ui/check-cfg/compact-names.stderr11
-rw-r--r--tests/ui/codegen/duplicated-path-in-error.gnu.stderr (renamed from tests/ui/codegen/duplicated-path-in-error.stderr)0
-rw-r--r--tests/ui/codegen/duplicated-path-in-error.musl.stderr2
-rw-r--r--tests/ui/codegen/duplicated-path-in-error.rs7
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs25
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr63
-rw-r--r--tests/ui/consts/const-eval/ub-slice-get-unchecked.rs3
-rw-r--r--tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr12
-rw-r--r--tests/ui/consts/const_transmute_type_id3.rs5
-rw-r--r--tests/ui/consts/const_transmute_type_id3.stderr4
-rw-r--r--tests/ui/consts/const_transmute_type_id5.rs21
-rw-r--r--tests/ui/consts/const_transmute_type_id5.stderr15
-rw-r--r--tests/ui/consts/issue-94675.rs4
-rw-r--r--tests/ui/consts/issue-94675.stderr27
-rw-r--r--tests/ui/consts/offset_ub.rs14
-rw-r--r--tests/ui/consts/offset_ub.stderr6
-rw-r--r--tests/ui/issues/issue-50571.fixed10
-rw-r--r--tests/ui/issues/issue-50571.rs10
-rw-r--r--tests/ui/issues/issue-50571.stderr15
-rw-r--r--tests/ui/macros/cfg_select.rs7
-rw-r--r--tests/ui/macros/cfg_select.stderr14
-rw-r--r--tests/ui/macros/macro-outer-attributes.stderr14
-rw-r--r--tests/ui/parser/better-expected.rs2
-rw-r--r--tests/ui/parser/better-expected.stderr12
-rw-r--r--tests/ui/parser/issues/error-pattern-issue-50571.rs11
-rw-r--r--tests/ui/parser/issues/error-pattern-issue-50571.stderr28
-rw-r--r--tests/ui/parser/issues/issue-35813-postfix-after-cast.rs3
-rw-r--r--tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr38
-rw-r--r--tests/ui/parser/recover/array-type-no-semi.rs17
-rw-r--r--tests/ui/parser/recover/array-type-no-semi.stderr71
-rw-r--r--tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs7
-rw-r--r--tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr21
-rw-r--r--tests/ui/precondition-checks/vec-from-parts.rs15
-rw-r--r--tests/ui/precondition-checks/vec-from-raw-parts.rs29
-rw-r--r--tests/ui/precondition-checks/vec-set-len.rs11
-rw-r--r--tests/ui/proc-macro/meta-macro-hygiene.stdout6
-rw-r--r--tests/ui/proc-macro/nonterminal-token-hygiene.stdout6
-rw-r--r--tests/ui/span/E0536.rs7
-rw-r--r--tests/ui/span/E0536.stderr6
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs2
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr26
-rw-r--r--triagebot.toml1
226 files changed, 3053 insertions, 3111 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e92afc14c20..dc8ac539a3a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -182,6 +182,11 @@ jobs:
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
 
+      # Workaround for spurious ci failures after mingw install
+      # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775
+      - name: ensure home dir exists
+        run: mkdir -p ~
+
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
 
diff --git a/Cargo.lock b/Cargo.lock
index 51fd06972f2..b8a8d7b7d23 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5070,14 +5070,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "suggest-tests"
-version = "0.1.0"
-dependencies = [
- "build_helper",
- "glob",
-]
-
-[[package]]
 name = "syn"
 version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 6d3425f4115..67c7a9d67ed 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,7 +39,6 @@ members = [
   "src/tools/rustdoc-gui-test",
   "src/tools/rustdoc-themes",
   "src/tools/rustfmt",
-  "src/tools/suggest-tests",
   "src/tools/test-float-parse",
   "src/tools/tidy",
   "src/tools/tier-check",
diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs
index 323a8fab6d5..069bff67b97 100644
--- a/compiler/rustc_ast/src/expand/mod.rs
+++ b/compiler/rustc_ast/src/expand/mod.rs
@@ -1,24 +1,7 @@
 //! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
 
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::Ident;
-use rustc_span::def_id::DefId;
-
-use crate::MetaItem;
 
 pub mod allocator;
 pub mod autodiff_attrs;
 pub mod typetree;
-
-#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
-pub struct StrippedCfgItem<ModId = DefId> {
-    pub parent_module: ModId,
-    pub ident: Ident,
-    pub cfg: MetaItem,
-}
-
-impl<ModId> StrippedCfgItem<ModId> {
-    pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
-        StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg }
-    }
-}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 348fe2ee40a..1c96a375035 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -42,7 +42,7 @@ use std::sync::Arc;
 
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{self as ast, *};
-use rustc_attr_parsing::{AttributeParser, OmitDoc};
+use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -192,7 +192,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // interact with `gen`/`async gen` blocks
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
 
-            attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
+            attribute_parser: AttributeParser::new(
+                tcx.sess,
+                tcx.features(),
+                registered_tools,
+                Late,
+            ),
             delayed_lints: Vec::new(),
         }
     }
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 9b14ed88978..3dedeb1b372 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -3,7 +3,7 @@ use rustc_ast::token::CommentKind;
 use rustc_ast::{self as ast, AttrStyle};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Span, Symbol};
+use rustc_span::{Ident, Span, Symbol};
 use thin_vec::ThinVec;
 
 use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
@@ -69,6 +69,7 @@ pub enum ReprAttr {
     ReprAlign(Align),
 }
 pub use ReprAttr::*;
+use rustc_span::def_id::DefId;
 
 pub enum TransparencyError {
     UnknownTransparency(Symbol, Span),
@@ -140,6 +141,30 @@ pub enum UsedBy {
     Linker,
 }
 
+#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
+pub struct StrippedCfgItem<ModId = DefId> {
+    pub parent_module: ModId,
+    pub ident: Ident,
+    pub cfg: (CfgEntry, Span),
+}
+
+impl<ModId> StrippedCfgItem<ModId> {
+    pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
+        StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg }
+    }
+}
+
+#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum CfgEntry {
+    All(ThinVec<CfgEntry>, Span),
+    Any(ThinVec<CfgEntry>, Span),
+    Not(Box<CfgEntry>, Span),
+    Bool(bool, Span),
+    NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span },
+    Version(Option<RustcVersion>, Span),
+}
+
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -349,6 +374,9 @@ pub enum AttributeKind {
     /// Represents `#[path]`
     Path(Symbol, Span),
 
+    /// Represents `#[pointee]`
+    Pointee(Span),
+
     /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
     PubTransparent(Span),
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 494b570c86c..3e2dc0a15b2 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -57,6 +57,7 @@ impl AttributeKind {
             ParenSugar(..) => No,
             PassByValue(..) => Yes,
             Path(..) => No,
+            Pointee(..) => No,
             PubTransparent(..) => Yes,
             Repr { .. } => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index a8d9229cbc3..a56855b3bd3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -1,247 +1,291 @@
-use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
-use rustc_ast_pretty::pprust;
-use rustc_attr_data_structures::RustcVersion;
-use rustc_feature::{Features, GatedCfg, find_gated_cfg};
+use rustc_ast::{LitKind, NodeId};
+use rustc_attr_data_structures::{CfgEntry, RustcVersion};
+use rustc_feature::{AttributeTemplate, Features, template};
 use rustc_session::Session;
 use rustc_session::config::ExpectedValues;
+use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
-use rustc_session::lint::{BuiltinLintDiag, Lint};
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
 
-use crate::session_diagnostics::{self, UnsupportedLiteralReason};
-use crate::{fluent_generated, parse_version};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
+use crate::{
+    CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
+};
 
-/// Emitter of a builtin lint from `cfg_matches`.
-///
-/// Used to support emitting a lint (currently on check-cfg), either:
-///  - as an early buffered lint (in `rustc`)
-///  - or has a "normal" lint from HIR (in `rustdoc`)
-pub trait CfgMatchesLintEmitter {
-    fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag);
-}
+pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate");
 
-impl CfgMatchesLintEmitter for NodeId {
-    fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) {
-        sess.psess.buffer_lint(lint, sp, *self, diag);
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct Condition {
-    pub name: Symbol,
-    pub name_span: Span,
-    pub value: Option<Symbol>,
-    pub value_span: Option<Span>,
-    pub span: Span,
+pub fn parse_cfg_attr<'c, S: Stage>(
+    cx: &'c mut AcceptContext<'_, '_, S>,
+    args: &'c ArgParser<'_>,
+) -> Option<CfgEntry> {
+    let ArgParser::List(list) = args else {
+        cx.expected_list(cx.attr_span);
+        return None;
+    };
+    let Some(single) = list.single() else {
+        cx.expected_single_argument(list.span);
+        return None;
+    };
+    parse_cfg_entry(cx, single)
 }
 
-/// Tests if a cfg-pattern matches the cfg set
-pub fn cfg_matches(
-    cfg: &MetaItemInner,
-    sess: &Session,
-    lint_emitter: impl CfgMatchesLintEmitter,
-    features: Option<&Features>,
-) -> bool {
-    eval_condition(cfg, sess, features, &mut |cfg| {
-        try_gate_cfg(cfg.name, cfg.span, sess, features);
-        match sess.psess.check_config.expecteds.get(&cfg.name) {
-            Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
-                lint_emitter.emit_span_lint(
-                    sess,
-                    UNEXPECTED_CFGS,
-                    cfg.span,
-                    BuiltinLintDiag::UnexpectedCfgValue(
-                        (cfg.name, cfg.name_span),
-                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
-                    ),
-                );
+fn parse_cfg_entry<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    item: &MetaItemOrLitParser<'_>,
+) -> Option<CfgEntry> {
+    Some(match item {
+        MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() {
+            ArgParser::List(list) => match meta.path().word_sym() {
+                Some(sym::not) => {
+                    let Some(single) = list.single() else {
+                        cx.expected_single_argument(list.span);
+                        return None;
+                    };
+                    CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span)
+                }
+                Some(sym::any) => CfgEntry::Any(
+                    list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(),
+                    list.span,
+                ),
+                Some(sym::all) => CfgEntry::All(
+                    list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(),
+                    list.span,
+                ),
+                Some(sym::target) => parse_cfg_entry_target(cx, list, meta.span())?,
+                Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?,
+                _ => {
+                    cx.emit_err(session_diagnostics::InvalidPredicate {
+                        span: meta.span(),
+                        predicate: meta.path().to_string(),
+                    });
+                    return None;
+                }
+            },
+            a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
+                let Some(name) = meta.path().word_sym() else {
+                    cx.emit_err(session_diagnostics::CfgPredicateIdentifier {
+                        span: meta.path().span(),
+                    });
+                    return None;
+                };
+                parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)?
             }
-            None if sess.psess.check_config.exhaustive_names => {
-                lint_emitter.emit_span_lint(
-                    sess,
-                    UNEXPECTED_CFGS,
-                    cfg.span,
-                    BuiltinLintDiag::UnexpectedCfgName(
-                        (cfg.name, cfg.name_span),
-                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
-                    ),
-                );
+        },
+        MetaItemOrLitParser::Lit(lit) => match lit.kind {
+            LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
+            _ => {
+                cx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: lit.span });
+                return None;
             }
-            _ => { /* not unexpected */ }
-        }
-        sess.psess.config.contains(&(cfg.name, cfg.value))
+        },
+        MetaItemOrLitParser::Err(_, _) => return None,
     })
 }
 
-fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
-    let gate = find_gated_cfg(|sym| sym == name);
-    if let (Some(feats), Some(gated_cfg)) = (features, gate) {
-        gate_cfg(gated_cfg, span, sess, feats);
-    }
+fn parse_cfg_entry_version<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    list: &MetaItemListParser<'_>,
+    meta_span: Span,
+) -> Option<CfgEntry> {
+    try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features()));
+    let Some(version) = list.single() else {
+        cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span });
+        return None;
+    };
+    let Some(version_lit) = version.lit() else {
+        cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() });
+        return None;
+    };
+    let Some(version_str) = version_lit.value_str() else {
+        cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span });
+        return None;
+    };
+
+    let min_version = parse_version(version_str).or_else(|| {
+        cx.sess()
+            .dcx()
+            .emit_warn(session_diagnostics::UnknownVersionLiteral { span: version_lit.span });
+        None
+    });
+
+    Some(CfgEntry::Version(min_version, list.span))
 }
 
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
-    let (cfg, feature, has_feature) = gated_cfg;
-    if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
-        let explain = format!("`cfg({cfg})` is experimental and subject to change");
-        feature_err(sess, *feature, cfg_span, explain).emit();
+fn parse_cfg_entry_target<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    list: &MetaItemListParser<'_>,
+    meta_span: Span,
+) -> Option<CfgEntry> {
+    if !cx.features().cfg_target_compact() {
+        feature_err(
+            cx.sess(),
+            sym::cfg_target_compact,
+            meta_span,
+            fluent_generated::attr_parsing_unstable_cfg_target_compact,
+        )
+        .emit();
     }
-}
 
-/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
-/// evaluate individual items.
-pub fn eval_condition(
-    cfg: &MetaItemInner,
-    sess: &Session,
-    features: Option<&Features>,
-    eval: &mut impl FnMut(Condition) -> bool,
-) -> bool {
-    let dcx = sess.dcx();
-
-    let cfg = match cfg {
-        MetaItemInner::MetaItem(meta_item) => meta_item,
-        MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
-            return *b;
-        }
-        _ => {
-            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
-                span: cfg.span(),
-                reason: UnsupportedLiteralReason::CfgBoolean,
-                is_bytestr: false,
-                start_point_span: sess.source_map().start_point(cfg.span()),
+    let mut result = ThinVec::new();
+    for sub_item in list.mixed() {
+        // First, validate that this is a NameValue item
+        let Some(sub_item) = sub_item.meta_item() else {
+            cx.expected_name_value(sub_item.span(), None);
+            continue;
+        };
+        let Some(nv) = sub_item.args().name_value() else {
+            cx.expected_name_value(sub_item.span(), None);
+            continue;
+        };
+
+        // Then, parse it as a name-value item
+        let Some(name) = sub_item.path().word_sym() else {
+            cx.emit_err(session_diagnostics::CfgPredicateIdentifier {
+                span: sub_item.path().span(),
             });
-            return false;
+            return None;
+        };
+        let name = Symbol::intern(&format!("target_{name}"));
+        if let Some(cfg) =
+            parse_name_value(name, sub_item.path().span(), Some(nv), sub_item.span(), cx)
+        {
+            result.push(cfg);
+        }
+    }
+    Some(CfgEntry::All(result, list.span))
+}
+
+fn parse_name_value<S: Stage>(
+    name: Symbol,
+    name_span: Span,
+    value: Option<&NameValueParser>,
+    span: Span,
+    cx: &mut AcceptContext<'_, '_, S>,
+) -> Option<CfgEntry> {
+    try_gate_cfg(name, span, cx.sess(), cx.features_option());
+
+    let value = match value {
+        None => None,
+        Some(value) => {
+            let Some(value_str) = value.value_as_str() else {
+                cx.expected_string_literal(value.value_span, Some(value.value_as_lit()));
+                return None;
+            };
+            Some((value_str, value.value_span))
         }
     };
 
-    match &cfg.kind {
-        MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
-            try_gate_cfg(sym::version, cfg.span, sess, features);
-            let (min_version, span) = match &mis[..] {
-                [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
-                    (sym, span)
-                }
-                [
-                    MetaItemInner::Lit(MetaItemLit { span, .. })
-                    | MetaItemInner::MetaItem(MetaItem { span, .. }),
-                ] => {
-                    dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
-                    return false;
+    Some(CfgEntry::NameValue { name, name_span, value, span })
+}
+
+pub fn eval_config_entry(
+    sess: &Session,
+    cfg_entry: &CfgEntry,
+    id: NodeId,
+    features: Option<&Features>,
+) -> EvalConfigResult {
+    match cfg_entry {
+        CfgEntry::All(subs, ..) => {
+            let mut all = None;
+            for sub in subs {
+                let res = eval_config_entry(sess, sub, id, features);
+                // We cannot short-circuit because `eval_config_entry` emits some lints
+                if !res.as_bool() {
+                    all.get_or_insert(res);
                 }
-                [..] => {
-                    dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
-                        span: cfg.span,
-                    });
-                    return false;
+            }
+            all.unwrap_or_else(|| EvalConfigResult::True)
+        }
+        CfgEntry::Any(subs, span) => {
+            let mut any = None;
+            for sub in subs {
+                let res = eval_config_entry(sess, sub, id, features);
+                // We cannot short-circuit because `eval_config_entry` emits some lints
+                if res.as_bool() {
+                    any.get_or_insert(res);
                 }
-            };
-            let Some(min_version) = parse_version(*min_version) else {
-                dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span });
-                return false;
-            };
-
-            // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
-            if sess.psess.assume_incomplete_release {
-                RustcVersion::current_overridable() > min_version
+            }
+            any.unwrap_or_else(|| EvalConfigResult::False {
+                reason: cfg_entry.clone(),
+                reason_span: *span,
+            })
+        }
+        CfgEntry::Not(sub, span) => {
+            if eval_config_entry(sess, sub, id, features).as_bool() {
+                EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
             } else {
-                RustcVersion::current_overridable() >= min_version
+                EvalConfigResult::True
             }
         }
-        MetaItemKind::List(mis) => {
-            for mi in mis.iter() {
-                if mi.meta_item_or_bool().is_none() {
-                    dcx.emit_err(session_diagnostics::UnsupportedLiteral {
-                        span: mi.span(),
-                        reason: UnsupportedLiteralReason::Generic,
-                        is_bytestr: false,
-                        start_point_span: sess.source_map().start_point(mi.span()),
-                    });
-                    return false;
-                }
+        CfgEntry::Bool(b, span) => {
+            if *b {
+                EvalConfigResult::True
+            } else {
+                EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
             }
-
-            // The unwraps below may look dangerous, but we've already asserted
-            // that they won't fail with the loop above.
-            match cfg.name() {
-                Some(sym::any) => mis
-                    .iter()
-                    // We don't use any() here, because we want to evaluate all cfg condition
-                    // as eval_condition can (and does) extra checks
-                    .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
-                Some(sym::all) => mis
-                    .iter()
-                    // We don't use all() here, because we want to evaluate all cfg condition
-                    // as eval_condition can (and does) extra checks
-                    .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
-                Some(sym::not) => {
-                    let [mi] = mis.as_slice() else {
-                        dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
-                        return false;
-                    };
-
-                    !eval_condition(mi, sess, features, eval)
-                }
-                Some(sym::target) => {
-                    if let Some(features) = features
-                        && !features.cfg_target_compact()
-                    {
-                        feature_err(
-                            sess,
-                            sym::cfg_target_compact,
-                            cfg.span,
-                            fluent_generated::attr_parsing_unstable_cfg_target_compact,
-                        )
-                        .emit();
-                    }
-
-                    mis.iter().fold(true, |res, mi| {
-                        let Some(mut mi) = mi.meta_item().cloned() else {
-                            dcx.emit_err(session_diagnostics::CfgPredicateIdentifier {
-                                span: mi.span(),
-                            });
-                            return false;
-                        };
-
-                        if let [seg, ..] = &mut mi.path.segments[..] {
-                            seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
-                        }
-
-                        res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval)
-                    })
+        }
+        CfgEntry::NameValue { name, name_span, value, span } => {
+            match sess.psess.check_config.expecteds.get(name) {
+                Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => {
+                    id.emit_span_lint(
+                        sess,
+                        UNEXPECTED_CFGS,
+                        *span,
+                        BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
+                    );
                 }
-                _ => {
-                    dcx.emit_err(session_diagnostics::InvalidPredicate {
-                        span: cfg.span,
-                        predicate: pprust::path_to_string(&cfg.path),
-                    });
-                    false
+                None if sess.psess.check_config.exhaustive_names => {
+                    id.emit_span_lint(
+                        sess,
+                        UNEXPECTED_CFGS,
+                        *span,
+                        BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
+                    );
                 }
+                _ => { /* not unexpected */ }
+            }
+
+            if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
+                EvalConfigResult::True
+            } else {
+                EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
             }
         }
-        MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
-            dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
-            true
-        }
-        MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
-                span: lit.span,
-                reason: UnsupportedLiteralReason::CfgString,
-                is_bytestr: lit.kind.is_bytestr(),
-                start_point_span: sess.source_map().start_point(lit.span),
-            });
-            true
+        CfgEntry::Version(min_version, version_span) => {
+            let Some(min_version) = min_version else {
+                return EvalConfigResult::False {
+                    reason: cfg_entry.clone(),
+                    reason_span: *version_span,
+                };
+            };
+            // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
+            let min_version_ok = if sess.psess.assume_incomplete_release {
+                RustcVersion::current_overridable() > *min_version
+            } else {
+                RustcVersion::current_overridable() >= *min_version
+            };
+            if min_version_ok {
+                EvalConfigResult::True
+            } else {
+                EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *version_span }
+            }
         }
-        MetaItemKind::Word | MetaItemKind::NameValue(..) => {
-            let ident = cfg.ident().expect("multi-segment cfg predicate");
-            eval(Condition {
-                name: ident.name,
-                name_span: ident.span,
-                value: cfg.value_str(),
-                value_span: cfg.name_value_literal_span(),
-                span: cfg.span,
-            })
+    }
+}
+
+pub enum EvalConfigResult {
+    True,
+    False { reason: CfgEntry, reason_span: Span },
+}
+
+impl EvalConfigResult {
+    pub fn as_bool(&self) -> bool {
+        match self {
+            EvalConfigResult::True => true,
+            EvalConfigResult::False { .. } => false,
         }
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
new file mode 100644
index 00000000000..c5025a8b6ea
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
@@ -0,0 +1,247 @@
+use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
+use rustc_ast_pretty::pprust;
+use rustc_attr_data_structures::RustcVersion;
+use rustc_feature::{Features, GatedCfg, find_gated_cfg};
+use rustc_session::Session;
+use rustc_session::config::ExpectedValues;
+use rustc_session::lint::builtin::UNEXPECTED_CFGS;
+use rustc_session::lint::{BuiltinLintDiag, Lint};
+use rustc_session::parse::feature_err;
+use rustc_span::{Span, Symbol, sym};
+
+use crate::session_diagnostics::{self, UnsupportedLiteralReason};
+use crate::{fluent_generated, parse_version};
+
+/// Emitter of a builtin lint from `cfg_matches`.
+///
+/// Used to support emitting a lint (currently on check-cfg), either:
+///  - as an early buffered lint (in `rustc`)
+///  - or has a "normal" lint from HIR (in `rustdoc`)
+pub trait CfgMatchesLintEmitter {
+    fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag);
+}
+
+impl CfgMatchesLintEmitter for NodeId {
+    fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) {
+        sess.psess.buffer_lint(lint, sp, *self, diag);
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct Condition {
+    pub name: Symbol,
+    pub name_span: Span,
+    pub value: Option<Symbol>,
+    pub value_span: Option<Span>,
+    pub span: Span,
+}
+
+/// Tests if a cfg-pattern matches the cfg set
+pub fn cfg_matches(
+    cfg: &MetaItemInner,
+    sess: &Session,
+    lint_emitter: impl CfgMatchesLintEmitter,
+    features: Option<&Features>,
+) -> bool {
+    eval_condition(cfg, sess, features, &mut |cfg| {
+        try_gate_cfg(cfg.name, cfg.span, sess, features);
+        match sess.psess.check_config.expecteds.get(&cfg.name) {
+            Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
+                lint_emitter.emit_span_lint(
+                    sess,
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    BuiltinLintDiag::UnexpectedCfgValue(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
+                );
+            }
+            None if sess.psess.check_config.exhaustive_names => {
+                lint_emitter.emit_span_lint(
+                    sess,
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    BuiltinLintDiag::UnexpectedCfgName(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
+                );
+            }
+            _ => { /* not unexpected */ }
+        }
+        sess.psess.config.contains(&(cfg.name, cfg.value))
+    })
+}
+
+pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
+    let gate = find_gated_cfg(|sym| sym == name);
+    if let (Some(feats), Some(gated_cfg)) = (features, gate) {
+        gate_cfg(gated_cfg, span, sess, feats);
+    }
+}
+
+#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
+fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
+    let (cfg, feature, has_feature) = gated_cfg;
+    if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
+        let explain = format!("`cfg({cfg})` is experimental and subject to change");
+        feature_err(sess, *feature, cfg_span, explain).emit();
+    }
+}
+
+/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
+/// evaluate individual items.
+pub fn eval_condition(
+    cfg: &MetaItemInner,
+    sess: &Session,
+    features: Option<&Features>,
+    eval: &mut impl FnMut(Condition) -> bool,
+) -> bool {
+    let dcx = sess.dcx();
+
+    let cfg = match cfg {
+        MetaItemInner::MetaItem(meta_item) => meta_item,
+        MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
+            return *b;
+        }
+        _ => {
+            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: cfg.span(),
+                reason: UnsupportedLiteralReason::CfgBoolean,
+                is_bytestr: false,
+                start_point_span: sess.source_map().start_point(cfg.span()),
+            });
+            return false;
+        }
+    };
+
+    match &cfg.kind {
+        MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
+            try_gate_cfg(sym::version, cfg.span, sess, features);
+            let (min_version, span) = match &mis[..] {
+                [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
+                    (sym, span)
+                }
+                [
+                    MetaItemInner::Lit(MetaItemLit { span, .. })
+                    | MetaItemInner::MetaItem(MetaItem { span, .. }),
+                ] => {
+                    dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
+                    return false;
+                }
+                [..] => {
+                    dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
+                        span: cfg.span,
+                    });
+                    return false;
+                }
+            };
+            let Some(min_version) = parse_version(*min_version) else {
+                dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span });
+                return false;
+            };
+
+            // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
+            if sess.psess.assume_incomplete_release {
+                RustcVersion::current_overridable() > min_version
+            } else {
+                RustcVersion::current_overridable() >= min_version
+            }
+        }
+        MetaItemKind::List(mis) => {
+            for mi in mis.iter() {
+                if mi.meta_item_or_bool().is_none() {
+                    dcx.emit_err(session_diagnostics::UnsupportedLiteral {
+                        span: mi.span(),
+                        reason: UnsupportedLiteralReason::Generic,
+                        is_bytestr: false,
+                        start_point_span: sess.source_map().start_point(mi.span()),
+                    });
+                    return false;
+                }
+            }
+
+            // The unwraps below may look dangerous, but we've already asserted
+            // that they won't fail with the loop above.
+            match cfg.name() {
+                Some(sym::any) => mis
+                    .iter()
+                    // We don't use any() here, because we want to evaluate all cfg condition
+                    // as eval_condition can (and does) extra checks
+                    .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
+                Some(sym::all) => mis
+                    .iter()
+                    // We don't use all() here, because we want to evaluate all cfg condition
+                    // as eval_condition can (and does) extra checks
+                    .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
+                Some(sym::not) => {
+                    let [mi] = mis.as_slice() else {
+                        dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
+                        return false;
+                    };
+
+                    !eval_condition(mi, sess, features, eval)
+                }
+                Some(sym::target) => {
+                    if let Some(features) = features
+                        && !features.cfg_target_compact()
+                    {
+                        feature_err(
+                            sess,
+                            sym::cfg_target_compact,
+                            cfg.span,
+                            fluent_generated::attr_parsing_unstable_cfg_target_compact,
+                        )
+                        .emit();
+                    }
+
+                    mis.iter().fold(true, |res, mi| {
+                        let Some(mut mi) = mi.meta_item().cloned() else {
+                            dcx.emit_err(session_diagnostics::CfgPredicateIdentifier {
+                                span: mi.span(),
+                            });
+                            return false;
+                        };
+
+                        if let [seg, ..] = &mut mi.path.segments[..] {
+                            seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
+                        }
+
+                        res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval)
+                    })
+                }
+                _ => {
+                    dcx.emit_err(session_diagnostics::InvalidPredicate {
+                        span: cfg.span,
+                        predicate: pprust::path_to_string(&cfg.path),
+                    });
+                    false
+                }
+            }
+        }
+        MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
+            dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
+            true
+        }
+        MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: lit.span,
+                reason: UnsupportedLiteralReason::CfgString,
+                is_bytestr: lit.kind.is_bytestr(),
+                start_point_span: sess.source_map().start_point(lit.span),
+            });
+            true
+        }
+        MetaItemKind::Word | MetaItemKind::NameValue(..) => {
+            let ident = cfg.ident().expect("multi-segment cfg predicate");
+            eval(Condition {
+                name: ident.name,
+                name_span: ident.span,
+                value: cfg.value_str(),
+                value_span: cfg.name_value_literal_span(),
+                span: cfg.span,
+            })
+        }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 68c716d1a99..200f1381960 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -27,6 +27,7 @@ use crate::session_diagnostics::UnusedMultiple;
 
 pub(crate) mod allow_unstable;
 pub(crate) mod cfg;
+pub(crate) mod cfg_old;
 pub(crate) mod codegen_attrs;
 pub(crate) mod confusables;
 pub(crate) mod deprecation;
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index ee8a33ae9c4..d5e088effd5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -145,3 +145,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
 }
+
+pub(crate) struct PointeeParser;
+impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser {
+    const PATH: &[Symbol] = &[sym::pointee];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee;
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 6c70f2ee4ee..567341d1517 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -1,6 +1,5 @@
 use std::cell::RefCell;
 use std::collections::BTreeMap;
-use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
@@ -48,8 +47,8 @@ use crate::attributes::test_attrs::IgnoreParser;
 use crate::attributes::traits::{
     AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
     DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
-    ParenSugarParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
-    UnsafeSpecializationMarkerParser,
+    ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser,
+    TypeConstParser, UnsafeSpecializationMarkerParser,
 };
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
@@ -178,6 +177,7 @@ attribute_parsers!(
         Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>,
         Single<WithoutArgs<ParenSugarParser>>,
         Single<WithoutArgs<PassByValueParser>>,
+        Single<WithoutArgs<PointeeParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
         Single<WithoutArgs<SpecializationTraitParser>>,
         Single<WithoutArgs<StdInternalSymbolParser>>,
@@ -202,7 +202,11 @@ pub trait Stage: Sized + 'static + Sealed {
 
     fn parsers() -> &'static group_type!(Self);
 
-    fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
+    fn emit_err<'sess>(
+        &self,
+        sess: &'sess Session,
+        diag: impl for<'x> Diagnostic<'x>,
+    ) -> ErrorGuaranteed;
 }
 
 // allow because it's a sealed trait
@@ -214,8 +218,16 @@ impl Stage for Early {
     fn parsers() -> &'static group_type!(Self) {
         &early::ATTRIBUTE_PARSERS
     }
-    fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
-        sess.dcx().create_err(diag).delay_as_bug()
+    fn emit_err<'sess>(
+        &self,
+        sess: &'sess Session,
+        diag: impl for<'x> Diagnostic<'x>,
+    ) -> ErrorGuaranteed {
+        if self.emit_errors {
+            sess.dcx().emit_err(diag)
+        } else {
+            sess.dcx().create_err(diag).delay_as_bug()
+        }
     }
 }
 
@@ -228,20 +240,29 @@ impl Stage for Late {
     fn parsers() -> &'static group_type!(Self) {
         &late::ATTRIBUTE_PARSERS
     }
-    fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
+    fn emit_err<'sess>(
+        &self,
+        tcx: &'sess Session,
+        diag: impl for<'x> Diagnostic<'x>,
+    ) -> ErrorGuaranteed {
         tcx.dcx().emit_err(diag)
     }
 }
 
 /// used when parsing attributes for miscellaneous things *before* ast lowering
-pub struct Early;
+pub struct Early {
+    /// Whether to emit errors or delay them as a bug
+    /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
+    /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
+    pub emit_errors: bool,
+}
 /// used when parsing attributes during ast lowering
 pub struct Late;
 
 /// Context given to every attribute parser when accepting
 ///
 /// Gives [`AttributeParser`]s enough information to create errors, for example.
-pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
+pub struct AcceptContext<'f, 'sess, S: Stage> {
     pub(crate) shared: SharedContext<'f, 'sess, S>,
     /// The span of the attribute currently being parsed
     pub(crate) attr_span: Span,
@@ -257,7 +278,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
 
 impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
     pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
-        S::emit_err(&self.sess, diag)
+        self.stage.emit_err(&self.sess, diag)
     }
 
     /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -472,7 +493,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
 ///
 /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
 /// errors, for example.
-pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
+pub struct SharedContext<'p, 'sess, S: Stage> {
     /// The parse context, gives access to the session and the
     /// diagnostics context.
     pub(crate) cx: &'p mut AttributeParser<'sess, S>,
@@ -540,7 +561,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
     pub(crate) tools: Vec<Symbol>,
     features: Option<&'sess Features>,
     sess: &'sess Session,
-    stage: PhantomData<S>,
+    stage: S,
 
     /// *Only* parse attributes with this symbol.
     ///
@@ -569,13 +590,14 @@ impl<'sess> AttributeParser<'sess, Early> {
         sym: Symbol,
         target_span: Span,
         target_node_id: NodeId,
+        features: Option<&'sess Features>,
     ) -> Option<Attribute> {
         let mut p = Self {
-            features: None,
+            features,
             tools: Vec::new(),
             parse_only: Some(sym),
             sess,
-            stage: PhantomData,
+            stage: Early { emit_errors: false },
         };
         let mut parsed = p.parse_attribute_list(
             attrs,
@@ -591,11 +613,55 @@ impl<'sess> AttributeParser<'sess, Early> {
 
         parsed.pop()
     }
+
+    pub fn parse_single<T>(
+        sess: &'sess Session,
+        attr: &ast::Attribute,
+        target_span: Span,
+        target_node_id: NodeId,
+        features: Option<&'sess Features>,
+        emit_errors: bool,
+        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
+        template: &AttributeTemplate,
+    ) -> T {
+        let mut parser = Self {
+            features,
+            tools: Vec::new(),
+            parse_only: None,
+            sess,
+            stage: Early { emit_errors },
+        };
+        let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
+            panic!("parse_single called on a doc attr")
+        };
+        let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
+        let path = meta_parser.path();
+        let args = meta_parser.args();
+        let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
+            shared: SharedContext {
+                cx: &mut parser,
+                target_span,
+                target_id: target_node_id,
+                emit_lint: &mut |_lint| {
+                    panic!("can't emit lints here for now (nothing uses this atm)");
+                },
+            },
+            attr_span: attr.span,
+            template,
+            attr_path: path.get_attribute_path(),
+        };
+        parse_fn(&mut cx, args)
+    }
 }
 
 impl<'sess, S: Stage> AttributeParser<'sess, S> {
-    pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
-        Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
+    pub fn new(
+        sess: &'sess Session,
+        features: &'sess Features,
+        tools: Vec<Symbol>,
+        stage: S,
+    ) -> Self {
+        Self { features: Some(features), tools, parse_only: None, sess, stage }
     }
 
     pub(crate) fn sess(&self) -> &'sess Session {
@@ -606,6 +672,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
         self.features.expect("features not available at this point in the compiler")
     }
 
+    pub(crate) fn features_option(&self) -> Option<&'sess Features> {
+        self.features
+    }
+
     pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
         self.sess().dcx()
     }
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 47eeb63bad3..2102a26108b 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -90,7 +90,8 @@ mod lints;
 pub mod parser;
 mod session_diagnostics;
 
-pub use attributes::cfg::*;
+pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
+pub use attributes::cfg_old::*;
 pub use attributes::util::{
     find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
 };
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 8a240639d75..97bf3d1c549 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -593,7 +593,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                 diag.code(E0565);
             }
             AttributeParseErrorReason::ExpectedNameValue(None) => {
-                // The suggestion we add below this match already contains enough information
+                // If the span is the entire attribute, the suggestion we add below this match already contains enough information
+                if self.span != self.attr_span {
+                    diag.span_label(
+                        self.span,
+                        format!("expected this to be of the form `... = \"...\"`"),
+                    );
+                }
             }
             AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
                 diag.span_label(
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 183927edb02..ae186d744c4 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -81,11 +81,11 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l
 builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
 builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
 
-builtin_macros_cfg_select_no_matches = none of the rules in this `cfg_select` evaluated to true
+builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true
 
-builtin_macros_cfg_select_unreachable = unreachable rule
+builtin_macros_cfg_select_unreachable = unreachable predicate
     .label = always matches
-    .label2 = this rules is never reached
+    .label2 = this predicate is never reached
 
 builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
 
diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs
index 2dc387d5866..f22d5f255c2 100644
--- a/compiler/rustc_builtin_macros/src/cfg_select.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_select.rs
@@ -1,12 +1,12 @@
 use rustc_ast::tokenstream::TokenStream;
 use rustc_attr_parsing as attr;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
-use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectRule, parse_cfg_select};
+use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
 use rustc_span::{Ident, Span, sym};
 
 use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
 
-/// Selects the first arm whose rule evaluates to true.
+/// Selects the first arm whose predicate evaluates to true.
 fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
     for (cfg, tt, arm_span) in branches.reachable {
         if attr::cfg_matches(
@@ -30,11 +30,11 @@ pub(super) fn expand_cfg_select<'cx>(
     ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
         Ok(branches) => {
             if let Some((underscore, _, _)) = branches.wildcard {
-                // Warn for every unreachable rule. We store the fully parsed branch for rustfmt.
-                for (rule, _, _) in &branches.unreachable {
-                    let span = match rule {
-                        CfgSelectRule::Wildcard(underscore) => underscore.span,
-                        CfgSelectRule::Cfg(cfg) => cfg.span(),
+                // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
+                for (predicate, _, _) in &branches.unreachable {
+                    let span = match predicate {
+                        CfgSelectPredicate::Wildcard(underscore) => underscore.span,
+                        CfgSelectPredicate::Cfg(cfg) => cfg.span(),
                     };
                     let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
                     ecx.dcx().emit_warn(err);
@@ -50,7 +50,7 @@ pub(super) fn expand_cfg_select<'cx>(
                     Ident::with_dummy_span(sym::cfg_select),
                 );
             } else {
-                // Emit a compiler error when none of the rules matched.
+                // Emit a compiler error when none of the predicates matched.
                 let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
                 DummyResult::any(sp, guar)
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 8c3093acea4..c55a9e73e38 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
         match item {
             Annotatable::Item(item) => {
                 let is_packed = matches!(
-                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
                     Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
                 );
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 506286fc255..313bf6d20a6 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -879,9 +879,7 @@ pub(crate) fn codegen(
                     .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name);
                 let thin_bc =
                     module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode");
-                unsafe {
-                    embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc);
-                }
+                embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc);
             }
         }
 
@@ -945,7 +943,7 @@ pub(crate) fn codegen(
             // binaries. So we must clone the module to produce the asm output
             // if we are also producing object code.
             let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj {
-                unsafe { llvm::LLVMCloneModule(llmod) }
+                llvm::LLVMCloneModule(llmod)
             } else {
                 llmod
             };
@@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) ->
 }
 
 /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself.
-unsafe fn embed_bitcode(
+fn embed_bitcode(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     llcx: &llvm::Context,
     llmod: &llvm::Module,
@@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode(
     // Unfortunately, LLVM provides no way to set custom section flags. For ELF
     // and COFF we emit the sections using module level inline assembly for that
     // reason (see issue #90326 for historical background).
-    unsafe {
-        if cgcx.target_is_like_darwin
-            || cgcx.target_is_like_aix
-            || cgcx.target_arch == "wasm32"
-            || cgcx.target_arch == "wasm64"
-        {
-            // We don't need custom section flags, create LLVM globals.
-            let llconst = common::bytes_in_context(llcx, bitcode);
-            let llglobal =
-                llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module");
-            llvm::set_initializer(llglobal, llconst);
-
-            llvm::set_section(llglobal, bitcode_section_name(cgcx));
-            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
-            llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
-
-            let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
-            let llglobal =
-                llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline");
-            llvm::set_initializer(llglobal, llconst);
-            let section = if cgcx.target_is_like_darwin {
-                c"__LLVM,__cmdline"
-            } else if cgcx.target_is_like_aix {
-                c".info"
-            } else {
-                c".llvmcmd"
-            };
-            llvm::set_section(llglobal, section);
-            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
+
+    if cgcx.target_is_like_darwin
+        || cgcx.target_is_like_aix
+        || cgcx.target_arch == "wasm32"
+        || cgcx.target_arch == "wasm64"
+    {
+        // We don't need custom section flags, create LLVM globals.
+        let llconst = common::bytes_in_context(llcx, bitcode);
+        let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module");
+        llvm::set_initializer(llglobal, llconst);
+
+        llvm::set_section(llglobal, bitcode_section_name(cgcx));
+        llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
+        llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
+
+        let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
+        let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline");
+        llvm::set_initializer(llglobal, llconst);
+        let section = if cgcx.target_is_like_darwin {
+            c"__LLVM,__cmdline"
+        } else if cgcx.target_is_like_aix {
+            c".info"
         } else {
-            // We need custom section flags, so emit module-level inline assembly.
-            let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
-            let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
-            llvm::append_module_inline_asm(llmod, &asm);
-            let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
-            llvm::append_module_inline_asm(llmod, &asm);
-        }
+            c".llvmcmd"
+        };
+        llvm::set_section(llglobal, section);
+        llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
+    } else {
+        // We need custom section flags, so emit module-level inline assembly.
+        let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
+        let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
+        llvm::append_module_inline_asm(llmod, &asm);
+        let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
+        llvm::append_module_inline_asm(llmod, &asm);
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 9c3b866aa3c..514923ad6f3 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -302,10 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             return;
         }
 
-        let id_str = "branch_weights";
-        let id = unsafe {
-            llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len())
-        };
+        let id = self.cx.create_metadata(b"branch_weights");
 
         // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used.
         // This function handles switch instructions with more than 2 targets and it needs to
@@ -637,17 +634,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         } else if place.layout.is_llvm_immediate() {
             let mut const_llval = None;
             let llty = place.layout.llvm_type(self);
-            unsafe {
-                if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
-                    if llvm::LLVMIsGlobalConstant(global) == llvm::True {
-                        if let Some(init) = llvm::LLVMGetInitializer(global) {
-                            if self.val_ty(init) == llty {
-                                const_llval = Some(init);
-                            }
+            if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
+                if llvm::LLVMIsGlobalConstant(global) == llvm::True {
+                    if let Some(init) = llvm::LLVMGetInitializer(global) {
+                        if self.val_ty(init) == llty {
+                            const_llval = Some(init);
                         }
                     }
                 }
             }
+
             let llval = const_llval.unwrap_or_else(|| {
                 let load = self.load(llty, place.val.llval, place.val.align);
                 if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr {
@@ -1721,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             } else {
                 cfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
-            let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
+            let typeid_metadata = self.cx.create_metadata(typeid.as_bytes());
             let dbg_loc = self.get_dbg_loc();
 
             // Test whether the function pointer is associated with the type identifier using the
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 5afb9a60d42..dff68472847 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>(
         outer_pos = 1;
     }
 
-    let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
-    let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
-    let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
-    let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap();
-    let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
-    let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap();
+    let enzyme_const = cx.create_metadata(b"enzyme_const");
+    let enzyme_out = cx.create_metadata(b"enzyme_out");
+    let enzyme_dup = cx.create_metadata(b"enzyme_dup");
+    let enzyme_dupv = cx.create_metadata(b"enzyme_dupv");
+    let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed");
+    let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv");
 
     while activity_pos < inputs.len() {
         let diff_activity = inputs[activity_pos as usize];
@@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>(
         let mut args = Vec::with_capacity(num_args as usize + 1);
         args.push(fn_to_diff);
 
-        let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap();
+        let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return");
         if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) {
             args.push(cx.get_metadata_value(enzyme_primal_ret));
         }
         if attrs.width > 1 {
-            let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap();
+            let enzyme_width = cx.create_metadata(b"enzyme_width");
             args.push(cx.get_metadata_value(enzyme_width));
             args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64));
         }
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index b9b5c776d86..f9ab96b5789 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
                 bug!("symbol `{}` is already defined", sym);
             });
             llvm::set_initializer(g, sc);
-            unsafe {
-                llvm::LLVMSetGlobalConstant(g, True);
-                llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
-            }
+
+            llvm::set_global_constant(g, true);
+            llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global);
+
             llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
             // Cast to default address space if globals are in a different addrspace
             let g = self.const_pointercast(g, self.type_ptr());
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 5deddb3ed98..0b96b63bc85 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -17,13 +17,12 @@ use rustc_middle::ty::{self, Instance};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
-use crate::common::{AsCCharPtr, CodegenCx};
+use crate::common::CodegenCx;
 use crate::errors::SymbolAlreadyDefined;
-use crate::llvm::{self, True};
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
-use crate::{base, debuginfo};
+use crate::{base, debuginfo, llvm};
 
 pub(crate) fn const_alloc_to_llvm<'ll>(
     cx: &CodegenCx<'ll, '_>,
@@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> {
         };
         llvm::set_initializer(gv, cv);
         set_global_alignment(self, gv, align);
-        llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
+        llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global);
         gv
     }
 
@@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> {
             return gv;
         }
         let gv = self.static_addr_of_mut(cv, align, kind);
-        unsafe {
-            llvm::LLVMSetGlobalConstant(gv, True);
-        }
+        llvm::set_global_constant(gv, true);
+
         self.const_globals.borrow_mut().insert(cv, gv);
         gv
     }
@@ -398,149 +396,140 @@ impl<'ll> CodegenCx<'ll, '_> {
     }
 
     fn codegen_static_item(&mut self, def_id: DefId) {
-        unsafe {
-            assert!(
-                llvm::LLVMGetInitializer(
-                    self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap()
-                )
-                .is_none()
-            );
-            let attrs = self.tcx.codegen_fn_attrs(def_id);
+        assert!(
+            llvm::LLVMGetInitializer(
+                self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap()
+            )
+            .is_none()
+        );
+        let attrs = self.tcx.codegen_fn_attrs(def_id);
 
-            let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
-                // Error has already been reported
-                return;
-            };
-            let alloc = alloc.inner();
+        let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
+            // Error has already been reported
+            return;
+        };
+        let alloc = alloc.inner();
 
-            let val_llty = self.val_ty(v);
+        let val_llty = self.val_ty(v);
 
-            let g = self.get_static_inner(def_id, val_llty);
-            let llty = self.get_type_of_global(g);
+        let g = self.get_static_inner(def_id, val_llty);
+        let llty = self.get_type_of_global(g);
 
-            let g = if val_llty == llty {
-                g
-            } else {
-                // codegen_static_initializer creates the global value just from the
-                // `Allocation` data by generating one big struct value that is just
-                // all the bytes and pointers after each other. This will almost never
-                // match the type that the static was declared with. Unfortunately
-                // we can't just LLVMConstBitCast our way out of it because that has very
-                // specific rules on what can be cast. So instead of adding a new way to
-                // generate static initializers that match the static's type, we picked
-                // the easier option and retroactively change the type of the static item itself.
-                let name = llvm::get_value_name(g);
-                llvm::set_value_name(g, b"");
-
-                let linkage = llvm::get_linkage(g);
-                let visibility = llvm::get_visibility(g);
-
-                let new_g = llvm::LLVMRustGetOrInsertGlobal(
-                    self.llmod,
-                    name.as_c_char_ptr(),
-                    name.len(),
-                    val_llty,
-                );
-
-                llvm::set_linkage(new_g, linkage);
-                llvm::set_visibility(new_g, visibility);
-
-                // The old global has had its name removed but is returned by
-                // get_static since it is in the instance cache. Provide an
-                // alternative lookup that points to the new global so that
-                // global_asm! can compute the correct mangled symbol name
-                // for the global.
-                self.renamed_statics.borrow_mut().insert(def_id, new_g);
-
-                // To avoid breaking any invariants, we leave around the old
-                // global for the moment; we'll replace all references to it
-                // with the new global later. (See base::codegen_backend.)
-                self.statics_to_rauw.borrow_mut().push((g, new_g));
-                new_g
-            };
-            set_global_alignment(self, g, alloc.align);
-            llvm::set_initializer(g, v);
-
-            self.assume_dso_local(g, true);
-
-            // Forward the allocation's mutability (picked by the const interner) to LLVM.
-            if alloc.mutability.is_not() {
-                llvm::LLVMSetGlobalConstant(g, llvm::True);
-            }
+        let g = if val_llty == llty {
+            g
+        } else {
+            // codegen_static_initializer creates the global value just from the
+            // `Allocation` data by generating one big struct value that is just
+            // all the bytes and pointers after each other. This will almost never
+            // match the type that the static was declared with. Unfortunately
+            // we can't just LLVMConstBitCast our way out of it because that has very
+            // specific rules on what can be cast. So instead of adding a new way to
+            // generate static initializers that match the static's type, we picked
+            // the easier option and retroactively change the type of the static item itself.
+            let name = String::from_utf8(llvm::get_value_name(g))
+                .expect("we declare our statics with a utf8-valid name");
+            llvm::set_value_name(g, b"");
+
+            let linkage = llvm::get_linkage(g);
+            let visibility = llvm::get_visibility(g);
+
+            let new_g = self.declare_global(&name, val_llty);
+
+            llvm::set_linkage(new_g, linkage);
+            llvm::set_visibility(new_g, visibility);
+
+            // The old global has had its name removed but is returned by
+            // get_static since it is in the instance cache. Provide an
+            // alternative lookup that points to the new global so that
+            // global_asm! can compute the correct mangled symbol name
+            // for the global.
+            self.renamed_statics.borrow_mut().insert(def_id, new_g);
+
+            // To avoid breaking any invariants, we leave around the old
+            // global for the moment; we'll replace all references to it
+            // with the new global later. (See base::codegen_backend.)
+            self.statics_to_rauw.borrow_mut().push((g, new_g));
+            new_g
+        };
+        set_global_alignment(self, g, alloc.align);
+        llvm::set_initializer(g, v);
 
-            debuginfo::build_global_var_di_node(self, def_id, g);
+        self.assume_dso_local(g, true);
 
-            if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
-                llvm::set_thread_local_mode(g, self.tls_model);
-            }
+        // Forward the allocation's mutability (picked by the const interner) to LLVM.
+        if alloc.mutability.is_not() {
+            llvm::set_global_constant(g, true);
+        }
 
-            // Wasm statics with custom link sections get special treatment as they
-            // go into custom sections of the wasm executable. The exception to this
-            // is the `.init_array` section which are treated specially by the wasm linker.
-            if self.tcx.sess.target.is_like_wasm
-                && attrs
-                    .link_section
-                    .map(|link_section| !link_section.as_str().starts_with(".init_array"))
-                    .unwrap_or(true)
-            {
-                if let Some(section) = attrs.link_section {
-                    let section = llvm::LLVMMDStringInContext2(
-                        self.llcx,
-                        section.as_str().as_c_char_ptr(),
-                        section.as_str().len(),
-                    );
-                    assert!(alloc.provenance().ptrs().is_empty());
-
-                    // The `inspect` method is okay here because we checked for provenance, and
-                    // because we are doing this access to inspect the final interpreter state (not
-                    // as part of the interpreter execution).
-                    let bytes =
-                        alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
-                    let alloc =
-                        llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
-                    let data = [section, alloc];
-                    let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
-                    let val = self.get_metadata_value(meta);
+        debuginfo::build_global_var_di_node(self, def_id, g);
+
+        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+            llvm::set_thread_local_mode(g, self.tls_model);
+        }
+
+        // Wasm statics with custom link sections get special treatment as they
+        // go into custom sections of the wasm executable. The exception to this
+        // is the `.init_array` section which are treated specially by the wasm linker.
+        if self.tcx.sess.target.is_like_wasm
+            && attrs
+                .link_section
+                .map(|link_section| !link_section.as_str().starts_with(".init_array"))
+                .unwrap_or(true)
+        {
+            if let Some(section) = attrs.link_section {
+                let section = self.create_metadata(section.as_str().as_bytes());
+                assert!(alloc.provenance().ptrs().is_empty());
+
+                // The `inspect` method is okay here because we checked for provenance, and
+                // because we are doing this access to inspect the final interpreter state (not
+                // as part of the interpreter execution).
+                let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
+                let alloc = self.create_metadata(bytes);
+                let data = [section, alloc];
+                let meta =
+                    unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) };
+                let val = self.get_metadata_value(meta);
+                unsafe {
                     llvm::LLVMAddNamedMetadataOperand(
                         self.llmod,
                         c"wasm.custom_sections".as_ptr(),
                         val,
-                    );
-                }
-            } else {
-                base::set_link_section(g, attrs);
+                    )
+                };
             }
+        } else {
+            base::set_link_section(g, attrs);
+        }
 
-            base::set_variable_sanitizer_attrs(g, attrs);
-
-            if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
-                // `USED` and `USED_LINKER` can't be used together.
-                assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
-
-                // The semantics of #[used] in Rust only require the symbol to make it into the
-                // object file. It is explicitly allowed for the linker to strip the symbol if it
-                // is dead, which means we are allowed to use `llvm.compiler.used` instead of
-                // `llvm.used` here.
-                //
-                // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
-                // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
-                // in the handling of `.init_array` (the static constructor list) in versions of
-                // the gold linker (prior to the one released with binutils 2.36).
-                //
-                // That said, we only ever emit these when `#[used(compiler)]` is explicitly
-                // requested. This is to avoid similar breakage on other targets, in particular
-                // MachO targets have *their* static constructor lists broken if `llvm.compiler.used`
-                // is emitted rather than `llvm.used`. However, that check happens when assigning
-                // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to
-                // take care of it here.
-                self.add_compiler_used_global(g);
-            }
-            if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
-                // `USED` and `USED_LINKER` can't be used together.
-                assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER));
+        base::set_variable_sanitizer_attrs(g, attrs);
+
+        if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
+            // `USED` and `USED_LINKER` can't be used together.
+            assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
+
+            // The semantics of #[used] in Rust only require the symbol to make it into the
+            // object file. It is explicitly allowed for the linker to strip the symbol if it
+            // is dead, which means we are allowed to use `llvm.compiler.used` instead of
+            // `llvm.used` here.
+            //
+            // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
+            // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
+            // in the handling of `.init_array` (the static constructor list) in versions of
+            // the gold linker (prior to the one released with binutils 2.36).
+            //
+            // That said, we only ever emit these when `#[used(compiler)]` is explicitly
+            // requested. This is to avoid similar breakage on other targets, in particular
+            // MachO targets have *their* static constructor lists broken if `llvm.compiler.used`
+            // is emitted rather than `llvm.used`. However, that check happens when assigning
+            // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to
+            // take care of it here.
+            self.add_compiler_used_global(g);
+        }
+        if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
+            // `USED` and `USED_LINKER` can't be used together.
+            assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER));
 
-                self.add_used_global(g);
-            }
+            self.add_used_global(g);
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 90582e23b04..6a23becaa96 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -34,7 +34,6 @@ use smallvec::SmallVec;
 
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
-use crate::common::AsCCharPtr;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
 use crate::llvm::Metadata;
 use crate::type_::Type;
@@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>(
     let mod_name = SmallCStr::new(mod_name);
     let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
 
+    let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size());
+
     let mut target_data_layout = sess.target.data_layout.to_string();
     let llvm_version = llvm_util::get_version();
 
@@ -473,18 +474,14 @@ pub(crate) unsafe fn create_module<'ll>(
     #[allow(clippy::option_env_unwrap)]
     let rustc_producer =
         format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
-    let name_metadata = unsafe {
-        llvm::LLVMMDStringInContext2(
-            llcx,
-            rustc_producer.as_c_char_ptr(),
-            rustc_producer.as_bytes().len(),
-        )
-    };
+
+    let name_metadata = cx.create_metadata(rustc_producer.as_bytes());
+
     unsafe {
         llvm::LLVMAddNamedMetadataOperand(
             llmod,
             c"llvm.ident".as_ptr(),
-            &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
+            &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
         );
     }
 
@@ -698,10 +695,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         }
     }
 
-    pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
-        Some(unsafe {
+    pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata {
+        unsafe {
             llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
-        })
+        }
     }
 
     pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 49ee96a41d6..61555ac2f6f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -74,7 +74,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
             llvm::set_section(section_var, c".debug_gdb_scripts");
             llvm::set_initializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
-            llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
+            llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global);
             llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 9b4736e50e6..0e9dbfba658 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
 use std::sync::Arc;
 use std::{iter, ptr};
 
-use libc::{c_char, c_longlong, c_uint};
+use libc::{c_longlong, c_uint};
 use rustc_abi::{Align, Size};
 use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo};
 use rustc_codegen_ssa::traits::*;
@@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
     };
 
     let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
+    let typeid = cx.create_metadata(trait_ref_typeid.as_bytes());
 
     unsafe {
-        let typeid = llvm::LLVMMDStringInContext2(
-            cx.llcx,
-            trait_ref_typeid.as_ptr() as *const c_char,
-            trait_ref_typeid.as_bytes().len(),
-        );
         let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
         llvm::LLVMRustGlobalAddMetadata(
             vtable,
@@ -1630,7 +1626,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
     // When full debuginfo is enabled, we want to try and prevent vtables from being
     // merged. Otherwise debuggers will have a hard time mapping from dyn pointer
     // to concrete type.
-    llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
+    llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No);
 
     let vtable_name =
         compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 2419ec1f888..eb75716d768 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>(
     };
 
     llvm::SetFunctionCallConv(llfn, callconv);
-    llvm::SetUnnamedAddress(llfn, unnamed);
+    llvm::set_unnamed_address(llfn, unnamed);
     llvm::set_visibility(llfn, visibility);
 
     llfn
@@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
                 {
                     let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
                     if typeids.insert(typeid.clone()) {
-                        self.add_type_metadata(llfn, typeid);
+                        self.add_type_metadata(llfn, typeid.as_bytes());
                     }
                 }
             } else {
@@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
                 .map(cfi::TypeIdOptions::from_iter)
                 {
                     let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
-                    self.add_type_metadata(llfn, typeid);
+                    self.add_type_metadata(llfn, typeid.as_bytes());
                 }
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 5c34ab2e304..0b1e632cbc4 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1009,7 +1009,7 @@ unsafe extern "C" {
         ModuleID: *const c_char,
         C: &Context,
     ) -> &Module;
-    pub(crate) fn LLVMCloneModule(M: &Module) -> &Module;
+    pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module;
 
     /// Data layout. See Module::getDataLayout.
     pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char;
@@ -1168,18 +1168,18 @@ unsafe extern "C" {
     pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type;
 
     // Operations on global variables
-    pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
+    pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
     pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
     pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
     pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
     pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
     pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value);
-    pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
+    pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
     pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value);
-    pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
+    pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
     pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
-    pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
-    pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
+    pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
+    pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
     pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
 
     // Operations on attributes
@@ -1718,7 +1718,7 @@ unsafe extern "C" {
 
     pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
-    pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
+    pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
 
     pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 3fc83fca352..154ba4fd690 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) {
     set_comdat(llmod, val, &name);
 }
 
-pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
-    unsafe {
-        LLVMSetUnnamedAddress(global, unnamed);
-    }
+pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) {
+    LLVMSetUnnamedAddress(global, unnamed);
 }
 
 pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
@@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) {
 }
 
 pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) {
-    unsafe {
-        LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
-    }
+    LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
 }
 
 pub(crate) fn get_linkage(llglobal: &Value) -> Linkage {
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 3f38e1e191b..8f70270f203 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> {
         }
 
         // Thread-local variables generally don't support copy relocations.
-        let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) }
-            .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True);
+        let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
+            .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True);
         if is_thread_local_var {
             return false;
         }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index ee472e75ed4..89365503138 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -2,7 +2,7 @@ use std::borrow::Borrow;
 use std::hash::{Hash, Hasher};
 use std::{fmt, ptr};
 
-use libc::{c_char, c_uint};
+use libc::c_uint;
 use rustc_abi::{AddressSpace, Align, Integer, Reg, Size};
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::*;
@@ -298,8 +298,8 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 }
 
 impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn add_type_metadata(&self, function: &'ll Value, typeid: String) {
-        let typeid_metadata = self.typeid_metadata(typeid).unwrap();
+    fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
+        let typeid_metadata = self.create_metadata(typeid);
         unsafe {
             let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
             llvm::LLVMRustGlobalAddMetadata(
@@ -310,8 +310,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
-        let typeid_metadata = self.typeid_metadata(typeid).unwrap();
+    fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
+        let typeid_metadata = self.create_metadata(typeid);
         unsafe {
             let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
             llvm::LLVMGlobalSetMetadata(
@@ -322,10 +322,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> {
-        Some(unsafe {
-            llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len())
-        })
+    fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> {
+        Some(self.create_metadata(typeid))
     }
 
     fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 2aa5c3c27ea..34ad35a729b 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         && bx.cx().sess().lto() == Lto::Fat
     {
         if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
-            let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
+            let typeid =
+                bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap();
             let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
             return func;
         } else if nonnull {
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index dcd9e25b2c9..32c24965e1b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes {
 // For backends that support CFI using type membership (i.e., testing whether a given pointer is
 // associated with a type identifier).
 pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes {
-    fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {}
-    fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {}
-    fn typeid_metadata(&self, _typeid: String) -> Option<Self::Metadata> {
+    fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {}
+    fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {}
+    fn typeid_metadata(&self, _typeid: &[u8]) -> Option<Self::Metadata> {
         None
     }
     fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index b767ca9a3c2..c9b7356432d 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -296,19 +296,22 @@ const_eval_pointer_arithmetic_overflow =
     overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
 
 const_eval_pointer_out_of_bounds =
-    {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg ->
-        [false] {$alloc_size_minus_ptr_offset ->
-                [0] is at or beyond the end of the allocation of size {$alloc_size ->
-                    [1] 1 byte
-                    *[x] {$alloc_size} bytes
+    {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg ->
+        [true] points to before the beginning of the allocation
+        *[false] {$inbounds_size_is_neg ->
+            [false] {$alloc_size_minus_ptr_offset ->
+                        [0] is at or beyond the end of the allocation of size {$alloc_size ->
+                            [1] 1 byte
+                            *[x] {$alloc_size} bytes
+                        }
+                        [1] is only 1 byte from the end of the allocation
+                        *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
+                    }
+            *[true] {$ptr_offset_abs ->
+                    [0] is at the beginning of the allocation
+                    *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
                 }
-                [1] is only 1 byte from the end of the allocation
-                *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
-            }
-        *[true] {$ptr_offset_abs ->
-                [0] is at the beginning of the allocation
-                *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
-            }
+        }
     }
 
 const_eval_pointer_use_after_free =
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index ad3e02580f3..1503f3bcd99 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -6,7 +6,7 @@ use std::borrow::Cow;
 use either::{Left, Right};
 use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout};
+use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::sym;
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 41fc8d47cd3..11e7706fe60 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
-    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
-    TyAndLayout,
+    self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf,
+    LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
 use rustc_middle::{mir, span_bug};
@@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
     }
 }
 
-impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
-    /// This inherent method takes priority over the trait method with the same name in LayoutOf,
-    /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
-    /// See [LayoutOf::layout_of] for the original documentation.
-    #[inline(always)]
-    pub fn layout_of(
-        &self,
-        ty: Ty<'tcx>,
-    ) -> <InterpCx<'tcx, M> as LayoutOfHelpers<'tcx>>::LayoutOfResult {
-        let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind());
-        LayoutOf::layout_of(self, ty)
-    }
-}
-
 impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
     type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>;
 
@@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
     }
 }
 
+impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
+    /// This inherent method takes priority over the trait method with the same name in LayoutOf,
+    /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
+    /// See [LayoutOf::layout_of] for the original documentation.
+    #[inline(always)]
+    pub fn layout_of(&self, ty: Ty<'tcx>) -> <Self as LayoutOfHelpers<'tcx>>::LayoutOfResult {
+        let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind());
+        LayoutOf::layout_of(self, ty)
+    }
+
+    /// This inherent method takes priority over the trait method with the same name in FnAbiOf,
+    /// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span.
+    /// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation.
+    #[inline(always)]
+    pub fn fn_abi_of_fn_ptr(
+        &self,
+        sig: ty::PolyFnSig<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
+        let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args);
+        FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args)
+    }
+
+    /// This inherent method takes priority over the trait method with the same name in FnAbiOf,
+    /// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span.
+    /// See [FnAbiOf::fn_abi_of_instance] for the original documentation.
+    #[inline(always)]
+    pub fn fn_abi_of_instance(
+        &self,
+        instance: ty::Instance<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
+        let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args);
+        FnAbiOf::fn_abi_of_instance(self, instance, extra_args)
+    }
+}
+
 /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1eba1f2f03c..22d29eda913 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         )?;
         self.copy_op_allow_transmute(&op, dest)?;
 
-        // Give the first pointer-size bytes provenance that knows about the type id.
+        // Give the each pointer-sized chunk provenance that knows about the type id.
         // Here we rely on `TypeId` being a newtype around an array of pointers, so we
-        // first project to its only field and then the first array element.
+        // first project to its only field and then the array elements.
         let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
         let first = self.project_field(dest, FieldIdx::ZERO)?;
-        let first = self.project_index(&first, 0)?;
-        let offset = self.read_scalar(&first)?.to_target_usize(&tcx)?;
-        let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset));
-        let ptr = self.global_root_pointer(ptr)?;
-        let val = Scalar::from_pointer(ptr, &tcx);
-        self.write_scalar(val, &first)
+        let mut elem_iter = self.project_array_fields(&first)?;
+        while let Some((_, elem)) = elem_iter.next(self)? {
+            // Decorate this part of the hash with provenance; leave the integer part unchanged.
+            let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?;
+            let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(hash_fragment));
+            let ptr = self.global_root_pointer(ptr)?;
+            let val = Scalar::from_pointer(ptr, &tcx);
+            self.write_scalar(val, &elem)?;
+        }
+        interp_ok(())
     }
 
     /// Returns `true` if emulation happened.
@@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let mut a_fields = self.project_array_fields(&a_fields)?;
                 let mut b_fields = self.project_array_fields(&b_fields)?;
 
-                let (_idx, a) = a_fields
-                    .next(self)?
-                    .expect("we know the layout of TypeId has at least 2 array elements");
-                let a = self.deref_pointer(&a)?;
-                let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
-
-                let (_idx, b) = b_fields
-                    .next(self)?
-                    .expect("we know the layout of TypeId has at least 2 array elements");
-                let b = self.deref_pointer(&b)?;
-                let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
+                let mut provenance_a = None;
+                let mut provenance_b = None;
+                let mut provenance_matches = true;
 
-                let provenance_matches = a == b;
+                while let Some((i, a)) = a_fields.next(self)? {
+                    let (_, b) = b_fields.next(self)?.unwrap();
 
-                let mut eq_id = offset_a == offset_b;
+                    let a = self.deref_pointer(&a)?;
+                    let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
 
-                while let Some((_, a)) = a_fields.next(self)? {
-                    let (_, b) = b_fields.next(self)?.unwrap();
+                    let b = self.deref_pointer(&b)?;
+                    let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
 
-                    let a = self.read_target_usize(&a)?;
-                    let b = self.read_target_usize(&b)?;
-                    eq_id &= a == b;
-                }
+                    if *provenance_a.get_or_insert(a) != a {
+                        throw_ub_format!(
+                            "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
+                        )
+                    }
+                    if *provenance_b.get_or_insert(b) != b {
+                        throw_ub_format!(
+                            "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
+                        )
+                    }
+                    provenance_matches &= a == b;
 
-                if !eq_id && provenance_matches {
-                    throw_ub_format!(
-                        "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents"
-                    )
+                    if offset_a != offset_b && provenance_matches {
+                        throw_ub_format!(
+                            "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents"
+                        )
+                    }
                 }
 
                 self.write_scalar(Scalar::from_bool(provenance_matches), dest)?;
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 833fcc38817..629dcc3523c 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -5,7 +5,6 @@
 use either::Either;
 use rustc_abi::{FIRST_VARIANT, FieldIdx};
 use rustc_index::IndexSlice;
-use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::source_map::Spanned;
diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md
index c081a3d9cfa..f00d1773944 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0536.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0536.md
@@ -3,22 +3,20 @@ The `not` cfg-predicate was malformed.
 Erroneous code example:
 
 ```compile_fail,E0536
-#[cfg(not())] // error: expected 1 cfg-pattern
-pub fn something() {}
-
-pub fn main() {}
+pub fn main() {
+    if cfg!(not()) { }
+}
 ```
 
 The `not` predicate expects one cfg-pattern. Example:
 
 ```
-#[cfg(not(target_os = "linux"))] // ok!
-pub fn something() {}
-
-pub fn main() {}
+pub fn main() {
+    if cfg!(not(target_os = "linux")) { } // ok!
+}
 ```
 
-For more information about the `cfg` attribute, read the section on
+For more information about the `cfg` macro, read the section on
 [Conditional Compilation][conditional-compilation] in the Reference.
 
 [conditional-compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 757a7e1c8e7..ce3006c2604 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -11,7 +11,7 @@ use rustc_ast::token::MetaVarKind;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
-use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
+use rustc_attr_data_structures::{AttributeKind, CfgEntry, Deprecation, Stability, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
@@ -1128,7 +1128,13 @@ pub trait ResolverExpand {
     /// HIR proc macros items back to their harness items.
     fn declare_proc_macro(&mut self, id: NodeId);
 
-    fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem);
+    fn append_stripped_cfg_item(
+        &mut self,
+        parent_node: NodeId,
+        ident: Ident,
+        cfg: CfgEntry,
+        cfg_span: Span,
+    );
 
     /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
     fn registered_tools(&self) -> &RegisteredTools;
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 170ac39d1ec..6922ddfd6bd 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -11,6 +11,9 @@ use rustc_ast::{
     NodeId, NormalAttr,
 };
 use rustc_attr_parsing as attr;
+use rustc_attr_parsing::{
+    AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr,
+};
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
     ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
@@ -18,6 +21,7 @@ use rustc_feature::{
 };
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::validate_attr;
+use rustc_parse::validate_attr::deny_builtin_meta_unsafety;
 use rustc_session::Session;
 use rustc_session::parse::feature_err;
 use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
@@ -161,7 +165,10 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
     attrs
         .iter()
         .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
-        .take_while(|attr| !is_cfg(attr) || strip_unconfigured.cfg_true(attr).0)
+        .take_while(|attr| {
+            !is_cfg(attr)
+                || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool()
+        })
         .collect()
 }
 
@@ -394,26 +401,42 @@ impl<'a> StripUnconfigured<'a> {
 
     /// Determines if a node with the given attributes should be included in this configuration.
     fn in_cfg(&self, attrs: &[Attribute]) -> bool {
-        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0)
+        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool())
     }
 
-    pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
-        let meta_item = match validate_attr::parse_meta(&self.sess.psess, attr) {
-            Ok(meta_item) => meta_item,
+    pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult {
+        // We need to run this to do basic validation of the attribute, such as that lits are valid, etc
+        // FIXME(jdonszelmann) this should not be necessary in the future
+        match validate_attr::parse_meta(&self.sess.psess, attr) {
+            Ok(_) => {}
             Err(err) => {
                 err.emit();
-                return (true, None);
+                return EvalConfigResult::True;
             }
-        };
+        }
 
-        validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item);
+        // Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check
+        deny_builtin_meta_unsafety(
+            self.sess.dcx(),
+            attr.get_normal_item().unsafety,
+            &rustc_ast::Path::from_ident(attr.ident().unwrap()),
+        );
+
+        let Some(cfg) = AttributeParser::parse_single(
+            self.sess,
+            attr,
+            attr.span,
+            node,
+            self.features,
+            true,
+            parse_cfg_attr,
+            &CFG_TEMPLATE,
+        ) else {
+            // Cfg attribute was not parsable, give up
+            return EvalConfigResult::True;
+        };
 
-        (
-            parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| {
-                attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features)
-            }),
-            Some(meta_item),
-        )
+        eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features)
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
@@ -465,6 +488,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
+/// FIXME: Still used by Rustdoc, should be removed after
 pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> {
     let span = meta_item.span;
     match meta_item.meta_item_list() {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 2de09aa1a28..f99060e9a21 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -13,6 +13,7 @@ use rustc_ast::{
     MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
 };
 use rustc_ast_pretty::pprust;
+use rustc_attr_parsing::EvalConfigResult;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_errors::PResult;
 use rustc_feature::Features;
@@ -2166,19 +2167,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn expand_cfg_true(
         &mut self,
-        node: &mut impl HasAttrs,
+        node: &mut (impl HasAttrs + HasNodeId),
         attr: ast::Attribute,
         pos: usize,
-    ) -> (bool, Option<ast::MetaItem>) {
-        let (res, meta_item) = self.cfg().cfg_true(&attr);
-        if res {
+    ) -> EvalConfigResult {
+        let res = self.cfg().cfg_true(&attr, node.node_id());
+        if res.as_bool() {
             // A trace attribute left in AST in place of the original `cfg` attribute.
             // It can later be used by lints or other diagnostics.
             let trace_attr = attr_into_trace(attr, sym::cfg_trace);
             node.visit_attrs(|attrs| attrs.insert(pos, trace_attr));
         }
 
-        (res, meta_item)
+        res
     }
 
     fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
@@ -2199,20 +2200,21 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             return match self.take_first_attr(&mut node) {
                 Some((attr, pos, derives)) => match attr.name() {
                     Some(sym::cfg) => {
-                        let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
-                        if res {
-                            continue;
-                        }
-
-                        if let Some(meta_item) = meta_item {
-                            for ident in node.declared_idents() {
-                                self.cx.resolver.append_stripped_cfg_item(
-                                    self.cx.current_expansion.lint_node_id,
-                                    ident,
-                                    meta_item.clone(),
-                                )
+                        let res = self.expand_cfg_true(&mut node, attr, pos);
+                        match res {
+                            EvalConfigResult::True => continue,
+                            EvalConfigResult::False { reason, reason_span } => {
+                                for ident in node.declared_idents() {
+                                    self.cx.resolver.append_stripped_cfg_item(
+                                        self.cx.current_expansion.lint_node_id,
+                                        ident,
+                                        reason.clone(),
+                                        reason_span,
+                                    )
+                                }
                             }
                         }
+
                         Default::default()
                     }
                     Some(sym::cfg_attr) => {
@@ -2291,7 +2293,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 Some((attr, pos, derives)) => match attr.name() {
                     Some(sym::cfg) => {
                         let span = attr.span;
-                        if self.expand_cfg_true(node, attr, pos).0 {
+                        if self.expand_cfg_true(node, attr, pos).as_bool() {
                             continue;
                         }
 
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index df010f87098..ca57c4f3164 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -295,6 +295,12 @@ impl DefKind {
         }
     }
 
+    /// This is a "module" in name resolution sense.
+    #[inline]
+    pub fn is_module_like(self) -> bool {
+        matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait)
+    }
+
     #[inline]
     pub fn is_fn_like(self) -> bool {
         matches!(
@@ -720,6 +726,15 @@ impl<Id> Res<Id> {
         }
     }
 
+    /// If this is a "module" in name resolution sense, return its `DefId`.
+    #[inline]
+    pub fn module_like_def_id(&self) -> Option<DefId> {
+        match self {
+            Res::Def(def_kind, def_id) if def_kind.is_module_like() => Some(*def_id),
+            _ => None,
+        }
+    }
+
     /// A human readable name for the res kind ("function", "module", etc.).
     pub fn descr(&self) -> &'static str {
         match *self {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index cb106962be1..364ad38556b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -49,7 +49,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             } = self.lower_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
-                hir::BoundConstness::Never,
+                trait_bound.modifiers.constness,
                 hir::BoundPolarity::Positive,
                 dummy_self,
                 &mut user_written_bounds,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index bc9badbb232..db89396d1dc 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -167,7 +167,7 @@ impl NonCamelCaseTypes {
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = matches!(
-            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id),
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None),
             Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
         );
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 19954459cb5..57a672c45f7 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -3,7 +3,7 @@ use std::mem;
 use std::sync::Arc;
 
 use rustc_attr_data_structures::Deprecation;
-use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::arena::ArenaAllocatable;
@@ -510,10 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         }
                         Entry::Vacant(entry) => {
                             entry.insert(parent);
-                            if matches!(
-                                child.res,
-                                Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _)
-                            ) {
+                            if child.res.module_like_def_id().is_some() {
                                 bfs_queue.push_back(def_id);
                             }
                         }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 8347626080e..915c9731688 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -7,7 +7,7 @@ use def_path_hash_map::DefPathHashMapRef;
 use encoder::EncodeContext;
 pub use encoder::{EncodedMetadata, encode_metadata, rendered_const};
 use rustc_abi::{FieldIdx, ReprOptions, VariantIdx};
-use rustc_ast::expand::StrippedCfgItem;
+use rustc_attr_data_structures::StrippedCfgItem;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_hir::PreciseCapturingArgKind;
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index f140ab4755b..43a7af9ce38 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -110,7 +110,7 @@ macro_rules! arena_types {
             [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>,
             [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>,
             [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
-            [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem,
+            [] stripped_cfg_items: rustc_attr_data_structures::StrippedCfgItem,
             [] mod_child: rustc_middle::metadata::ModChild,
             [] features: rustc_feature::Features,
             [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 842d118449a..935cc889574 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -69,8 +69,8 @@ use std::sync::Arc;
 
 use rustc_abi::Align;
 use rustc_arena::TypedArena;
-use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr_data_structures::StrippedCfgItem;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a352ab3fd08..6e8f1e8fdd5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -25,10 +25,9 @@ pub use generic_args::{GenericArgKind, TermKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
 use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
-use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
 pub use rustc_ast_ir::{Movability, Mutability, try_visit};
-use rustc_attr_data_structures::{AttributeKind, find_attr};
+use rustc_attr_data_structures::{AttributeKind, StrippedCfgItem, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 3d601fc0533..dbacbe21edb 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -87,7 +87,7 @@ trivially_parameterized_over_tcx! {
     ty::IntrinsicDef,
     rustc_ast::Attribute,
     rustc_ast::DelimArgs,
-    rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
+    rustc_attr_data_structures::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
     rustc_attr_data_structures::ConstStability,
     rustc_attr_data_structures::DefaultBodyStability,
     rustc_attr_data_structures::Deprecation,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7c48a4b0885..8f0f9b21dc1 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3454,9 +3454,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
                         collect_fn(&child.ident, ns, def_id);
                     }
 
-                    if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
-                        && seen_defs.insert(def_id)
-                    {
+                    if defkind.is_module_like() && seen_defs.insert(def_id) {
                         queue.push(def_id);
                     }
                 }
diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs
index 24a05afff4a..2c6fb224d70 100644
--- a/compiler/rustc_parse/src/parser/cfg_select.rs
+++ b/compiler/rustc_parse/src/parser/cfg_select.rs
@@ -7,7 +7,7 @@ use rustc_span::Span;
 use crate::exp;
 use crate::parser::Parser;
 
-pub enum CfgSelectRule {
+pub enum CfgSelectPredicate {
     Cfg(MetaItemInner),
     Wildcard(Token),
 }
@@ -20,7 +20,7 @@ pub struct CfgSelectBranches {
     pub wildcard: Option<(Token, TokenStream, Span)>,
     /// All branches after the first wildcard, including further wildcards.
     /// These branches are kept for formatting.
-    pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>,
+    pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
 }
 
 /// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where
@@ -52,7 +52,7 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches
             match branches.wildcard {
                 None => branches.wildcard = Some((underscore, tts, span)),
                 Some(_) => {
-                    branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span))
+                    branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span))
                 }
             }
         } else {
@@ -64,7 +64,9 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches
 
             match branches.wildcard {
                 None => branches.reachable.push((meta_item, tts, span)),
-                Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)),
+                Some(_) => {
+                    branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span))
+                }
             }
         }
     }
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index a997be3405d..740dd10ea8b 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -575,14 +575,69 @@ impl<'a> Parser<'a> {
                 self.expect(exp!(CloseBracket))?;
             }
             TyKind::Array(elt_ty, length)
-        } else {
-            self.expect(exp!(CloseBracket))?;
+        } else if self.eat(exp!(CloseBracket)) {
             TyKind::Slice(elt_ty)
+        } else {
+            self.maybe_recover_array_ty_without_semi(elt_ty)?
         };
 
         Ok(ty)
     }
 
+    /// Recover from malformed array type syntax.
+    ///
+    /// This method attempts to recover from cases like:
+    /// - `[u8, 5]` → suggests using `;`, return a Array type
+    /// - `[u8 5]` → suggests using `;`, return a Array type
+    /// Consider to add more cases in the future.
+    fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P<Ty>) -> PResult<'a, TyKind> {
+        let span = self.token.span;
+        let token_descr = super::token_descr(&self.token);
+        let mut err =
+            self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr));
+        err.span_label(span, "expected `;` or `]`");
+        err.note("you might have meant to write a slice or array type");
+
+        // If we cannot recover, return the error immediately.
+        if !self.may_recover() {
+            return Err(err);
+        }
+
+        let snapshot = self.create_snapshot_for_diagnostic();
+
+        let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) {
+            // Consume common erroneous separators.
+            self.prev_token.span
+        } else {
+            self.token.span.shrink_to_lo()
+        };
+
+        // we first try to parse pattern like `[u8 5]`
+        let length = match self.parse_expr_anon_const() {
+            Ok(length) => length,
+            Err(e) => {
+                e.cancel();
+                self.restore_snapshot(snapshot);
+                return Err(err);
+            }
+        };
+
+        if let Err(e) = self.expect(exp!(CloseBracket)) {
+            e.cancel();
+            self.restore_snapshot(snapshot);
+            return Err(err);
+        }
+
+        err.span_suggestion_verbose(
+            suggestion_span,
+            "you might have meant to use `;` as the separator",
+            ";",
+            Applicability::MaybeIncorrect,
+        );
+        err.emit();
+        Ok(TyKind::Array(elt_ty, length))
+    }
+
     fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
         let and_span = self.prev_token.span;
         let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 5c748e956a0..783d79d978a 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -4,9 +4,9 @@ use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::DelimSpan;
 use rustc_ast::{
     self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId,
-    Safety,
+    Path, Safety,
 };
-use rustc_errors::{Applicability, FatalError, PResult};
+use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult};
 use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_session::errors::report_lit_error;
 use rustc_session::lint::BuiltinLintDiag;
@@ -247,14 +247,12 @@ pub fn check_attribute_safety(
 
 // Called by `check_builtin_meta_item` and code that manually denies
 // `unsafe(...)` in `cfg`
-pub fn deny_builtin_meta_unsafety(psess: &ParseSess, meta: &MetaItem) {
+pub fn deny_builtin_meta_unsafety(diag: DiagCtxtHandle<'_>, unsafety: Safety, name: &Path) {
     // This only supports denying unsafety right now - making builtin attributes
     // support unsafety will requite us to thread the actual `Attribute` through
     // for the nice diagnostics.
-    if let Safety::Unsafe(unsafe_span) = meta.unsafety {
-        psess
-            .dcx()
-            .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
+    if let Safety::Unsafe(unsafe_span) = unsafety {
+        diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() });
     }
 }
 
@@ -299,6 +297,7 @@ pub fn check_builtin_meta_item(
                 | sym::align
                 | sym::deprecated
                 | sym::optimize
+                | sym::pointee
                 | sym::cold
                 | sym::target_feature
                 | sym::rustc_allow_const_fn_unstable
@@ -326,7 +325,7 @@ pub fn check_builtin_meta_item(
     }
 
     if deny_unsafety {
-        deny_builtin_meta_unsafety(psess, meta);
+        deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path);
     }
 }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 820255afe27..2009ddc1e2d 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -251,6 +251,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     AttributeKind::BodyStability { .. }
                     | AttributeKind::ConstStabilityIndirect
                     | AttributeKind::MacroTransparency(_)
+                    | AttributeKind::Pointee(..)
                     | AttributeKind::Dummy
                     | AttributeKind::OmitGdbPrettyPrinterSection,
                 ) => { /* do nothing  */ }
@@ -381,7 +382,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             | sym::cfg_attr_trace
                             // need to be fixed
                             | sym::cfi_encoding // FIXME(cfi_encoding)
-                            | sym::pointee // FIXME(derive_coerce_pointee)
                             | sym::instruction_set // broken on stable!!!
                             | sym::windows_subsystem // broken on stable!!!
                             | sym::patchable_function_entry // FIXME(patchable_function_entry)
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 6979d89a8e7..5a1be618cee 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -20,9 +20,9 @@ use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_index::bit_set::DenseBitSet;
 use rustc_metadata::creader::LoadedMacro;
+use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
-use rustc_middle::ty::Feed;
-use rustc_middle::{bug, ty};
+use rustc_middle::ty::{Feed, Visibility};
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::{Ident, Span, Symbol, kw, sym};
 use tracing::debug;
@@ -33,54 +33,42 @@ use crate::imports::{ImportData, ImportKind};
 use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use crate::{
     BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot,
-    NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError,
-    Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, errors,
+    NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used,
+    VisResolutionError, errors,
 };
 
 type Res = def::Res<NodeId>;
 
-impl<'ra, Id: Into<DefId>> ToNameBinding<'ra>
-    for (Module<'ra>, ty::Visibility<Id>, Span, LocalExpnId)
-{
-    fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> {
-        arenas.alloc_name_binding(NameBindingData {
-            kind: NameBindingKind::Module(self.0),
-            ambiguity: None,
-            warn_ambiguity: false,
-            vis: self.1.to_def_id(),
-            span: self.2,
-            expansion: self.3,
-        })
-    }
-}
-
-impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
-    fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> {
-        arenas.alloc_name_binding(NameBindingData {
-            kind: NameBindingKind::Res(self.0),
-            ambiguity: None,
-            warn_ambiguity: false,
-            vis: self.1.to_def_id(),
-            span: self.2,
-            expansion: self.3,
-        })
-    }
-}
-
 impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
-    pub(crate) fn define<T>(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T)
-    where
-        T: ToNameBinding<'ra>,
-    {
-        let binding = def.to_name_binding(self.arenas);
+    pub(crate) fn define_binding(
+        &mut self,
+        parent: Module<'ra>,
+        ident: Ident,
+        ns: Namespace,
+        binding: NameBinding<'ra>,
+    ) {
         let key = self.new_disambiguated_key(ident, ns);
         if let Err(old_binding) = self.try_define(parent, key, binding, false) {
             self.report_conflict(parent, ident, ns, old_binding, binding);
         }
     }
 
+    fn define(
+        &mut self,
+        parent: Module<'ra>,
+        ident: Ident,
+        ns: Namespace,
+        res: Res,
+        vis: Visibility<impl Into<DefId>>,
+        span: Span,
+        expn_id: LocalExpnId,
+    ) {
+        let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id);
+        self.define_binding(parent, ident, ns, binding)
+    }
+
     /// Walks up the tree of definitions starting at `def_id`,
     /// stopping at the first encountered module.
     /// Parent block modules for arbitrary def-ids are not recorded for the local crate,
@@ -121,7 +109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         if !def_id.is_local() {
             // Query `def_kind` is not used because query system overhead is too expensive here.
             let def_kind = self.cstore().def_kind_untracked(def_id);
-            if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind {
+            if def_kind.is_module_like() {
                 let parent = self
                     .tcx
                     .opt_parent(def_id)
@@ -223,12 +211,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let expansion = parent_scope.expansion;
         // Record primary definitions.
         match res {
-            Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => {
-                let module = self.expect_module(def_id);
-                self.define(parent, ident, TypeNS, (module, vis, span, expansion));
-            }
             Res::Def(
-                DefKind::Struct
+                DefKind::Mod
+                | DefKind::Enum
+                | DefKind::Trait
+                | DefKind::Struct
                 | DefKind::Union
                 | DefKind::Variant
                 | DefKind::TyAlias
@@ -239,7 +226,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 _,
             )
             | Res::PrimTy(..)
-            | Res::ToolMod => self.define(parent, ident, TypeNS, (res, vis, span, expansion)),
+            | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion),
             Res::Def(
                 DefKind::Fn
                 | DefKind::AssocFn
@@ -248,9 +235,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 | DefKind::AssocConst
                 | DefKind::Ctor(..),
                 _,
-            ) => self.define(parent, ident, ValueNS, (res, vis, span, expansion)),
+            ) => self.define(parent, ident, ValueNS, res, vis, span, expansion),
             Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
-                self.define(parent, ident, MacroNS, (res, vis, span, expansion))
+                self.define(parent, ident, MacroNS, res, vis, span, expansion)
             }
             Res::Def(
                 DefKind::TyParam
@@ -294,10 +281,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         Res::Def(self.r.tcx.def_kind(def_id), def_id)
     }
 
-    fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
+    fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility {
         self.try_resolve_visibility(vis, true).unwrap_or_else(|err| {
             self.r.report_vis_error(err);
-            ty::Visibility::Public
+            Visibility::Public
         })
     }
 
@@ -305,10 +292,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         &mut self,
         vis: &'ast ast::Visibility,
         finalize: bool,
-    ) -> Result<ty::Visibility, VisResolutionError<'ast>> {
+    ) -> Result<Visibility, VisResolutionError<'ast>> {
         let parent_scope = &self.parent_scope;
         match vis.kind {
-            ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
+            ast::VisibilityKind::Public => Ok(Visibility::Public),
             ast::VisibilityKind::Inherited => {
                 Ok(match self.parent_scope.module.kind {
                     // Any inherited visibility resolved directly inside an enum or trait
@@ -318,7 +305,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         self.r.tcx.visibility(def_id).expect_local()
                     }
                     // Otherwise, the visibility is restricted to the nearest parent `mod` item.
-                    _ => ty::Visibility::Restricted(
+                    _ => Visibility::Restricted(
                         self.parent_scope.module.nearest_parent_mod().expect_local(),
                     ),
                 })
@@ -366,9 +353,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         }
                         if module.is_normal() {
                             match res {
-                                Res::Err => Ok(ty::Visibility::Public),
+                                Res::Err => Ok(Visibility::Public),
                                 _ => {
-                                    let vis = ty::Visibility::Restricted(res.def_id());
+                                    let vis = Visibility::Restricted(res.def_id());
                                     if self.r.is_accessible_from(vis, parent_scope.module) {
                                         Ok(vis.expect_local())
                                     } else {
@@ -433,7 +420,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         item: &ast::Item,
         root_span: Span,
         root_id: NodeId,
-        vis: ty::Visibility,
+        vis: Visibility,
     ) {
         let current_module = self.parent_scope.module;
         let import = self.r.arenas.alloc_import(ImportData {
@@ -481,7 +468,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         list_stem: bool,
         // The whole `use` item
         item: &Item,
-        vis: ty::Visibility,
+        vis: Visibility,
         root_span: Span,
     ) {
         debug!(
@@ -690,7 +677,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         true,
                         // The whole `use` item
                         item,
-                        ty::Visibility::Restricted(
+                        Visibility::Restricted(
                             self.parent_scope.module.nearest_parent_mod().expect_local(),
                         ),
                         root_span,
@@ -706,7 +693,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         ident: Ident,
         feed: Feed<'tcx, LocalDefId>,
         adt_res: Res,
-        adt_vis: ty::Visibility,
+        adt_vis: Visibility,
         adt_span: Span,
     ) {
         let parent_scope = &self.parent_scope;
@@ -714,7 +701,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let expansion = parent_scope.expansion;
 
         // Define a name in the type namespace if it is not anonymous.
-        self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion));
+        self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion);
         self.r.feed_visibility(feed, adt_vis);
         let def_id = feed.key();
 
@@ -766,7 +753,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             }
 
             ItemKind::Mod(_, ident, ref mod_kind) => {
-                let module = self.r.new_module(
+                self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
+
+                if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
+                    self.r.mods_with_parse_errors.insert(def_id);
+                }
+                self.parent_scope.module = self.r.new_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
@@ -774,24 +766,16 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     parent.no_implicit_prelude
                         || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude),
                 );
-                self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-
-                if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
-                    self.r.mods_with_parse_errors.insert(def_id);
-                }
-
-                // Descend into the module.
-                self.parent_scope.module = module;
             }
 
             // These items live in the value namespace.
             ItemKind::Const(box ConstItem { ident, .. })
             | ItemKind::Delegation(box Delegation { ident, .. })
             | ItemKind::Static(box StaticItem { ident, .. }) => {
-                self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+                self.r.define(parent, ident, ValueNS, res, vis, sp, expansion);
             }
             ItemKind::Fn(box Fn { ident, .. }) => {
-                self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+                self.r.define(parent, ident, ValueNS, res, vis, sp, expansion);
 
                 // Functions introducing procedural macros reserve a slot
                 // in the macro namespace as well (see #52225).
@@ -800,19 +784,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
 
             // These items live in the type namespace.
             ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => {
-                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
             }
 
             ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => {
-                let module = self.r.new_module(
+                self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
+
+                self.parent_scope.module = self.r.new_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
                     item.span,
                     parent.no_implicit_prelude,
                 );
-                self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-                self.parent_scope.module = module;
             }
 
             // These items live in both the type and value namespaces.
@@ -834,7 +818,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     let mut ctor_vis = if vis.is_public()
                         && ast::attr::contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(CRATE_DEF_ID)
+                        Visibility::Restricted(CRATE_DEF_ID)
                     } else {
                         vis
                     };
@@ -847,7 +831,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         // constructor visibility should still be determined correctly.
                         let field_vis = self
                             .try_resolve_visibility(&field.vis, false)
-                            .unwrap_or(ty::Visibility::Public);
+                            .unwrap_or(Visibility::Public);
                         if ctor_vis.is_at_least(field_vis, self.r.tcx) {
                             ctor_vis = field_vis;
                         }
@@ -856,7 +840,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     let feed = self.r.feed(ctor_node_id);
                     let ctor_def_id = feed.key();
                     let ctor_res = self.res(ctor_def_id);
-                    self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
+                    self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion);
                     self.r.feed_visibility(feed, ctor_vis);
                     // We need the field visibility spans also for the constructor for E0603.
                     self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields());
@@ -896,7 +880,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         item: &Item,
         ident: Ident,
         local_def_id: LocalDefId,
-        vis: ty::Visibility,
+        vis: Visibility,
         parent: Module<'ra>,
     ) {
         let sp = item.span;
@@ -920,8 +904,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         }
         .map(|module| {
             let used = self.process_macro_use_imports(item, module);
-            let vis = ty::Visibility::<LocalDefId>::Public;
-            let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas);
+            let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion);
             (used, Some(ModuleOrUniformRoot::Module(module)), binding)
         })
         .unwrap_or((true, None, self.r.dummy_binding));
@@ -978,7 +961,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 );
             }
         }
-        self.r.define(parent, ident, TypeNS, imported_binding);
+        self.r.define_binding(parent, ident, TypeNS, imported_binding);
     }
 
     /// Constructs the reduced graph for one foreign item.
@@ -995,7 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let parent = self.parent_scope.module;
         let expansion = self.parent_scope.expansion;
         let vis = self.resolve_visibility(&item.vis);
-        self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion));
+        self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
         self.r.feed_visibility(feed, vis);
     }
 
@@ -1081,7 +1064,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: ty::Visibility::Restricted(CRATE_DEF_ID),
+                vis: Visibility::Restricted(CRATE_DEF_ID),
             })
         };
 
@@ -1231,11 +1214,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             self.r.macro_names.insert(ident);
             let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export);
             let vis = if is_macro_export {
-                ty::Visibility::Public
+                Visibility::Public
             } else {
-                ty::Visibility::Restricted(CRATE_DEF_ID)
+                Visibility::Restricted(CRATE_DEF_ID)
             };
-            let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
+            let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion);
             self.r.set_binding_parent_module(binding, parent_scope.module);
             self.r.all_macro_rules.insert(ident.name);
             if is_macro_export {
@@ -1254,7 +1237,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 });
                 self.r.import_use_map.insert(import, Used::Other);
                 let import_binding = self.r.import(binding, import);
-                self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
+                self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding);
             } else {
                 self.r.check_reserved_macro_name(ident, res);
                 self.insert_unused_macro(ident, def_id, item.id);
@@ -1275,14 +1258,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 // Visibilities must not be resolved non-speculatively twice
                 // and we already resolved this one as a `fn` item visibility.
                 ItemKind::Fn(..) => {
-                    self.try_resolve_visibility(&item.vis, false).unwrap_or(ty::Visibility::Public)
+                    self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public)
                 }
                 _ => self.resolve_visibility(&item.vis),
             };
             if !vis.is_public() {
                 self.insert_unused_macro(ident, def_id, item.id);
             }
-            self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
+            self.r.define(module, ident, MacroNS, res, vis, span, expansion);
             self.r.feed_visibility(feed, vis);
             self.parent_scope.macro_rules
         }
@@ -1418,7 +1401,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         if ctxt == AssocCtxt::Trait {
             let parent = self.parent_scope.module;
             let expansion = self.parent_scope.expansion;
-            self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion));
+            self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
         } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) {
             let impl_def_id = self.r.tcx.local_parent(local_def_id);
             let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns);
@@ -1503,13 +1486,13 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let feed = self.r.feed(variant.id);
         let def_id = feed.key();
         let vis = self.resolve_visibility(&variant.vis);
-        self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id));
+        self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id);
         self.r.feed_visibility(feed, vis);
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
         let ctor_vis =
             if vis.is_public() && ast::attr::contains_name(&variant.attrs, sym::non_exhaustive) {
-                ty::Visibility::Restricted(CRATE_DEF_ID)
+                Visibility::Restricted(CRATE_DEF_ID)
             } else {
                 vis
             };
@@ -1519,7 +1502,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             let feed = self.r.feed(ctor_node_id);
             let ctor_def_id = feed.key();
             let ctor_res = self.res(ctor_def_id);
-            self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
+            self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id);
             self.r.feed_visibility(feed, ctor_vis);
         }
 
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index e2caf632dd2..781e2ce9704 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -132,6 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
                     Vec::new(),
+                    Early { emit_errors: false },
                 );
                 let attrs = parser.parse_attribute_list(
                     &i.attrs,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index b2f16fb1dfb..11e4a729ae2 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,11 +1,10 @@
-use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{
-    self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
-};
+use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path};
 use rustc_ast_pretty::pprust;
-use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr};
+use rustc_attr_data_structures::{
+    self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr,
+};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
@@ -233,12 +232,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             return;
         }
 
-        let old_kind = match (ns, old_binding.module()) {
+        let old_kind = match (ns, old_binding.res()) {
             (ValueNS, _) => "value",
             (MacroNS, _) => "macro",
             (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
-            (TypeNS, Some(module)) if module.is_normal() => "module",
-            (TypeNS, Some(module)) if module.is_trait() => "trait",
+            (TypeNS, Res::Def(DefKind::Mod, _)) => "module",
+            (TypeNS, Res::Def(DefKind::Trait, _)) => "trait",
             (TypeNS, _) => "type",
         };
 
@@ -1320,7 +1319,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
 
                 // collect submodules to explore
-                if let Some(module) = name_binding.module() {
+                if let Some(def_id) = name_binding.res().module_like_def_id() {
                     // form the path
                     let mut path_segments = path_segments.clone();
                     path_segments.push(ast::PathSegment::from_ident(ident));
@@ -1340,14 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
                     if !is_extern_crate_that_also_appears_in_prelude || alias_import {
                         // add the module to the lookup
-                        if seen_modules.insert(module.def_id()) {
+                        if seen_modules.insert(def_id) {
                             if via_import { &mut worklist_via_import } else { &mut worklist }.push(
                                 (
-                                    module,
+                                    this.expect_module(def_id),
                                     path_segments,
                                     child_accessible,
                                     child_doc_visible,
-                                    is_stable && this.is_stable(module.def_id(), name_binding.span),
+                                    is_stable && this.is_stable(def_id, name_binding.span),
                                 ),
                             );
                         }
@@ -2095,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         true, // re-export
                     ));
                 }
-                NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
+                NameBindingKind::Res(_) => {}
             }
             let first = binding == first_binding;
             let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
@@ -2307,25 +2306,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     .ok()
                 };
                 if let Some(binding) = binding {
-                    let mut found = |what| {
-                        msg = format!(
-                            "expected {}, found {} `{}` in {}",
-                            ns.descr(),
-                            what,
-                            ident,
-                            parent
-                        )
-                    };
-                    if binding.module().is_some() {
-                        found("module")
-                    } else {
-                        match binding.res() {
-                            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
-                            // indirectly *calls* the resolver, and would cause a query cycle.
-                            Res::Def(kind, id) => found(kind.descr(id)),
-                            _ => found(ns_to_try.descr()),
-                        }
-                    }
+                    msg = format!(
+                        "expected {}, found {} `{ident}` in {parent}",
+                        ns.descr(),
+                        binding.res().descr(),
+                    );
                 };
             }
             (msg, None)
@@ -2860,17 +2845,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             let note = errors::FoundItemConfigureOut { span: ident.span };
             err.subdiagnostic(note);
 
-            if let MetaItemKind::List(nested) = &cfg.kind
-                && let MetaItemInner::MetaItem(meta_item) = &nested[0]
-                && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
-            {
-                let note = errors::ItemWasBehindFeature {
-                    feature: feature_name.symbol,
-                    span: meta_item.span,
-                };
+            if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 {
+                let note = errors::ItemWasBehindFeature { feature, span: cfg.1 };
                 err.subdiagnostic(note);
             } else {
-                let note = errors::ItemWasCfgOut { span: cfg.span };
+                let note = errors::ItemWasCfgOut { span: cfg.1 };
                 err.subdiagnostic(note);
             }
         }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 99297de40d5..84d66c15f00 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -3,11 +3,10 @@ use Namespace::*;
 use rustc_ast::{self as ast, NodeId};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
-use rustc_middle::{bug, ty};
+use rustc_middle::bug;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::parse::feature_err;
-use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
 use rustc_span::{Ident, Span, kw, sym};
 use tracing::{debug, instrument};
@@ -20,11 +19,9 @@ use crate::{
     AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize,
     ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding,
     NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope,
-    ScopeSet, Segment, ToNameBinding, Used, Weak, errors,
+    ScopeSet, Segment, Used, Weak, errors,
 };
 
-type Visibility = ty::Visibility<LocalDefId>;
-
 #[derive(Copy, Clone)]
 pub enum UsePrelude {
     No,
@@ -464,13 +461,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
-                                        let binding = (
+                                        let binding = this.arenas.new_pub_res_binding(
                                             Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
-                                            Visibility::Public,
                                             derive.span,
                                             LocalExpnId::ROOT,
-                                        )
-                                            .to_name_binding(this.arenas);
+                                        );
                                         result = Ok((binding, Flags::empty()));
                                         break;
                                     }
@@ -1637,11 +1632,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
 
                     let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
-                    if let Some(next_module) = binding.module() {
-                        if self.mods_with_parse_errors.contains(&next_module.def_id()) {
+                    if let Some(def_id) = binding.res().module_like_def_id() {
+                        if self.mods_with_parse_errors.contains(&def_id) {
                             module_had_parse_errors = true;
                         }
-                        module = Some(ModuleOrUniformRoot::Module(next_module));
+                        module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id)));
                         record_segment_res(self, res);
                     } else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
                         if binding.is_import() {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 40c63a3edf3..9a031ee03e0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -11,7 +11,8 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err};
 use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_hir::def_id::DefId;
 use rustc_middle::metadata::{ModChild, Reexport};
-use rustc_middle::{span_bug, ty};
+use rustc_middle::span_bug;
+use rustc_middle::ty::Visibility;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
     AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
@@ -88,7 +89,7 @@ pub(crate) enum ImportKind<'ra> {
         is_prelude: bool,
         // The visibility of the greatest re-export.
         // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
-        max_vis: Cell<Option<ty::Visibility>>,
+        max_vis: Cell<Option<Visibility>>,
         id: NodeId,
     },
     ExternCrate {
@@ -185,7 +186,7 @@ pub(crate) struct ImportData<'ra> {
     /// |`use ::foo`      | `ModuleOrUniformRoot::CrateRootAndExternPrelude`    | a special case in 2015 edition |
     /// |`use foo`        | `ModuleOrUniformRoot::CurrentScope`                 | - |
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
-    pub vis: ty::Visibility,
+    pub vis: Visibility,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -679,9 +680,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             NameBindingKind::Res(res) => {
                                 Some(self.def_id_to_node_id(res.def_id().expect_local()))
                             }
-                            NameBindingKind::Module(module) => {
-                                Some(self.def_id_to_node_id(module.def_id().expect_local()))
-                            }
                             NameBindingKind::Import { import, .. } => import.id(),
                         };
                         if let Some(binding_id) = binding_id {
@@ -875,7 +873,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         }
                         // We need the `target`, `source` can be extracted.
                         let imported_binding = this.import(binding, import);
-                        this.define(parent, target, ns, imported_binding);
+                        this.define_binding(parent, target, ns, imported_binding);
                         PendingBinding::Ready(Some(imported_binding))
                     }
                     Err(Determinacy::Determined) => {
@@ -1283,7 +1281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
             if !binding.vis.is_at_least(import.vis, this.tcx) {
                 reexport_error = Some((ns, binding));
-                if let ty::Visibility::Restricted(binding_def_id) = binding.vis
+                if let Visibility::Restricted(binding_def_id) = binding.vis
                     && binding_def_id.is_top_level_module()
                 {
                     crate_private_reexport = true;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 44a567f7810..3ef98100d09 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -28,7 +28,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_bound_vars::Set1;
-use rustc_middle::ty::DelegationFnSig;
+use rustc_middle::ty::{DelegationFnSig, Visibility};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
 use rustc_session::lint::{self, BuiltinLintDiag};
@@ -638,8 +638,8 @@ impl PathSource<'_, '_, '_> {
 enum MaybeExported<'a> {
     Ok(NodeId),
     Impl(Option<DefId>),
-    ImplItem(Result<DefId, &'a Visibility>),
-    NestedUse(&'a Visibility),
+    ImplItem(Result<DefId, &'a ast::Visibility>),
+    NestedUse(&'a ast::Visibility),
 }
 
 impl MaybeExported<'_> {
@@ -3463,7 +3463,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                     span,
                     "error should be emitted when an unexpected trait item is used",
                 );
-                rustc_middle::ty::Visibility::Public
+                Visibility::Public
             };
             this.r.feed_visibility(this.r.feed(id), vis);
         };
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index b669796bb02..a4601cb44eb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2656,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 if result.is_some() || !name_binding.vis.is_visible_locally() {
                     return;
                 }
-                if let Some(module) = name_binding.module() {
+                if let Some(module_def_id) = name_binding.res().module_like_def_id() {
                     // form the path
                     let mut path_segments = path_segments.clone();
                     path_segments.push(ast::PathSegment::from_ident(ident));
-                    let module_def_id = module.def_id();
                     let doc_visible = doc_visible
                         && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id));
                     if module_def_id == def_id {
                         let path =
                             Path { span: name_binding.span, segments: path_segments, tokens: None };
                         result = Some((
-                            module,
+                            r.expect_module(module_def_id),
                             ImportSuggestion {
                                 did: Some(def_id),
                                 descr: "module",
@@ -2682,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     } else {
                         // add the module to the lookup
                         if seen_modules.insert(module_def_id) {
+                            let module = r.expect_module(module_def_id);
                             worklist.push((module, path_segments, doc_visible));
                         }
                     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f8d1b6783e3..b0b29bc2eae 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -36,12 +36,12 @@ use late::{
 };
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use rustc_arena::{DroplessArena, TypedArena};
-use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{
     self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs,
     LitKind, NodeId, Path, attr,
 };
+use rustc_attr_data_structures::StrippedCfgItem;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
@@ -65,7 +65,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{
     self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt,
-    ResolverOutputs, TyCtxt, TyCtxtFeed,
+    ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility,
 };
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
@@ -579,7 +579,7 @@ struct ModuleData<'ra> {
     globs: RefCell<Vec<Import<'ra>>>,
 
     /// Used to memoize the traits in this module for faster searches through all traits in scope.
-    traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>)]>>>,
+    traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
 
     /// Span of the module itself. Used for error reporting.
     span: Span,
@@ -655,12 +655,12 @@ impl<'ra> Module<'ra> {
         let mut traits = self.traits.borrow_mut();
         if traits.is_none() {
             let mut collected_traits = Vec::new();
-            self.for_each_child(resolver, |_, name, ns, binding| {
+            self.for_each_child(resolver, |r, name, ns, binding| {
                 if ns != TypeNS {
                     return;
                 }
-                if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() {
-                    collected_traits.push((name, binding))
+                if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
+                    collected_traits.push((name, binding, r.as_mut().get_module(def_id)))
                 }
             });
             *traits = Some(collected_traits.into_boxed_slice());
@@ -674,7 +674,6 @@ impl<'ra> Module<'ra> {
         }
     }
 
-    // Public for rustdoc.
     fn def_id(self) -> DefId {
         self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
     }
@@ -749,7 +748,7 @@ struct NameBindingData<'ra> {
     warn_ambiguity: bool,
     expansion: LocalExpnId,
     span: Span,
-    vis: ty::Visibility<DefId>,
+    vis: Visibility<DefId>,
 }
 
 /// All name bindings are unique and allocated on a same arena,
@@ -769,20 +768,9 @@ impl std::hash::Hash for NameBindingData<'_> {
     }
 }
 
-trait ToNameBinding<'ra> {
-    fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>;
-}
-
-impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> {
-    fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> {
-        self
-    }
-}
-
 #[derive(Clone, Copy, Debug)]
 enum NameBindingKind<'ra> {
     Res(Res),
-    Module(Module<'ra>),
     Import { binding: NameBinding<'ra>, import: Import<'ra> },
 }
 
@@ -875,18 +863,9 @@ struct AmbiguityError<'ra> {
 }
 
 impl<'ra> NameBindingData<'ra> {
-    fn module(&self) -> Option<Module<'ra>> {
-        match self.kind {
-            NameBindingKind::Module(module) => Some(module),
-            NameBindingKind::Import { binding, .. } => binding.module(),
-            _ => None,
-        }
-    }
-
     fn res(&self) -> Res {
         match self.kind {
             NameBindingKind::Res(res) => res,
-            NameBindingKind::Module(module) => module.res().unwrap(),
             NameBindingKind::Import { binding, .. } => binding.res(),
         }
     }
@@ -921,7 +900,7 @@ impl<'ra> NameBindingData<'ra> {
                 DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..),
                 _,
             )) => true,
-            NameBindingKind::Res(..) | NameBindingKind::Module(..) => false,
+            NameBindingKind::Res(..) => false,
         }
     }
 
@@ -930,11 +909,7 @@ impl<'ra> NameBindingData<'ra> {
             NameBindingKind::Import { import, .. } => {
                 matches!(import.kind, ImportKind::ExternCrate { .. })
             }
-            NameBindingKind::Module(module)
-                if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind =>
-            {
-                def_id.is_crate_root()
-            }
+            NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(),
             _ => false,
         }
     }
@@ -1108,7 +1083,7 @@ pub struct Resolver<'ra, 'tcx> {
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>,
     glob_error: Option<ErrorGuaranteed>,
-    visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
+    visibilities_for_hashing: Vec<(LocalDefId, Visibility)>,
     used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
 
@@ -1181,7 +1156,7 @@ pub struct Resolver<'ra, 'tcx> {
     /// Table for mapping struct IDs into struct constructor IDs,
     /// it's not used during normal resolution, only for better error reporting.
     /// Also includes of list of each fields visibility
-    struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
+    struct_constructors: LocalDefIdMap<(Res, Visibility<DefId>, Vec<Visibility<DefId>>)>,
 
     lint_buffer: LintBuffer,
 
@@ -1255,6 +1230,32 @@ pub struct ResolverArenas<'ra> {
 }
 
 impl<'ra> ResolverArenas<'ra> {
+    fn new_res_binding(
+        &'ra self,
+        res: Res,
+        vis: Visibility<DefId>,
+        span: Span,
+        expansion: LocalExpnId,
+    ) -> NameBinding<'ra> {
+        self.alloc_name_binding(NameBindingData {
+            kind: NameBindingKind::Res(res),
+            ambiguity: None,
+            warn_ambiguity: false,
+            vis,
+            span,
+            expansion,
+        })
+    }
+
+    fn new_pub_res_binding(
+        &'ra self,
+        res: Res,
+        span: Span,
+        expn_id: LocalExpnId,
+    ) -> NameBinding<'ra> {
+        self.new_res_binding(res, Visibility::Public, span, expn_id)
+    }
+
     fn new_module(
         &'ra self,
         parent: Option<Module<'ra>>,
@@ -1278,8 +1279,8 @@ impl<'ra> ResolverArenas<'ra> {
         }
         if let Some(def_id) = def_id {
             module_map.insert(def_id, module);
-            let vis = ty::Visibility::<DefId>::Public;
-            let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self);
+            let res = module.res().unwrap();
+            let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT);
             module_self_bindings.insert(module, binding);
         }
         module
@@ -1470,8 +1471,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
 
         let registered_tools = tcx.registered_tools(());
-
-        let pub_vis = ty::Visibility::<DefId>::Public;
         let edition = tcx.sess.edition();
 
         let mut resolver = Resolver {
@@ -1520,12 +1519,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             macro_expanded_macro_export_errors: BTreeSet::new(),
 
             arenas,
-            dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas),
+            dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT),
             builtin_types_bindings: PrimTy::ALL
                 .iter()
                 .map(|prim_ty| {
-                    let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT)
-                        .to_name_binding(arenas);
+                    let res = Res::PrimTy(*prim_ty);
+                    let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
                     (prim_ty.name(), binding)
                 })
                 .collect(),
@@ -1533,16 +1532,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 .iter()
                 .map(|builtin_attr| {
                     let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name));
-                    let binding =
-                        (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas);
+                    let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
                     (builtin_attr.name, binding)
                 })
                 .collect(),
             registered_tool_bindings: registered_tools
                 .iter()
                 .map(|ident| {
-                    let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT)
-                        .to_name_binding(arenas);
+                    let res = Res::ToolMod;
+                    let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT);
                     (*ident, binding)
                 })
                 .collect(),
@@ -1605,7 +1603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
         resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope);
-        resolver.feed_visibility(crate_feed, ty::Visibility::Public);
+        resolver.feed_visibility(crate_feed, Visibility::Public);
 
         resolver
     }
@@ -1659,7 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         Default::default()
     }
 
-    fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) {
+    fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) {
         let feed = feed.upgrade(self.tcx);
         feed.visibility(vis.to_def_id());
         self.visibilities_for_hashing.push((feed.def_id(), vis));
@@ -1837,10 +1835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ) {
         module.ensure_traits(self);
         let traits = module.traits.borrow();
-        for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() {
-            if self.trait_may_have_item(trait_binding.module(), assoc_item) {
+        for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() {
+            if self.trait_may_have_item(trait_module, assoc_item) {
                 let def_id = trait_binding.res().def_id();
-                let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name);
+                let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name);
                 found_traits.push(TraitCandidate { def_id, import_ids });
             }
         }
@@ -2110,11 +2108,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         self.pat_span_map.insert(node, span);
     }
 
-    fn is_accessible_from(
-        &self,
-        vis: ty::Visibility<impl Into<DefId>>,
-        module: Module<'ra>,
-    ) -> bool {
+    fn is_accessible_from(&self, vis: Visibility<impl Into<DefId>>, module: Module<'ra>) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod(), self.tcx)
     }
 
@@ -2174,9 +2168,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 } else {
                     self.crate_loader(|c| c.maybe_process_path_extern(ident.name))?
                 };
-                let crate_root = self.expect_module(crate_id.as_def_id());
-                let vis = ty::Visibility::<DefId>::Public;
-                (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas)
+                let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
+                self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT)
             })
         });
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 5864b035f73..c17d74659db 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -5,10 +5,9 @@ use std::cell::Cell;
 use std::mem;
 use std::sync::Arc;
 
-use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::{self as ast, Crate, NodeId, attr};
 use rustc_ast_pretty::pprust;
-use rustc_attr_data_structures::StabilityLevel;
+use rustc_attr_data_structures::{CfgEntry, StabilityLevel, StrippedCfgItem};
 use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
 use rustc_expand::base::{
     Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
@@ -21,7 +20,7 @@ use rustc_expand::expand::{
 use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_middle::middle::stability;
-use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility};
+use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
     LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
@@ -42,7 +41,7 @@ use crate::imports::Import;
 use crate::{
     BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind,
     ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError,
-    Resolver, ScopeSet, Segment, ToNameBinding, Used,
+    Resolver, ScopeSet, Segment, Used,
 };
 
 type Res = def::Res<NodeId>;
@@ -437,8 +436,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
             .iter()
             .map(|(_, ident)| {
                 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
-                let binding = (res, Visibility::<DefId>::Public, ident.span, expn_id)
-                    .to_name_binding(self.arenas);
+                let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id);
                 (*ident, binding)
             })
             .collect();
@@ -485,8 +483,18 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
         self.proc_macros.push(self.local_def_id(id))
     }
 
-    fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem) {
-        self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, ident, cfg });
+    fn append_stripped_cfg_item(
+        &mut self,
+        parent_node: NodeId,
+        ident: Ident,
+        cfg: CfgEntry,
+        cfg_span: Span,
+    ) {
+        self.stripped_cfg_items.push(StrippedCfgItem {
+            parent_module: parent_node,
+            ident,
+            cfg: (cfg, cfg_span),
+        });
     }
 
     fn registered_tools(&self) -> &RegisteredTools {
diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs
index 737550eb73e..9912fad1756 100644
--- a/compiler/rustc_type_ir/src/walk.rs
+++ b/compiler/rustc_type_ir/src/walk.rs
@@ -12,12 +12,6 @@ use crate::{self as ty, Interner};
 // avoid heap allocations.
 type TypeWalkerStack<I> = SmallVec<[<I as Interner>::GenericArg; 8]>;
 
-pub struct TypeWalker<I: Interner> {
-    stack: TypeWalkerStack<I>,
-    last_subtree: usize,
-    pub visited: SsoHashSet<I::GenericArg>,
-}
-
 /// An iterator for walking the type tree.
 ///
 /// It's very easy to produce a deeply
@@ -26,6 +20,12 @@ pub struct TypeWalker<I: Interner> {
 /// in this situation walker only visits each type once.
 /// It maintains a set of visited types and
 /// skips any types that are already there.
+pub struct TypeWalker<I: Interner> {
+    stack: TypeWalkerStack<I>,
+    last_subtree: usize,
+    pub visited: SsoHashSet<I::GenericArg>,
+}
+
 impl<I: Interner> TypeWalker<I> {
     pub fn new(root: I::GenericArg) -> Self {
         Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 4ad65e678c3..6b6e4df4cba 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -155,6 +155,7 @@
 #![feature(try_trait_v2)]
 #![feature(try_with_capacity)]
 #![feature(tuple_trait)]
+#![feature(ub_checks)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
 #![feature(unwrap_infallible)]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1df6ab672ea..9856e9c18ec 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ops::{self, Index, IndexMut, Range, RangeBounds};
 use core::ptr::{self, NonNull};
 use core::slice::{self, SliceIndex};
-use core::{fmt, intrinsics};
+use core::{fmt, intrinsics, ub_checks};
 
 #[stable(feature = "extract_if", since = "1.87.0")]
 pub use self::extract_if::ExtractIf;
@@ -1058,6 +1058,11 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
+        ub_checks::assert_unsafe_precondition!(
+            check_library_ub,
+            "Vec::from_raw_parts_in requires that length <= capacity",
+            (length: usize = length, capacity: usize = capacity) => length <= capacity
+        );
         unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
     }
 
@@ -1174,6 +1179,11 @@ impl<T, A: Allocator> Vec<T, A> {
     #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")]
     // #[unstable(feature = "box_vec_non_null", issue = "130364")]
     pub unsafe fn from_parts_in(ptr: NonNull<T>, length: usize, capacity: usize, alloc: A) -> Self {
+        ub_checks::assert_unsafe_precondition!(
+            check_library_ub,
+            "Vec::from_parts_in requires that length <= capacity",
+            (length: usize = length, capacity: usize = capacity) => length <= capacity
+        );
         unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
     }
 
@@ -1950,7 +1960,11 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn set_len(&mut self, new_len: usize) {
-        debug_assert!(new_len <= self.capacity());
+        ub_checks::assert_unsafe_precondition!(
+            check_library_ub,
+            "Vec::set_len requires that new_len <= capacity()",
+            (new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity
+        );
 
         self.len = new_len;
     }
@@ -3695,7 +3709,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// This is optimal if:
     ///
     /// * The tail (elements in the vector after `range`) is empty,
-    /// * or `replace_with` yields fewer or equal elements than `range`’s length
+    /// * or `replace_with` yields fewer or equal elements than `range`'s length
     /// * or the lower bound of its `size_hint()` is exact.
     ///
     /// Otherwise, a temporary vector is allocated and the tail is moved twice.
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 16356f749c9..62203e132b7 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] {
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> Index<I> for [T; N]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T, I, const N: usize> const Index<I> for [T; N]
 where
-    [T]: Index<I>,
+    [T]: ~const Index<I>,
 {
     type Output = <[T] as Index<I>>::Output;
 
@@ -387,9 +388,10 @@ where
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> IndexMut<I> for [T; N]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T, I, const N: usize> const IndexMut<I> for [T; N]
 where
-    [T]: IndexMut<I>,
+    [T]: ~const IndexMut<I>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut Self::Output {
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 6b9cbb06435..1b6dbc2f428 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -196,16 +196,14 @@ pub macro assert_matches {
     },
 }
 
-/// A macro for defining `#[cfg]` match-like statements.
+/// Selects code at compile-time based on `cfg` predicates.
 ///
-/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
-/// `#[cfg]` cases, emitting the implementation which matches first.
+/// This macro evaluates, at compile-time, a series of `cfg` predicates,
+/// selects the first that is true, and emits the code guarded by that
+/// predicate. The code guarded by other predicates is not emitted.
 ///
-/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
-/// without having to rewrite each clause multiple times.
-///
-/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when
-/// all previous declarations do not evaluate to true.
+/// An optional trailing `_` wildcard can be used to specify a fallback. If
+/// none of the predicates are true, a [`compile_error`] is emitted.
 ///
 /// # Example
 ///
@@ -225,7 +223,7 @@ pub macro assert_matches {
 /// }
 /// ```
 ///
-/// If desired, it is possible to return expressions through the use of surrounding braces:
+/// The `cfg_select!` macro can also be used in expression position:
 ///
 /// ```
 /// #![feature(cfg_select)]
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 55fa91d0b9f..c460f38bd2e 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -94,9 +94,9 @@ macro_rules! sh_impl_signed {
             #[inline]
             fn shl(self, other: $f) -> Wrapping<$t> {
                 if other < 0 {
-                    Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32))
+                    Wrapping(self.0.wrapping_shr(-other as u32))
                 } else {
-                    Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
+                    Wrapping(self.0.wrapping_shl(other as u32))
                 }
             }
         }
@@ -119,9 +119,9 @@ macro_rules! sh_impl_signed {
             #[inline]
             fn shr(self, other: $f) -> Wrapping<$t> {
                 if other < 0 {
-                    Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32))
+                    Wrapping(self.0.wrapping_shl(-other as u32))
                 } else {
-                    Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
+                    Wrapping(self.0.wrapping_shr(other as u32))
                 }
             }
         }
@@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned {
 
             #[inline]
             fn shl(self, other: $f) -> Wrapping<$t> {
-                Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
+                Wrapping(self.0.wrapping_shl(other as u32))
             }
         }
         forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
@@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned {
 
             #[inline]
             fn shr(self, other: $f) -> Wrapping<$t> {
-                Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
+                Wrapping(self.0.wrapping_shr(other as u32))
             }
         }
         forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
@@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned {
 }
 
 wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 }
-
-mod shift_max {
-    #![allow(non_upper_case_globals)]
-
-    #[cfg(target_pointer_width = "16")]
-    mod platform {
-        pub(crate) const usize: u32 = super::u16;
-        pub(crate) const isize: u32 = super::i16;
-    }
-
-    #[cfg(target_pointer_width = "32")]
-    mod platform {
-        pub(crate) const usize: u32 = super::u32;
-        pub(crate) const isize: u32 = super::i32;
-    }
-
-    #[cfg(target_pointer_width = "64")]
-    mod platform {
-        pub(crate) const usize: u32 = super::u64;
-        pub(crate) const isize: u32 = super::i64;
-    }
-
-    pub(super) const i8: u32 = (1 << 3) - 1;
-    pub(super) const i16: u32 = (1 << 4) - 1;
-    pub(super) const i32: u32 = (1 << 5) - 1;
-    pub(super) const i64: u32 = (1 << 6) - 1;
-    pub(super) const i128: u32 = (1 << 7) - 1;
-    pub(super) use self::platform::isize;
-
-    pub(super) const u8: u32 = i8;
-    pub(super) const u16: u32 = i16;
-    pub(super) const u32: u32 = i32;
-    pub(super) const u64: u32 = i64;
-    pub(super) const u128: u32 = i128;
-    pub(super) use self::platform::usize;
-}
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 8092fa9eb2f..d8489e9a949 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -55,6 +55,8 @@
 #[doc(alias = "]")]
 #[doc(alias = "[")]
 #[doc(alias = "[]")]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
 pub trait Index<Idx: ?Sized> {
     /// The returned type after indexing.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -165,7 +167,9 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
 #[doc(alias = "[")]
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
-pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+#[const_trait]
+pub trait IndexMut<Idx: ?Sized>: ~const Index<Idx> {
     /// Performs the mutable indexing (`container[index]`) operation.
     ///
     /// # Panics
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 27b0c6830db..2ad520b7ead 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1524,10 +1524,11 @@ impl<T> *const [T] {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
     #[inline]
-    pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+    pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked(self) }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 73efdf04454..579e2461103 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1881,10 +1881,11 @@ impl<T> *mut [T] {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
     #[inline(always)]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked_mut(self) }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index c4ca29a3679..62da6567cca 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1597,10 +1597,11 @@ impl<T> NonNull<[T]> {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         // As a consequence, the resulting pointer cannot be null.
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index 2276112a27b..5cd7956291c 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -186,14 +186,17 @@ impl<T> IntoBounds<T> for Range<T> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-impl<T> From<Range<T>> for legacy::Range<T> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T> const From<Range<T>> for legacy::Range<T> {
     #[inline]
     fn from(value: Range<T>) -> Self {
         Self { start: value.start, end: value.end }
     }
 }
+
 #[unstable(feature = "new_range_api", issue = "125687")]
-impl<T> From<legacy::Range<T>> for Range<T> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T> const From<legacy::Range<T>> for Range<T> {
     #[inline]
     fn from(value: legacy::Range<T>) -> Self {
         Self { start: value.start, end: value.end }
@@ -362,7 +365,8 @@ impl<T> IntoBounds<T> for RangeInclusive<T> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
     #[inline]
     fn from(value: RangeInclusive<T>) -> Self {
         Self::new(value.start, value.end)
@@ -506,14 +510,16 @@ impl<T> IntoBounds<T> for RangeFrom<T> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
     #[inline]
     fn from(value: RangeFrom<T>) -> Self {
         Self { start: value.start }
     }
 }
 #[unstable(feature = "new_range_api", issue = "125687")]
-impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
     #[inline]
     fn from(value: legacy::RangeFrom<T>) -> Self {
         Self { start: value.start }
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index f725c3fdd94..322b3580ede 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition;
 use crate::{ops, range};
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T, I> const ops::Index<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     type Output = I::Output;
 
@@ -19,9 +20,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<T, I> const ops::IndexMut<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     #[inline(always)]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -158,6 +160,8 @@ mod private_slice_index {
     message = "the type `{T}` cannot be indexed by `{Self}`",
     label = "slice indices are of type `usize` or ranges of `usize`"
 )]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
 pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// The output type returned by methods.
     #[stable(feature = "slice_get_slice", since = "1.28.0")]
@@ -208,7 +212,8 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 
 /// The methods `index` and `index_mut` panic if the index is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for usize {
     type Output = T;
 
     #[inline]
@@ -278,7 +283,8 @@ unsafe impl<T> SliceIndex<[T]> for usize {
 
 /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
 /// than there are for a general `Range<usize>` (which might be `100..3`).
-unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
     type Output = [T];
 
     #[inline]
@@ -354,7 +360,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
 /// - the start of the range is greater than the end of the range or
 /// - the end of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -453,7 +460,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for range::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -491,7 +499,8 @@ unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
 
 /// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
     type Output = [T];
 
     #[inline]
@@ -529,7 +538,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
 
 /// The methods `index` and `index_mut` panic if the start of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -574,7 +584,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for range::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -611,7 +622,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
     type Output = [T];
 
     #[inline]
@@ -650,7 +662,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
 /// - the start of the range is greater than the end of the range or
 /// - the end of the range is out of bounds.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -693,7 +706,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for range::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -731,7 +745,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
 
 /// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     type Output = [T];
 
     #[inline]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index abcba5a621e..32419024db9 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -568,9 +568,10 @@ impl<T> [T] {
     #[rustc_no_implicit_autorefs]
     #[inline]
     #[must_use]
-    pub fn get<I>(&self, index: I) -> Option<&I::Output>
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
+    pub const fn get<I>(&self, index: I) -> Option<&I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get(self)
     }
@@ -594,9 +595,10 @@ impl<T> [T] {
     #[rustc_no_implicit_autorefs]
     #[inline]
     #[must_use]
-    pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
+    pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get_mut(self)
     }
@@ -633,9 +635,10 @@ impl<T> [T] {
     #[inline]
     #[must_use]
     #[track_caller]
-    pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
+    pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
         // the slice is dereferenceable because `self` is a safe reference.
@@ -677,9 +680,10 @@ impl<T> [T] {
     #[inline]
     #[must_use]
     #[track_caller]
-    pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
+    pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
         // the slice is dereferenceable because `self` is a safe reference.
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index fba3436496e..18a516c0f60 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -589,8 +589,9 @@ impl str {
     /// assert!(v.get(..42).is_none());
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
     #[inline]
-    pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+    pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
         i.get(self)
     }
 
@@ -621,8 +622,9 @@ impl str {
     /// assert_eq!("HEllo", v);
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_index", issue = "143775")]
     #[inline]
-    pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+    pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
         i.get_mut(self)
     }
 
@@ -952,6 +954,7 @@ impl str {
     ///
     /// The caller must ensure that `mid` is a valid byte offset from the start
     /// of the string and falls on the boundary of a UTF-8 code point.
+    #[inline]
     const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) {
         let len = self.len();
         let ptr = self.as_ptr();
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index b9559c83171..42ffc591b5b 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -49,9 +49,10 @@ impl PartialOrd for str {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::Index<I> for str
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<I> const ops::Index<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     type Output = I::Output;
 
@@ -62,9 +63,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::IndexMut<I> for str
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+impl<I> const ops::IndexMut<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -92,7 +94,8 @@ const fn str_index_overflow_fail() -> ! {
 ///
 /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::RangeFull {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -156,7 +159,8 @@ unsafe impl SliceIndex<str> for ops::RangeFull {
 /// // &s[3 .. 100];
 /// ```
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::Range<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -260,7 +264,8 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl SliceIndex<str> for range::Range<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for range::Range<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -431,7 +436,8 @@ unsafe impl SliceIndex<str> for (ops::Bound<usize>, ops::Bound<usize>) {
 /// Panics if `end` does not point to the starting byte offset of a
 /// character (as defined by `is_char_boundary`), or if `end > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -499,7 +505,8 @@ unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
 /// Panics if `begin` does not point to the starting byte offset of
 /// a character (as defined by `is_char_boundary`), or if `begin > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -554,7 +561,8 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for range::RangeFrom<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -625,7 +633,8 @@ unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
 /// to the ending byte offset of a character (`end + 1` is either a starting
 /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -662,7 +671,8 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
 }
 
 #[unstable(feature = "new_range_api", issue = "125687")]
-unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -713,7 +723,8 @@ unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
 /// (`end + 1` is either a starting byte offset as defined by
 /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs
index 38df09a91c1..36d6a20a944 100644
--- a/library/coretests/tests/floats/f128.rs
+++ b/library/coretests/tests/floats/f128.rs
@@ -1,9 +1,7 @@
 // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy
 #![cfg(target_has_reliable_f128)]
 
-use core::ops::{Add, Div, Mul, Sub};
 use std::f128::consts;
-use std::num::FpCategory as Fp;
 
 use super::{assert_approx_eq, assert_biteq};
 
@@ -38,161 +36,10 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u128 = 0x00005555555555555555555555555555;
 
-#[test]
-fn test_num_f128() {
-    // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128`
-    // function is available on all platforms.
-    let ten = 10f128;
-    let two = 2f128;
-    assert_biteq!(ten.add(two), ten + two);
-    assert_biteq!(ten.sub(two), ten - two);
-    assert_biteq!(ten.mul(two), ten * two);
-    assert_biteq!(ten.div(two), ten / two);
-    #[cfg(any(miri, target_has_reliable_f128_math))]
-    assert_biteq!(core::ops::Rem::rem(ten, two), ten % two);
-}
-
 // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
 // the intrinsics.
 
 #[test]
-fn test_infinity() {
-    let inf: f128 = f128::INFINITY;
-    assert!(inf.is_infinite());
-    assert!(!inf.is_finite());
-    assert!(inf.is_sign_positive());
-    assert!(!inf.is_sign_negative());
-    assert!(!inf.is_nan());
-    assert!(!inf.is_normal());
-    assert_eq!(Fp::Infinite, inf.classify());
-}
-
-#[test]
-fn test_neg_infinity() {
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    assert!(neg_inf.is_infinite());
-    assert!(!neg_inf.is_finite());
-    assert!(!neg_inf.is_sign_positive());
-    assert!(neg_inf.is_sign_negative());
-    assert!(!neg_inf.is_nan());
-    assert!(!neg_inf.is_normal());
-    assert_eq!(Fp::Infinite, neg_inf.classify());
-}
-
-#[test]
-fn test_zero() {
-    let zero: f128 = 0.0f128;
-    assert_biteq!(0.0, zero);
-    assert!(!zero.is_infinite());
-    assert!(zero.is_finite());
-    assert!(zero.is_sign_positive());
-    assert!(!zero.is_sign_negative());
-    assert!(!zero.is_nan());
-    assert!(!zero.is_normal());
-    assert_eq!(Fp::Zero, zero.classify());
-}
-
-#[test]
-fn test_neg_zero() {
-    let neg_zero: f128 = -0.0;
-    assert_eq!(0.0, neg_zero);
-    assert_biteq!(-0.0, neg_zero);
-    assert!(!neg_zero.is_infinite());
-    assert!(neg_zero.is_finite());
-    assert!(!neg_zero.is_sign_positive());
-    assert!(neg_zero.is_sign_negative());
-    assert!(!neg_zero.is_nan());
-    assert!(!neg_zero.is_normal());
-    assert_eq!(Fp::Zero, neg_zero.classify());
-}
-
-#[test]
-fn test_one() {
-    let one: f128 = 1.0f128;
-    assert_biteq!(1.0, one);
-    assert!(!one.is_infinite());
-    assert!(one.is_finite());
-    assert!(one.is_sign_positive());
-    assert!(!one.is_sign_negative());
-    assert!(!one.is_nan());
-    assert!(one.is_normal());
-    assert_eq!(Fp::Normal, one.classify());
-}
-
-#[test]
-fn test_is_nan() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    assert!(nan.is_nan());
-    assert!(!0.0f128.is_nan());
-    assert!(!5.3f128.is_nan());
-    assert!(!(-10.732f128).is_nan());
-    assert!(!inf.is_nan());
-    assert!(!neg_inf.is_nan());
-}
-
-#[test]
-fn test_is_infinite() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    assert!(!nan.is_infinite());
-    assert!(inf.is_infinite());
-    assert!(neg_inf.is_infinite());
-    assert!(!0.0f128.is_infinite());
-    assert!(!42.8f128.is_infinite());
-    assert!(!(-109.2f128).is_infinite());
-}
-
-#[test]
-fn test_is_finite() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    assert!(!nan.is_finite());
-    assert!(!inf.is_finite());
-    assert!(!neg_inf.is_finite());
-    assert!(0.0f128.is_finite());
-    assert!(42.8f128.is_finite());
-    assert!((-109.2f128).is_finite());
-}
-
-#[test]
-fn test_is_normal() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    let zero: f128 = 0.0f128;
-    let neg_zero: f128 = -0.0;
-    assert!(!nan.is_normal());
-    assert!(!inf.is_normal());
-    assert!(!neg_inf.is_normal());
-    assert!(!zero.is_normal());
-    assert!(!neg_zero.is_normal());
-    assert!(1f128.is_normal());
-    assert!(1e-4931f128.is_normal());
-    assert!(!1e-4932f128.is_normal());
-}
-
-#[test]
-fn test_classify() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    let zero: f128 = 0.0f128;
-    let neg_zero: f128 = -0.0;
-    assert_eq!(nan.classify(), Fp::Nan);
-    assert_eq!(inf.classify(), Fp::Infinite);
-    assert_eq!(neg_inf.classify(), Fp::Infinite);
-    assert_eq!(zero.classify(), Fp::Zero);
-    assert_eq!(neg_zero.classify(), Fp::Zero);
-    assert_eq!(1f128.classify(), Fp::Normal);
-    assert_eq!(1e-4931f128.classify(), Fp::Normal);
-    assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
-}
-
-#[test]
 #[cfg(any(miri, target_has_reliable_f128_math))]
 fn test_abs() {
     assert_biteq!(f128::INFINITY.abs(), f128::INFINITY);
diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs
index f6749d796cc..351c008a37b 100644
--- a/library/coretests/tests/floats/f16.rs
+++ b/library/coretests/tests/floats/f16.rs
@@ -2,7 +2,6 @@
 #![cfg(target_has_reliable_f16)]
 
 use std::f16::consts;
-use std::num::FpCategory as Fp;
 
 use super::{assert_approx_eq, assert_biteq};
 
@@ -43,152 +42,10 @@ const NAN_MASK1: u16 = 0x02aa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u16 = 0x0155;
 
-#[test]
-fn test_num_f16() {
-    super::test_num(10f16, 2f16);
-}
-
 // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
 // the intrinsics.
 
 #[test]
-fn test_infinity() {
-    let inf: f16 = f16::INFINITY;
-    assert!(inf.is_infinite());
-    assert!(!inf.is_finite());
-    assert!(inf.is_sign_positive());
-    assert!(!inf.is_sign_negative());
-    assert!(!inf.is_nan());
-    assert!(!inf.is_normal());
-    assert_eq!(Fp::Infinite, inf.classify());
-}
-
-#[test]
-fn test_neg_infinity() {
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    assert!(neg_inf.is_infinite());
-    assert!(!neg_inf.is_finite());
-    assert!(!neg_inf.is_sign_positive());
-    assert!(neg_inf.is_sign_negative());
-    assert!(!neg_inf.is_nan());
-    assert!(!neg_inf.is_normal());
-    assert_eq!(Fp::Infinite, neg_inf.classify());
-}
-
-#[test]
-fn test_zero() {
-    let zero: f16 = 0.0f16;
-    assert_biteq!(0.0, zero);
-    assert!(!zero.is_infinite());
-    assert!(zero.is_finite());
-    assert!(zero.is_sign_positive());
-    assert!(!zero.is_sign_negative());
-    assert!(!zero.is_nan());
-    assert!(!zero.is_normal());
-    assert_eq!(Fp::Zero, zero.classify());
-}
-
-#[test]
-fn test_neg_zero() {
-    let neg_zero: f16 = -0.0;
-    assert_eq!(0.0, neg_zero);
-    assert_biteq!(-0.0, neg_zero);
-    assert!(!neg_zero.is_infinite());
-    assert!(neg_zero.is_finite());
-    assert!(!neg_zero.is_sign_positive());
-    assert!(neg_zero.is_sign_negative());
-    assert!(!neg_zero.is_nan());
-    assert!(!neg_zero.is_normal());
-    assert_eq!(Fp::Zero, neg_zero.classify());
-}
-
-#[test]
-fn test_one() {
-    let one: f16 = 1.0f16;
-    assert_biteq!(1.0, one);
-    assert!(!one.is_infinite());
-    assert!(one.is_finite());
-    assert!(one.is_sign_positive());
-    assert!(!one.is_sign_negative());
-    assert!(!one.is_nan());
-    assert!(one.is_normal());
-    assert_eq!(Fp::Normal, one.classify());
-}
-
-#[test]
-fn test_is_nan() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    assert!(nan.is_nan());
-    assert!(!0.0f16.is_nan());
-    assert!(!5.3f16.is_nan());
-    assert!(!(-10.732f16).is_nan());
-    assert!(!inf.is_nan());
-    assert!(!neg_inf.is_nan());
-}
-
-#[test]
-fn test_is_infinite() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    assert!(!nan.is_infinite());
-    assert!(inf.is_infinite());
-    assert!(neg_inf.is_infinite());
-    assert!(!0.0f16.is_infinite());
-    assert!(!42.8f16.is_infinite());
-    assert!(!(-109.2f16).is_infinite());
-}
-
-#[test]
-fn test_is_finite() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    assert!(!nan.is_finite());
-    assert!(!inf.is_finite());
-    assert!(!neg_inf.is_finite());
-    assert!(0.0f16.is_finite());
-    assert!(42.8f16.is_finite());
-    assert!((-109.2f16).is_finite());
-}
-
-#[test]
-fn test_is_normal() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    let zero: f16 = 0.0f16;
-    let neg_zero: f16 = -0.0;
-    assert!(!nan.is_normal());
-    assert!(!inf.is_normal());
-    assert!(!neg_inf.is_normal());
-    assert!(!zero.is_normal());
-    assert!(!neg_zero.is_normal());
-    assert!(1f16.is_normal());
-    assert!(1e-4f16.is_normal());
-    assert!(!1e-5f16.is_normal());
-}
-
-#[test]
-fn test_classify() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    let zero: f16 = 0.0f16;
-    let neg_zero: f16 = -0.0;
-    assert_eq!(nan.classify(), Fp::Nan);
-    assert_eq!(inf.classify(), Fp::Infinite);
-    assert_eq!(neg_inf.classify(), Fp::Infinite);
-    assert_eq!(zero.classify(), Fp::Zero);
-    assert_eq!(neg_zero.classify(), Fp::Zero);
-    assert_eq!(1f16.classify(), Fp::Normal);
-    assert_eq!(1e-4f16.classify(), Fp::Normal);
-    assert_eq!(1e-5f16.classify(), Fp::Subnormal);
-}
-
-#[test]
 #[cfg(any(miri, target_has_reliable_f16_math))]
 fn test_abs() {
     assert_biteq!(f16::INFINITY.abs(), f16::INFINITY);
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs
index f5d5723fea4..267b0e4e294 100644
--- a/library/coretests/tests/floats/f32.rs
+++ b/library/coretests/tests/floats/f32.rs
@@ -1,6 +1,5 @@
 use core::f32;
 use core::f32::consts;
-use core::num::FpCategory as Fp;
 
 use super::{assert_approx_eq, assert_biteq};
 
@@ -31,148 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555;
 const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 };
 
 #[test]
-fn test_num_f32() {
-    super::test_num(10f32, 2f32);
-}
-
-#[test]
-fn test_infinity() {
-    let inf: f32 = f32::INFINITY;
-    assert!(inf.is_infinite());
-    assert!(!inf.is_finite());
-    assert!(inf.is_sign_positive());
-    assert!(!inf.is_sign_negative());
-    assert!(!inf.is_nan());
-    assert!(!inf.is_normal());
-    assert_eq!(Fp::Infinite, inf.classify());
-}
-
-#[test]
-fn test_neg_infinity() {
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    assert!(neg_inf.is_infinite());
-    assert!(!neg_inf.is_finite());
-    assert!(!neg_inf.is_sign_positive());
-    assert!(neg_inf.is_sign_negative());
-    assert!(!neg_inf.is_nan());
-    assert!(!neg_inf.is_normal());
-    assert_eq!(Fp::Infinite, neg_inf.classify());
-}
-
-#[test]
-fn test_zero() {
-    let zero: f32 = 0.0f32;
-    assert_biteq!(0.0, zero);
-    assert!(!zero.is_infinite());
-    assert!(zero.is_finite());
-    assert!(zero.is_sign_positive());
-    assert!(!zero.is_sign_negative());
-    assert!(!zero.is_nan());
-    assert!(!zero.is_normal());
-    assert_eq!(Fp::Zero, zero.classify());
-}
-
-#[test]
-fn test_neg_zero() {
-    let neg_zero: f32 = -0.0;
-    assert_eq!(0.0, neg_zero);
-    assert_biteq!(-0.0, neg_zero);
-    assert!(!neg_zero.is_infinite());
-    assert!(neg_zero.is_finite());
-    assert!(!neg_zero.is_sign_positive());
-    assert!(neg_zero.is_sign_negative());
-    assert!(!neg_zero.is_nan());
-    assert!(!neg_zero.is_normal());
-    assert_eq!(Fp::Zero, neg_zero.classify());
-}
-
-#[test]
-fn test_one() {
-    let one: f32 = 1.0f32;
-    assert_biteq!(1.0, one);
-    assert!(!one.is_infinite());
-    assert!(one.is_finite());
-    assert!(one.is_sign_positive());
-    assert!(!one.is_sign_negative());
-    assert!(!one.is_nan());
-    assert!(one.is_normal());
-    assert_eq!(Fp::Normal, one.classify());
-}
-
-#[test]
-fn test_is_nan() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    assert!(nan.is_nan());
-    assert!(!0.0f32.is_nan());
-    assert!(!5.3f32.is_nan());
-    assert!(!(-10.732f32).is_nan());
-    assert!(!inf.is_nan());
-    assert!(!neg_inf.is_nan());
-}
-
-#[test]
-fn test_is_infinite() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    assert!(!nan.is_infinite());
-    assert!(inf.is_infinite());
-    assert!(neg_inf.is_infinite());
-    assert!(!0.0f32.is_infinite());
-    assert!(!42.8f32.is_infinite());
-    assert!(!(-109.2f32).is_infinite());
-}
-
-#[test]
-fn test_is_finite() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    assert!(!nan.is_finite());
-    assert!(!inf.is_finite());
-    assert!(!neg_inf.is_finite());
-    assert!(0.0f32.is_finite());
-    assert!(42.8f32.is_finite());
-    assert!((-109.2f32).is_finite());
-}
-
-#[test]
-fn test_is_normal() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    let zero: f32 = 0.0f32;
-    let neg_zero: f32 = -0.0;
-    assert!(!nan.is_normal());
-    assert!(!inf.is_normal());
-    assert!(!neg_inf.is_normal());
-    assert!(!zero.is_normal());
-    assert!(!neg_zero.is_normal());
-    assert!(1f32.is_normal());
-    assert!(1e-37f32.is_normal());
-    assert!(!1e-38f32.is_normal());
-}
-
-#[test]
-fn test_classify() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    let zero: f32 = 0.0f32;
-    let neg_zero: f32 = -0.0;
-    assert_eq!(nan.classify(), Fp::Nan);
-    assert_eq!(inf.classify(), Fp::Infinite);
-    assert_eq!(neg_inf.classify(), Fp::Infinite);
-    assert_eq!(zero.classify(), Fp::Zero);
-    assert_eq!(neg_zero.classify(), Fp::Zero);
-    assert_eq!(1f32.classify(), Fp::Normal);
-    assert_eq!(1e-37f32.classify(), Fp::Normal);
-    assert_eq!(1e-38f32.classify(), Fp::Subnormal);
-}
-
-#[test]
 fn test_abs() {
     assert_biteq!(f32::INFINITY.abs(), f32::INFINITY);
     assert_biteq!(1f32.abs(), 1f32);
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs
index 34af87c241e..735b7a76515 100644
--- a/library/coretests/tests/floats/f64.rs
+++ b/library/coretests/tests/floats/f64.rs
@@ -1,6 +1,5 @@
 use core::f64;
 use core::f64::consts;
-use core::num::FpCategory as Fp;
 
 use super::{assert_approx_eq, assert_biteq};
 
@@ -26,147 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
 const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
 
 #[test]
-fn test_num_f64() {
-    super::test_num(10f64, 2f64);
-}
-
-#[test]
-fn test_infinity() {
-    let inf: f64 = f64::INFINITY;
-    assert!(inf.is_infinite());
-    assert!(!inf.is_finite());
-    assert!(inf.is_sign_positive());
-    assert!(!inf.is_sign_negative());
-    assert!(!inf.is_nan());
-    assert!(!inf.is_normal());
-    assert_eq!(Fp::Infinite, inf.classify());
-}
-
-#[test]
-fn test_neg_infinity() {
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    assert!(neg_inf.is_infinite());
-    assert!(!neg_inf.is_finite());
-    assert!(!neg_inf.is_sign_positive());
-    assert!(neg_inf.is_sign_negative());
-    assert!(!neg_inf.is_nan());
-    assert!(!neg_inf.is_normal());
-    assert_eq!(Fp::Infinite, neg_inf.classify());
-}
-
-#[test]
-fn test_zero() {
-    let zero: f64 = 0.0f64;
-    assert_biteq!(0.0, zero);
-    assert!(!zero.is_infinite());
-    assert!(zero.is_finite());
-    assert!(zero.is_sign_positive());
-    assert!(!zero.is_sign_negative());
-    assert!(!zero.is_nan());
-    assert!(!zero.is_normal());
-    assert_eq!(Fp::Zero, zero.classify());
-}
-
-#[test]
-fn test_neg_zero() {
-    let neg_zero: f64 = -0.0;
-    assert_eq!(0.0, neg_zero);
-    assert_biteq!(-0.0, neg_zero);
-    assert!(!neg_zero.is_infinite());
-    assert!(neg_zero.is_finite());
-    assert!(!neg_zero.is_sign_positive());
-    assert!(neg_zero.is_sign_negative());
-    assert!(!neg_zero.is_nan());
-    assert!(!neg_zero.is_normal());
-    assert_eq!(Fp::Zero, neg_zero.classify());
-}
-
-#[test]
-fn test_one() {
-    let one: f64 = 1.0f64;
-    assert_biteq!(1.0, one);
-    assert!(!one.is_infinite());
-    assert!(one.is_finite());
-    assert!(one.is_sign_positive());
-    assert!(!one.is_sign_negative());
-    assert!(!one.is_nan());
-    assert!(one.is_normal());
-    assert_eq!(Fp::Normal, one.classify());
-}
-
-#[test]
-fn test_is_nan() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    assert!(nan.is_nan());
-    assert!(!0.0f64.is_nan());
-    assert!(!5.3f64.is_nan());
-    assert!(!(-10.732f64).is_nan());
-    assert!(!inf.is_nan());
-    assert!(!neg_inf.is_nan());
-}
-
-#[test]
-fn test_is_infinite() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    assert!(!nan.is_infinite());
-    assert!(inf.is_infinite());
-    assert!(neg_inf.is_infinite());
-    assert!(!0.0f64.is_infinite());
-    assert!(!42.8f64.is_infinite());
-    assert!(!(-109.2f64).is_infinite());
-}
-
-#[test]
-fn test_is_finite() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    assert!(!nan.is_finite());
-    assert!(!inf.is_finite());
-    assert!(!neg_inf.is_finite());
-    assert!(0.0f64.is_finite());
-    assert!(42.8f64.is_finite());
-    assert!((-109.2f64).is_finite());
-}
-
-#[test]
-fn test_is_normal() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    let zero: f64 = 0.0f64;
-    let neg_zero: f64 = -0.0;
-    assert!(!nan.is_normal());
-    assert!(!inf.is_normal());
-    assert!(!neg_inf.is_normal());
-    assert!(!zero.is_normal());
-    assert!(!neg_zero.is_normal());
-    assert!(1f64.is_normal());
-    assert!(1e-307f64.is_normal());
-    assert!(!1e-308f64.is_normal());
-}
-
-#[test]
-fn test_classify() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    let zero: f64 = 0.0f64;
-    let neg_zero: f64 = -0.0;
-    assert_eq!(nan.classify(), Fp::Nan);
-    assert_eq!(inf.classify(), Fp::Infinite);
-    assert_eq!(neg_inf.classify(), Fp::Infinite);
-    assert_eq!(zero.classify(), Fp::Zero);
-    assert_eq!(neg_zero.classify(), Fp::Zero);
-    assert_eq!(1e-307f64.classify(), Fp::Normal);
-    assert_eq!(1e-308f64.classify(), Fp::Subnormal);
-}
-
-#[test]
 fn test_abs() {
     assert_biteq!(f64::INFINITY.abs(), f64::INFINITY);
     assert_biteq!(1f64.abs(), 1f64);
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs
index 36743a7d6df..43431bba695 100644
--- a/library/coretests/tests/floats/mod.rs
+++ b/library/coretests/tests/floats/mod.rs
@@ -1,28 +1,40 @@
-use std::fmt;
 use std::num::FpCategory as Fp;
 use std::ops::{Add, Div, Mul, Rem, Sub};
 
-/// Set the default tolerance for float comparison based on the type.
-trait Approx {
-    const LIM: Self;
+trait TestableFloat {
+    /// Set the default tolerance for float comparison based on the type.
+    const APPROX: Self;
+    const MIN_POSITIVE_NORMAL: Self;
+    const MAX_SUBNORMAL: Self;
 }
 
-impl Approx for f16 {
-    const LIM: Self = 1e-3;
+impl TestableFloat for f16 {
+    const APPROX: Self = 1e-3;
+    const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
+    const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
 }
-impl Approx for f32 {
-    const LIM: Self = 1e-6;
+
+impl TestableFloat for f32 {
+    const APPROX: Self = 1e-6;
+    const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
+    const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
 }
-impl Approx for f64 {
-    const LIM: Self = 1e-6;
+
+impl TestableFloat for f64 {
+    const APPROX: Self = 1e-6;
+    const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
+    const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
 }
-impl Approx for f128 {
-    const LIM: Self = 1e-9;
+
+impl TestableFloat for f128 {
+    const APPROX: Self = 1e-9;
+    const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
+    const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
 }
 
 /// Determine the tolerance for values of the argument type.
-const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T {
-    T::LIM
+const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
+    T::APPROX
 }
 
 // We have runtime ("rt") and const versions of these macros.
@@ -187,9 +199,11 @@ macro_rules! float_test {
             $( $( #[$const_meta] )+ )?
             mod const_ {
                 #[allow(unused)]
-                use super::Approx;
+                use super::TestableFloat;
                 #[allow(unused)]
                 use std::num::FpCategory as Fp;
+                #[allow(unused)]
+                use std::ops::{Add, Div, Mul, Rem, Sub};
                 // Shadow the runtime versions of the macro with const-compatible versions.
                 #[allow(unused)]
                 use $crate::floats::{
@@ -229,31 +243,43 @@ macro_rules! float_test {
     };
 }
 
-/// Helper function for testing numeric operations
-pub fn test_num<T>(ten: T, two: T)
-where
-    T: PartialEq
-        + Add<Output = T>
-        + Sub<Output = T>
-        + Mul<Output = T>
-        + Div<Output = T>
-        + Rem<Output = T>
-        + fmt::Debug
-        + Copy,
-{
-    assert_eq!(ten.add(two), ten + two);
-    assert_eq!(ten.sub(two), ten - two);
-    assert_eq!(ten.mul(two), ten * two);
-    assert_eq!(ten.div(two), ten / two);
-    assert_eq!(ten.rem(two), ten % two);
-}
-
 mod f128;
 mod f16;
 mod f32;
 mod f64;
 
 float_test! {
+    name: num,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let two: Float = 2.0;
+        let ten: Float = 10.0;
+        assert_biteq!(ten.add(two), ten + two);
+        assert_biteq!(ten.sub(two), ten - two);
+        assert_biteq!(ten.mul(two), ten * two);
+        assert_biteq!(ten.div(two), ten / two);
+    }
+}
+
+// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on
+// all platforms.
+float_test! {
+    name: num_rem,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16_math))],
+        f128: #[cfg(any(miri, target_has_reliable_f128_math))],
+    },
+    test<Float> {
+        let two: Float = 2.0;
+        let ten: Float = 10.0;
+        assert_biteq!(ten.rem(two), ten % two);
+    }
+}
+
+float_test! {
     name: nan,
     attrs: {
         f16: #[cfg(any(miri, target_has_reliable_f16))],
@@ -274,6 +300,213 @@ float_test! {
 }
 
 float_test! {
+    name: infinity,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let inf: Float = Float::INFINITY;
+        assert!(inf.is_infinite());
+        assert!(!inf.is_finite());
+        assert!(inf.is_sign_positive());
+        assert!(!inf.is_sign_negative());
+        assert!(!inf.is_nan());
+        assert!(!inf.is_normal());
+        assert!(matches!(inf.classify(), Fp::Infinite));
+    }
+}
+
+float_test! {
+    name: neg_infinity,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let neg_inf: Float = Float::NEG_INFINITY;
+        assert!(neg_inf.is_infinite());
+        assert!(!neg_inf.is_finite());
+        assert!(!neg_inf.is_sign_positive());
+        assert!(neg_inf.is_sign_negative());
+        assert!(!neg_inf.is_nan());
+        assert!(!neg_inf.is_normal());
+        assert!(matches!(neg_inf.classify(), Fp::Infinite));
+    }
+}
+
+float_test! {
+    name: zero,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let zero: Float = 0.0;
+        assert_biteq!(0.0, zero);
+        assert!(!zero.is_infinite());
+        assert!(zero.is_finite());
+        assert!(zero.is_sign_positive());
+        assert!(!zero.is_sign_negative());
+        assert!(!zero.is_nan());
+        assert!(!zero.is_normal());
+        assert!(matches!(zero.classify(), Fp::Zero));
+    }
+}
+
+float_test! {
+    name: neg_zero,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let neg_zero: Float = -0.0;
+        assert!(0.0 == neg_zero);
+        assert_biteq!(-0.0, neg_zero);
+        assert!(!neg_zero.is_infinite());
+        assert!(neg_zero.is_finite());
+        assert!(!neg_zero.is_sign_positive());
+        assert!(neg_zero.is_sign_negative());
+        assert!(!neg_zero.is_nan());
+        assert!(!neg_zero.is_normal());
+        assert!(matches!(neg_zero.classify(), Fp::Zero));
+    }
+}
+
+float_test! {
+    name: one,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let one: Float = 1.0;
+        assert_biteq!(1.0, one);
+        assert!(!one.is_infinite());
+        assert!(one.is_finite());
+        assert!(one.is_sign_positive());
+        assert!(!one.is_sign_negative());
+        assert!(!one.is_nan());
+        assert!(one.is_normal());
+        assert!(matches!(one.classify(), Fp::Normal));
+    }
+}
+
+float_test! {
+    name: is_nan,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        let zero: Float = 0.0;
+        let pos: Float = 5.3;
+        let neg: Float = -10.732;
+        assert!(nan.is_nan());
+        assert!(!zero.is_nan());
+        assert!(!pos.is_nan());
+        assert!(!neg.is_nan());
+        assert!(!inf.is_nan());
+        assert!(!neg_inf.is_nan());
+    }
+}
+
+float_test! {
+    name: is_infinite,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        let zero: Float = 0.0;
+        let pos: Float = 42.8;
+        let neg: Float = -109.2;
+        assert!(!nan.is_infinite());
+        assert!(inf.is_infinite());
+        assert!(neg_inf.is_infinite());
+        assert!(!zero.is_infinite());
+        assert!(!pos.is_infinite());
+        assert!(!neg.is_infinite());
+    }
+}
+
+float_test! {
+    name: is_finite,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        let zero: Float = 0.0;
+        let pos: Float = 42.8;
+        let neg: Float = -109.2;
+        assert!(!nan.is_finite());
+        assert!(!inf.is_finite());
+        assert!(!neg_inf.is_finite());
+        assert!(zero.is_finite());
+        assert!(pos.is_finite());
+        assert!(neg.is_finite());
+    }
+}
+
+float_test! {
+    name: is_normal,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        let zero: Float = 0.0;
+        let neg_zero: Float = -0.0;
+        let one : Float = 1.0;
+        assert!(!nan.is_normal());
+        assert!(!inf.is_normal());
+        assert!(!neg_inf.is_normal());
+        assert!(!zero.is_normal());
+        assert!(!neg_zero.is_normal());
+        assert!(one.is_normal());
+        assert!(Float::MIN_POSITIVE_NORMAL.is_normal());
+        assert!(!Float::MAX_SUBNORMAL.is_normal());
+    }
+}
+
+float_test! {
+    name: classify,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        let zero: Float = 0.0;
+        let neg_zero: Float = -0.0;
+        let one: Float = 1.0;
+        assert!(matches!(nan.classify(), Fp::Nan));
+        assert!(matches!(inf.classify(), Fp::Infinite));
+        assert!(matches!(neg_inf.classify(), Fp::Infinite));
+        assert!(matches!(zero.classify(), Fp::Zero));
+        assert!(matches!(neg_zero.classify(), Fp::Zero));
+        assert!(matches!(one.classify(), Fp::Normal));
+        assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal));
+        assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal));
+    }
+}
+
+float_test! {
     name: min,
     attrs: {
         f16: #[cfg(any(miri, target_has_reliable_f16_math))],
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index fdef736c0c0..e2249bd7f6a 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -20,6 +20,7 @@
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
 #![feature(const_float_round_methods)]
+#![feature(const_ops)]
 #![feature(const_ref_cell)]
 #![feature(const_trait_impl)]
 #![feature(core_float_math)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 62ece4b6961..86d23df5238 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -92,6 +92,9 @@ backtrace = [
     'object/rustc-dep-of-std',
     'miniz_oxide/rustc-dep-of-std',
 ]
+# Disable symbolization in backtraces. For use with -Zbuild-std.
+# FIXME: Ideally this should be an additive backtrace-symbolization feature
+backtrace-trace-only = []
 
 panic-unwind = ["dep:panic_unwind"]
 compiler-builtins-c = ["alloc/compiler-builtins-c"]
diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs
index efa6a896dad..272d0fa4d1a 100644
--- a/library/std/src/sys/backtrace.rs
+++ b/library/std/src/sys/backtrace.rs
@@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                 return false;
             }
 
-            let mut hit = false;
-            backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
-                hit = true;
-
-                // `__rust_end_short_backtrace` means we are done hiding symbols
-                // for now. Print until we see `__rust_begin_short_backtrace`.
-                if print_fmt == PrintFmt::Short {
-                    if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
-                        if sym.contains("__rust_end_short_backtrace") {
-                            print = true;
-                            return;
-                        }
-                        if print && sym.contains("__rust_begin_short_backtrace") {
-                            print = false;
-                            return;
-                        }
-                        if !print {
-                            omitted_count += 1;
+            if cfg!(feature = "backtrace-trace-only") {
+                const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
+                let frame_ip = frame.ip();
+                res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
+            } else {
+                let mut hit = false;
+                backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+                    hit = true;
+
+                    // `__rust_end_short_backtrace` means we are done hiding symbols
+                    // for now. Print until we see `__rust_begin_short_backtrace`.
+                    if print_fmt == PrintFmt::Short {
+                        if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
+                            if sym.contains("__rust_end_short_backtrace") {
+                                print = true;
+                                return;
+                            }
+                            if print && sym.contains("__rust_begin_short_backtrace") {
+                                print = false;
+                                return;
+                            }
+                            if !print {
+                                omitted_count += 1;
+                            }
                         }
                     }
-                }
 
-                if print {
-                    if omitted_count > 0 {
-                        debug_assert!(print_fmt == PrintFmt::Short);
-                        // only print the message between the middle of frames
-                        if !first_omit {
-                            let _ = writeln!(
-                                bt_fmt.formatter(),
-                                "      [... omitted {} frame{} ...]",
-                                omitted_count,
-                                if omitted_count > 1 { "s" } else { "" }
-                            );
+                    if print {
+                        if omitted_count > 0 {
+                            debug_assert!(print_fmt == PrintFmt::Short);
+                            // only print the message between the middle of frames
+                            if !first_omit {
+                                let _ = writeln!(
+                                    bt_fmt.formatter(),
+                                    "      [... omitted {} frame{} ...]",
+                                    omitted_count,
+                                    if omitted_count > 1 { "s" } else { "" }
+                                );
+                            }
+                            first_omit = false;
+                            omitted_count = 0;
                         }
-                        first_omit = false;
-                        omitted_count = 0;
+                        res = bt_fmt.frame().symbol(frame, symbol);
                     }
-                    res = bt_fmt.frame().symbol(frame, symbol);
+                });
+                #[cfg(target_os = "nto")]
+                if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
+                    if !hit && print {
+                        use crate::backtrace_rs::SymbolName;
+                        res = bt_fmt.frame().print_raw(
+                            frame.ip(),
+                            Some(SymbolName::new("__my_thread_exit".as_bytes())),
+                            None,
+                            None,
+                        );
+                    }
+                    return false;
                 }
-            });
-            #[cfg(target_os = "nto")]
-            if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
                 if !hit && print {
-                    use crate::backtrace_rs::SymbolName;
-                    res = bt_fmt.frame().print_raw(
-                        frame.ip(),
-                        Some(SymbolName::new("__my_thread_exit".as_bytes())),
-                        None,
-                        None,
-                    );
+                    res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
                 }
-                return false;
-            }
-            if !hit && print {
-                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
             }
 
             idx += 1;
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 7cd44873313..0ad014ccd3e 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -469,6 +469,29 @@ impl<T: 'static> LocalKey<Cell<T>> {
     pub fn replace(&'static self, value: T) -> T {
         self.with(|cell| cell.replace(value))
     }
+
+    /// Updates the contained value using a function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(local_key_cell_update)]
+    /// use std::cell::Cell;
+    ///
+    /// thread_local! {
+    ///     static X: Cell<i32> = const { Cell::new(5) };
+    /// }
+    ///
+    /// X.update(|x| x + 1);
+    /// assert_eq!(X.get(), 6);
+    /// ```
+    #[unstable(feature = "local_key_cell_update", issue = "143989")]
+    pub fn update(&'static self, f: impl FnOnce(T) -> T)
+    where
+        T: Copy,
+    {
+        self.with(|cell| cell.update(f))
+    }
 }
 
 impl<T: 'static> LocalKey<RefCell<T>> {
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 290c2eeed44..032f5272a9c 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -20,6 +20,7 @@ test = { path = "../test", public = true }
 [features]
 default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
 backtrace = ["std/backtrace"]
+backtrace-trace-only = ["std/backtrace-trace-only"]
 compiler-builtins-c = ["std/compiler-builtins-c"]
 compiler-builtins-mem = ["std/compiler-builtins-mem"]
 compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"]
diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs
index fcb6abea434..c2ad9a4df59 100644
--- a/src/bootstrap/src/core/build_steps/mod.rs
+++ b/src/bootstrap/src/core/build_steps/mod.rs
@@ -11,7 +11,6 @@ pub(crate) mod llvm;
 pub(crate) mod perf;
 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;
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
deleted file mode 100644
index fd4918961ad..00000000000
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-//! Attempt to magically identify good tests to run
-
-use std::path::PathBuf;
-use std::str::FromStr;
-
-use clap::Parser;
-
-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) {
-    let git_config = builder.config.git_config();
-    let suggestions = builder
-        .tool_cmd(Tool::SuggestTests)
-        .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
-        .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
-        .run_capture_stdout(builder)
-        .stdout();
-
-    let suggestions = suggestions
-        .lines()
-        .map(|line| {
-            let mut sections = line.split_ascii_whitespace();
-
-            // this code expects one suggestion per line in the following format:
-            // <x_subcommand> {some number of flags} [optional stage number]
-            let cmd = sections.next().unwrap();
-            let stage = sections.next_back().and_then(|s| str::parse(s).ok());
-            let paths: Vec<PathBuf> = sections.map(|p| PathBuf::from_str(p).unwrap()).collect();
-
-            (cmd, stage, paths)
-        })
-        .collect::<Vec<_>>();
-
-    if !suggestions.is_empty() {
-        println!("==== SUGGESTIONS ====");
-        for sug in &suggestions {
-            print!("x {} ", sug.0);
-            if let Some(stage) = sug.1 {
-                print!("--stage {stage} ");
-            }
-
-            for path in &sug.2 {
-                print!("{} ", path.display());
-            }
-            println!();
-        }
-        println!("=====================");
-    } else {
-        println!("No suggestions found!");
-        return;
-    }
-
-    if run {
-        for sug in suggestions {
-            let mut build: crate::Build = builder.build.clone();
-            build.config.paths = sug.2;
-            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;
-            }
-            build.build();
-        }
-    } else {
-        println!("HELP: consider using the `--run` flag to automatically run suggested tests");
-    }
-}
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 757eac1475c..9e7ea5c115f 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -47,12 +47,11 @@ impl Step for CrateBootstrap {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        // This step is responsible for several different tool paths. By default
-        // it will test all of them, but requesting specific tools on the
-        // command-line (e.g. `./x test suggest-tests`) will test only the
-        // specified tools.
+        // This step is responsible for several different tool paths.
+        //
+        // By default, it will test all of them, but requesting specific tools on the command-line
+        // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools.
         run.path("src/tools/jsondoclint")
-            .path("src/tools/suggest-tests")
             .path("src/tools/replace-version-placeholder")
             .path("src/tools/coverage-dump")
             // We want `./x test tidy` to _run_ the tidy tool, not its tests.
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 814a44b9a13..1c994b0ccfc 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -517,7 +517,6 @@ bootstrap_tool!(
     ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
     CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
     GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
-    SuggestTests, "src/tools/suggest-tests", "suggest-tests";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
     // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
     RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index d5a290d804c..a3b471ca56e 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -113,7 +113,7 @@ impl Cargo {
 
         match cmd_kind {
             // No need to configure the target linker for these command types.
-            Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {}
+            Kind::Clean | Kind::Check | Kind::Format | Kind::Setup => {}
             _ => {
                 cargo.configure_linker(builder, mode);
             }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 7115c5a1cbe..1b75d00b30e 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -845,7 +845,6 @@ pub enum Kind {
     #[value(alias = "r")]
     Run,
     Setup,
-    Suggest,
     Vendor,
     Perf,
 }
@@ -869,7 +868,6 @@ impl Kind {
             Kind::Install => "install",
             Kind::Run => "run",
             Kind::Setup => "setup",
-            Kind::Suggest => "suggest",
             Kind::Vendor => "vendor",
             Kind::Perf => "perf",
         }
@@ -881,7 +879,6 @@ impl Kind {
             Kind::Bench => "Benchmarking",
             Kind::Doc => "Documenting",
             Kind::Run => "Running",
-            Kind::Suggest => "Suggesting",
             Kind::Clippy => "Linting",
             Kind::Perf => "Profiling & benchmarking",
             _ => {
@@ -1201,7 +1198,7 @@ impl<'a> Builder<'a> {
             Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
             Kind::Vendor => describe!(vendor::Vendor),
             // special-cased in Build::build()
-            Kind::Format | Kind::Suggest | Kind::Perf => vec![],
+            Kind::Format | Kind::Perf => vec![],
             Kind::MiriTest | Kind::MiriSetup => unreachable!(),
         }
     }
@@ -1269,7 +1266,6 @@ impl<'a> Builder<'a> {
             Subcommand::Run { .. } => (Kind::Run, &paths[..]),
             Subcommand::Clean { .. } => (Kind::Clean, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
-            Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]),
             Subcommand::Setup { profile: ref path } => (
                 Kind::Setup,
                 path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 0039d44785c..28958b60fc3 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1050,7 +1050,6 @@ impl Config {
             | Subcommand::Run { .. }
             | Subcommand::Setup { .. }
             | Subcommand::Format { .. }
-            | Subcommand::Suggest { .. }
             | Subcommand::Vendor { .. } => flags_stage.unwrap_or(0),
         };
 
@@ -1098,7 +1097,6 @@ impl Config {
                 | Subcommand::Run { .. }
                 | Subcommand::Setup { .. }
                 | Subcommand::Format { .. }
-                | Subcommand::Suggest { .. }
                 | Subcommand::Vendor { .. }
                 | Subcommand::Perf { .. } => {}
             }
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 155b6f58758..1547ca44494 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -481,13 +481,6 @@ Arguments:
         #[arg(value_name = "<PROFILE>|hook|editor|link")]
         profile: Option<PathBuf>,
     },
-    /// Suggest a subset of tests to run, based on modified files
-    #[command(long_about = "\n")]
-    Suggest {
-        /// run suggested tests
-        #[arg(long)]
-        run: bool,
-    },
     /// Vendor dependencies
     Vendor {
         /// Additional `Cargo.toml` to sync and vendor
@@ -518,7 +511,6 @@ impl Subcommand {
             Subcommand::Install => Kind::Install,
             Subcommand::Run { .. } => Kind::Run,
             Subcommand::Setup { .. } => Kind::Setup,
-            Subcommand::Suggest { .. } => Kind::Suggest,
             Subcommand::Vendor { .. } => Kind::Vendor,
             Subcommand::Perf { .. } => Kind::Perf,
         }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index f2119e84cce..b39d464493e 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -216,7 +216,6 @@ than building it.
             build.config.cmd,
             Subcommand::Clean { .. }
                 | Subcommand::Check { .. }
-                | Subcommand::Suggest { .. }
                 | Subcommand::Format { .. }
                 | Subcommand::Setup { .. }
         );
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 66a164703b7..44be51815c7 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -651,11 +651,9 @@ impl Build {
         // Handle hard-coded subcommands.
         {
             #[cfg(feature = "tracing")]
-            let _hardcoded_span = span!(
-                tracing::Level::DEBUG,
-                "handling hardcoded subcommands (Format, Suggest, Perf)"
-            )
-            .entered();
+            let _hardcoded_span =
+                span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Perf)")
+                    .entered();
 
             match &self.config.cmd {
                 Subcommand::Format { check, all } => {
@@ -666,9 +664,6 @@ impl Build {
                         &self.config.paths,
                     );
                 }
-                Subcommand::Suggest { run } => {
-                    return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run);
-                }
                 Subcommand::Perf(args) => {
                     return core::build_steps::perf::perf(&builder::Builder::new(self), args);
                 }
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index dcafeb80f90..d3926df9650 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -67,7 +67,6 @@ pub fn fill_compilers(build: &mut Build) {
         // We don't need to check cross targets for these commands.
         crate::Subcommand::Clean { .. }
         | crate::Subcommand::Check { .. }
-        | crate::Subcommand::Suggest { .. }
         | crate::Subcommand::Format { .. }
         | crate::Subcommand::Setup { .. } => {
             build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect()
@@ -221,10 +220,15 @@ fn default_compiler(
         }
 
         t if t.contains("-wasi") => {
-            let root = build
-                .wasi_sdk_path
-                .as_ref()
-                .expect("WASI_SDK_PATH mut be configured for a -wasi target");
+            let root = if let Some(path) = build.wasi_sdk_path.as_ref() {
+                path
+            } else {
+                if build.config.is_running_on_ci {
+                    panic!("ERROR: WASI_SDK_PATH must be configured for a -wasi target on CI");
+                }
+                println!("WARNING: WASI_SDK_PATH not set, using default cc/cxx compiler");
+                return None;
+            };
             let compiler = match compiler {
                 Language::C => format!("{t}-clang"),
                 Language::CPlusPlus => format!("{t}-clang++"),
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 1f6ed8129da..d888a7863bc 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -476,4 +476,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "Option `tool.TOOL_NAME.features` now works on any subcommand, not just `build`.",
     },
+    ChangeInfo {
+        change_id: 143630,
+        severity: ChangeSeverity::Warning,
+        summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs
index 862c4449624..9b1ccc32cb6 100644
--- a/src/bootstrap/src/utils/metrics.rs
+++ b/src/bootstrap/src/utils/metrics.rs
@@ -43,7 +43,7 @@ pub(crate) struct BuildMetrics {
     state: RefCell<MetricsState>,
 }
 
-/// NOTE: this isn't really cloning anything, but `x suggest` doesn't need metrics so this is probably ok.
+// NOTE: this isn't really cloning anything, but necessary for `Build: Clone`.
 impl Clone for BuildMetrics {
     fn clone(&self) -> Self {
         Self::init()
diff --git a/src/doc/book b/src/doc/book
-Subproject ef1ce8f87a8b18feb1b6a9cf9a4939a79bde679
+Subproject b2d1a0821e12a676b496d61891b8e3d374a8e83
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 41f688a598a5022b749e23d37f3c524f6a0b28e
+Subproject fe88fbb68391a465680dd91109f0a151a1676f3
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 8b61acfaea822e9ac926190bc8f15791c33336e
+Subproject 3ff384320598bbe8d8cfe5cb8f18f78a3a3e6b1
diff --git a/src/doc/reference b/src/doc/reference
-Subproject e9fc99f107840813916f62e16b3f6d9556e1f2d
+Subproject 1f45bd41fa6c17b7c048ed6bfe5f168c4311206
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 288b4e4948add43f387cad35adc7b1c54ca6fe1
+Subproject e386be5f44af711854207c11fdd61bb576270b0
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 7f2f32c62ff..651e2925ad5 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -35,7 +35,6 @@
         - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md)
         - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md)
     - [Performance testing](./tests/perf.md)
-    - [Suggest tests tool](./tests/suggest-tests.md)
     - [Misc info](./tests/misc.md)
 - [Debugging the compiler](./compiler-debugging.md)
     - [Using the tracing/logging instrumentation](./tracing.md)
diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md
index 9a8ab353e02..97314d80369 100644
--- a/src/doc/rustc-dev-guide/src/building/quickstart.md
+++ b/src/doc/rustc-dev-guide/src/building/quickstart.md
@@ -61,9 +61,6 @@ and check the output.
 Use `--bless` if you've made a change and want to update the `.stderr` files
 with the new output.
 
-> `./x suggest` can also be helpful for suggesting which tests to run after a
-> change.
-
 Congrats, you are now ready to make a change to the compiler! If you have more
 questions, [the full chapter](./how-to-build-and-run.md) might contain the
 answers, and if it doesn't, feel free to ask for help on
diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md
index bfb2f4d1084..7f626314f71 100644
--- a/src/doc/rustc-dev-guide/src/building/suggested.md
+++ b/src/doc/rustc-dev-guide/src/building/suggested.md
@@ -270,23 +270,6 @@ run the tests at some later time. You can then use `git bisect` to track down
 is that you are left with a fairly fine-grained set of commits at the end, all
 of which build and pass tests. This often helps reviewing.
 
-## `x suggest`
-
-The `x suggest` subcommand suggests (and runs) a subset of the extensive
-`rust-lang/rust` tests based on files you have changed. This is especially
-useful for new contributors who have not mastered the arcane `x` flags yet and
-more experienced contributors as a shorthand for reducing mental effort. In all
-cases it is useful not to run the full tests (which can take on the order of
-tens of minutes) and just run a subset which are relevant to your changes. For
-example, running `tidy` and `linkchecker` is useful when editing Markdown files,
-whereas UI tests are much less likely to be helpful. While `x suggest` is a
-useful tool, it does not guarantee perfect coverage (just as PR CI isn't a
-substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for
-more information and contribution instructions.
-
-Please note that `x suggest` is in a beta state currently and the tests that it
-will suggest are limited.
-
 ## Configuring `rustup` to use nightly
 
 Some parts of the bootstrap process uses pinned, nightly versions of tools like
diff --git a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md b/src/doc/rustc-dev-guide/src/tests/suggest-tests.md
deleted file mode 100644
index 663e8a5af3b..00000000000
--- a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# Suggest tests tool
-
-This chapter is about the internals of and contribution instructions for the
-`suggest-tests` tool. For a high-level overview of the tool, see [this
-section](../building/suggested.md#x-suggest). This tool is currently in a beta
-state and is tracked by [this](https://github.com/rust-lang/rust/issues/109933)
-issue on Github. Currently the number of tests it will suggest are very limited
-in scope, we are looking to expand this (contributions welcome!).
-
-## Internals
-
-The tool is defined in a separate crate
-([`src/tools/suggest-tests`](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests))
-which outputs suggestions which are parsed by a shim in bootstrap
-([`src/bootstrap/src/core/build_steps/suggest.rs`](https://github.com/rust-lang/rust/blob/master/src/bootstrap/src/core/build_steps/suggest.rs)).
-The only notable thing the bootstrap shim does is (when invoked with the `--run`
-flag) use bootstrap's internal mechanisms to create a new `Builder` and uses it
-to invoke the suggested commands. The `suggest-tests` crate is where the fun
-happens, two kinds of suggestions are defined: "static" and "dynamic"
-suggestions.
-
-### Static suggestions
-
-Defined
-[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/static_suggestions.rs).
-Static suggestions are simple: they are just
-[globs](https://crates.io/crates/glob) which map to a `x` command. In
-`suggest-tests`, this is implemented with a simple `macro_rules` macro.
-
-### Dynamic suggestions
-
-Defined
-[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/dynamic_suggestions.rs).
-These are more complicated than static suggestions and are implemented as
-functions with the following signature: `fn(&Path) -> Vec<Suggestion>`. In other
-words, each suggestion takes a path to a modified file and (after running
-arbitrary Rust code) can return any number of suggestions, or none. Dynamic
-suggestions are useful for situations where fine-grained control over
-suggestions is needed. For example, modifications to the `compiler/xyz/` path
-should trigger the `x test compiler/xyz` suggestion. In the future, dynamic
-suggestions might even read file contents to determine if (what) tests should
-run.
-
-## Adding a suggestion
-
-The following steps should serve as a rough guide to add suggestions to
-`suggest-tests` (very welcome!):
-
-1. Determine the rules for your suggestion. Is it simple and operates only on a
-   single path or does it match globs? Does it need fine-grained control over
-   the resulting command or does "one size fit all"?
-2. Based on the previous step, decide if your suggestion should be implemented
-   as either static or dynamic.
-3. Implement the suggestion. If it is dynamic then a test is highly recommended,
-   to verify that your logic is correct and to give an example of the
-   suggestion. See the
-   [tests.rs](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/tests.rs)
-   file.
-4. Open a PR implementing your suggestion. **(TODO: add example PR)**
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
index e80ff85edad..b173bf82b44 100644
--- a/src/doc/rustc/src/platform-support/netbsd.md
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -32,10 +32,11 @@ are built for NetBSD 8.x but also work on newer OS versions).
 ## Target Maintainers
 
 [@he32](https://github.com/he32)
+[@0323pin](https://github.com/0323pin)
 
 Further contacts:
 
-- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust
+- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust188/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust.  Note that we have the convention of having multiple rust versions active in pkgsrc-wip at any one time, so the version number is part of the directory name, and from time to time old versions are culled so this is not a fully "stable" link.
 - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc.
 - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself
 
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index d3da1f353e2..28a228d5464 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -73,7 +73,6 @@ complete -c x -n "__fish_x_needs_command" -a "dist" -d 'Build distribution artif
 complete -c x -n "__fish_x_needs_command" -a "install" -d 'Install distribution artifacts'
 complete -c x -n "__fish_x_needs_command" -a "run" -d 'Run tools contained in this repository'
 complete -c x -n "__fish_x_needs_command" -a "setup" -d 'Set up the environment for development'
-complete -c x -n "__fish_x_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files'
 complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies'
 complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`'
 complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F
@@ -599,42 +598,6 @@ complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'E
 complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers'
 complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')'
-complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
-complete -c x -n "__fish_x_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}"
-complete -c x -n "__fish_x_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}"
-complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x -n "__fish_x_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
-complete -c x -n "__fish_x_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f
-complete -c x -n "__fish_x_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
-complete -c x -n "__fish_x_using_subcommand suggest" -l run -d 'run suggested tests'
-complete -c x -n "__fish_x_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
-complete -c x -n "__fish_x_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation'
-complete -c x -n "__fish_x_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones'
-complete -c x -n "__fish_x_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything'
-complete -c x -n "__fish_x_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims'
-complete -c x -n "__fish_x_using_subcommand suggest" -l json-output -d 'use message-format=json'
-complete -c x -n "__fish_x_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)'
-complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)'
-complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags'
-complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
-complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers'
-complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F
 complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index b5b59c58bba..0c9b3828273 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts')
             [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository')
             [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development')
-            [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files')
             [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies')
             [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`')
             break
@@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
         }
-        'x;suggest' {
-            [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
-            [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
-            [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
-            [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
-            [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
-            [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
-            [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format')
-            [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
-            [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
-            [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
-            [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
-            [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout')
-            [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
-            [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
-            [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour')
-            [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output')
-            [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
-            [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
-            [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
-            [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
-            [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
-            [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests')
-            [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
-            [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
-            [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
-            [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation')
-            [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones')
-            [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
-            [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims')
-            [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
-            [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)')
-            [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)')
-            [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags')
-            [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation')
-            [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers')
-            [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
-            [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
-            break
-        }
         'x;vendor' {
             [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index da7680a879d..43ae7424e27 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -73,7 +73,6 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "dist" -d 'Build distribution
 complete -c x.py -n "__fish_x.py_needs_command" -a "install" -d 'Install distribution artifacts'
 complete -c x.py -n "__fish_x.py_needs_command" -a "run" -d 'Run tools contained in this repository'
 complete -c x.py -n "__fish_x.py_needs_command" -a "setup" -d 'Set up the environment for development'
-complete -c x.py -n "__fish_x.py_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files'
 complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependencies'
 complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`'
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F
@@ -599,42 +598,6 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers'
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l run -d 'run suggested tests'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l json-output -d 'use message-format=json'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers'
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 3fc8e7d5bbd..4311e383d64 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts')
             [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository')
             [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development')
-            [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files')
             [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies')
             [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`')
             break
@@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
         }
-        'x.py;suggest' {
-            [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
-            [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
-            [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
-            [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
-            [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
-            [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
-            [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format')
-            [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
-            [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
-            [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
-            [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
-            [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout')
-            [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
-            [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
-            [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour')
-            [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output')
-            [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
-            [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
-            [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
-            [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
-            [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
-            [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests')
-            [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
-            [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
-            [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
-            [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation')
-            [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones')
-            [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
-            [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims')
-            [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
-            [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)')
-            [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)')
-            [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags')
-            [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation')
-            [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers')
-            [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
-            [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
-            break
-        }
         'x.py;vendor' {
             [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 8f13de282fb..f31bdb58dc4 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -54,9 +54,6 @@ _x.py() {
             x.py,setup)
                 cmd="x.py__setup"
                 ;;
-            x.py,suggest)
-                cmd="x.py__suggest"
-                ;;
             x.py,test)
                 cmd="x.py__test"
                 ;;
@@ -85,7 +82,7 @@ _x.py() {
 
     case "${cmd}" in
         x.py)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf"
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf"
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -3877,192 +3874,6 @@ _x.py() {
             COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
             return 0
             ;;
-        x.py__suggest)
-            opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
-            if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
-                COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
-                return 0
-            fi
-            case "${prev}" in
-                --config)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --build-dir)
-                    COMPREPLY=()
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o plusdirs
-                    fi
-                    return 0
-                    ;;
-                --build)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --host)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --target)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --exclude)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --skip)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --rustc-error-format)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --on-fail)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --stage)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --keep-stage)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --keep-stage-std)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --src)
-                    COMPREPLY=()
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o plusdirs
-                    fi
-                    return 0
-                    ;;
-                --jobs)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                -j)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --warnings)
-                    COMPREPLY=($(compgen -W "deny warn default" -- "${cur}"))
-                    return 0
-                    ;;
-                --color)
-                    COMPREPLY=($(compgen -W "always never auto" -- "${cur}"))
-                    return 0
-                    ;;
-                --rust-profile-generate)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --rust-profile-use)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --llvm-profile-use)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --reproducible-artifact)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --set)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --ci)
-                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
-                    return 0
-                    ;;
-                *)
-                    COMPREPLY=()
-                    ;;
-            esac
-            COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
-            return 0
-            ;;
         x.py__test)
             opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index 60ce9002116..aff35b31e21 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \
 '*::paths -- paths for the subcommand:_files' \
 && ret=0
 ;;
-(suggest)
-_arguments "${_arguments_options[@]}" : \
-'--config=[TOML configuration file for build]:FILE:_files' \
-'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[host target of the stage0 compiler]:BUILD:' \
-'--host=[host targets to build]:HOST:' \
-'--target=[target targets to build]:TARGET:' \
-'*--exclude=[build paths to exclude]:PATH:_files' \
-'*--skip=[build paths to skip]:PATH:_files' \
-'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \
-'--on-fail=[command to run on failure]:CMD:_cmdstring' \
-'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \
-'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \
-'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \
-'--src=[path to the root of the rust checkout]:DIR:_files -/' \
-'-j+[number of jobs to run in parallel]:JOBS:' \
-'--jobs=[number of jobs to run in parallel]:JOBS:' \
-'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \
-'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \
-'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \
-'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \
-'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \
-'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \
-'*--set=[override options in bootstrap.toml]:section.option=value:' \
-'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
-'--run[run suggested tests]' \
-'*-v[use verbose output (-vv for very verbose)]' \
-'*--verbose[use verbose output (-vv for very verbose)]' \
-'-i[use incremental compilation]' \
-'--incremental[use incremental compilation]' \
-'--include-default-paths[include default paths in addition to the provided ones]' \
-'--dry-run[dry run; don'\''t build anything]' \
-'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \
-'--json-output[use message-format=json]' \
-'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \
-'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \
-'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \
-'--enable-bolt-settings[Enable BOLT link flags]' \
-'--skip-stage0-validation[Skip stage0 compiler validation]' \
-'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \
-'-h[Print help (see more with '\''--help'\'')]' \
-'--help[Print help (see more with '\''--help'\'')]' \
-'*::paths -- paths for the subcommand:_files' \
-&& ret=0
-;;
 (vendor)
 _arguments "${_arguments_options[@]}" : \
 '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \
@@ -1120,7 +1075,6 @@ _x.py_commands() {
 'install:Install distribution artifacts' \
 'run:Run tools contained in this repository' \
 'setup:Set up the environment for development' \
-'suggest:Suggest a subset of tests to run, based on modified files' \
 'vendor:Vendor dependencies' \
 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \
     )
@@ -1227,11 +1181,6 @@ _x.py__setup_commands() {
     local commands; commands=()
     _describe -t commands 'x.py setup commands' commands "$@"
 }
-(( $+functions[_x.py__suggest_commands] )) ||
-_x.py__suggest_commands() {
-    local commands; commands=()
-    _describe -t commands 'x.py suggest commands' commands "$@"
-}
 (( $+functions[_x.py__test_commands] )) ||
 _x.py__test_commands() {
     local commands; commands=()
diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh
index f6ecf4cebf4..927d8f7661c 100644
--- a/src/etc/completions/x.sh
+++ b/src/etc/completions/x.sh
@@ -54,9 +54,6 @@ _x() {
             x,setup)
                 cmd="x__setup"
                 ;;
-            x,suggest)
-                cmd="x__suggest"
-                ;;
             x,test)
                 cmd="x__test"
                 ;;
@@ -85,7 +82,7 @@ _x() {
 
     case "${cmd}" in
         x)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf"
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf"
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -3877,192 +3874,6 @@ _x() {
             COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
             return 0
             ;;
-        x__suggest)
-            opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
-            if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
-                COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
-                return 0
-            fi
-            case "${prev}" in
-                --config)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --build-dir)
-                    COMPREPLY=()
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o plusdirs
-                    fi
-                    return 0
-                    ;;
-                --build)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --host)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --target)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --exclude)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --skip)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --rustc-error-format)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --on-fail)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --stage)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --keep-stage)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --keep-stage-std)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --src)
-                    COMPREPLY=()
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o plusdirs
-                    fi
-                    return 0
-                    ;;
-                --jobs)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                -j)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --warnings)
-                    COMPREPLY=($(compgen -W "deny warn default" -- "${cur}"))
-                    return 0
-                    ;;
-                --color)
-                    COMPREPLY=($(compgen -W "always never auto" -- "${cur}"))
-                    return 0
-                    ;;
-                --rust-profile-generate)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --rust-profile-use)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --llvm-profile-use)
-                    local oldifs
-                    if [ -n "${IFS+x}" ]; then
-                        oldifs="$IFS"
-                    fi
-                    IFS=$'\n'
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    if [ -n "${oldifs+x}" ]; then
-                        IFS="$oldifs"
-                    fi
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o filenames
-                    fi
-                    return 0
-                    ;;
-                --reproducible-artifact)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
-                --set)
-                    COMPREPLY=("${cur}")
-                    if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-                        compopt -o nospace
-                    fi
-                    return 0
-                    ;;
-                --ci)
-                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
-                    return 0
-                    ;;
-                *)
-                    COMPREPLY=()
-                    ;;
-            esac
-            COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
-            return 0
-            ;;
         x__test)
             opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index 452a26fef07..28ad00f3a0d 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \
 '*::paths -- paths for the subcommand:_files' \
 && ret=0
 ;;
-(suggest)
-_arguments "${_arguments_options[@]}" : \
-'--config=[TOML configuration file for build]:FILE:_files' \
-'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[host target of the stage0 compiler]:BUILD:' \
-'--host=[host targets to build]:HOST:' \
-'--target=[target targets to build]:TARGET:' \
-'*--exclude=[build paths to exclude]:PATH:_files' \
-'*--skip=[build paths to skip]:PATH:_files' \
-'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \
-'--on-fail=[command to run on failure]:CMD:_cmdstring' \
-'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \
-'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \
-'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \
-'--src=[path to the root of the rust checkout]:DIR:_files -/' \
-'-j+[number of jobs to run in parallel]:JOBS:' \
-'--jobs=[number of jobs to run in parallel]:JOBS:' \
-'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \
-'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \
-'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \
-'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \
-'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \
-'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \
-'*--set=[override options in bootstrap.toml]:section.option=value:' \
-'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
-'--run[run suggested tests]' \
-'*-v[use verbose output (-vv for very verbose)]' \
-'*--verbose[use verbose output (-vv for very verbose)]' \
-'-i[use incremental compilation]' \
-'--incremental[use incremental compilation]' \
-'--include-default-paths[include default paths in addition to the provided ones]' \
-'--dry-run[dry run; don'\''t build anything]' \
-'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \
-'--json-output[use message-format=json]' \
-'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \
-'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \
-'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \
-'--enable-bolt-settings[Enable BOLT link flags]' \
-'--skip-stage0-validation[Skip stage0 compiler validation]' \
-'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \
-'-h[Print help (see more with '\''--help'\'')]' \
-'--help[Print help (see more with '\''--help'\'')]' \
-'*::paths -- paths for the subcommand:_files' \
-&& ret=0
-;;
 (vendor)
 _arguments "${_arguments_options[@]}" : \
 '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \
@@ -1120,7 +1075,6 @@ _x_commands() {
 'install:Install distribution artifacts' \
 'run:Run tools contained in this repository' \
 'setup:Set up the environment for development' \
-'suggest:Suggest a subset of tests to run, based on modified files' \
 'vendor:Vendor dependencies' \
 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \
     )
@@ -1227,11 +1181,6 @@ _x__setup_commands() {
     local commands; commands=()
     _describe -t commands 'x setup commands' commands "$@"
 }
-(( $+functions[_x__suggest_commands] )) ||
-_x__suggest_commands() {
-    local commands; commands=()
-    _describe -t commands 'x suggest commands' commands "$@"
-}
 (( $+functions[_x__test_commands] )) ||
 _x__test_commands() {
     local commands; commands=()
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3ecd41db2dd..20babc6168b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -759,79 +759,48 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
-        const ALLOWED_ATTRIBUTES: &[Symbol] =
-            &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
+    /// Get a list of attributes excluding `#[repr]` to display.
+    ///
+    /// Only used by the HTML output-format.
+    fn attributes_without_repr(&self) -> Vec<String> {
         self.attrs
             .other_attrs
             .iter()
-            .filter_map(|attr| {
-                if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
+            .filter_map(|attr| match attr {
+                hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
                     Some(format!("#[link_section = \"{name}\"]"))
                 }
-                // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
-                // It is also used by cargo-semver-checks.
-                else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
+                hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
                     Some("#[no_mangle]".to_string())
-                } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
-                {
+                }
+                hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
                     Some(format!("#[export_name = \"{name}\"]"))
-                } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr {
+                }
+                hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
                     Some("#[non_exhaustive]".to_string())
-                } else if is_json {
-                    match attr {
-                        // rustdoc-json stores this in `Item::deprecation`, so we
-                        // don't want it it `Item::attrs`.
-                        hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
-                        // We have separate pretty-printing logic for `#[repr(..)]` attributes.
-                        hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None,
-                        // target_feature is special-cased because cargo-semver-checks uses it
-                        hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => {
-                            let mut output = String::new();
-                            for (i, (feature, _)) in features.iter().enumerate() {
-                                if i != 0 {
-                                    output.push_str(", ");
-                                }
-                                output.push_str(&format!("enable=\"{}\"", feature.as_str()));
-                            }
-                            Some(format!("#[target_feature({output})]"))
-                        }
-                        hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => {
-                            Some("#[automatically_derived]".to_string())
-                        }
-                        _ => Some({
-                            let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
-                            assert_eq!(s.pop(), Some('\n'));
-                            s
-                        }),
-                    }
-                } else {
-                    if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
-                        return None;
-                    }
-                    Some(
-                        rustc_hir_pretty::attribute_to_string(&tcx, attr)
-                            .replace("\\\n", "")
-                            .replace('\n', "")
-                            .replace("  ", " "),
-                    )
                 }
+                _ => None,
             })
             .collect()
     }
 
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
-        let mut attrs = self.attributes_without_repr(tcx, is_json);
+    /// Get a list of attributes to display on this item.
+    ///
+    /// Only used by the HTML output-format.
+    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
+        let mut attrs = self.attributes_without_repr();
 
-        if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
+        if let Some(repr_attr) = self.repr(tcx, cache) {
             attrs.push(repr_attr);
         }
         attrs
     }
 
     /// Returns a stringified `#[repr(...)]` attribute.
-    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
-        repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
+    ///
+    /// Only used by the HTML output-format.
+    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
+        repr_attributes(tcx, cache, self.def_id()?, self.type_())
     }
 
     pub fn is_doc_hidden(&self) -> bool {
@@ -843,12 +812,14 @@ impl Item {
     }
 }
 
+/// Return a string representing the `#[repr]` attribute if present.
+///
+/// Only used by the HTML output-format.
 pub(crate) fn repr_attributes(
     tcx: TyCtxt<'_>,
     cache: &Cache,
     def_id: DefId,
     item_type: ItemType,
-    is_json: bool,
 ) -> Option<String> {
     use rustc_abi::IntegerType;
 
@@ -865,7 +836,6 @@ pub(crate) fn repr_attributes(
         // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
         // field is public in case all fields are 1-ZST fields.
         let render_transparent = cache.document_private
-            || is_json
             || adt
                 .all_fields()
                 .find(|field| {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 70f3f54e4c0..06de4944d97 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1191,7 +1191,7 @@ fn render_assoc_item(
 // a whitespace prefix and newline.
 fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
     fmt::from_fn(move |f| {
-        for a in it.attributes(cx.tcx(), cx.cache(), false) {
+        for a in it.attributes(cx.tcx(), cx.cache()) {
             writeln!(f, "{prefix}{a}")?;
         }
         Ok(())
@@ -1207,7 +1207,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
 // When an attribute is rendered inside a <code> tag, it is formatted using
 // a div to produce a newline after it.
 fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
-    for attr in it.attributes(cx.tcx(), cx.cache(), false) {
+    for attr in it.attributes(cx.tcx(), cx.cache()) {
         render_code_attribute(CodeAttribute(attr), w);
     }
 }
@@ -1219,7 +1219,7 @@ fn render_repr_attributes_in_code(
     def_id: DefId,
     item_type: ItemType,
 ) {
-    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) {
+    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
         render_code_attribute(CodeAttribute(repr), w);
     }
 }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index e33bdc0db32..667d39e9bc2 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1487,12 +1487,11 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
                     self.cx.cache(),
                     self.def_id,
                     ItemType::Union,
-                    false,
                 ) {
                     writeln!(f, "{repr}")?;
                 };
             } else {
-                for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) {
+                for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) {
                     writeln!(f, "{a}")?;
                 }
             }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index e7163bead92..0a84d8caa30 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -5,10 +5,12 @@
 use rustc_abi::ExternAbi;
 use rustc_ast::ast;
 use rustc_attr_data_structures::{self as attrs, DeprecatedSince};
+use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HeaderSafety, Safety};
 use rustc_metadata::rendered_const;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::{bug, ty};
 use rustc_span::{Pos, kw, sym};
 use rustdoc_json_types::*;
@@ -39,7 +41,12 @@ impl JsonRenderer<'_> {
             })
             .collect();
         let docs = item.opt_doc_value();
-        let attrs = item.attributes(self.tcx, &self.cache, true);
+        let attrs = item
+            .attrs
+            .other_attrs
+            .iter()
+            .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx))
+            .collect();
         let span = item.span(self.tcx);
         let visibility = item.visibility(self.tcx);
         let clean::ItemInner { name, item_id, .. } = *item.inner;
@@ -886,3 +893,93 @@ impl FromClean<ItemType> for ItemKind {
         }
     }
 }
+
+/// Maybe convert a attribute from hir to json.
+///
+/// Returns `None` if the attribute shouldn't be in the output.
+fn maybe_from_hir_attr(
+    attr: &hir::Attribute,
+    item_id: ItemId,
+    tcx: TyCtxt<'_>,
+) -> Option<Attribute> {
+    use attrs::AttributeKind as AK;
+
+    let kind = match attr {
+        hir::Attribute::Parsed(kind) => kind,
+
+        hir::Attribute::Unparsed(_) => {
+            // FIXME: We should handle `#[doc(hidden)]`.
+            return Some(other_attr(tcx, attr));
+        }
+    };
+
+    Some(match kind {
+        AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation.
+        AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
+
+        AK::MustUse { reason, span: _ } => {
+            Attribute::MustUse { reason: reason.map(|s| s.to_string()) }
+        }
+        AK::Repr { .. } => repr_attr(
+            tcx,
+            item_id.as_def_id().expect("all items that could have #[repr] have a DefId"),
+        ),
+        AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()),
+        AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()),
+        AK::TargetFeature(features, _span) => Attribute::TargetFeature {
+            enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(),
+        },
+
+        AK::NoMangle(_) => Attribute::NoMangle,
+        AK::NonExhaustive(_) => Attribute::NonExhaustive,
+        AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived,
+
+        _ => other_attr(tcx, attr),
+    })
+}
+
+fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute {
+    let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
+    assert_eq!(s.pop(), Some('\n'));
+    Attribute::Other(s)
+}
+
+fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute {
+    let repr = tcx.adt_def(def_id).repr();
+
+    let kind = if repr.c() {
+        ReprKind::C
+    } else if repr.transparent() {
+        ReprKind::Transparent
+    } else if repr.simd() {
+        ReprKind::Simd
+    } else {
+        ReprKind::Rust
+    };
+
+    let align = repr.align.map(|a| a.bytes());
+    let packed = repr.pack.map(|p| p.bytes());
+    let int = repr.int.map(format_integer_type);
+
+    Attribute::Repr(AttributeRepr { kind, align, packed, int })
+}
+
+fn format_integer_type(it: rustc_abi::IntegerType) -> String {
+    use rustc_abi::Integer::*;
+    use rustc_abi::IntegerType::*;
+    match it {
+        Pointer(true) => "isize",
+        Pointer(false) => "usize",
+        Fixed(I8, true) => "i8",
+        Fixed(I8, false) => "u8",
+        Fixed(I16, true) => "i16",
+        Fixed(I16, false) => "u16",
+        Fixed(I32, true) => "i32",
+        Fixed(I32, false) => "u32",
+        Fixed(I64, true) => "i64",
+        Fixed(I64, false) => "u64",
+        Fixed(I128, true) => "i128",
+        Fixed(I128, false) => "u128",
+    }
+    .to_owned()
+}
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 0e72ddd9db1..6235b0e8576 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
 // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
 // are deliberately not in a doc comment, because they need not be in public docs.)
 //
-// Latest feature: Pretty printing of no_mangle attributes changed
-pub const FORMAT_VERSION: u32 = 53;
+// Latest feature: Structured Attributes
+pub const FORMAT_VERSION: u32 = 54;
 
 /// The root of the emitted JSON blob.
 ///
@@ -195,13 +195,94 @@ pub struct Item {
     /// - `#[repr(C)]` and other reprs also appear as themselves,
     ///   though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`.
     ///   Multiple repr attributes on the same item may be combined into an equivalent single attr.
-    pub attrs: Vec<String>,
+    pub attrs: Vec<Attribute>,
     /// Information about the item’s deprecation, if present.
     pub deprecation: Option<Deprecation>,
     /// The type-specific fields describing this item.
     pub inner: ItemEnum,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+/// An attribute, e.g. `#[repr(C)]`
+///
+/// This doesn't include:
+/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead.
+/// - `#[deprecated]`. These are in [`Item::deprecation`] instead.
+pub enum Attribute {
+    /// `#[non_exhaustive]`
+    NonExhaustive,
+
+    /// `#[must_use]`
+    MustUse { reason: Option<String> },
+
+    /// `#[export_name = "name"]`
+    ExportName(String),
+
+    /// `#[link_section = "name"]`
+    LinkSection(String),
+
+    /// `#[automatically_derived]`
+    AutomaticallyDerived,
+
+    /// `#[repr]`
+    Repr(AttributeRepr),
+
+    /// `#[no_mangle]`
+    NoMangle,
+
+    /// #[target_feature(enable = "feature1", enable = "feature2")]
+    TargetFeature { enable: Vec<String> },
+
+    /// Something else.
+    ///
+    /// Things here are explicitly *not* covered by the [`FORMAT_VERSION`]
+    /// constant, and may change without bumping the format version.
+    ///
+    /// As an implementation detail, this is currently either:
+    /// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"`
+    /// 2. The attribute as it appears in source form, like
+    ///    `"#[optimize(speed)]"`.
+    Other(String),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+/// The contents of a `#[repr(...)]` attribute.
+///
+/// Used in [`Attribute::Repr`].
+pub struct AttributeRepr {
+    /// The representation, e.g. `#[repr(C)]`, `#[repr(transparent)]`
+    pub kind: ReprKind,
+
+    /// Alignment in bytes, if explicitly specified by `#[repr(align(...)]`.
+    pub align: Option<u64>,
+    /// Alignment in bytes, if explicitly specified by `#[repr(packed(...)]]`.
+    pub packed: Option<u64>,
+
+    /// The integer type for an enum descriminant, if explicitly specified.
+    ///
+    /// e.g. `"i32"`, for `#[repr(C, i32)]`
+    pub int: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+/// The kind of `#[repr]`.
+///
+/// See [AttributeRepr::kind]`.
+pub enum ReprKind {
+    /// `#[repr(Rust)]`
+    ///
+    /// Also the default.
+    Rust,
+    /// `#[repr(C)]`
+    C,
+    /// `#[repr(transparent)]
+    Transparent,
+    /// `#[repr(simd)]`
+    Simd,
+}
+
 /// A range of source code.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Span {
@@ -1343,7 +1424,7 @@ pub struct Static {
 
     /// Is the static `unsafe`?
     ///
-    /// This is only true if it's in an `extern` block, and not explicity marked
+    /// This is only true if it's in an `extern` block, and not explicitly marked
     /// as `safe`.
     ///
     /// ```rust
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject eabb4cd923deb73e714f7ad3f5234d68ca284db
+Subproject 6833aa715d724437dc1247d0166afe314ab6854
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 6bf968a3132..93133ea0bfd 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -971,6 +971,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-mips64",
     "only-msp430",
     "only-msvc",
+    "only-musl",
     "only-nightly",
     "only-nvptx64",
     "only-powerpc",
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 35d3e7e647c..ccfff7fa94b 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -13,7 +13,7 @@ use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
-use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
 use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
 use rustc_session::config::CrateType;
 use rustc_span::{Span, Symbol};
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs
new file mode 100644
index 00000000000..107a3db91d8
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let v: Vec<u16> = vec![1, 2];
+    // This read is also misaligned. We make sure that the OOB message has priority.
+    let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation
+    panic!("this should never print: {}", x);
+}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr
new file mode 100644
index 00000000000..5c37caa1ebf
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr
@@ -0,0 +1,21 @@
+error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation
+  --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
+   |
+LL |     let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) };
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
+   |
+LL |     let v: Vec<u16> = vec![1, 2];
+   |                       ^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs
new file mode 100644
index 00000000000..0085e2af367
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let v = [0i8; 4];
+    let x = &v as *const i8;
+    let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation
+    panic!("this should never print: {:?}", x);
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr
new file mode 100644
index 00000000000..495aaf8d40e
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation
+  --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
+   |
+LL |     let x = unsafe { x.wrapping_offset(-1).offset(-1) };
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
+   |
+LL |     let v = [0i8; 4];
+   |         ^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index bda08423487..b9741431b50 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec<String>) {
         std::process::exit(code);
     } else {
         println!("died due to signal {}", code);
-        std::process::exit(3);
+        // Behave like bash and other tools and exit with 128 + the signal
+        // number. That way we can avoid special case code in other places.
+        std::process::exit(128 + code);
     }
 }
 
diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs
index e4d244e14a4..0e11360bd5a 100644
--- a/src/tools/run-make-support/src/symbols.rs
+++ b/src/tools/run-make-support/src/symbols.rs
@@ -1,6 +1,7 @@
+use std::collections::BTreeSet;
 use std::path::Path;
 
-use object::{self, Object, ObjectSymbol, SymbolIterator};
+use object::{self, Object, ObjectSymbol};
 
 /// Given an [`object::File`], find the exported dynamic symbol names via
 /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear
@@ -14,47 +15,180 @@ pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) ->
         .collect()
 }
 
-/// Iterate through the symbols in an object file. See [`object::Object::symbols`].
+/// Check an object file's symbols for any matching **substrings**. That is, if an object file
+/// contains a symbol named `hello_world`, it will be matched against a provided `substrings` of
+/// `["hello", "bar"]`.
+///
+/// Returns `true` if **any** of the symbols found in the object file at `path` contain a
+/// **substring** listed in `substrings`.
 ///
 /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
 /// parsed as a recognized object file.
+///
+/// # Platform-specific behavior
+///
+/// On Windows MSVC, the binary (e.g. `main.exe`) does not contain the symbols, but in the separate
+/// PDB file instead. Furthermore, you will need to use [`crate::llvm::llvm_pdbutil`] as `object`
+/// crate does not handle PDB files.
 #[track_caller]
-pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R
+pub fn object_contains_any_symbol_substring<P, S>(path: P, substrings: &[S]) -> bool
 where
     P: AsRef<Path>,
-    F: FnOnce(&mut SymbolIterator<'_, '_>) -> R,
+    S: AsRef<str>,
 {
     let path = path.as_ref();
     let blob = crate::fs::read(path);
-    let f = object::File::parse(&*blob)
+    let obj = object::File::parse(&*blob)
         .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
-    let mut iter = f.symbols();
-    func(&mut iter)
+    let substrings = substrings.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
+    for sym in obj.symbols() {
+        for substring in &substrings {
+            if sym.name_bytes().unwrap().windows(substring.len()).any(|x| x == substring.as_bytes())
+            {
+                return true;
+            }
+        }
+    }
+    false
 }
 
-/// Check an object file's symbols for substrings.
+/// Check an object file's symbols for any exact matches against those provided in
+/// `candidate_symbols`.
 ///
-/// Returns `true` if any of the symbols found in the object file at `path` contain a substring
-/// listed in `substrings`.
+/// Returns `true` if **any** of the symbols found in the object file at `path` contain an **exact
+/// match** against those listed in `candidate_symbols`. Take care to account for (1) platform
+/// differences and (2) calling convention and symbol decorations differences.
 ///
 /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
 /// parsed as a recognized object file.
+///
+/// # Platform-specific behavior
+///
+/// See [`object_contains_any_symbol_substring`].
 #[track_caller]
-pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool {
-    with_symbol_iter(path, |syms| {
-        for sym in syms {
-            for substring in substrings {
-                if sym
-                    .name_bytes()
-                    .unwrap()
-                    .windows(substring.len())
-                    .any(|x| x == substring.as_bytes())
-                {
-                    eprintln!("{:?} contains {}", sym, substring);
-                    return true;
-                }
+pub fn object_contains_any_symbol<P, S>(path: P, candidate_symbols: &[S]) -> bool
+where
+    P: AsRef<Path>,
+    S: AsRef<str>,
+{
+    let path = path.as_ref();
+    let blob = crate::fs::read(path);
+    let obj = object::File::parse(&*blob)
+        .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
+    let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
+    for sym in obj.symbols() {
+        for candidate_symbol in &candidate_symbols {
+            if sym.name_bytes().unwrap() == candidate_symbol.as_bytes() {
+                return true;
             }
         }
-        false
-    })
+    }
+    false
+}
+
+#[derive(Debug, PartialEq)]
+pub enum ContainsAllSymbolSubstringsOutcome<'a> {
+    Ok,
+    MissingSymbolSubstrings(BTreeSet<&'a str>),
+}
+
+/// Check an object file's symbols for presence of all of provided **substrings**. That is, if an
+/// object file contains symbols `["hello", "goodbye", "world"]`, it will be matched against a list
+/// of `substrings` of `["he", "go"]`. In this case, `he` is a substring of `hello`, and `go` is a
+/// substring of `goodbye`, so each of `substrings` was found.
+///
+/// Returns `true` if **all** `substrings` were present in the names of symbols for the given object
+/// file (as substrings of symbol names).
+///
+/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
+/// parsed as a recognized object file.
+///
+/// # Platform-specific behavior
+///
+/// See [`object_contains_any_symbol_substring`].
+#[track_caller]
+pub fn object_contains_all_symbol_substring<'s, P, S>(
+    path: P,
+    substrings: &'s [S],
+) -> ContainsAllSymbolSubstringsOutcome<'s>
+where
+    P: AsRef<Path>,
+    S: AsRef<str>,
+{
+    let path = path.as_ref();
+    let blob = crate::fs::read(path);
+    let obj = object::File::parse(&*blob)
+        .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
+    let substrings = substrings.iter().map(|s| s.as_ref());
+    let mut unmatched_symbol_substrings = BTreeSet::from_iter(substrings);
+    unmatched_symbol_substrings.retain(|unmatched_symbol_substring| {
+        for sym in obj.symbols() {
+            if sym
+                .name_bytes()
+                .unwrap()
+                .windows(unmatched_symbol_substring.len())
+                .any(|x| x == unmatched_symbol_substring.as_bytes())
+            {
+                return false;
+            }
+        }
+
+        true
+    });
+
+    if unmatched_symbol_substrings.is_empty() {
+        ContainsAllSymbolSubstringsOutcome::Ok
+    } else {
+        ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(unmatched_symbol_substrings)
+    }
+}
+
+#[derive(Debug, PartialEq)]
+pub enum ContainsAllSymbolsOutcome<'a> {
+    Ok,
+    MissingSymbols(BTreeSet<&'a str>),
+}
+
+/// Check an object file contains all symbols provided in `candidate_symbols`.
+///
+/// Returns `true` if **all** of the symbols in `candidate_symbols` are found within the object file
+/// at `path` by **exact match**. Take care to account for (1) platform differences and (2) calling
+/// convention and symbol decorations differences.
+///
+/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
+/// parsed as a recognized object file.
+///
+/// # Platform-specific behavior
+///
+/// See [`object_contains_any_symbol_substring`].
+#[track_caller]
+pub fn object_contains_all_symbols<P, S>(
+    path: P,
+    candidate_symbols: &[S],
+) -> ContainsAllSymbolsOutcome<'_>
+where
+    P: AsRef<Path>,
+    S: AsRef<str>,
+{
+    let path = path.as_ref();
+    let blob = crate::fs::read(path);
+    let obj = object::File::parse(&*blob)
+        .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
+    let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref());
+    let mut unmatched_symbols = BTreeSet::from_iter(candidate_symbols);
+    unmatched_symbols.retain(|unmatched_symbol| {
+        for sym in obj.symbols() {
+            if sym.name_bytes().unwrap() == unmatched_symbol.as_bytes() {
+                return false;
+            }
+        }
+
+        true
+    });
+
+    if unmatched_symbols.is_empty() {
+        ContainsAllSymbolsOutcome::Ok
+    } else {
+        ContainsAllSymbolsOutcome::MissingSymbols(unmatched_symbols)
+    }
 }
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 050ddf47bae..27798d6aeb0 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -885,9 +885,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.51"
+version = "0.4.52"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328"
+checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec"
 dependencies = [
  "ammonia",
  "anyhow",
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 69c0cfaf5c9..c7c6e39f157 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.51"
+version = "0.4.52"
 default-features = false
 features = ["search"]
diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml
deleted file mode 100644
index d6f86078d7e..00000000000
--- a/src/tools/suggest-tests/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "suggest-tests"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-glob = "0.3.0"
-build_helper = { version = "0.1.0", path = "../../build_helper" }
diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs
deleted file mode 100644
index f09720f1c91..00000000000
--- a/src/tools/suggest-tests/src/dynamic_suggestions.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use std::path::Path;
-
-use crate::Suggestion;
-
-type DynamicSuggestion = fn(&Path) -> Vec<Suggestion>;
-
-pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[
-    |path: &Path| -> Vec<Suggestion> {
-        if path.starts_with("compiler/") || path.starts_with("library/") {
-            let path = path.components().take(2).collect::<Vec<_>>();
-
-            vec![Suggestion::with_single_path(
-                "test",
-                None,
-                &format!(
-                    "{}/{}",
-                    path[0].as_os_str().to_str().unwrap(),
-                    path[1].as_os_str().to_str().unwrap()
-                ),
-            )]
-        } else {
-            Vec::new()
-        }
-    },
-    |path: &Path| -> Vec<Suggestion> {
-        if path.starts_with("compiler/rustc_pattern_analysis") {
-            vec![Suggestion::new("test", None, &["tests/ui", "--test-args", "pattern"])]
-        } else {
-            Vec::new()
-        }
-    },
-];
diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs
deleted file mode 100644
index cc1288c6b72..00000000000
--- a/src/tools/suggest-tests/src/lib.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use std::fmt::{self, Display};
-use std::path::Path;
-
-use dynamic_suggestions::DYNAMIC_SUGGESTIONS;
-use glob::Pattern;
-use static_suggestions::static_suggestions;
-
-mod dynamic_suggestions;
-mod static_suggestions;
-
-#[cfg(test)]
-mod tests;
-
-macro_rules! sug {
-    ($cmd:expr) => {
-        Suggestion::new($cmd, None, &[])
-    };
-
-    ($cmd:expr, $paths:expr) => {
-        Suggestion::new($cmd, None, $paths.as_slice())
-    };
-
-    ($cmd:expr, $stage:expr, $paths:expr) => {
-        Suggestion::new($cmd, Some($stage), $paths.as_slice())
-    };
-}
-
-pub(crate) use sug;
-
-pub fn get_suggestions<T: AsRef<str>>(modified_files: &[T]) -> Vec<Suggestion> {
-    let mut suggestions = Vec::new();
-
-    // static suggestions
-    for (globs, sugs) in static_suggestions().iter() {
-        let globs = globs
-            .iter()
-            .map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!"))
-            .collect::<Vec<_>>();
-        let matches_some_glob = |file: &str| globs.iter().any(|glob| glob.matches(file));
-
-        if modified_files.iter().map(AsRef::as_ref).any(matches_some_glob) {
-            suggestions.extend_from_slice(sugs);
-        }
-    }
-
-    // dynamic suggestions
-    for sug in DYNAMIC_SUGGESTIONS {
-        for file in modified_files {
-            let sugs = sug(Path::new(file.as_ref()));
-
-            suggestions.extend_from_slice(&sugs);
-        }
-    }
-
-    suggestions.sort();
-    suggestions.dedup();
-
-    suggestions
-}
-
-#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
-pub struct Suggestion {
-    pub cmd: String,
-    pub stage: Option<u32>,
-    pub paths: Vec<String>,
-}
-
-impl Suggestion {
-    pub fn new(cmd: &str, stage: Option<u32>, paths: &[&str]) -> Self {
-        Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() }
-    }
-
-    pub fn with_single_path(cmd: &str, stage: Option<u32>, path: &str) -> Self {
-        Self::new(cmd, stage, &[path])
-    }
-}
-
-impl Display for Suggestion {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        write!(f, "{} ", self.cmd)?;
-
-        for path in &self.paths {
-            write!(f, "{} ", path)?;
-        }
-
-        if let Some(stage) = self.stage {
-            write!(f, "{}", stage)?;
-        } else {
-            // write a sentinel value here (in place of a stage) to be consumed
-            // by the shim in bootstrap, it will be read and ignored.
-            write!(f, "N/A")?;
-        }
-
-        Ok(())
-    }
-}
diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs
deleted file mode 100644
index d84f8e9fa1b..00000000000
--- a/src/tools/suggest-tests/src/main.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use std::process::ExitCode;
-
-use build_helper::git::{GitConfig, get_git_modified_files};
-use suggest_tests::get_suggestions;
-
-fn main() -> ExitCode {
-    let modified_files = get_git_modified_files(
-        &GitConfig {
-            nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
-            git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"),
-        },
-        None,
-        &Vec::new(),
-    );
-    let modified_files = match modified_files {
-        Ok(files) => files,
-        Err(err) => {
-            eprintln!("Could not get modified files from git: \"{err}\"");
-            return ExitCode::FAILURE;
-        }
-    };
-
-    let suggestions = get_suggestions(&modified_files);
-
-    for sug in &suggestions {
-        println!("{sug}");
-    }
-
-    ExitCode::SUCCESS
-}
-
-fn env(key: &str) -> String {
-    match std::env::var(key) {
-        Ok(var) => var,
-        Err(err) => {
-            eprintln!("suggest-tests: failed to read environment variable {key}: {err}");
-            std::process::exit(1);
-        }
-    }
-}
diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs
deleted file mode 100644
index d363d583b54..00000000000
--- a/src/tools/suggest-tests/src/static_suggestions.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use std::sync::OnceLock;
-
-use crate::{Suggestion, sug};
-
-// FIXME: perhaps this could use `std::lazy` when it is stabilized
-macro_rules! static_suggestions {
-    ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => {
-        pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec<Suggestion>)]
-        {
-            static S: OnceLock<Vec<(Vec<&'static str>, Vec<Suggestion>)>> = OnceLock::new();
-            S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*])
-        }
-    }
-}
-
-static_suggestions! {
-    ["*.md"] => [
-        sug!("test", 0, ["linkchecker"]),
-    ],
-
-    ["compiler/*"] => [
-        sug!("check"),
-        sug!("test", 1, ["tests/ui", "tests/run-make"]),
-    ],
-
-    ["compiler/rustc_mir_transform/*"] => [
-        sug!("test", 1, ["mir-opt"]),
-    ],
-
-    [
-        "compiler/rustc_mir_transform/src/coverage/*",
-        "compiler/rustc_codegen_llvm/src/coverageinfo/*",
-    ] => [
-        sug!("test", 1, ["coverage"]),
-    ],
-
-    ["src/librustdoc/*"] => [
-        sug!("test", 1, ["rustdoc"]),
-    ],
-}
diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs
deleted file mode 100644
index b4149136fa3..00000000000
--- a/src/tools/suggest-tests/src/tests.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-macro_rules! sugg_test {
-    ( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => {
-        $(
-            #[test]
-            fn $name() {
-                let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::<Vec<_>>();
-                assert_eq!(suggestions, $suggestions);
-            }
-        )*
-    };
-}
-
-sugg_test! {
-    test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] =>
-        ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"],
-
-    test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"],
-
-    test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] =>
-        ["test library/std N/A", "test rustdoc 1"]
-}
diff --git a/src/tools/tidy/src/filenames.rs b/src/tools/tidy/src/filenames.rs
new file mode 100644
index 00000000000..53115f4eaa4
--- /dev/null
+++ b/src/tools/tidy/src/filenames.rs
@@ -0,0 +1,40 @@
+//! Tidy check to ensure that there are no filenames containing forbidden characters
+//! checked into the source tree by accident:
+//! - Non-UTF8 filenames
+//! - Control characters such as CR or TAB
+//! - Filenames containing ":" as they are not supported on Windows
+//!
+//! Only files added to git are checked, as it may be acceptable to have temporary
+//! invalid filenames in the local directory during development.
+
+use std::path::Path;
+use std::process::Command;
+
+pub fn check(root_path: &Path, bad: &mut bool) {
+    let stat_output = Command::new("git")
+        .arg("-C")
+        .arg(root_path)
+        .args(["ls-files", "-z"])
+        .output()
+        .unwrap()
+        .stdout;
+    for filename in stat_output.split(|&b| b == 0) {
+        match str::from_utf8(filename) {
+            Err(_) => tidy_error!(
+                bad,
+                r#"non-UTF8 file names are not supported: "{}""#,
+                String::from_utf8_lossy(filename),
+            ),
+            Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!(
+                bad,
+                r#"control characters are not supported in file names: "{}""#,
+                String::from_utf8_lossy(filename),
+            ),
+            Ok(name) if name.contains(':') => tidy_error!(
+                bad,
+                r#"":" is not supported in file names because of Windows compatibility: "{name}""#,
+            ),
+            _ => (),
+        }
+    }
+}
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index cac4dba2b49..8b57db23d01 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2338,7 +2338,6 @@ ui/issues/issue-50415.rs
 ui/issues/issue-50442.rs
 ui/issues/issue-50471.rs
 ui/issues/issue-50518.rs
-ui/issues/issue-50571.rs
 ui/issues/issue-50581.rs
 ui/issues/issue-50582.rs
 ui/issues/issue-50585.rs
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 77855392b4d..ade4055b5bd 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -167,6 +167,7 @@ pub mod error_codes;
 pub mod ext_tool_checks;
 pub mod extdeps;
 pub mod features;
+pub mod filenames;
 pub mod fluent_alphabetical;
 pub mod fluent_period;
 mod fluent_used;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index a67f7a511b5..0f1116a632e 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -155,6 +155,8 @@ fn main() {
 
         check!(triagebot, &root_path);
 
+        check!(filenames, &root_path);
+
         let collected = {
             drain_handles(&mut handles);
 
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index b1ace74e5bd..7e295731c56 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1619;
+const ISSUES_ENTRY_LIMIT: u32 = 1616;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs
new file mode 100644
index 00000000000..73826214aac
--- /dev/null
+++ b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs
@@ -0,0 +1,92 @@
+//! `run_make_support::symbols` helpers self test.
+
+// Only intended as a basic smoke test, does not try to account for platform or calling convention
+// specific symbol decorations.
+//@ only-x86_64-unknown-linux-gnu
+//@ ignore-cross-compile
+
+use std::collections::BTreeSet;
+
+use object::{Object, ObjectSymbol};
+use run_make_support::symbols::{
+    ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome,
+    object_contains_all_symbol_substring, object_contains_all_symbols, object_contains_any_symbol,
+    object_contains_any_symbol_substring,
+};
+use run_make_support::{object, rfs, rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("sample.rs").emit("obj").edition("2024").run();
+
+    // `sample.rs` has two `no_mangle` functions, `eszett` and `beta`, in addition to `main`.
+    //
+    // These two symbol names and the test substrings used below are carefully picked to make sure
+    // they do not overlap with `sample` and contain non-hex characters, to avoid accidentally
+    // matching against CGU names like `sample.dad0f15d00c84e70-cgu.0`.
+
+    let obj_filename = "sample.o";
+    let blob = rfs::read(obj_filename);
+    let obj = object::File::parse(&*blob).unwrap();
+    eprintln!("found symbols:");
+    for sym in obj.symbols() {
+        eprintln!("symbol = {}", sym.name().unwrap());
+    }
+
+    // `hello` contains `hel`
+    assert!(object_contains_any_symbol_substring(obj_filename, &["zett"]));
+    assert!(object_contains_any_symbol_substring(obj_filename, &["zett", "does_not_exist"]));
+    assert!(!object_contains_any_symbol_substring(obj_filename, &["does_not_exist"]));
+
+    assert!(object_contains_any_symbol(obj_filename, &["eszett"]));
+    assert!(object_contains_any_symbol(obj_filename, &["eszett", "beta"]));
+    assert!(!object_contains_any_symbol(obj_filename, &["zett"]));
+    assert!(!object_contains_any_symbol(obj_filename, &["does_not_exist"]));
+
+    assert_eq!(
+        object_contains_all_symbol_substring(obj_filename, &["zett"]),
+        ContainsAllSymbolSubstringsOutcome::Ok
+    );
+    assert_eq!(
+        object_contains_all_symbol_substring(obj_filename, &["zett", "bet"]),
+        ContainsAllSymbolSubstringsOutcome::Ok
+    );
+    assert_eq!(
+        object_contains_all_symbol_substring(obj_filename, &["does_not_exist"]),
+        ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([
+            "does_not_exist"
+        ]))
+    );
+    assert_eq!(
+        object_contains_all_symbol_substring(obj_filename, &["zett", "does_not_exist"]),
+        ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([
+            "does_not_exist"
+        ]))
+    );
+    assert_eq!(
+        object_contains_all_symbol_substring(obj_filename, &["zett", "bet", "does_not_exist"]),
+        ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([
+            "does_not_exist"
+        ]))
+    );
+
+    assert_eq!(
+        object_contains_all_symbols(obj_filename, &["eszett"]),
+        ContainsAllSymbolsOutcome::Ok
+    );
+    assert_eq!(
+        object_contains_all_symbols(obj_filename, &["eszett", "beta"]),
+        ContainsAllSymbolsOutcome::Ok
+    );
+    assert_eq!(
+        object_contains_all_symbols(obj_filename, &["zett"]),
+        ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"]))
+    );
+    assert_eq!(
+        object_contains_all_symbols(obj_filename, &["zett", "beta"]),
+        ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"]))
+    );
+    assert_eq!(
+        object_contains_all_symbols(obj_filename, &["does_not_exist"]),
+        ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["does_not_exist"]))
+    );
+}
diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs
new file mode 100644
index 00000000000..3566d299766
--- /dev/null
+++ b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs
@@ -0,0 +1,13 @@
+#![crate_type = "lib"]
+
+#[unsafe(no_mangle)]
+pub extern "C" fn eszett() -> i8 {
+    42
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn beta() -> u32 {
+    1
+}
+
+fn main() {}
diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs
index af6ff6c2983..b7f18b384cb 100644
--- a/tests/run-make/fmt-write-bloat/rmake.rs
+++ b/tests/run-make/fmt-write-bloat/rmake.rs
@@ -20,7 +20,7 @@
 use run_make_support::artifact_names::bin_name;
 use run_make_support::env::std_debug_assertions_enabled;
 use run_make_support::rustc;
-use run_make_support::symbols::any_symbol_contains;
+use run_make_support::symbols::object_contains_any_symbol_substring;
 
 fn main() {
     rustc().input("main.rs").opt().run();
@@ -31,5 +31,5 @@ fn main() {
         // otherwise, add them to the list of symbols to deny.
         panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]);
     }
-    assert!(!any_symbol_contains(bin_name("main"), &panic_syms));
+    assert!(!object_contains_any_symbol_substring(bin_name("main"), &panic_syms));
 }
diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs
index bcdb84132d3..456321e2f56 100644
--- a/tests/run-make/used/rmake.rs
+++ b/tests/run-make/used/rmake.rs
@@ -8,9 +8,9 @@
 // https://rust-lang.github.io/rfcs/2386-used.html
 
 use run_make_support::rustc;
-use run_make_support::symbols::any_symbol_contains;
+use run_make_support::symbols::object_contains_any_symbol_substring;
 
 fn main() {
     rustc().opt_level("3").emit("obj").input("used.rs").run();
-    assert!(any_symbol_contains("used.o", &["FOO"]));
+    assert!(object_contains_any_symbol_substring("used.o", &["FOO"]));
 }
diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs
index 4e1ab3d145e..9ba310d3655 100644
--- a/tests/rustdoc-json/attrs/automatically_derived.rs
+++ b/tests/rustdoc-json/attrs/automatically_derived.rs
@@ -9,5 +9,5 @@ impl Default for Manual {
     }
 }
 
-//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]'
+//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["automatically_derived"]'
 //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]'
diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs
index e219345d669..ec1926e894e 100644
--- a/tests/rustdoc-json/attrs/cold.rs
+++ b/tests/rustdoc-json/attrs/cold.rs
@@ -1,3 +1,3 @@
-//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]'
+//@ is "$.index[?(@.name=='cold_fn')].attrs" '[{"other": "#[attr = Cold]"}]'
 #[cold]
 pub fn cold_fn() {}
diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs
index 254e9f6ef5b..451d9b9eb37 100644
--- a/tests/rustdoc-json/attrs/export_name_2021.rs
+++ b/tests/rustdoc-json/attrs/export_name_2021.rs
@@ -1,6 +1,6 @@
 //@ edition: 2021
 #![no_std]
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
+//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]'
 #[export_name = "altered"]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs
index 8129c109306..7e398db92ab 100644
--- a/tests/rustdoc-json/attrs/export_name_2024.rs
+++ b/tests/rustdoc-json/attrs/export_name_2024.rs
@@ -2,8 +2,8 @@
 #![no_std]
 
 // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024
-// is still `#[export_name = ..]` without the `unsafe` attribute wrapper.
+// doesn't mention the `unsafe`.
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
+//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]'
 #[unsafe(export_name = "altered")]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs
index b9ea6ab1d10..2aed49a48a5 100644
--- a/tests/rustdoc-json/attrs/inline.rs
+++ b/tests/rustdoc-json/attrs/inline.rs
@@ -1,11 +1,11 @@
-//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]'
+//@ is "$.index[?(@.name=='just_inline')].attrs" '[{"other": "#[attr = Inline(Hint)]"}]'
 #[inline]
 pub fn just_inline() {}
 
-//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]'
+//@ is "$.index[?(@.name=='inline_always')].attrs" '[{"other": "#[attr = Inline(Always)]"}]'
 #[inline(always)]
 pub fn inline_always() {}
 
-//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]'
+//@ is "$.index[?(@.name=='inline_never')].attrs" '[{"other": "#[attr = Inline(Never)]"}]'
 #[inline(never)]
 pub fn inline_never() {}
diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs
index a1312f4210b..acd8ecd0e30 100644
--- a/tests/rustdoc-json/attrs/link_section_2021.rs
+++ b/tests/rustdoc-json/attrs/link_section_2021.rs
@@ -1,6 +1,7 @@
 //@ edition: 2021
 #![no_std]
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
+//@ count "$.index[?(@.name=='example')].attrs[*]" 1
+//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"'
 #[link_section = ".text"]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs
index edb028451a8..8107493229b 100644
--- a/tests/rustdoc-json/attrs/link_section_2024.rs
+++ b/tests/rustdoc-json/attrs/link_section_2024.rs
@@ -4,6 +4,7 @@
 // Since the 2024 edition the link_section attribute must use the unsafe qualification.
 // However, the unsafe qualification is not shown by rustdoc.
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
+//@ count "$.index[?(@.name=='example')].attrs[*]" 1
+//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"'
 #[unsafe(link_section = ".text")]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs
index 3ca6f5a75a5..3f924c5169c 100644
--- a/tests/rustdoc-json/attrs/must_use.rs
+++ b/tests/rustdoc-json/attrs/must_use.rs
@@ -1,9 +1,9 @@
 #![no_std]
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]'
+//@ is "$.index[?(@.name=='example')].attrs[*].must_use.reason" null
 #[must_use]
 pub fn example() -> impl Iterator<Item = i64> {}
 
-//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]'
+//@ is "$.index[?(@.name=='explicit_message')].attrs[*].must_use.reason" '"does nothing if you do not use it"'
 #[must_use = "does nothing if you do not use it"]
 pub fn explicit_message() -> impl Iterator<Item = i64> {}
diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs
index 588be7256db..703dcb56491 100644
--- a/tests/rustdoc-json/attrs/no_mangle_2021.rs
+++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs
@@ -1,6 +1,6 @@
 //@ edition: 2021
 #![no_std]
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
+//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]'
 #[no_mangle]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs
index 0d500e20e6c..8af00eeda6b 100644
--- a/tests/rustdoc-json/attrs/no_mangle_2024.rs
+++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs
@@ -4,6 +4,6 @@
 // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024
 // is still `#[no_mangle]` without the `unsafe` attribute wrapper.
 
-//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
+//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]'
 #[unsafe(no_mangle)]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs
index b95f1a8171f..e4e6c8fd53b 100644
--- a/tests/rustdoc-json/attrs/non_exhaustive.rs
+++ b/tests/rustdoc-json/attrs/non_exhaustive.rs
@@ -1,18 +1,18 @@
 #![no_std]
 
-//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]'
+//@ is "$.index[?(@.name=='MyEnum')].attrs" '["non_exhaustive"]'
 #[non_exhaustive]
 pub enum MyEnum {
     First,
 }
 
 pub enum NonExhaustiveVariant {
-    //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]'
+    //@ is "$.index[?(@.name=='Variant')].attrs" '["non_exhaustive"]'
     #[non_exhaustive]
     Variant(i64),
 }
 
-//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]'
+//@ is "$.index[?(@.name=='MyStruct')].attrs" '["non_exhaustive"]'
 #[non_exhaustive]
 pub struct MyStruct {
     pub x: i64,
diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs
index 0bed0ad18c3..5988120ab2f 100644
--- a/tests/rustdoc-json/attrs/optimize.rs
+++ b/tests/rustdoc-json/attrs/optimize.rs
@@ -1,13 +1,13 @@
 #![feature(optimize_attribute)]
 
-//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]'
+//@ is "$.index[?(@.name=='speed')].attrs" '[{"other": "#[attr = Optimize(Speed)]"}]'
 #[optimize(speed)]
 pub fn speed() {}
 
-//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]'
+//@ is "$.index[?(@.name=='size')].attrs" '[{"other": "#[attr = Optimize(Size)]"}]'
 #[optimize(size)]
 pub fn size() {}
 
-//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]'
+//@ is "$.index[?(@.name=='none')].attrs" '[{"other": "#[attr = Optimize(DoNotOptimize)]"}]'
 #[optimize(none)]
 pub fn none() {}
diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs
index c6debda7f1c..f9d3417c485 100644
--- a/tests/rustdoc-json/attrs/repr_align.rs
+++ b/tests/rustdoc-json/attrs/repr_align.rs
@@ -1,6 +1,7 @@
 #![no_std]
 
-//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]'
+//@ count "$.index[?(@.name=='Aligned')].attrs[*]" 1
+//@ is "$.index[?(@.name=='Aligned')].attrs[*].repr.align" 4
 #[repr(align(4))]
 pub struct Aligned {
     a: i8,
diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs
index e6219413f30..89dbc16cb2a 100644
--- a/tests/rustdoc-json/attrs/repr_c.rs
+++ b/tests/rustdoc-json/attrs/repr_c.rs
@@ -1,16 +1,28 @@
 #![no_std]
 
-//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]'
+//@ count "$.index[?(@.name=='ReprCStruct')].attrs" 1
+//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.kind" '"c"'
+//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.int" null
+//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.packed" null
+//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.align" null
 #[repr(C)]
 pub struct ReprCStruct(pub i64);
 
-//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]'
+//@ count "$.index[?(@.name=='ReprCEnum')].attrs" 1
+//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.kind" '"c"'
+//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.int" null
+//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.packed" null
+//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.align" null
 #[repr(C)]
 pub enum ReprCEnum {
     First,
 }
 
-//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]'
+//@ count "$.index[?(@.name=='ReprCUnion')].attrs" 1
+//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.kind" '"c"'
+//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.int" null
+//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.packed" null
+//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.align" null
 #[repr(C)]
 pub union ReprCUnion {
     pub left: i64,
diff --git a/tests/rustdoc-json/attrs/repr_c_int_enum.rs b/tests/rustdoc-json/attrs/repr_c_int_enum.rs
new file mode 100644
index 00000000000..e90bcf2b5c6
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_c_int_enum.rs
@@ -0,0 +1,11 @@
+//@ count "$.index[?(@.name=='Foo')].attrs" 1
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.kind" '"c"'
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u8"'
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.packed" null
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.align" 16
+#[repr(C, u8)]
+#[repr(align(16))]
+pub enum Foo {
+    A(bool) = b'A',
+    B(char) = b'C',
+}
diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs
index 6fe29c5eac0..bd4a8563b6f 100644
--- a/tests/rustdoc-json/attrs/repr_combination.rs
+++ b/tests/rustdoc-json/attrs/repr_combination.rs
@@ -1,35 +1,34 @@
 #![no_std]
 
 // Combinations of `#[repr(..)]` attributes.
-// Rustdoc JSON emits normalized output, regardless of the original source.
 
-//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]'
+//@ is "$.index[?(@.name=='ReprCI8')].attrs" '[{"repr":{"align":null,"int":"i8","kind":"c","packed":null}}]'
 #[repr(C, i8)]
 pub enum ReprCI8 {
     First,
 }
 
-//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]'
+//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '[{"repr":{"align":null,"int":"i16","kind":"c","packed":null}}]'
 #[repr(C)]
 #[repr(i16)]
 pub enum SeparateReprCI16 {
     First,
 }
 
-//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]'
+//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '[{"repr":{"align":null,"int":"usize","kind":"c","packed":null}}]'
 #[repr(usize, C)]
 pub enum ReversedReprCUsize {
     First,
 }
 
-//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]'
+//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":1}}]'
 #[repr(C, packed)]
 pub struct ReprCPacked {
     a: i8,
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
+//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]'
 #[repr(C)]
 #[repr(packed(2))]
 pub struct SeparateReprCPacked {
@@ -37,21 +36,21 @@ pub struct SeparateReprCPacked {
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
+//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]'
 #[repr(packed(2), C)]
 pub struct ReversedReprCPacked {
     a: i8,
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]'
+//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '[{"repr":{"align":16,"int":null,"kind":"c","packed":null}}]'
 #[repr(C, align(16))]
 pub struct ReprCAlign {
     a: i8,
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
+//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]'
 #[repr(C)]
 #[repr(align(2))]
 pub struct SeparateReprCAlign {
@@ -59,25 +58,25 @@ pub struct SeparateReprCAlign {
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
+//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]'
 #[repr(align(2), C)]
 pub struct ReversedReprCAlign {
     a: i8,
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
+//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]'
 #[repr(C, align(16), isize)]
 pub enum AlignedExplicitRepr {
     First,
 }
 
-//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
+//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]'
 #[repr(isize, C, align(16))]
 pub enum ReorderedAlignedExplicitRepr {
     First,
 }
 
-//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]'
+//@ is "$.index[?(@.name=='Transparent')].attrs" '[{"repr":{"align":null,"int":null,"kind":"transparent","packed":null}}]'
 #[repr(transparent)]
 pub struct Transparent(i64);
diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs
index 9b09f341d4f..79e17f53ad9 100644
--- a/tests/rustdoc-json/attrs/repr_int_enum.rs
+++ b/tests/rustdoc-json/attrs/repr_int_enum.rs
@@ -1,18 +1,27 @@
 #![no_std]
 
-//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]'
+//@ is "$.index[?(@.name=='I8')].attrs[*].repr.int" '"i8"'
+//@ is "$.index[?(@.name=='I8')].attrs[*].repr.kind" '"rust"'
+//@ is "$.index[?(@.name=='I8')].attrs[*].repr.align" null
+//@ is "$.index[?(@.name=='I8')].attrs[*].repr.packed" null
 #[repr(i8)]
 pub enum I8 {
     First,
 }
 
-//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]'
+//@ is "$.index[?(@.name=='I32')].attrs[*].repr.int" '"i32"'
+//@ is "$.index[?(@.name=='I32')].attrs[*].repr.kind" '"rust"'
+//@ is "$.index[?(@.name=='I32')].attrs[*].repr.align" null
+//@ is "$.index[?(@.name=='I32')].attrs[*].repr.packed" null
 #[repr(i32)]
 pub enum I32 {
     First,
 }
 
-//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]'
+//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.int" '"usize"'
+//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.kind" '"rust"'
+//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.align" null
+//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.packed" null
 #[repr(usize)]
 pub enum Usize {
     First,
diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs
index 9f3fd86c4b0..ab573835b45 100644
--- a/tests/rustdoc-json/attrs/repr_packed.rs
+++ b/tests/rustdoc-json/attrs/repr_packed.rs
@@ -1,16 +1,18 @@
 #![no_std]
 
 // Note the normalization:
-// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON.
+// `#[repr(packed)]` in source becomes `{"repr": {"packed": 1, ...}}` in rustdoc JSON.
 //
-//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]'
+//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.packed" 1
+//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.kind" '"rust"'
 #[repr(packed)]
 pub struct Packed {
     a: i8,
     b: i64,
 }
 
-//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]'
+//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.packed" 4
+//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.kind" '"rust"'
 #[repr(packed(4))]
 pub struct PackedAligned {
     a: i8,
diff --git a/tests/rustdoc-json/attrs/target_feature.rs b/tests/rustdoc-json/attrs/target_feature.rs
index 01bc4f54d32..efe3752c166 100644
--- a/tests/rustdoc-json/attrs/target_feature.rs
+++ b/tests/rustdoc-json/attrs/target_feature.rs
@@ -1,38 +1,49 @@
-//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]'
 //@ is "$.index[?(@.name=='test1')].inner.function.header.is_unsafe" false
+//@ count "$.index[?(@.name=='test1')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test1')].attrs[*].target_feature.enable" '["avx"]'
 #[target_feature(enable = "avx")]
 pub fn test1() {}
 
-//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
 //@ is "$.index[?(@.name=='test2')].inner.function.header.is_unsafe" false
+//@ count "$.index[?(@.name=='test2')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test2')].attrs[*].target_feature.enable" '["avx", "avx2"]'
 #[target_feature(enable = "avx,avx2")]
 pub fn test2() {}
 
-//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
 //@ is "$.index[?(@.name=='test3')].inner.function.header.is_unsafe" false
+//@ count "$.index[?(@.name=='test3')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test3')].attrs[*].target_feature.enable" '["avx", "avx2"]'
 #[target_feature(enable = "avx", enable = "avx2")]
 pub fn test3() {}
 
-//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]'
 //@ is "$.index[?(@.name=='test4')].inner.function.header.is_unsafe" false
+//@ count "$.index[?(@.name=='test4')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test4')].attrs[*].target_feature.enable" '["avx", "avx2", "avx512f"]'
 #[target_feature(enable = "avx", enable = "avx2,avx512f")]
 pub fn test4() {}
 
-//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
+//@ count "$.index[?(@.name=='test5')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test5')].attrs[*].target_feature.enable" '["avx", "avx2"]'
+#[target_feature(enable = "avx")]
+#[target_feature(enable = "avx2")]
+pub fn test5() {}
+
 //@ is "$.index[?(@.name=='test_unsafe_fn')].inner.function.header.is_unsafe" true
+//@ count "$.index[?(@.name=='test_unsafe_fn')].attrs[*]" 1
+//@ is    "$.index[?(@.name=='test_unsafe_fn')].attrs[*].target_feature.enable" '["avx"]'
 #[target_feature(enable = "avx")]
 pub unsafe fn test_unsafe_fn() {}
 
 pub struct Example;
 
 impl Example {
-    //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
     //@ is "$.index[?(@.name=='safe_assoc_fn')].inner.function.header.is_unsafe" false
+    //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]'
     #[target_feature(enable = "avx")]
     pub fn safe_assoc_fn() {}
 
-    //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
     //@ is "$.index[?(@.name=='unsafe_assoc_fn')].inner.function.header.is_unsafe" true
+    //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]'
     #[target_feature(enable = "avx")]
     pub unsafe fn unsafe_assoc_fn() {}
 }
diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs
index ea669e6a0b3..fed0e545798 100644
--- a/tests/rustdoc-json/enums/discriminant/struct.rs
+++ b/tests/rustdoc-json/enums/discriminant/struct.rs
@@ -1,5 +1,5 @@
 #[repr(i32)]
-//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"i32"'
 pub enum Foo {
     //@ is    "$.index[?(@.name=='Struct')].inner.variant.discriminant" null
     //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0
diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs
index 1b8e791eb23..54bba76a063 100644
--- a/tests/rustdoc-json/enums/discriminant/tuple.rs
+++ b/tests/rustdoc-json/enums/discriminant/tuple.rs
@@ -1,5 +1,5 @@
 #[repr(u32)]
-//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u32"'
 pub enum Foo {
     //@ is    "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null
     //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0
diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs
index fea546c9fb6..3198fc2529e 100644
--- a/tests/rustdoc-json/keyword_private.rs
+++ b/tests/rustdoc-json/keyword_private.rs
@@ -5,7 +5,7 @@
 
 //@ !has "$.index[?(@.name=='match')]"
 //@ has  "$.index[?(@.name=='foo')]"
-//@ is   "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]'
+//@ is   "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"'
 //@ is   "$.index[?(@.name=='foo')].docs" '"this is a test!"'
 #[doc(keyword = "match")]
 /// this is a test!
@@ -13,7 +13,7 @@ pub mod foo {}
 
 //@ !has "$.index[?(@.name=='break')]"
 //@ has "$.index[?(@.name=='bar')]"
-//@ is   "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]'
+//@ is   "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"'
 //@ is   "$.index[?(@.name=='bar')].docs" '"hello"'
 #[doc(keyword = "break")]
 /// hello
diff --git a/tests/rustdoc-json/visibility/doc_hidden_documented.rs b/tests/rustdoc-json/visibility/doc_hidden_documented.rs
index 6e9ef48680b..f05e4f9d92d 100644
--- a/tests/rustdoc-json/visibility/doc_hidden_documented.rs
+++ b/tests/rustdoc-json/visibility/doc_hidden_documented.rs
@@ -1,15 +1,15 @@
 //@ compile-flags: --document-hidden-items
 #![no_std]
 
-//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]'
+//@ is "$.index[?(@.name=='func')].attrs" '[{"other": "#[doc(hidden)]"}]'
 #[doc(hidden)]
 pub fn func() {}
 
-//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]'
+//@ is "$.index[?(@.name=='Unit')].attrs" '[{"other": "#[doc(hidden)]"}]'
 #[doc(hidden)]
 pub struct Unit;
 
-//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]'
+//@ is "$.index[?(@.name=='hidden')].attrs" '[{"other": "#[doc(hidden)]"}]'
 #[doc(hidden)]
 pub mod hidden {
     //@ is "$.index[?(@.name=='Inner')].attrs" '[]'
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index aa52de63a60..5026687b97b 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -100,7 +100,7 @@
 //~^ ERROR malformed
 //~| ERROR the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
 #[cfg]
-//~^ ERROR is not followed by parentheses
+//~^ ERROR malformed
 #[cfg_attr]
 //~^ ERROR malformed
 #[instruction_set]
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 3dc3c32c936..56f2be353e7 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -1,8 +1,11 @@
-error: `cfg` is not followed by parentheses
+error[E0539]: malformed `cfg` attribute input
   --> $DIR/malformed-attrs.rs:102:1
    |
 LL | #[cfg]
-   | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+   | ^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg(predicate)]`
 
 error: malformed `cfg_attr` attribute input
   --> $DIR/malformed-attrs.rs:104:1
diff --git a/tests/ui/cfg/cfg-target-compact-errors.rs b/tests/ui/cfg/cfg-target-compact-errors.rs
index e00d42fe4d9..cfb19c58a19 100644
--- a/tests/ui/cfg/cfg-target-compact-errors.rs
+++ b/tests/ui/cfg/cfg-target-compact-errors.rs
@@ -3,19 +3,23 @@
 #![feature(cfg_target_compact)]
 
 #[cfg(target(o::o))]
-//~^ ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
 fn one() {}
 
 #[cfg(target(os = 8))]
-//~^ ERROR literal in `cfg` predicate value must be a string
+//~^ ERROR malformed `cfg` attribute input
 fn two() {}
 
 #[cfg(target(os = "linux", pointer(width = "64")))]
-//~^ ERROR invalid predicate `target_pointer`
+//~^ ERROR malformed `cfg` attribute input
 fn three() {}
 
 #[cfg(target(true))]
-//~^ ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
 fn four() {}
 
+#[cfg(target(clippy::os = "linux"))]
+//~^ ERROR `cfg` predicate key must be an identifier
+fn five() {}
+
 fn main() {}
diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr
index 219d9732c32..7df6729e881 100644
--- a/tests/ui/cfg/cfg-target-compact-errors.stderr
+++ b/tests/ui/cfg/cfg-target-compact-errors.stderr
@@ -1,28 +1,45 @@
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-target-compact-errors.rs:5:14
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-target-compact-errors.rs:5:1
    |
 LL | #[cfg(target(o::o))]
-   |              ^^^^
+   | ^^^^^^^^^^^^^----^^^
+   | |            |
+   | |            expected this to be of the form `... = "..."`
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error[E0565]: literal in `cfg` predicate value must be a string
-  --> $DIR/cfg-target-compact-errors.rs:9:19
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-target-compact-errors.rs:9:1
    |
 LL | #[cfg(target(os = 8))]
-   |                   ^
+   | ^^^^^^^^^^^^^^^^^^-^^^
+   | |                 |
+   | |                 expected a string literal here
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error[E0537]: invalid predicate `target_pointer`
-  --> $DIR/cfg-target-compact-errors.rs:13:28
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-target-compact-errors.rs:13:1
    |
 LL | #[cfg(target(os = "linux", pointer(width = "64")))]
-   |                            ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^^^
+   | |                          |
+   | |                          expected this to be of the form `... = "..."`
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-target-compact-errors.rs:17:14
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-target-compact-errors.rs:17:1
    |
 LL | #[cfg(target(true))]
-   |              ^^^^
+   | ^^^^^^^^^^^^^----^^^
+   | |            |
+   | |            expected this to be of the form `... = "..."`
+   | help: must be of the form: `#[cfg(predicate)]`
+
+error: `cfg` predicate key must be an identifier
+  --> $DIR/cfg-target-compact-errors.rs:21:14
+   |
+LL | #[cfg(target(clippy::os = "linux"))]
+   |              ^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0537, E0565.
-For more information about an error, try `rustc --explain E0537`.
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr
index 2facd960763..188f6d7aa5d 100644
--- a/tests/ui/cfg/cfg-version/syntax.stderr
+++ b/tests/ui/cfg/cfg-version/syntax.stderr
@@ -17,10 +17,10 @@ LL | #[cfg(version(false))]
    |               ^^^^^
 
 error: expected single version literal
-  --> $DIR/syntax.rs:23:7
+  --> $DIR/syntax.rs:23:14
    |
 LL | #[cfg(version("1.43", "1.44", "1.45"))]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unknown version literal format, assuming it refers to a future version
   --> $DIR/syntax.rs:51:15
diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr
index 3e32a856e95..155b3db2f42 100644
--- a/tests/ui/cfg/diagnostics-cross-crate.stderr
+++ b/tests/ui/cfg/diagnostics-cross-crate.stderr
@@ -10,10 +10,10 @@ note: found an item that was configured out
 LL |     pub mod doesnt_exist {
    |             ^^^^^^^^^^^^
 note: the item is gated here
-  --> $DIR/auxiliary/cfged_out.rs:5:5
+  --> $DIR/auxiliary/cfged_out.rs:5:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0425]: cannot find function `uwu` in crate `cfged_out`
   --> $DIR/diagnostics-cross-crate.rs:7:16
@@ -33,10 +33,10 @@ note: found an item that was configured out
 LL |     pub fn uwu() {}
    |            ^^^
 note: the item is gated here
-  --> $DIR/auxiliary/cfged_out.rs:2:5
+  --> $DIR/auxiliary/cfged_out.rs:2:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0425]: cannot find function `meow` in module `cfged_out::inner::right`
   --> $DIR/diagnostics-cross-crate.rs:24:30
@@ -67,10 +67,10 @@ note: found an item that was configured out
 LL | pub fn vanished() {}
    |        ^^^^^^^^
 note: the item is gated here
-  --> $DIR/auxiliary/cfged_out.rs:21:1
+  --> $DIR/auxiliary/cfged_out.rs:21:7
    |
 LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/cfg/diagnostics-reexport-2.stderr b/tests/ui/cfg/diagnostics-reexport-2.stderr
index 95ac5a19b0b..e1f91fcc5d1 100644
--- a/tests/ui/cfg/diagnostics-reexport-2.stderr
+++ b/tests/ui/cfg/diagnostics-reexport-2.stderr
@@ -10,10 +10,10 @@ note: found an item that was configured out
 LL |     pub mod gated {
    |             ^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport-2.rs:4:5
+  --> $DIR/diagnostics-reexport-2.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0433]: failed to resolve: could not find `gated` in `reexport2`
   --> $DIR/diagnostics-reexport-2.rs:46:16
@@ -27,10 +27,10 @@ note: found an item that was configured out
 LL |     pub mod gated {
    |             ^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport-2.rs:4:5
+  --> $DIR/diagnostics-reexport-2.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0433]: failed to resolve: could not find `gated` in `reexport30`
   --> $DIR/diagnostics-reexport-2.rs:50:17
@@ -44,10 +44,10 @@ note: found an item that was configured out
 LL |     pub mod gated {
    |             ^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport-2.rs:4:5
+  --> $DIR/diagnostics-reexport-2.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0433]: failed to resolve: could not find `gated` in `reexport31`
   --> $DIR/diagnostics-reexport-2.rs:54:17
@@ -61,10 +61,10 @@ note: found an item that was configured out
 LL |     pub mod gated {
    |             ^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport-2.rs:4:5
+  --> $DIR/diagnostics-reexport-2.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0433]: failed to resolve: could not find `gated` in `reexport32`
   --> $DIR/diagnostics-reexport-2.rs:58:17
@@ -78,10 +78,10 @@ note: found an item that was configured out
 LL |     pub mod gated {
    |             ^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport-2.rs:4:5
+  --> $DIR/diagnostics-reexport-2.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr
index 95dc4fac945..bf1bbcba7e4 100644
--- a/tests/ui/cfg/diagnostics-reexport.stderr
+++ b/tests/ui/cfg/diagnostics-reexport.stderr
@@ -10,10 +10,10 @@ note: found an item that was configured out
 LL |     pub fn x() {}
    |            ^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport.rs:17:5
+  --> $DIR/diagnostics-reexport.rs:17:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0432]: unresolved imports `b::x`, `b::y`
   --> $DIR/diagnostics-reexport.rs:22:13
@@ -29,20 +29,20 @@ note: found an item that was configured out
 LL |     pub fn x() {}
    |            ^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport.rs:28:5
+  --> $DIR/diagnostics-reexport.rs:28:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 note: found an item that was configured out
   --> $DIR/diagnostics-reexport.rs:32:12
    |
 LL |     pub fn y() {}
    |            ^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport.rs:31:5
+  --> $DIR/diagnostics-reexport.rs:31:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0425]: cannot find function `uwu` in module `inner`
   --> $DIR/diagnostics-reexport.rs:38:12
@@ -56,10 +56,10 @@ note: found an item that was configured out
 LL |     pub use super::uwu;
    |                    ^^^
 note: the item is gated here
-  --> $DIR/diagnostics-reexport.rs:7:5
+  --> $DIR/diagnostics-reexport.rs:7:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr
index 75a1bc39a01..121f25ca090 100644
--- a/tests/ui/cfg/diagnostics-same-crate.stderr
+++ b/tests/ui/cfg/diagnostics-same-crate.stderr
@@ -10,10 +10,10 @@ note: found an item that was configured out
 LL |     pub mod doesnt_exist {
    |             ^^^^^^^^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-same-crate.rs:8:5
+  --> $DIR/diagnostics-same-crate.rs:8:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0432]: unresolved import `super::inner::doesnt_exist`
   --> $DIR/diagnostics-same-crate.rs:35:23
@@ -27,10 +27,10 @@ note: found an item that was configured out
 LL |     pub mod doesnt_exist {
    |             ^^^^^^^^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-same-crate.rs:8:5
+  --> $DIR/diagnostics-same-crate.rs:8:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
   --> $DIR/diagnostics-same-crate.rs:54:12
@@ -44,10 +44,10 @@ note: found an item that was configured out
 LL |     pub mod doesnt_exist {
    |             ^^^^^^^^^^^^
 note: the item is gated here
-  --> $DIR/diagnostics-same-crate.rs:8:5
+  --> $DIR/diagnostics-same-crate.rs:8:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0425]: cannot find function `uwu` in module `inner`
   --> $DIR/diagnostics-same-crate.rs:49:12
@@ -61,10 +61,10 @@ note: found an item that was configured out
 LL |     pub fn uwu() {}
    |            ^^^
 note: the item is gated here
-  --> $DIR/diagnostics-same-crate.rs:4:5
+  --> $DIR/diagnostics-same-crate.rs:4:11
    |
 LL |     #[cfg(false)]
-   |     ^^^^^^^^^^^^^
+   |           ^^^^^
 
 error[E0425]: cannot find function `meow` in module `inner::right`
   --> $DIR/diagnostics-same-crate.rs:58:19
diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs
index 931afdf986f..fbf8f9d2002 100644
--- a/tests/ui/check-cfg/compact-names.rs
+++ b/tests/ui/check-cfg/compact-names.rs
@@ -13,4 +13,8 @@ pub fn expected() {}
 //~^ WARNING unexpected `cfg` condition name
 pub fn unexpected() {}
 
+#[cfg(target(os = "windows", architecture = "arm"))]
+//~^ WARNING unexpected `cfg` condition name
+pub fn unexpected2() {}
+
 fn main() {}
diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr
index 74ed0337e3b..3221b4e07ec 100644
--- a/tests/ui/check-cfg/compact-names.stderr
+++ b/tests/ui/check-cfg/compact-names.stderr
@@ -8,5 +8,14 @@ LL | #[cfg(target(os = "linux", architecture = "arm"))]
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
-warning: 1 warning emitted
+warning: unexpected `cfg` condition name: `target_architecture`
+  --> $DIR/compact-names.rs:16:30
+   |
+LL | #[cfg(target(os = "windows", architecture = "arm"))]
+   |                              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+warning: 2 warnings emitted
 
diff --git a/tests/ui/codegen/duplicated-path-in-error.stderr b/tests/ui/codegen/duplicated-path-in-error.gnu.stderr
index d0d34e2f934..d0d34e2f934 100644
--- a/tests/ui/codegen/duplicated-path-in-error.stderr
+++ b/tests/ui/codegen/duplicated-path-in-error.gnu.stderr
diff --git a/tests/ui/codegen/duplicated-path-in-error.musl.stderr b/tests/ui/codegen/duplicated-path-in-error.musl.stderr
new file mode 100644
index 00000000000..2892ebffdde
--- /dev/null
+++ b/tests/ui/codegen/duplicated-path-in-error.musl.stderr
@@ -0,0 +1,2 @@
+error: couldn't load codegen backend /non-existing-one.so: Error loading shared library /non-existing-one.so: No such file or directory
+
diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs
index a446395de20..fed93828ee2 100644
--- a/tests/ui/codegen/duplicated-path-in-error.rs
+++ b/tests/ui/codegen/duplicated-path-in-error.rs
@@ -1,8 +1,15 @@
+//@ revisions: musl gnu
 //@ only-linux
+//@ ignore-cross-compile because this relies on host libc behaviour
 //@ compile-flags: -Zcodegen-backend=/non-existing-one.so
+//@[gnu] only-gnu
+//@[musl] only-musl
 
 // This test ensures that the error of the "not found dylib" doesn't duplicate
 // the path of the dylib.
+//
+// glibc and musl have different dlopen error messages, so the expected error
+// message differs between the two.
 
 fn main() {}
 
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 47418b4e091..df87a3d846e 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -1,16 +1,24 @@
-#[cfg] //~ ERROR `cfg` is not followed by parentheses
+#[cfg]
+//~^ ERROR malformed `cfg` attribute
+//~| NOTE expected this to be a list
 struct S1;
 
-#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
+#[cfg = 10]
+//~^ ERROR malformed `cfg` attribute
+//~| NOTE expected this to be a list
 struct S2;
 
-#[cfg()] //~ ERROR `cfg` predicate is not specified
+#[cfg()]
+//~^ ERROR malformed `cfg` attribute
+//~| NOTE expected a single argument here
 struct S3;
 
-#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
+#[cfg(a, b)]
+//~^ ERROR malformed `cfg` attribute
+//~| NOTE expected a single argument here
 struct S4;
 
-#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
+#[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier
 struct S5;
 
 #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
@@ -19,10 +27,12 @@ struct S6;
 #[cfg(a())] //~ ERROR invalid predicate `a`
 struct S7;
 
-#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
+#[cfg(a = 10)] //~ ERROR malformed `cfg` attribute input
+//~^ NOTE expected a string literal here
 struct S8;
 
-#[cfg(a = b"hi")]  //~ ERROR literal in `cfg` predicate value must be a string
+#[cfg(a = b"hi")]  //~ ERROR malformed `cfg` attribute input
+//~^ NOTE expected a normal string literal, not a byte string literal
 struct S9;
 
 macro_rules! generate_s10 {
@@ -34,5 +44,6 @@ macro_rules! generate_s10 {
 }
 
 generate_s10!(concat!("nonexistent"));
+//~^ NOTE in this expansion of generate_s10!
 
 fn main() {}
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 66ce2ee9858..75e9b9209c0 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -1,61 +1,78 @@
-error: `cfg` is not followed by parentheses
+error[E0539]: malformed `cfg` attribute input
   --> $DIR/cfg-attr-syntax-validation.rs:1:1
    |
 LL | #[cfg]
-   | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+   | ^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error: `cfg` is not followed by parentheses
-  --> $DIR/cfg-attr-syntax-validation.rs:4:1
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:6:1
    |
 LL | #[cfg = 10]
-   | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+   | ^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error: `cfg` predicate is not specified
-  --> $DIR/cfg-attr-syntax-validation.rs:7:1
+error[E0805]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:11:1
    |
 LL | #[cfg()]
-   | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+   | ^^^^^--^
+   | |    |
+   | |    expected a single argument here
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error: multiple `cfg` predicates are specified
-  --> $DIR/cfg-attr-syntax-validation.rs:10:10
+error[E0805]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:16:1
    |
 LL | #[cfg(a, b)]
-   |          ^
+   | ^^^^^------^
+   | |    |
+   | |    expected a single argument here
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error: `cfg` predicate key cannot be a literal
-  --> $DIR/cfg-attr-syntax-validation.rs:13:7
+error: `cfg` predicate key must be an identifier
+  --> $DIR/cfg-attr-syntax-validation.rs:21:7
    |
 LL | #[cfg("str")]
    |       ^^^^^
 
 error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-attr-syntax-validation.rs:16:7
+  --> $DIR/cfg-attr-syntax-validation.rs:24:7
    |
 LL | #[cfg(a::b)]
    |       ^^^^
 
 error[E0537]: invalid predicate `a`
-  --> $DIR/cfg-attr-syntax-validation.rs:19:7
+  --> $DIR/cfg-attr-syntax-validation.rs:27:7
    |
 LL | #[cfg(a())]
    |       ^^^
 
-error[E0565]: literal in `cfg` predicate value must be a string
-  --> $DIR/cfg-attr-syntax-validation.rs:22:11
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:30:1
    |
 LL | #[cfg(a = 10)]
-   |           ^^
+   | ^^^^^^^^^^--^^
+   | |         |
+   | |         expected a string literal here
+   | help: must be of the form: `#[cfg(predicate)]`
 
-error[E0565]: literal in `cfg` predicate value must be a string
-  --> $DIR/cfg-attr-syntax-validation.rs:25:11
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:34:1
    |
 LL | #[cfg(a = b"hi")]
-   |           -^^^^
+   | ^^^^^^^^^^-^^^^^^
    |           |
    |           help: consider removing the prefix
+   |
+   = note: expected a normal string literal, not a byte string literal
 
 error: expected unsuffixed literal, found `expr` metavariable
-  --> $DIR/cfg-attr-syntax-validation.rs:30:25
+  --> $DIR/cfg-attr-syntax-validation.rs:40:25
    |
 LL |         #[cfg(feature = $expr)]
    |                         ^^^^^
@@ -67,5 +84,5 @@ LL | generate_s10!(concat!("nonexistent"));
 
 error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0537, E0565.
+Some errors have detailed explanations: E0537, E0539, E0805.
 For more information about an error, try `rustc --explain E0537`.
diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
index e805ac01c9d..ad2b49e6049 100644
--- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
+++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
@@ -1,9 +1,10 @@
-//@ known-bug: #110395
+#![feature(const_index, const_trait_impl)]
 
 const A: [(); 5] = [(), (), (), (), ()];
 
 // Since the indexing is on a ZST, the addresses are all fine,
 // but we should still catch the bad range.
 const B: &[()] = unsafe { A.get_unchecked(3..1) };
+//~^ ERROR: slice::get_unchecked requires that the range is within the slice
 
 fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
index 6e428079afe..88ea310f19c 100644
--- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
+++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
@@ -1,11 +1,11 @@
-error[E0015]: cannot call non-const method `core::slice::<impl [()]>::get_unchecked::<std::ops::Range<usize>>` in constants
-  --> $DIR/ub-slice-get-unchecked.rs:7:29
+error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice
+              
+              This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
+  --> $DIR/ub-slice-get-unchecked.rs:7:27
    |
 LL | const B: &[()] = unsafe { A.get_unchecked(3..1) };
-   |                             ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   |                           ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs
index ed5ff769701..f1bb8cddf77 100644
--- a/tests/ui/consts/const_transmute_type_id3.rs
+++ b/tests/ui/consts/const_transmute_type_id3.rs
@@ -1,3 +1,6 @@
+//! Test that all bytes of a TypeId must have the
+//! TypeId marker provenance.
+
 #![feature(const_type_id, const_trait_impl, const_cmp)]
 
 use std::any::TypeId;
@@ -10,7 +13,7 @@ const _: () = {
         std::ptr::write(ptr.offset(1), 999);
     }
     assert!(a == b);
-    //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents
+    //~^ ERROR: pointer must point to some allocation
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr
index 8cfdcfebaa4..e731f496652 100644
--- a/tests/ui/consts/const_transmute_type_id3.stderr
+++ b/tests/ui/consts/const_transmute_type_id3.stderr
@@ -1,5 +1,5 @@
-error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents
-  --> $DIR/const_transmute_type_id3.rs:12:13
+error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x3e7[noalloc] which is a dangling pointer (it has no provenance)
+  --> $DIR/const_transmute_type_id3.rs:15:13
    |
 LL |     assert!(a == b);
    |             ^^^^^^ evaluation of `_` failed inside this call
diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs
new file mode 100644
index 00000000000..0a9ba01e0dd
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id5.rs
@@ -0,0 +1,21 @@
+//! Test that we require an equal TypeId to have the same integer
+//! part, even if the provenance matches.
+
+#![feature(const_type_id, const_trait_impl, const_cmp)]
+
+use std::any::TypeId;
+
+const _: () = {
+    let a = TypeId::of::<()>();
+    let mut b = TypeId::of::<()>();
+    unsafe {
+        let ptr = &mut b as *mut TypeId as *mut *const ();
+        // Copy the ptr at index 0 to index 1
+        let val = std::ptr::read(ptr);
+        std::ptr::write(ptr.offset(1), val);
+    }
+    assert!(a == b);
+    //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr
new file mode 100644
index 00000000000..59823fcc1c9
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id5.stderr
@@ -0,0 +1,15 @@
+error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+  --> $DIR/const_transmute_type_id5.rs:17:13
+   |
+LL |     assert!(a == b);
+   |             ^^^^^^ evaluation of `_` failed inside this call
+   |
+note: inside `<TypeId as PartialEq>::eq`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+note: inside `<TypeId as PartialEq>::eq::compiletime`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs
index 87c8b04452b..22791e7d15e 100644
--- a/tests/ui/consts/issue-94675.rs
+++ b/tests/ui/consts/issue-94675.rs
@@ -7,7 +7,9 @@ struct Foo<'a> {
 impl<'a> Foo<'a> {
     const fn spam(&mut self, baz: &mut Vec<u32>) {
         self.bar[0] = baz.len();
-        //~^ ERROR: cannot call
+        //~^ ERROR: `Vec<usize>: [const] Index<_>` is not satisfied
+        //~| ERROR: `Vec<usize>: [const] Index<usize>` is not satisfied
+        //~| ERROR: `Vec<usize>: [const] IndexMut<usize>` is not satisfied
     }
 }
 
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index 63a86b45633..608ce0cfef0 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -1,13 +1,24 @@
-error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-94675.rs:9:17
+error[E0277]: the trait bound `Vec<usize>: [const] Index<_>` is not satisfied
+  --> $DIR/issue-94675.rs:9:9
    |
 LL |         self.bar[0] = baz.len();
-   |                 ^^^
+   |         ^^^^^^^^^^^
+
+error[E0277]: the trait bound `Vec<usize>: [const] IndexMut<usize>` is not satisfied
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
+
+error[E0277]: the trait bound `Vec<usize>: [const] Index<usize>` is not satisfied
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
    |
-note: impl defined here, but it is not `const`
-  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+note: required by a bound in `std::ops::IndexMut::index_mut`
+  --> $SRC_DIR/core/src/ops/index.rs:LL:COL
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs
index 8c52586c485..98a50156a94 100644
--- a/tests/ui/consts/offset_ub.rs
+++ b/tests/ui/consts/offset_ub.rs
@@ -5,17 +5,17 @@ use std::ptr;
 //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes"
 
 
-pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR
-pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR
-pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR
+pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation
+pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation
+pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation
 
-pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR
-pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR
+pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize`
+pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize`
 pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR
 pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR
-pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR
+pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation
 
-pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR
+pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation
 pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~ ERROR
 
 // Make sure that we don't panic when computing abs(offset*size_of::<T>())
diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr
index 255583ce91c..d92ca09223d 100644
--- a/tests/ui/consts/offset_ub.stderr
+++ b/tests/ui/consts/offset_ub.stderr
@@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer
 LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here
 
-error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation
+error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation
   --> $DIR/offset_ub.rs:16:49
    |
-LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here
+LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here
 
 error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes
   --> $DIR/offset_ub.rs:18:50
diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed
deleted file mode 100644
index 6d73f17cca4..00000000000
--- a/tests/ui/issues/issue-50571.fixed
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ edition: 2015
-//@ run-rustfix
-
-#![allow(dead_code)]
-trait Foo {
-    fn foo(_: [i32; 2]) {}
-    //~^ ERROR: patterns aren't allowed in methods without bodies
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs
deleted file mode 100644
index dd840ffe4d1..00000000000
--- a/tests/ui/issues/issue-50571.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ edition: 2015
-//@ run-rustfix
-
-#![allow(dead_code)]
-trait Foo {
-    fn foo([a, b]: [i32; 2]) {}
-    //~^ ERROR: patterns aren't allowed in methods without bodies
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr
deleted file mode 100644
index 9b00fe0f5db..00000000000
--- a/tests/ui/issues/issue-50571.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0642]: patterns aren't allowed in methods without bodies
-  --> $DIR/issue-50571.rs:6:12
-   |
-LL |     fn foo([a, b]: [i32; 2]) {}
-   |            ^^^^^^
-   |
-help: give this argument a name or use an underscore to ignore it
-   |
-LL -     fn foo([a, b]: [i32; 2]) {}
-LL +     fn foo(_: [i32; 2]) {}
-   |
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0642`.
diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs
index a4d94836a09..461d2e0e8c1 100644
--- a/tests/ui/macros/cfg_select.rs
+++ b/tests/ui/macros/cfg_select.rs
@@ -18,10 +18,13 @@ fn arm_rhs_must_be_in_braces() -> i32 {
 cfg_select! {
     _ => {}
     true => {}
-    //~^ WARN unreachable rule
+    //~^ WARN unreachable predicate
 }
 
 cfg_select! {
-    //~^ ERROR none of the rules in this `cfg_select` evaluated to true
+    //~^ ERROR none of the predicates in this `cfg_select` evaluated to true
     false => {}
 }
+
+cfg_select! {}
+//~^ ERROR none of the predicates in this `cfg_select` evaluated to true
diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr
index fef5e95a6bc..6c18a7c189d 100644
--- a/tests/ui/macros/cfg_select.stderr
+++ b/tests/ui/macros/cfg_select.stderr
@@ -4,15 +4,15 @@ error: expected `{`, found `1`
 LL |         true => 1
    |                 ^ expected `{`
 
-warning: unreachable rule
+warning: unreachable predicate
   --> $DIR/cfg_select.rs:20:5
    |
 LL |     _ => {}
    |     - always matches
 LL |     true => {}
-   |     ^^^^ this rules is never reached
+   |     ^^^^ this predicate is never reached
 
-error: none of the rules in this `cfg_select` evaluated to true
+error: none of the predicates in this `cfg_select` evaluated to true
   --> $DIR/cfg_select.rs:24:1
    |
 LL | / cfg_select! {
@@ -21,5 +21,11 @@ LL | |     false => {}
 LL | | }
    | |_^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: none of the predicates in this `cfg_select` evaluated to true
+  --> $DIR/cfg_select.rs:29:1
+   |
+LL | cfg_select! {}
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr
index a894c90f4c3..9215754d4bb 100644
--- a/tests/ui/macros/macro-outer-attributes.stderr
+++ b/tests/ui/macros/macro-outer-attributes.stderr
@@ -10,16 +10,10 @@ note: found an item that was configured out
 LL |       pub fn bar() { });
    |              ^^^
 note: the item is gated here
-  --> $DIR/macro-outer-attributes.rs:5:45
-   |
-LL |                        $i:item) => (mod $nm { #[$a] $i }); }
-   |                                               ^^^^^
-LL |
-LL | / test!(a,
-LL | |       #[cfg(false)],
-LL | |       pub fn bar() { });
-   | |_______________________- in this macro invocation
-   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+  --> $DIR/macro-outer-attributes.rs:8:13
+   |
+LL |       #[cfg(false)],
+   |             ^^^^^
 help: consider importing this function
    |
 LL + use b::bar;
diff --git a/tests/ui/parser/better-expected.rs b/tests/ui/parser/better-expected.rs
index 16b61caa4df..91128c39691 100644
--- a/tests/ui/parser/better-expected.rs
+++ b/tests/ui/parser/better-expected.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
+    let x: [isize 3]; //~ ERROR expected `;` or `]`, found `3`
 }
diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr
index f4ec933be16..4646ce7eff0 100644
--- a/tests/ui/parser/better-expected.stderr
+++ b/tests/ui/parser/better-expected.stderr
@@ -1,10 +1,14 @@
-error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
+error: expected `;` or `]`, found `3`
   --> $DIR/better-expected.rs:2:19
    |
 LL |     let x: [isize 3];
-   |          -        ^ expected one of 7 possible tokens
-   |          |
-   |          while parsing the type for `x`
+   |                   ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL |     let x: [isize ;3];
+   |                   +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.rs b/tests/ui/parser/issues/error-pattern-issue-50571.rs
new file mode 100644
index 00000000000..0c2ce6052cb
--- /dev/null
+++ b/tests/ui/parser/issues/error-pattern-issue-50571.rs
@@ -0,0 +1,11 @@
+// There is a regression introduced for issue #143828
+//@ edition: 2015
+
+#![allow(dead_code)]
+trait Foo {
+    fn foo([a, b]: [i32; 2]) {}
+    //~^ ERROR: expected `;` or `]`, found `,`
+    //~| ERROR: patterns aren't allowed in methods without bodies
+}
+
+fn main() {}
diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr
new file mode 100644
index 00000000000..47457cff461
--- /dev/null
+++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr
@@ -0,0 +1,28 @@
+error: expected `;` or `]`, found `,`
+  --> $DIR/error-pattern-issue-50571.rs:6:14
+   |
+LL |     fn foo([a, b]: [i32; 2]) {}
+   |              ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL -     fn foo([a, b]: [i32; 2]) {}
+LL +     fn foo([a; b]: [i32; 2]) {}
+   |
+
+error[E0642]: patterns aren't allowed in methods without bodies
+  --> $DIR/error-pattern-issue-50571.rs:6:12
+   |
+LL |     fn foo([a, b]: [i32; 2]) {}
+   |            ^^^^^^
+   |
+help: give this argument a name or use an underscore to ignore it
+   |
+LL -     fn foo([a, b]: [i32; 2]) {}
+LL +     fn foo(_: [i32; 2]) {}
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0642`.
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs
index 316c612940c..439793ea8f7 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs
@@ -1,6 +1,6 @@
 //@ edition:2018
 #![crate_type = "lib"]
-#![feature(type_ascription)]
+#![feature(type_ascription, const_index, const_trait_impl)]
 use std::future::Future;
 use std::pin::Pin;
 
@@ -129,7 +129,6 @@ pub fn inside_block() {
 
 static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
 //~^ ERROR: cast cannot be followed by indexing
-//~| ERROR: cannot call non-const operator in statics
 
 static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]);
 //~^ ERROR: expected one of
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 64cf8baf9a5..ce7129da937 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]);
    |                        +                  +
 
 error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:134:36
+  --> $DIR/issue-35813-postfix-after-cast.rs:133:36
    |
 LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]);
    |                                    ^ expected one of `)`, `,`, `.`, `?`, or an operator
 
 error: cast cannot be followed by `?`
-  --> $DIR/issue-35813-postfix-after-cast.rs:139:5
+  --> $DIR/issue-35813-postfix-after-cast.rs:138:5
    |
 LL |     Err(0u64) as Result<u64,u64>?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -236,25 +236,25 @@ LL |     (Err(0u64) as Result<u64,u64>)?;
    |     +                            +
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:141:14
+  --> $DIR/issue-35813-postfix-after-cast.rs:140:14
    |
 LL |     Err(0u64): Result<u64,u64>?;
    |              ^ expected one of `.`, `;`, `?`, `}`, or an operator
 
 error: expected identifier, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:153:13
+  --> $DIR/issue-35813-postfix-after-cast.rs:152:13
    |
 LL |     drop_ptr: F();
    |             ^ expected identifier
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:160:13
+  --> $DIR/issue-35813-postfix-after-cast.rs:159:13
    |
 LL |     drop_ptr: fn(u8);
    |             ^ expected one of 8 possible tokens
 
 error: cast cannot be followed by a function call
-  --> $DIR/issue-35813-postfix-after-cast.rs:166:5
+  --> $DIR/issue-35813-postfix-after-cast.rs:165:5
    |
 LL |     drop as fn(u8)(0);
    |     ^^^^^^^^^^^^^^
@@ -265,13 +265,13 @@ LL |     (drop as fn(u8))(0);
    |     +              +
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:168:13
+  --> $DIR/issue-35813-postfix-after-cast.rs:167:13
    |
 LL |     drop_ptr: fn(u8)(0);
    |             ^ expected one of 8 possible tokens
 
 error: cast cannot be followed by `.await`
-  --> $DIR/issue-35813-postfix-after-cast.rs:173:5
+  --> $DIR/issue-35813-postfix-after-cast.rs:172:5
    |
 LL |     Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>.await;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -282,13 +282,13 @@ LL |     (Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>).await;
    |     +                                                     +
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:176:21
+  --> $DIR/issue-35813-postfix-after-cast.rs:175:21
    |
 LL |     Box::pin(noop()): Pin<Box<_>>.await;
    |                     ^ expected one of `.`, `;`, `?`, `}`, or an operator
 
 error: cast cannot be followed by a field access
-  --> $DIR/issue-35813-postfix-after-cast.rs:188:5
+  --> $DIR/issue-35813-postfix-after-cast.rs:187:5
    |
 LL |     Foo::default() as Foo.bar;
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -299,7 +299,7 @@ LL |     (Foo::default() as Foo).bar;
    |     +                     +
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
-  --> $DIR/issue-35813-postfix-after-cast.rs:190:19
+  --> $DIR/issue-35813-postfix-after-cast.rs:189:19
    |
 LL |     Foo::default(): Foo.bar;
    |                   ^ expected one of `.`, `;`, `?`, `}`, or an operator
@@ -322,21 +322,11 @@ LL |         if true { 33 } else { 44 }: i32.max(0)
    |                                   ^ expected one of `,`, `.`, `?`, or an operator
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/issue-35813-postfix-after-cast.rs:151:13
+  --> $DIR/issue-35813-postfix-after-cast.rs:150:13
    |
 LL |     drop as F();
    |             ^^^ only `Fn` traits may use parentheses
 
-error[E0015]: cannot call non-const operator in statics
-  --> $DIR/issue-35813-postfix-after-cast.rs:130:42
-   |
-LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
-   |                                          ^^^^^^
-   |
-   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
-   = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-
-error: aborting due to 40 previous errors
+error: aborting due to 39 previous errors
 
-Some errors have detailed explanations: E0015, E0214.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0214`.
diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs
new file mode 100644
index 00000000000..2cc5d979604
--- /dev/null
+++ b/tests/ui/parser/recover/array-type-no-semi.rs
@@ -0,0 +1,17 @@
+// when the next token is not a semicolon,
+// we should suggest to use semicolon if recovery is allowed
+// See issue #143828
+
+fn main() {
+    let x = 5;
+    let b: [i32, 5];
+    //~^ ERROR expected `;` or `]`, found `,`
+    let a: [i32, ];
+    //~^ ERROR expected `;` or `]`, found `,`
+    //~| ERROR expected value, found builtin type `i32` [E0423]
+    let c: [i32, x];
+    //~^ ERROR expected `;` or `]`, found `,`
+    //~| ERROR attempt to use a non-constant value in a constant [E0435]
+    let e: [i32 5];
+    //~^ ERROR expected `;` or `]`, found `5`
+}
diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr
new file mode 100644
index 00000000000..82330465144
--- /dev/null
+++ b/tests/ui/parser/recover/array-type-no-semi.stderr
@@ -0,0 +1,71 @@
+error: expected `;` or `]`, found `,`
+  --> $DIR/array-type-no-semi.rs:7:16
+   |
+LL |     let b: [i32, 5];
+   |                ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL -     let b: [i32, 5];
+LL +     let b: [i32; 5];
+   |
+
+error: expected `;` or `]`, found `,`
+  --> $DIR/array-type-no-semi.rs:9:16
+   |
+LL |     let a: [i32, ];
+   |          -     ^ expected `;` or `]`
+   |          |
+   |          while parsing the type for `a`
+   |          help: use `=` if you meant to assign
+   |
+   = note: you might have meant to write a slice or array type
+
+error: expected `;` or `]`, found `,`
+  --> $DIR/array-type-no-semi.rs:12:16
+   |
+LL |     let c: [i32, x];
+   |                ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL -     let c: [i32, x];
+LL +     let c: [i32; x];
+   |
+
+error: expected `;` or `]`, found `5`
+  --> $DIR/array-type-no-semi.rs:15:17
+   |
+LL |     let e: [i32 5];
+   |                 ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL |     let e: [i32 ;5];
+   |                 +
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/array-type-no-semi.rs:12:18
+   |
+LL |     let c: [i32, x];
+   |                  ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL -     let x = 5;
+LL +     const x: /* Type */ = 5;
+   |
+
+error[E0423]: expected value, found builtin type `i32`
+  --> $DIR/array-type-no-semi.rs:9:13
+   |
+LL |     let a: [i32, ];
+   |             ^^^ not a value
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0423, E0435.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs
index 560efecb91c..fb9a1c643fc 100644
--- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs
+++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs
@@ -1 +1,6 @@
-type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*`
+type v = [isize * 3];
+//~^ ERROR expected `;` or `]`, found `*`
+//~| WARN type `v` should have an upper camel case name [non_camel_case_types]
+
+
+fn main() {}
diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
index 5bc9c2ccf00..8d7938a1a46 100644
--- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
+++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
@@ -1,8 +1,23 @@
-error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*`
+error: expected `;` or `]`, found `*`
   --> $DIR/removed-syntax-fixed-vec.rs:1:17
    |
 LL | type v = [isize * 3];
-   |                 ^ expected one of 7 possible tokens
+   |                 ^ expected `;` or `]`
+   |
+   = note: you might have meant to write a slice or array type
+help: you might have meant to use `;` as the separator
+   |
+LL - type v = [isize * 3];
+LL + type v = [isize ; 3];
+   |
+
+warning: type `v` should have an upper camel case name
+  --> $DIR/removed-syntax-fixed-vec.rs:1:6
+   |
+LL | type v = [isize * 3];
+   |      ^ help: convert the identifier to upper camel case (notice the capitalization): `V`
+   |
+   = note: `#[warn(non_camel_case_types)]` on by default
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs
new file mode 100644
index 00000000000..0bafb5aa715
--- /dev/null
+++ b/tests/ui/precondition-checks/vec-from-parts.rs
@@ -0,0 +1,15 @@
+//@ run-fail
+//@ compile-flags: -Cdebug-assertions=yes
+//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity
+#![feature(allocator_api)]
+
+use std::ptr::NonNull;
+
+fn main() {
+    let ptr: NonNull<i32> = std::ptr::NonNull::dangling();
+    // Test Vec::from_parts_in with length > capacity
+    unsafe {
+        let alloc = std::alloc::Global;
+        let _vec = Vec::from_parts_in(ptr, 10, 5, alloc);
+    }
+}
diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs
new file mode 100644
index 00000000000..884d34c0a56
--- /dev/null
+++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs
@@ -0,0 +1,29 @@
+//@ run-fail
+//@ compile-flags: -Cdebug-assertions=yes
+//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity
+//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts
+
+#![feature(allocator_api)]
+
+fn main() {
+    let ptr = std::ptr::null_mut::<u8>();
+    // Test Vec::from_raw_parts with length > capacity
+    unsafe {
+        #[cfg(vec_from_raw_parts)]
+        let _vec = Vec::from_raw_parts(ptr, 10, 5);
+    }
+
+    // Test Vec::from_raw_parts_in with length > capacity
+    unsafe {
+        let alloc = std::alloc::Global;
+        #[cfg(vec_from_raw_parts_in)]
+        let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc);
+    }
+
+    // Test String::from_raw_parts with length > capacity
+    // Because it calls Vec::from_raw_parts, it should also fail
+    unsafe {
+        #[cfg(string_from_raw_parts)]
+        let _vec = String::from_raw_parts(ptr, 10, 5);
+    }
+}
diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs
new file mode 100644
index 00000000000..0987e7fe028
--- /dev/null
+++ b/tests/ui/precondition-checks/vec-set-len.rs
@@ -0,0 +1,11 @@
+//@ run-fail
+//@ compile-flags: -Cdebug-assertions=yes
+//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()
+
+fn main() {
+    let mut vec: Vec<i32> = Vec::with_capacity(5);
+    // Test set_len with length > capacity
+    unsafe {
+        vec.set_len(10);
+    }
+}
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index 1734b9afe92..91d16eca1b0 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -49,12 +49,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 
 SyntaxContexts:
 #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index 42257312a87..63741326e34 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -72,12 +72,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
-crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 
 SyntaxContexts:
 #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
diff --git a/tests/ui/span/E0536.rs b/tests/ui/span/E0536.rs
index 72de7b6f453..ae073363354 100644
--- a/tests/ui/span/E0536.rs
+++ b/tests/ui/span/E0536.rs
@@ -1,4 +1,3 @@
-#[cfg(not())] //~ ERROR E0536
-pub fn something() {}
-
-pub fn main() {}
+pub fn main() {
+    if cfg!(not()) { } //~ ERROR E0536
+}
diff --git a/tests/ui/span/E0536.stderr b/tests/ui/span/E0536.stderr
index b0f652208c4..6c25f9140a1 100644
--- a/tests/ui/span/E0536.stderr
+++ b/tests/ui/span/E0536.stderr
@@ -1,8 +1,8 @@
 error[E0536]: expected 1 cfg-pattern
-  --> $DIR/E0536.rs:1:7
+  --> $DIR/E0536.rs:2:13
    |
-LL | #[cfg(not())]
-   |       ^^^^^
+LL |     if cfg!(not()) { }
+   |             ^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
index ece87529c3e..1d1da9b0e3d 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
@@ -14,5 +14,7 @@ fn main() {
 trait NonConst {}
 const fn handle(_: &dyn const NonConst) {}
 //~^ ERROR const trait bounds are not allowed in trait object types
+//~| ERROR `const` can only be applied to `#[const_trait]` traits
 const fn take(_: &dyn [const] NonConst) {}
 //~^ ERROR `[const]` is not allowed here
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
index 090555c6377..06e0493024c 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
@@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {}
    |                         ^^^^^^^^^^^^^^
 
 error: `[const]` is not allowed here
-  --> $DIR/const-trait-bounds-trait-objects.rs:17:23
+  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
    |
 LL | const fn take(_: &dyn [const] NonConst) {}
    |                       ^^^^^^^
    |
    = note: trait objects cannot have `[const]` trait bounds
 
-error: aborting due to 4 previous errors
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:15:25
+   |
+LL | const fn handle(_: &dyn const NonConst) {}
+   |                         ^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
+
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
+   |
+LL | const fn take(_: &dyn [const] NonConst) {}
+   |                       ^^^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
+
+error: aborting due to 6 previous errors
 
diff --git a/triagebot.toml b/triagebot.toml
index 75e794c700d..2f8114aeb3b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -506,7 +506,6 @@ trigger_files = [
     "src/tools/remote-test-server",
     "src/tools/remote-test-client",
     "src/tools/rustdoc-gui-test",
-    "src/tools/suggest-tests",
 ]
 
 [autolabel."A-tidy"]