about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc/Cargo.toml1
-rw-r--r--compiler/rustc_abi/src/layout.rs11
-rw-r--r--compiler/rustc_abi/src/lib.rs15
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml5
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs82
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_index/Cargo.toml1
-rw-r--r--compiler/rustc_index/src/lib.rs11
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs6
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs1
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs35
-rw-r--r--config.example.toml3
-rw-r--r--library/alloc/Cargo.toml1
-rw-r--r--library/alloc/src/collections/btree/node/tests.rs2
-rw-r--r--library/core/Cargo.toml2
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/task/wake.rs103
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/waker.rs11
-rw-r--r--library/panic_unwind/Cargo.toml7
-rw-r--r--library/panic_unwind/src/lib.rs2
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/rtems/fs.rs374
-rw-r--r--library/std/src/os/rtems/mod.rs4
-rw-r--r--library/std/src/os/rtems/raw.rs33
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/args.rs1
-rw-r--r--library/std/src/sys/pal/unix/env.rs11
-rw-r--r--library/std/src/sys/pal/unix/fs.rs18
-rw-r--r--library/std/src/sys/pal/unix/mod.rs1
-rw-r--r--library/std/src/sys/pal/unix/os.rs19
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs6
-rw-r--r--library/std/src/sys/personality/mod.rs2
-rw-r--r--library/unwind/Cargo.toml7
-rw-r--r--library/unwind/src/lib.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs3
-rw-r--r--src/bootstrap/src/core/builder.rs12
-rw-r--r--src/bootstrap/src/core/config/config.rs26
-rw-r--r--src/bootstrap/src/core/sanity.rs13
-rw-r--r--src/bootstrap/src/lib.rs3
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile1
-rwxr-xr-xsrc/ci/docker/scripts/rfl-build.sh50
-rw-r--r--src/doc/not_found.md2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md52
-rw-r--r--src/librustdoc/clean/types.rs6
-rw-r--r--src/librustdoc/html/markdown.rs73
-rw-r--r--src/librustdoc/html/render/context.rs6
-rw-r--r--src/librustdoc/html/render/sidebar.rs282
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css14
-rw-r--r--src/librustdoc/html/static/js/main.js4
-rw-r--r--src/librustdoc/html/static/js/settings.js29
-rw-r--r--src/librustdoc/html/static/js/storage.js13
-rw-r--r--src/librustdoc/html/templates/sidebar.html49
-rw-r--r--src/librustdoc/html/toc.rs26
-rw-r--r--src/librustdoc/html/toc/tests.rs6
-rw-r--r--src/librustdoc/markdown.rs1
-rw-r--r--src/tools/build_helper/src/git.rs34
-rw-r--r--src/tools/compiletest/src/command-list.rs1
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/header/needs.rs5
-rw-r--r--src/tools/compiletest/src/lib.rs6
-rw-r--r--src/tools/miri/tests/pass/dyn-arbitrary-self.rs2
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/codegen/issues/issue-86106.rs1
-rw-r--r--tests/codegen/mem-replace-big-type.rs1
-rw-r--r--tests/codegen/slice-iter-nonnull.rs1
-rw-r--r--tests/codegen/vecdeque-drain.rs1
-rw-r--r--tests/mir-opt/building/receiver_ptr_mutability.rs2
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.rs1
-rw-r--r--tests/rustdoc-gui/sidebar-modnav-position.goml44
-rw-r--r--tests/rustdoc-gui/sidebar.goml45
-rw-r--r--tests/rustdoc/sidebar/module.rs16
-rw-r--r--tests/rustdoc/sidebar/sidebar-all-page.rs (renamed from tests/rustdoc/sidebar-all-page.rs)0
-rw-r--r--tests/rustdoc/sidebar/sidebar-items.rs (renamed from tests/rustdoc/sidebar-items.rs)0
-rw-r--r--tests/rustdoc/sidebar/sidebar-link-generation.rs (renamed from tests/rustdoc/sidebar-link-generation.rs)0
-rw-r--r--tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs (renamed from tests/rustdoc/sidebar-links-to-foreign-impl.rs)0
-rw-r--r--tests/rustdoc/sidebar/top-toc-html.rs23
-rw-r--r--tests/rustdoc/sidebar/top-toc-idmap.rs44
-rw-r--r--tests/rustdoc/sidebar/top-toc-nil.rs7
-rw-r--r--tests/rustdoc/strip-enum-variant.no-not-shown.html2
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs15
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr36
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr12
-rw-r--r--tests/ui/inference/auxiliary/inference_unstable_iterator.rs2
-rw-r--r--tests/ui/inference/auxiliary/inference_unstable_itertools.rs2
-rw-r--r--tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs2
-rw-r--r--tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs2
-rw-r--r--tests/ui/stats/hir-stats.rs3
-rw-r--r--tests/ui/structs-enums/type-sizes.rs1
106 files changed, 1549 insertions, 284 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ce78d921244..d6714199682 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3569,6 +3569,7 @@ dependencies = [
  "rustc_hir_pretty",
  "rustc_hir_typeck",
  "rustc_incremental",
+ "rustc_index",
  "rustc_infer",
  "rustc_interface",
  "rustc_lint",
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 5008069542f..a2fc9d5c408 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -30,5 +30,6 @@ features = ['unprefixed_malloc_on_supported_platforms']
 jemalloc = ['dep:jemalloc-sys']
 llvm = ['rustc_driver_impl/llvm']
 max_level_info = ['rustc_driver_impl/max_level_info']
+rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
 rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
 # tidy-alphabetical-end
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 5160b4ed0a2..7432768be4a 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -968,8 +968,8 @@ fn univariant<
     let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
     let mut max_repr_align = repr.align;
     let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
-    let optimize = !repr.inhibit_struct_field_reordering();
-    if optimize && fields.len() > 1 {
+    let optimize_field_order = !repr.inhibit_struct_field_reordering();
+    if optimize_field_order && fields.len() > 1 {
         let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
         let optimizing = &mut inverse_memory_index.raw[..end];
         let fields_excluding_tail = &fields.raw[..end];
@@ -1176,7 +1176,7 @@ fn univariant<
     // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
     // Field 5 would be the first element, so memory_index is i:
     // Note: if we didn't optimize, it's already right.
-    let memory_index = if optimize {
+    let memory_index = if optimize_field_order {
         inverse_memory_index.invert_bijective_mapping()
     } else {
         debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
@@ -1189,6 +1189,9 @@ fn univariant<
     }
     let mut layout_of_single_non_zst_field = None;
     let mut abi = Abi::Aggregate { sized };
+
+    let optimize_abi = !repr.inhibit_newtype_abi_optimization();
+
     // Try to make this a Scalar/ScalarPair.
     if sized && size.bytes() > 0 {
         // We skip *all* ZST here and later check if we are good in terms of alignment.
@@ -1205,7 +1208,7 @@ fn univariant<
                     match field.abi {
                         // For plain scalars, or vectors of them, we can't unpack
                         // newtypes for `#[repr(C)]`, as that affects C ABIs.
-                        Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
+                        Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => {
                             abi = field.abi;
                         }
                         // But scalar pairs are Rust-specific and get
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index df29b3d54f0..be42bc84932 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -43,14 +43,17 @@ bitflags! {
         const IS_SIMD            = 1 << 1;
         const IS_TRANSPARENT     = 1 << 2;
         // Internal only for now. If true, don't reorder fields.
+        // On its own it does not prevent ABI optimizations.
         const IS_LINEAR          = 1 << 3;
-        // If true, the type's layout can be randomized using
-        // the seed stored in `ReprOptions.field_shuffle_seed`
+        // If true, the type's crate has opted into layout randomization.
+        // Other flags can still inhibit reordering and thus randomization.
+        // The seed stored in `ReprOptions.field_shuffle_seed`.
         const RANDOMIZE_LAYOUT   = 1 << 4;
         // Any of these flags being set prevent field reordering optimisation.
-        const IS_UNOPTIMISABLE   = ReprFlags::IS_C.bits()
+        const FIELD_ORDER_UNOPTIMIZABLE   = ReprFlags::IS_C.bits()
                                  | ReprFlags::IS_SIMD.bits()
                                  | ReprFlags::IS_LINEAR.bits();
+        const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
     }
 }
 
@@ -139,10 +142,14 @@ impl ReprOptions {
         self.c() || self.int.is_some()
     }
 
+    pub fn inhibit_newtype_abi_optimization(&self) -> bool {
+        self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE)
+    }
+
     /// Returns `true` if this `#[repr()]` guarantees a fixed field order,
     /// e.g. `repr(C)` or `repr(<int>)`.
     pub fn inhibit_struct_field_reordering(&self) -> bool {
-        self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
+        self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some()
     }
 
     /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 91cbffcd707..6d6d3f35a4b 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -23,6 +23,7 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_hir_typeck = { path = "../rustc_hir_typeck" }
 rustc_incremental = { path = "../rustc_incremental" }
+rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_interface = { path = "../rustc_interface" }
 rustc_lint = { path = "../rustc_lint" }
@@ -72,6 +73,10 @@ ctrlc = "3.4.4"
 # tidy-alphabetical-start
 llvm = ['rustc_interface/llvm']
 max_level_info = ['rustc_log/max_level_info']
+rustc_randomized_layouts = [
+    'rustc_index/rustc_randomized_layouts',
+    'rustc_middle/rustc_randomized_layouts'
+]
 rustc_use_parallel_compiler = [
     'rustc_data_structures/rustc_use_parallel_compiler',
     'rustc_interface/rustc_use_parallel_compiler',
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index cd6adbda039..fba65883550 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -349,8 +349,10 @@ declare_features! (
     (unstable, adt_const_params, "1.56.0", Some(95174)),
     /// Allows defining an `#[alloc_error_handler]`.
     (unstable, alloc_error_handler, "1.29.0", Some(51540)),
-    /// Allows trait methods with arbitrary self types.
+    /// Allows inherent and trait methods with arbitrary self types.
     (unstable, arbitrary_self_types, "1.23.0", Some(44874)),
+    /// Allows inherent and trait methods with arbitrary self types that are raw pointers.
+    (unstable, arbitrary_self_types_pointers, "CURRENT_RUSTC_VERSION", Some(44874)),
     /// Enables experimental inline assembly support for additional architectures.
     (unstable, asm_experimental_arch, "1.58.0", Some(93335)),
     /// Allows using `label` operands in inline assembly.
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f83eac7cd6c..3627faf8dfc 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1652,6 +1652,13 @@ fn check_fn_or_method<'tcx>(
     }
 }
 
+/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`.
+#[derive(Clone, Copy, PartialEq)]
+enum ArbitrarySelfTypesLevel {
+    Basic,        // just arbitrary_self_types
+    WithPointers, // both arbitrary_self_types and arbitrary_self_types_pointers
+}
+
 #[instrument(level = "debug", skip(wfcx))]
 fn check_method_receiver<'tcx>(
     wfcx: &WfCheckingCtxt<'_, 'tcx>,
@@ -1684,14 +1691,27 @@ fn check_method_receiver<'tcx>(
         return Ok(());
     }
 
-    if tcx.features().arbitrary_self_types {
-        if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
-            // Report error; `arbitrary_self_types` was enabled.
-            return Err(tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }));
-        }
+    let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers {
+        Some(ArbitrarySelfTypesLevel::WithPointers)
+    } else if tcx.features().arbitrary_self_types {
+        Some(ArbitrarySelfTypesLevel::Basic)
     } else {
-        if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) {
-            return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
+        None
+    };
+
+    if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
+        return Err(match arbitrary_self_types_level {
+            // Wherever possible, emit a message advising folks that the features
+            // `arbitrary_self_types` or `arbitrary_self_types_pointers` might
+            // have helped.
+            None if receiver_is_valid(
+                wfcx,
+                span,
+                receiver_ty,
+                self_ty,
+                Some(ArbitrarySelfTypesLevel::Basic),
+            ) =>
+            {
                 // Report error; would have worked with `arbitrary_self_types`.
                 feature_err(
                     &tcx.sess,
@@ -1699,25 +1719,49 @@ fn check_method_receiver<'tcx>(
                     span,
                     format!(
                         "`{receiver_ty}` cannot be used as the type of `self` without \
-                         the `arbitrary_self_types` feature",
+                            the `arbitrary_self_types` feature",
                     ),
                 )
                 .with_help(fluent::hir_analysis_invalid_receiver_ty_help)
                 .emit()
-            } else {
-                // Report error; would not have worked with `arbitrary_self_types`.
+            }
+            None | Some(ArbitrarySelfTypesLevel::Basic)
+                if receiver_is_valid(
+                    wfcx,
+                    span,
+                    receiver_ty,
+                    self_ty,
+                    Some(ArbitrarySelfTypesLevel::WithPointers),
+                ) =>
+            {
+                // Report error; would have worked with `arbitrary_self_types_pointers`.
+                feature_err(
+                    &tcx.sess,
+                    sym::arbitrary_self_types_pointers,
+                    span,
+                    format!(
+                        "`{receiver_ty}` cannot be used as the type of `self` without \
+                            the `arbitrary_self_types_pointers` feature",
+                    ),
+                )
+                .with_help(fluent::hir_analysis_invalid_receiver_ty_help)
+                .emit()
+            }
+            _ =>
+            // Report error; would not have worked with `arbitrary_self_types[_pointers]`.
+            {
                 tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
-            });
-        }
+            }
+        });
     }
     Ok(())
 }
 
 /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
 /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
-/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
-/// strict: `receiver_ty` must implement `Receiver` and directly implement
-/// `Deref<Target = self_ty>`.
+/// through a `*const/mut T` raw pointer if  `arbitrary_self_types_pointers` is also enabled.
+/// If neither feature is enabled, the requirements are more strict: `receiver_ty` must implement
+/// `Receiver` and directly implement `Deref<Target = self_ty>`.
 ///
 /// N.B., there are cases this function returns `true` but causes an error to be emitted,
 /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
@@ -1727,7 +1771,7 @@ fn receiver_is_valid<'tcx>(
     span: Span,
     receiver_ty: Ty<'tcx>,
     self_ty: Ty<'tcx>,
-    arbitrary_self_types_enabled: bool,
+    arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
 ) -> bool {
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
@@ -1745,8 +1789,8 @@ fn receiver_is_valid<'tcx>(
 
     let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
 
-    // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
-    if arbitrary_self_types_enabled {
+    // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
+    if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
         autoderef = autoderef.include_raw_pointers();
     }
 
@@ -1772,7 +1816,7 @@ fn receiver_is_valid<'tcx>(
 
         // Without `feature(arbitrary_self_types)`, we require that each step in the
         // deref chain implement `receiver`.
-        if !arbitrary_self_types_enabled {
+        if arbitrary_self_types_enabled.is_none() {
             if !receiver_is_implemented(
                 wfcx,
                 receiver_trait_def_id,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 0cf5403b3c0..2fdba8446bd 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     mode,
                 }));
             } else if bad_ty.reached_raw_pointer
-                && !self.tcx.features().arbitrary_self_types
+                && !self.tcx.features().arbitrary_self_types_pointers
                 && !self.tcx.sess.at_least_rust_2018()
             {
                 // this case used to be allowed by the compiler,
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index 92ea3f278dc..f7d18f84e34 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -20,4 +20,5 @@ nightly = [
     "dep:rustc_macros",
     "rustc_index_macros/nightly",
 ]
+rustc_randomized_layouts = []
 # tidy-alphabetical-end
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index f773b5b46ad..52f354b8eca 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -33,8 +33,19 @@ pub use vec::IndexVec;
 ///
 /// </div>
 #[macro_export]
+#[cfg(not(feature = "rustc_randomized_layouts"))]
 macro_rules! static_assert_size {
     ($ty:ty, $size:expr) => {
         const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
     };
 }
+
+#[macro_export]
+#[cfg(feature = "rustc_randomized_layouts")]
+macro_rules! static_assert_size {
+    ($ty:ty, $size:expr) => {
+        // no effect other than using the statements.
+        // struct sizes are not deterministic under randomized layouts
+        const _: (usize, usize) = ($size, ::std::mem::size_of::<$ty>());
+    };
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7063f488209..25d33126754 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3706,7 +3706,7 @@ declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
 
 declare_lint! {
     /// The `missing_abi` lint detects cases where the ABI is omitted from
-    /// extern declarations.
+    /// `extern` declarations.
     ///
     /// ### Example
     ///
@@ -3720,10 +3720,12 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// Historically, Rust implicitly selected C as the ABI for extern
-    /// declarations. We expect to add new ABIs, like `C-unwind`, in the future,
-    /// though this has not yet happened, and especially with their addition
-    /// seeing the ABI easily will make code review easier.
+    /// For historic reasons, Rust implicitly selects `C` as the default ABI for
+    /// `extern` declarations. [Other ABIs] like `C-unwind` and `system` have
+    /// been added since then, and especially with their addition seeing the ABI
+    /// easily makes code review easier.
+    ///
+    /// [Other ABIs]: https://doc.rust-lang.org/reference/items/external-blocks.html#abi
     pub MISSING_ABI,
     Allow,
     "No declared ABI for extern declaration"
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 1264510a831..53da07aeaa6 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -247,8 +247,8 @@ provide! { tcx, def_id, other, cdata,
     explicit_predicates_of => { table }
     generics_of => { table }
     inferred_outlives_of => { table_defaulted_array }
-    explicit_super_predicates_of => { table }
-    explicit_implied_predicates_of => { table }
+    explicit_super_predicates_of => { table_defaulted_array }
+    explicit_implied_predicates_of => { table_defaulted_array }
     type_of => { table }
     type_alias_is_lazy => { table_direct }
     variances_of => { table }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 88256c4db04..c55583b39a6 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1443,9 +1443,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             if let DefKind::Trait = def_kind {
                 record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
-                record_array!(self.tables.explicit_super_predicates_of[def_id] <-
+                record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
                     self.tcx.explicit_super_predicates_of(def_id).skip_binder());
-                record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
+                record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
                     self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
 
                 let module_children = self.tcx.module_children_local(local_id);
@@ -1454,9 +1454,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             if let DefKind::TraitAlias = def_kind {
                 record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
-                record_array!(self.tables.explicit_super_predicates_of[def_id] <-
+                record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
                     self.tcx.explicit_super_predicates_of(def_id).skip_binder());
-                record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
+                record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
                     self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
             }
             if let DefKind::Trait | DefKind::Impl { .. } = def_kind {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a84923130c3..8180a507a51 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -390,6 +390,8 @@ define_tables! {
     explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
     associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>,
@@ -419,10 +421,6 @@ define_tables! {
     lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
     explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
-    explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
-    // As an optimization, we only store this for trait aliases,
-    // since it's identical to explicit_super_predicates_of for traits.
-    explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
     fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 69e3b703cce..b23589afb58 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -40,5 +40,6 @@ tracing = "0.1"
 
 [features]
 # tidy-alphabetical-start
+rustc_randomized_layouts = []
 rustc_use_parallel_compiler = ["dep:rustc-rayon-core"]
 # tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index c9bd702cce3..0320a91d142 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -337,6 +337,7 @@ macro_rules! define_callbacks {
                 // Ensure that values grow no larger than 64 bytes by accident.
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
+                #[cfg(not(feature = "rustc_randomized_layouts"))]
                 const _: () = {
                     if mem::size_of::<Value<'static>>() > 64 {
                         panic!("{}", concat!(
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cd94c0afad0..ee70a6346d9 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -35,6 +35,7 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
+use rustc_hir::LangItem;
 use rustc_index::IndexVec;
 use rustc_macros::{
     extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
@@ -1570,8 +1571,15 @@ impl<'tcx> TyCtxt<'tcx> {
             flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
         }
 
+        // box is special, on the one hand the compiler assumes an ordered layout, with the pointer
+        // always at offset zero. On the other hand we want scalar abi optimizations.
+        let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox);
+
         // This is here instead of layout because the choice must make it into metadata.
-        if !self.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) {
+        if is_box
+            || !self
+                .consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did)))
+        {
             flags.insert(ReprFlags::IS_LINEAR);
         }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 34765209605..36b31d10c4d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -407,6 +407,7 @@ symbols! {
         append_const_msg,
         arbitrary_enum_discriminant,
         arbitrary_self_types,
+        arbitrary_self_types_pointers,
         args,
         arith_offset,
         arm,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index e6b00c84254..6abd8a0d6b7 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1695,6 +1695,8 @@ supported_targets! {
     ("armv7r-none-eabihf", armv7r_none_eabihf),
     ("armv8r-none-eabihf", armv8r_none_eabihf),
 
+    ("armv7-rtems-eabihf", armv7_rtems_eabihf),
+
     ("x86_64-pc-solaris", x86_64_pc_solaris),
     ("sparcv9-sun-solaris", sparcv9_sun_solaris),
 
diff --git a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
new file mode 100644
index 00000000000..1edecac095f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
@@ -0,0 +1,35 @@
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        llvm_target: "armv7-unknown-none-eabihf".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("Armv7 RTEMS (Requires RTEMS toolchain and kernel".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            os: "rtems".into(),
+            families: cvs!["unix"],
+            abi: "eabihf".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+            linker: None,
+            relocation_model: RelocModel::Static,
+            panic_strategy: PanicStrategy::Abort,
+            features: "+thumb2,+neon,+vfp3".into(),
+            max_atomic_width: Some(64),
+            emit_debug_gdb_scripts: false,
+            // GCC defaults to 8 for arm-none here.
+            c_enum_min_bits: Some(8),
+            eh_frame_header: false,
+            no_default_libraries: false,
+            env: "newlib".into(),
+            ..Default::default()
+        },
+    }
+}
diff --git a/config.example.toml b/config.example.toml
index b967d5d9fe8..13f76933b16 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -519,6 +519,9 @@
 # are disabled statically" because `max_level_info` is enabled, set this value to `true`.
 #debug-logging = rust.debug-assertions (boolean)
 
+# Whether or not to build rustc, tools and the libraries with randomized type layout
+#randomize-layout = false
+
 # Whether or not overflow checks are enabled for the compiler and standard
 # library.
 #
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 4365bcc4ad0..1bd4434d4f7 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -52,4 +52,5 @@ check-cfg = [
     'cfg(no_global_oom_handling)',
     'cfg(no_rc)',
     'cfg(no_sync)',
+    'cfg(randomized_layouts)',
 ]
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index d230749d712..4d2fa0f0941 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -90,7 +90,7 @@ fn test_partial_eq() {
 
 #[test]
 #[cfg(target_arch = "x86_64")]
-#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization
+#[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization
 fn test_sizes() {
     assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
     assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index cace4582b48..94f343d0670 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -43,6 +43,8 @@ check-cfg = [
     'cfg(bootstrap)',
     'cfg(no_fp_fmt_parse)',
     'cfg(stdarch_intel_sde)',
+    # #[cfg(bootstrap)] rtems
+    'cfg(target_os, values("rtems"))',
     # core use #[path] imports to portable-simd `core_simd` crate
     # and to stdarch `core_arch` crate which messes-up with Cargo list
     # of declared features, we therefor expect any feature cfg
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index ec1f9052a15..dc107c5d22c 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -110,7 +110,7 @@ mod c_char_definition {
             all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
             all(target_os = "l4re", target_arch = "x86_64"),
             all(
-                any(target_os = "freebsd", target_os = "openbsd"),
+                any(target_os = "freebsd", target_os = "openbsd", target_os = "rtems"),
                 any(
                     target_arch = "aarch64",
                     target_arch = "arm",
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 7e5c1574f53..6924b3c13ec 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -60,22 +60,6 @@ impl RawWaker {
         RawWaker { data, vtable }
     }
 
-    /// Gets the `data` pointer used to create this `RawWaker`.
-    #[inline]
-    #[must_use]
-    #[unstable(feature = "waker_getters", issue = "96992")]
-    pub fn data(&self) -> *const () {
-        self.data
-    }
-
-    /// Gets the `vtable` pointer used to create this `RawWaker`.
-    #[inline]
-    #[must_use]
-    #[unstable(feature = "waker_getters", issue = "96992")]
-    pub fn vtable(&self) -> &'static RawWakerVTable {
-        self.vtable
-    }
-
     #[unstable(feature = "noop_waker", issue = "98286")]
     const NOOP: RawWaker = {
         const VTABLE: RawWakerVTable = RawWakerVTable::new(
@@ -509,6 +493,37 @@ impl Waker {
         a_data == b_data && ptr::eq(a_vtable, b_vtable)
     }
 
+    /// Creates a new `Waker` from the provided `data` pointer and `vtable`.
+    ///
+    /// The `data` pointer can be used to store arbitrary data as required
+    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
+    /// that is associated with the task.
+    /// The value of this pointer will get passed to all functions that are part
+    /// of the `vtable` as the first parameter.
+    ///
+    /// It is important to consider that the `data` pointer must point to a
+    /// thread safe type such as an `Arc`.
+    ///
+    /// The `vtable` customizes the behavior of a `Waker`. For each operation
+    /// on the `Waker`, the associated function in the `vtable` will be called.
+    ///
+    /// # Safety
+    ///
+    /// The behavior of the returned `Waker` is undefined if the contract defined
+    /// in [`RawWakerVTable`]'s documentation is not upheld.
+    ///
+    /// (Authors wishing to avoid unsafe code may implement the [`Wake`] trait instead, at the
+    /// cost of a required heap allocation.)
+    ///
+    /// [`Wake`]: ../../alloc/task/trait.Wake.html
+    #[inline]
+    #[must_use]
+    #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+    pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
+        Waker { waker: RawWaker { data, vtable } }
+    }
+
     /// Creates a new `Waker` from [`RawWaker`].
     ///
     /// # Safety
@@ -565,12 +580,20 @@ impl Waker {
         WAKER
     }
 
-    /// Gets a reference to the underlying [`RawWaker`].
+    /// Gets the `data` pointer used to create this `Waker`.
     #[inline]
     #[must_use]
-    #[unstable(feature = "waker_getters", issue = "96992")]
-    pub fn as_raw(&self) -> &RawWaker {
-        &self.waker
+    #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+    pub fn data(&self) -> *const () {
+        self.waker.data
+    }
+
+    /// Gets the `vtable` pointer used to create this `Waker`.
+    #[inline]
+    #[must_use]
+    #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+    pub fn vtable(&self) -> &'static RawWakerVTable {
+        self.waker.vtable
     }
 }
 
@@ -778,6 +801,30 @@ impl LocalWaker {
         a_data == b_data && ptr::eq(a_vtable, b_vtable)
     }
 
+    /// Creates a new `LocalWaker` from the provided `data` pointer and `vtable`.
+    ///
+    /// The `data` pointer can be used to store arbitrary data as required
+    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
+    /// that is associated with the task.
+    /// The value of this pointer will get passed to all functions that are part
+    /// of the `vtable` as the first parameter.
+    ///
+    /// The `vtable` customizes the behavior of a `LocalWaker`. For each
+    /// operation on the `LocalWaker`, the associated function in the `vtable`
+    /// will be called.
+    ///
+    /// # Safety
+    ///
+    /// The behavior of the returned `Waker` is undefined if the contract defined
+    /// in [`RawWakerVTable`]'s documentation is not upheld.
+    ///
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
+        LocalWaker { waker: RawWaker { data, vtable } }
+    }
+
     /// Creates a new `LocalWaker` from [`RawWaker`].
     ///
     /// The behavior of the returned `LocalWaker` is undefined if the contract defined
@@ -831,12 +878,20 @@ impl LocalWaker {
         WAKER
     }
 
-    /// Gets a reference to the underlying [`RawWaker`].
+    /// Gets the `data` pointer used to create this `LocalWaker`.
     #[inline]
     #[must_use]
-    #[unstable(feature = "waker_getters", issue = "96992")]
-    pub fn as_raw(&self) -> &RawWaker {
-        &self.waker
+    #[unstable(feature = "local_waker", issue = "118959")]
+    pub fn data(&self) -> *const () {
+        self.waker.data
+    }
+
+    /// Gets the `vtable` pointer used to create this `LocalWaker`.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    pub fn vtable(&self) -> &'static RawWakerVTable {
+        self.waker.vtable
     }
 }
 #[unstable(feature = "local_waker", issue = "118959")]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c205f028dd3..96fc621494f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -112,7 +112,6 @@
 #![feature(unsize)]
 #![feature(unsized_tuple_coercion)]
 #![feature(unwrap_infallible)]
-#![feature(waker_getters)]
 // tidy-alphabetical-end
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs
index 361e900e695..8f6bf0565fc 100644
--- a/library/core/tests/waker.rs
+++ b/library/core/tests/waker.rs
@@ -4,14 +4,13 @@ use std::task::{RawWaker, RawWakerVTable, Waker};
 #[test]
 fn test_waker_getters() {
     let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE);
-    assert_eq!(raw_waker.data() as usize, 42);
-    assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE));
-
     let waker = unsafe { Waker::from_raw(raw_waker) };
+    assert_eq!(waker.data() as usize, 42);
+    assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE));
+
     let waker2 = waker.clone();
-    let raw_waker2 = waker2.as_raw();
-    assert_eq!(raw_waker2.data() as usize, 43);
-    assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE));
+    assert_eq!(waker2.data() as usize, 43);
+    assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE));
 }
 
 static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml
index f830808d196..6d1f9764efb 100644
--- a/library/panic_unwind/Cargo.toml
+++ b/library/panic_unwind/Cargo.toml
@@ -20,3 +20,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
 libc = { version = "0.2", default-features = false }
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    # #[cfg(bootstrap)] rtems
+    'cfg(target_os, values("rtems"))',
+]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 2d174f4b1a4..4552fb68d26 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -48,7 +48,7 @@ cfg_if::cfg_if! {
         target_os = "psp",
         target_os = "xous",
         target_os = "solid_asp3",
-        all(target_family = "unix", not(target_os = "espidf")),
+        all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems"))),
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_family = "wasm",
     ))] {
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 82cfd603a21..e20fe9feff1 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -146,4 +146,6 @@ check-cfg = [
     # and to the `backtrace` crate which messes-up with Cargo list
     # of declared features, we therefor expect any feature cfg
     'cfg(feature, values(any()))',
+    # #[cfg(bootstrap)] rtems
+    'cfg(target_os, values("rtems"))',
 ]
diff --git a/library/std/build.rs b/library/std/build.rs
index 72254cafc85..ba1eece46f3 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -53,6 +53,7 @@ fn main() {
         || target_os == "uefi"
         || target_os == "teeos"
         || target_os == "zkvm"
+        || target_os == "rtems"
 
         // See src/bootstrap/src/core/build_steps/synthetic_targets.rs
         || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 020a8b324f4..a2496baa63f 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -143,6 +143,8 @@ pub mod nto;
 pub mod openbsd;
 #[cfg(target_os = "redox")]
 pub mod redox;
+#[cfg(target_os = "rtems")]
+pub mod rtems;
 #[cfg(target_os = "solaris")]
 pub mod solaris;
 #[cfg(target_os = "solid_asp3")]
diff --git a/library/std/src/os/rtems/fs.rs b/library/std/src/os/rtems/fs.rs
new file mode 100644
index 00000000000..bec0d41e42d
--- /dev/null
+++ b/library/std/src/os/rtems/fs.rs
@@ -0,0 +1,374 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the device ID on which this file resides.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_dev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ino());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+
+    /// Returns the file type and mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mode());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+
+    /// Returns the number of hard links to file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_nlink());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+
+    /// Returns the user ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_uid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+
+    /// Returns the group ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_gid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+
+    /// Returns the device ID that this file represents. Only relevant for special file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_rdev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+
+    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+    ///
+    /// The size of a symbolic link is the length of the pathname it contains,
+    /// without a terminating null byte.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_size());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+
+    /// Returns the last access time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+
+    /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+    ///
+    /// [`st_atime`]: Self::st_atime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+
+    /// Returns the last modification time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+
+    /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+    ///
+    /// [`st_mtime`]: Self::st_mtime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+
+    /// Returns the last status change time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+
+    /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+    ///
+    /// [`st_ctime`]: Self::st_ctime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+
+    /// Returns the "preferred" block size for efficient filesystem I/O.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blksize());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+
+    /// Returns the number of blocks allocated to the file, 512-byte units.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::rtems::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blocks());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+
+    fn st_atime_nsec(&self) -> i64 {
+        0
+    }
+
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+
+    fn st_mtime_nsec(&self) -> i64 {
+        0
+    }
+
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+
+    fn st_ctime_nsec(&self) -> i64 {
+        0
+    }
+
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/library/std/src/os/rtems/mod.rs b/library/std/src/os/rtems/mod.rs
new file mode 100644
index 00000000000..7275bfd1765
--- /dev/null
+++ b/library/std/src/os/rtems/mod.rs
@@ -0,0 +1,4 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![forbid(unsafe_op_in_unsafe_fn)]
+pub mod fs;
+pub(crate) mod raw;
diff --git a/library/std/src/os/rtems/raw.rs b/library/std/src/os/rtems/raw.rs
new file mode 100644
index 00000000000..113079cf4ab
--- /dev/null
+++ b/library/std/src/os/rtems/raw.rs
@@ -0,0 +1,33 @@
+//! rtems raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+    since = "1.8.0",
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = libc::blkcnt_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = libc::blksize_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = libc::dev_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = libc::ino_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = libc::mode_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = libc::nlink_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = libc::off_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = libc::time_t;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index c6581b9c4c8..7d2f0bd4efe 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -73,6 +73,8 @@ mod platform {
     pub use crate::os::openbsd::*;
     #[cfg(target_os = "redox")]
     pub use crate::os::redox::*;
+    #[cfg(target_os = "rtems")]
+    pub use crate::os::rtems::*;
     #[cfg(target_os = "solaris")]
     pub use crate::os::solaris::*;
     #[cfg(target_os = "vita")]
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index 9a37e1a0346..a943e3a581a 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -112,6 +112,7 @@ impl DoubleEndedIterator for Args {
     target_os = "aix",
     target_os = "nto",
     target_os = "hurd",
+    target_os = "rtems",
 ))]
 mod imp {
     use crate::ffi::c_char;
diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs
index fb1f868644d..b2d399b8791 100644
--- a/library/std/src/sys/pal/unix/env.rs
+++ b/library/std/src/sys/pal/unix/env.rs
@@ -240,6 +240,17 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "";
 }
 
+#[cfg(target_os = "rtems")]
+pub mod os {
+    pub const FAMILY: &str = "unix";
+    pub const OS: &str = "rtems";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".so";
+    pub const DLL_EXTENSION: &str = "so";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
+
 #[cfg(target_os = "vxworks")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 7fa147c9754..4ec577a0a01 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -478,6 +478,7 @@ impl FileAttr {
         target_os = "horizon",
         target_os = "vita",
         target_os = "hurd",
+        target_os = "rtems",
     )))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -490,7 +491,12 @@ impl FileAttr {
         SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64)
     }
 
-    #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
+    #[cfg(any(
+        target_os = "vxworks",
+        target_os = "espidf",
+        target_os = "vita",
+        target_os = "rtems",
+    ))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_mtime as i64, 0)
     }
@@ -506,6 +512,7 @@ impl FileAttr {
         target_os = "horizon",
         target_os = "vita",
         target_os = "hurd",
+        target_os = "rtems",
     )))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -518,7 +525,12 @@ impl FileAttr {
         SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64)
     }
 
-    #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
+    #[cfg(any(
+        target_os = "vxworks",
+        target_os = "espidf",
+        target_os = "vita",
+        target_os = "rtems"
+    ))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_atime as i64, 0)
     }
@@ -853,6 +865,7 @@ impl Drop for Dir {
             target_os = "fuchsia",
             target_os = "horizon",
             target_os = "vxworks",
+            target_os = "rtems",
         )))]
         {
             let fd = unsafe { libc::dirfd(self.0) };
@@ -970,6 +983,7 @@ impl DirEntry {
         target_os = "aix",
         target_os = "nto",
         target_os = "hurd",
+        target_os = "rtems",
         target_vendor = "apple",
     ))]
     pub fn ino(&self) -> u64 {
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index ba2f58f9c10..e8428eccb16 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -79,6 +79,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             target_os = "l4re",
             target_os = "horizon",
             target_os = "vita",
+            target_os = "rtems",
             // The poll on Darwin doesn't set POLLNVAL for closed fds.
             target_vendor = "apple",
         )))]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index a785b97ac8d..503f8915256 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -31,7 +31,7 @@ cfg_if::cfg_if! {
 }
 
 extern "C" {
-    #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
+    #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
     #[cfg_attr(
         any(
             target_os = "linux",
@@ -61,13 +61,14 @@ extern "C" {
 }
 
 /// Returns the platform-specific value of errno
-#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
+#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
 pub fn errno() -> i32 {
     unsafe { (*errno_location()) as i32 }
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
+// needed for readdir and syscall!
+#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))]
 #[allow(dead_code)] // but not all target cfgs actually end up using it
 pub fn set_errno(e: i32) {
     unsafe { *errno_location() = e as c_int }
@@ -78,6 +79,16 @@ pub fn errno() -> i32 {
     unsafe { libc::errnoGet() }
 }
 
+#[cfg(target_os = "rtems")]
+pub fn errno() -> i32 {
+    extern "C" {
+        #[thread_local]
+        static _tls_errno: c_int;
+    }
+
+    unsafe { _tls_errno as i32 }
+}
+
 #[cfg(target_os = "dragonfly")]
 pub fn errno() -> i32 {
     extern "C" {
@@ -472,7 +483,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-#[cfg(target_os = "redox")]
+#[cfg(any(target_os = "redox", target_os = "rtems"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     crate::fs::read_to_string("sys:exe").map(PathBuf::from)
 }
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 9d091f033e0..4bb22f36709 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -1089,13 +1089,13 @@ fn signal_string(signal: i32) -> &'static str {
         libc::SIGURG => " (SIGURG)",
         #[cfg(not(target_os = "l4re"))]
         libc::SIGXCPU => " (SIGXCPU)",
-        #[cfg(not(target_os = "l4re"))]
+        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
         libc::SIGXFSZ => " (SIGXFSZ)",
-        #[cfg(not(target_os = "l4re"))]
+        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
         libc::SIGVTALRM => " (SIGVTALRM)",
         #[cfg(not(target_os = "l4re"))]
         libc::SIGPROF => " (SIGPROF)",
-        #[cfg(not(target_os = "l4re"))]
+        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
         libc::SIGWINCH => " (SIGWINCH)",
         #[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
         libc::SIGIO => " (SIGIO)",
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 1a6ea1dafcb..68085d026c4 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -31,7 +31,7 @@ cfg_if::cfg_if! {
         target_os = "psp",
         target_os = "xous",
         target_os = "solid_asp3",
-        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
+        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")),
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
         mod gcc;
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index bbd1db8dfa5..590de31a678 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -34,3 +34,10 @@ llvm-libunwind = []
 # If crt-static is enabled, static link to `libunwind.a` provided by system
 # If crt-static is disabled, dynamic link to `libunwind.so` provided by system
 system-llvm-libunwind = []
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    # #[cfg(bootstrap)] rtems
+    'cfg(target_os, values("rtems"))',
+]
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 250af912e07..26ed00bfbd5 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -22,6 +22,7 @@ cfg_if::cfg_if! {
         target_os = "l4re",
         target_os = "none",
         target_os = "espidf",
+        target_os = "rtems",
     ))] {
         // These "unix" family members do not have unwinder.
     } else if #[cfg(any(
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 8c52df78ab6..91fbc57429a 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -93,7 +93,6 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
     if !verify_rustfmt_version(build) {
         return Ok(None);
     }
-
     get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"])
 }
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 84a6b26a491..a8e12540473 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1810,6 +1810,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         if builder.config.rust_optimize_tests {
             cmd.arg("--optimize-tests");
         }
+        if builder.config.rust_randomize_layout {
+            cmd.arg("--rust-randomized-layout");
+        }
         if builder.config.cmd.only_modified() {
             cmd.arg("--only-modified");
         }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index d7398b76cc9..304fe8da2bf 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1618,6 +1618,15 @@ impl<'a> Builder<'a> {
             rustflags.arg("-Csymbol-mangling-version=legacy");
         }
 
+        // FIXME: the following components don't build with `-Zrandomize-layout` yet:
+        // - wasm-component-ld, due to the `wast`crate
+        // - rust-analyzer, due to the rowan crate
+        // so we exclude entire categories of steps here due to lack of fine-grained control over
+        // rustflags.
+        if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc {
+            rustflags.arg("-Zrandomize-layout");
+        }
+
         // Enable compile-time checking of `cfg` names, values and Cargo `features`.
         //
         // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
@@ -2193,6 +2202,9 @@ impl<'a> Builder<'a> {
                 rustflags.arg("-Zvalidate-mir");
                 rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}"));
             }
+            if self.config.rust_randomize_layout {
+                rustflags.arg("--cfg=randomized_layouts");
+            }
             // Always enable inlining MIR when building the standard library.
             // Without this flag, MIR inlining is disabled when incremental compilation is enabled.
             // That causes some mir-opt tests which inline functions from the standard library to
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index fba80b92f45..f7cc9ee7219 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -268,7 +268,6 @@ pub struct Config {
     pub rust_debuginfo_level_std: DebuginfoLevel,
     pub rust_debuginfo_level_tools: DebuginfoLevel,
     pub rust_debuginfo_level_tests: DebuginfoLevel,
-    pub rust_split_debuginfo_for_build_triple: Option<SplitDebuginfo>, // FIXME: Deprecated field. Remove in Q3'24.
     pub rust_rpath: bool,
     pub rust_strip: bool,
     pub rust_frame_pointers: bool,
@@ -280,6 +279,7 @@ pub struct Config {
     pub rust_codegen_backends: Vec<String>,
     pub rust_verify_llvm_ir: bool,
     pub rust_thin_lto_import_instr_limit: Option<u32>,
+    pub rust_randomize_layout: bool,
     pub rust_remap_debuginfo: bool,
     pub rust_new_symbol_mangling: Option<bool>,
     pub rust_profile_use: Option<String>,
@@ -1090,6 +1090,7 @@ define_config! {
         codegen_units: Option<u32> = "codegen-units",
         codegen_units_std: Option<u32> = "codegen-units-std",
         debug_assertions: Option<bool> = "debug-assertions",
+        randomize_layout: Option<bool> = "randomize-layout",
         debug_assertions_std: Option<bool> = "debug-assertions-std",
         overflow_checks: Option<bool> = "overflow-checks",
         overflow_checks_std: Option<bool> = "overflow-checks-std",
@@ -1099,7 +1100,6 @@ define_config! {
         debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
         debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
         debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
-        split_debuginfo: Option<String> = "split-debuginfo",
         backtrace: Option<bool> = "backtrace",
         incremental: Option<bool> = "incremental",
         parallel_compiler: Option<bool> = "parallel-compiler",
@@ -1181,6 +1181,7 @@ impl Config {
             backtrace: true,
             rust_optimize: RustOptimize::Bool(true),
             rust_optimize_tests: true,
+            rust_randomize_layout: false,
             submodules: None,
             docs: true,
             docs_minification: true,
@@ -1636,10 +1637,10 @@ impl Config {
                 debuginfo_level_std: debuginfo_level_std_toml,
                 debuginfo_level_tools: debuginfo_level_tools_toml,
                 debuginfo_level_tests: debuginfo_level_tests_toml,
-                split_debuginfo,
                 backtrace,
                 incremental,
                 parallel_compiler,
+                randomize_layout,
                 default_linker,
                 channel,
                 description,
@@ -1695,18 +1696,6 @@ impl Config {
             debuginfo_level_tests = debuginfo_level_tests_toml;
             lld_enabled = lld_enabled_toml;
 
-            config.rust_split_debuginfo_for_build_triple = split_debuginfo
-                .as_deref()
-                .map(SplitDebuginfo::from_str)
-                .map(|v| v.expect("invalid value for rust.split-debuginfo"));
-
-            if config.rust_split_debuginfo_for_build_triple.is_some() {
-                println!(
-                    "WARNING: specifying `rust.split-debuginfo` is deprecated, use `target.{}.split-debuginfo` instead",
-                    config.build
-                );
-            }
-
             optimize = optimize_toml;
             omit_git_hash = omit_git_hash_toml;
             config.rust_new_symbol_mangling = new_symbol_mangling;
@@ -1729,6 +1718,7 @@ impl Config {
             set(&mut config.lld_mode, lld_mode);
             set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
 
+            config.rust_randomize_layout = randomize_layout.unwrap_or_default();
             config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
             config.rustc_parallel =
                 parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
@@ -2504,9 +2494,6 @@ impl Config {
         self.target_config
             .get(&target)
             .and_then(|t| t.split_debuginfo)
-            .or_else(|| {
-                if self.build == target { self.rust_split_debuginfo_for_build_triple } else { None }
-            })
             .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target))
     }
 
@@ -2900,6 +2887,7 @@ fn check_incompatible_options_for_ci_rustc(
     let Rust {
         // Following options are the CI rustc incompatible ones.
         optimize,
+        randomize_layout,
         debug_logging,
         debuginfo_level_rustc,
         llvm_tools,
@@ -2927,7 +2915,6 @@ fn check_incompatible_options_for_ci_rustc(
         debuginfo_level_std: _,
         debuginfo_level_tools: _,
         debuginfo_level_tests: _,
-        split_debuginfo: _,
         backtrace: _,
         parallel_compiler: _,
         musl_root: _,
@@ -2964,6 +2951,7 @@ fn check_incompatible_options_for_ci_rustc(
     // otherwise, we just print a warning with `warn` macro.
 
     err!(current_rust_config.optimize, optimize);
+    err!(current_rust_config.randomize_layout, randomize_layout);
     err!(current_rust_config.debug_logging, debug_logging);
     err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc);
     err!(current_rust_config.rpath, rpath);
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 60ec57d0d44..dbc712adadf 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -13,6 +13,8 @@ use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
 use std::{env, fs};
 
+use build_helper::git::warn_old_master_branch;
+
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::builder::Builder;
 use crate::builder::Kind;
@@ -34,6 +36,7 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
+    "armv7-rtems-eabihf",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@@ -374,4 +377,14 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
     if let Some(ref s) = build.config.ccache {
         cmd_finder.must_have(s);
     }
+
+    // this warning is useless in CI,
+    // and CI probably won't have the right branches anyway.
+    if !build_helper::ci::CiEnv::is_ci() {
+        if let Err(e) = warn_old_master_branch(&build.config.git_config(), &build.config.src)
+            .map_err(|e| e.to_string())
+        {
+            eprintln!("unable to check if upstream branch is old: {e}");
+        }
+    }
 }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 82b640f5423..5751c398f30 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -678,6 +678,9 @@ impl Build {
         if self.config.rustc_parallel {
             features.push("rustc_use_parallel_compiler");
         }
+        if self.config.rust_randomize_layout {
+            features.push("rustc_randomized_layouts");
+        }
 
         // If debug logging is on, then we want the default for tracing:
         // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 3ab14aade9f..3fec2d953d9 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -240,4 +240,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "New option `build.cargo-clippy` added for supporting the use of custom/external clippy.",
     },
+    ChangeInfo {
+        change_id: 129925,
+        severity: ChangeSeverity::Warning,
+        summary: "Removed `rust.split-debuginfo` as it was deprecated long time ago.",
+    },
 ];
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index 275acb47c33..3acc2ceb135 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -50,6 +50,7 @@ ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
       --llvm-root=/usr/lib/llvm-17 \
       --enable-llvm-link-shared \
+      --set rust.randomize-layout=true \
       --set rust.thin-lto-import-instr-limit=10
 
 COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index 389abb2fdd3..8011e07e92e 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -4,8 +4,8 @@ set -euo pipefail
 
 LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee
 
-# Build rustc, rustdoc and cargo
-../x.py build --stage 1 library rustdoc
+# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
+../x.py build --stage 2 library rustdoc clippy rustfmt
 ../x.py build --stage 0 cargo
 
 # Install rustup so that we can use the built toolchain easily, and also
@@ -16,7 +16,7 @@ sh rustup.sh -y --default-toolchain none
 source /cargo/env
 
 BUILD_DIR=$(realpath ./build)
-rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage1
+rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage2
 rustup default local
 
 mkdir -p rfl
@@ -62,11 +62,47 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \
     defconfig \
     rfl-for-rust-ci.config
 
-make -C linux LLVM=1 -j$(($(nproc) + 1)) \
-    samples/rust/rust_minimal.o \
-    samples/rust/rust_print.o \
-    drivers/net/phy/ax88796b_rust.o \
+BUILD_TARGETS="
+    samples/rust/rust_minimal.o
+    samples/rust/rust_print.o
+    drivers/net/phy/ax88796b_rust.o
     rust/doctests_kernel_generated.o
+"
+
+# Build a few Rust targets
+#
+# This does not include building the C side of the kernel nor linking,
+# which can find other issues, but it is much faster.
+#
+# This includes transforming `rustdoc` tests into KUnit ones thanks to
+# `CONFIG_RUST_KERNEL_DOCTESTS=y` above (which, for the moment, uses the
+# unstable `--test-builder` and `--no-run`).
+make -C linux LLVM=1 -j$(($(nproc) + 1)) \
+    $BUILD_TARGETS
 
+# Generate documentation
 make -C linux LLVM=1 -j$(($(nproc) + 1)) \
     rustdoc
+
+# Build macro expanded source (`-Zunpretty=expanded`)
+#
+# This target also formats the macro expanded code, thus it is also
+# intended to catch ICEs with formatting `-Zunpretty=expanded` output
+# like https://github.com/rust-lang/rustfmt/issues/6105.
+make -C linux LLVM=1 -j$(($(nproc) + 1)) \
+    samples/rust/rust_minimal.rsi
+
+# Re-build with Clippy enabled
+#
+# This should not introduce Clippy errors, since `CONFIG_WERROR` is not
+# set (thus no `-Dwarnings`) and the kernel uses `-W` for all Clippy
+# lints, including `clippy::all`. However, it could catch ICEs.
+make -C linux LLVM=1 -j$(($(nproc) + 1)) CLIPPY=1 \
+    $BUILD_TARGETS
+
+# Format the code
+#
+# This returns successfully even if there were changes, i.e. it is not
+# a check.
+make -C linux LLVM=1 -j$(($(nproc) + 1)) \
+    rustfmt
diff --git a/src/doc/not_found.md b/src/doc/not_found.md
index f0794fc0be3..9552759d2b8 100644
--- a/src/doc/not_found.md
+++ b/src/doc/not_found.md
@@ -2,7 +2,7 @@
 
 <!-- Completely hide the TOC and the section numbers -->
 <style type="text/css">
-#TOC { display: none; }
+#rustdoc-toc { display: none; }
 .header-section-number { display: none; }
 li {list-style-type: none; }
 #search-input {
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index b3a74a7716b..3e199539694 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -40,6 +40,7 @@
       - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
       - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
+    - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index a2641b22753..319dc9a7c08 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -280,6 +280,7 @@ target | std | host | notes
 `armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
+[`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? |  | RTEMS OS for ARM BSPs
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ |  | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
diff --git a/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md
new file mode 100644
index 00000000000..2791c21ee45
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md
@@ -0,0 +1,52 @@
+# `armv7-rtems-eabihf`
+
+**Tier: 3**
+
+ARM targets for the [RTEMS realtime operating system](https://www.rtems.org)  using the RTEMS gcc cross-compiler for linking against the libraries of a specified Board Support Package (BSP).
+
+## Target maintainers
+
+- [@thesummer](https://github.com/thesummer)
+
+## Requirements
+
+The target does not support host tools. Only cross-compilation is possible.
+The cross-compiler toolchain can be obtained by following the installation instructions
+of the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html). Additionally to the cross-compiler also a compiled BSP
+for a board fitting the architecture needs to be available on the host.
+Currently tested has been the BSP `xilinx_zynq_a9_qemu` of RTEMS 6.
+
+`std` support is available, but not yet fully tested. Do NOT use in flight software!
+
+The target follows the EABI calling convention for `extern "C"`.
+
+The resulting binaries are in ELF format.
+
+## Building the target
+
+The target can be built by the standard compiler of Rust.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+In order to build an RTEMS executable it is also necessary to have a basic RTEMS configuration (in C) compiled to link against as this configures the operating system.
+An example can be found at this [`rtems-sys`](https://github.com/thesummer/rtems-sys) crate which could be added as an dependency to your application.
+
+## Testing
+
+The resulting binaries run fine on an emulated target (possibly also on a real Zedboard or similar).
+For example, on qemu the following command can execute the binary:
+```sh
+qemu-system-arm -no-reboot -serial null -serial mon:stdio -net none -nographic -M xilinx-zynq-a9 -m 512M -kernel <binary file>
+```
+
+While basic execution of the unit test harness seems to work. However, running the Rust testsuite on the (emulated) hardware has not yet been tested.
+
+## Cross-compilation toolchains and C code
+
+Compatible C-code can be built with the RTEMS cross-compiler toolchain `arm-rtems6-gcc`.
+For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html).
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 58fcfc4ed8d..5666b229078 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -512,9 +512,6 @@ impl Item {
     pub(crate) fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
     }
-    pub(crate) fn is_trait(&self) -> bool {
-        self.type_() == ItemType::Trait
-    }
     pub(crate) fn is_struct(&self) -> bool {
         self.type_() == ItemType::Struct
     }
@@ -542,9 +539,6 @@ impl Item {
     pub(crate) fn is_ty_method(&self) -> bool {
         self.type_() == ItemType::TyMethod
     }
-    pub(crate) fn is_type_alias(&self) -> bool {
-        self.type_() == ItemType::TypeAlias
-    }
     pub(crate) fn is_primitive(&self) -> bool {
         self.type_() == ItemType::Primitive
     }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index e37c24c1438..6f4665db6f1 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -51,12 +51,12 @@ use tracing::{debug, trace};
 use crate::clean::RenderedLink;
 use crate::doctest;
 use crate::doctest::GlobalTestOptions;
-use crate::html::escape::Escape;
+use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::length_limit::HtmlWithLimit;
 use crate::html::render::small_url_encode;
-use crate::html::toc::TocBuilder;
+use crate::html::toc::{Toc, TocBuilder};
 
 #[cfg(test)]
 mod tests;
@@ -102,6 +102,7 @@ pub struct Markdown<'a> {
 /// A struct like `Markdown` that renders the markdown with a table of contents.
 pub(crate) struct MarkdownWithToc<'a> {
     pub(crate) content: &'a str,
+    pub(crate) links: &'a [RenderedLink],
     pub(crate) ids: &'a mut IdMap,
     pub(crate) error_codes: ErrorCodes,
     pub(crate) edition: Edition,
@@ -533,9 +534,11 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
             let id = self.id_map.derive(id);
 
             if let Some(ref mut builder) = self.toc {
+                let mut text_header = String::new();
+                plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header);
                 let mut html_header = String::new();
-                html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
-                let sec = builder.push(level as u32, html_header, id.clone());
+                html_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut html_header);
+                let sec = builder.push(level as u32, text_header, html_header, id.clone());
                 self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0));
             }
 
@@ -1412,10 +1415,23 @@ impl Markdown<'_> {
 }
 
 impl MarkdownWithToc<'_> {
-    pub(crate) fn into_string(self) -> String {
-        let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
+    pub(crate) fn into_parts(self) -> (Toc, String) {
+        let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } =
+            self;
 
-        let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
+        // This is actually common enough to special-case
+        if md.is_empty() {
+            return (Toc { entries: Vec::new() }, String::new());
+        }
+        let mut replacer = |broken_link: BrokenLink<'_>| {
+            links
+                .iter()
+                .find(|link| &*link.original_text == &*broken_link.reference)
+                .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
+        };
+
+        let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
+        let p = p.into_offset_iter();
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
@@ -1429,7 +1445,11 @@ impl MarkdownWithToc<'_> {
             html::push_html(&mut s, p);
         }
 
-        format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
+        (toc.into_toc(), s)
+    }
+    pub(crate) fn into_string(self) -> String {
+        let (toc, s) = self.into_parts();
+        format!("<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
     }
 }
 
@@ -1608,7 +1628,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
 
     let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
 
-    for event in p {
+    plain_text_from_events(p, &mut s);
+
+    s
+}
+
+pub(crate) fn plain_text_from_events<'a>(
+    events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
+    s: &mut String,
+) {
+    for event in events {
         match &event {
             Event::Text(text) => s.push_str(text),
             Event::Code(code) => {
@@ -1623,8 +1652,29 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
             _ => (),
         }
     }
+}
 
-    s
+pub(crate) fn html_text_from_events<'a>(
+    events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
+    s: &mut String,
+) {
+    for event in events {
+        match &event {
+            Event::Text(text) => {
+                write!(s, "{}", EscapeBodyText(text)).expect("string alloc infallible")
+            }
+            Event::Code(code) => {
+                s.push_str("<code>");
+                write!(s, "{}", EscapeBodyText(code)).expect("string alloc infallible");
+                s.push_str("</code>");
+            }
+            Event::HardBreak | Event::SoftBreak => s.push(' '),
+            Event::Start(Tag::CodeBlock(..)) => break,
+            Event::End(TagEnd::Paragraph) => break,
+            Event::End(TagEnd::Heading(..)) => break,
+            _ => (),
+        }
+    }
 }
 
 #[derive(Debug)]
@@ -1975,7 +2025,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("default-settings".into(), 1);
     map.insert("sidebar-vars".into(), 1);
     map.insert("copy-path".into(), 1);
-    map.insert("TOC".into(), 1);
+    map.insert("rustdoc-toc".into(), 1);
+    map.insert("rustdoc-modnav".into(), 1);
     // This is the list of IDs used by rustdoc sections (but still generated by
     // rustdoc).
     map.insert("fields".into(), 1);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 19386fe5e69..9fe43e428f2 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -15,7 +15,7 @@ use rustc_span::{sym, FileName, Symbol};
 use tracing::info;
 
 use super::print_item::{full_path, item_path, print_item};
-use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar};
+use super::sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar};
 use super::write_shared::write_shared;
 use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath};
 use crate::clean::types::ExternalLocation;
@@ -617,12 +617,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let all = shared.all.replace(AllTypes::new());
         let mut sidebar = Buffer::html();
 
-        let blocks = sidebar_module_like(all.item_sections());
+        // all.html is not customizable, so a blank id map is fine
+        let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate);
         let bar = Sidebar {
             title_prefix: "",
             title: "",
             is_crate: false,
             is_mod: false,
+            parent_is_crate: false,
             blocks: vec![blocks],
             path: String::new(),
         };
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 5b9c93ef74a..c75c28ef0a3 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -13,7 +13,24 @@ use crate::clean;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::format::Buffer;
-use crate::html::markdown::IdMap;
+use crate::html::markdown::{IdMap, MarkdownWithToc};
+
+#[derive(Clone, Copy)]
+pub(crate) enum ModuleLike {
+    Module,
+    Crate,
+}
+
+impl ModuleLike {
+    pub(crate) fn is_crate(self) -> bool {
+        matches!(self, ModuleLike::Crate)
+    }
+}
+impl<'a> From<&'a clean::Item> for ModuleLike {
+    fn from(it: &'a clean::Item) -> ModuleLike {
+        if it.is_crate() { ModuleLike::Crate } else { ModuleLike::Module }
+    }
+}
 
 #[derive(Template)]
 #[template(path = "sidebar.html")]
@@ -21,6 +38,7 @@ pub(super) struct Sidebar<'a> {
     pub(super) title_prefix: &'static str,
     pub(super) title: &'a str,
     pub(super) is_crate: bool,
+    pub(super) parent_is_crate: bool,
     pub(super) is_mod: bool,
     pub(super) blocks: Vec<LinkBlock<'a>>,
     pub(super) path: String,
@@ -63,15 +81,19 @@ impl<'a> LinkBlock<'a> {
 /// A link to an item. Content should not be escaped.
 #[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
 pub(crate) struct Link<'a> {
-    /// The content for the anchor tag
+    /// The content for the anchor tag and title attr
     name: Cow<'a, str>,
+    /// The content for the anchor tag (if different from name)
+    name_html: Option<Cow<'a, str>>,
     /// The id of an anchor within the page (without a `#` prefix)
     href: Cow<'a, str>,
+    /// Nested list of links (used only in top-toc)
+    children: Vec<Link<'a>>,
 }
 
 impl<'a> Link<'a> {
     pub fn new(href: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self {
-        Self { href: href.into(), name: name.into() }
+        Self { href: href.into(), name: name.into(), children: vec![], name_html: None }
     }
     pub fn empty() -> Link<'static> {
         Link::new("", "")
@@ -95,17 +117,21 @@ pub(crate) mod filters {
 }
 
 pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
-    let blocks: Vec<LinkBlock<'_>> = match *it.kind {
-        clean::StructItem(ref s) => sidebar_struct(cx, it, s),
-        clean::TraitItem(ref t) => sidebar_trait(cx, it, t),
-        clean::PrimitiveItem(_) => sidebar_primitive(cx, it),
-        clean::UnionItem(ref u) => sidebar_union(cx, it, u),
-        clean::EnumItem(ref e) => sidebar_enum(cx, it, e),
-        clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t),
-        clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)],
-        clean::ForeignTypeItem => sidebar_foreign_type(cx, it),
-        _ => vec![],
-    };
+    let mut ids = IdMap::new();
+    let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
+    match *it.kind {
+        clean::StructItem(ref s) => sidebar_struct(cx, it, s, &mut blocks),
+        clean::TraitItem(ref t) => sidebar_trait(cx, it, t, &mut blocks),
+        clean::PrimitiveItem(_) => sidebar_primitive(cx, it, &mut blocks),
+        clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks),
+        clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks),
+        clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks),
+        clean::ModuleItem(ref m) => {
+            blocks.push(sidebar_module(&m.items, &mut ids, ModuleLike::from(it)))
+        }
+        clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks),
+        _ => {}
+    }
     // The sidebar is designed to display sibling functions, modules and
     // other miscellaneous information. since there are lots of sibling
     // items (and that causes quadratic growth in large modules),
@@ -113,15 +139,9 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
     // still, we don't move everything into JS because we want to preserve
     // as much HTML as possible in order to allow non-JS-enabled browsers
     // to navigate the documentation (though slightly inefficiently).
-    let (title_prefix, title) = if it.is_struct()
-        || it.is_trait()
-        || it.is_primitive()
-        || it.is_union()
-        || it.is_enum()
-        // crate title is displayed as part of logo lockup
-        || (it.is_mod() && !it.is_crate())
-        || it.is_type_alias()
-    {
+    //
+    // crate title is displayed as part of logo lockup
+    let (title_prefix, title) = if !blocks.is_empty() && !it.is_crate() {
         (
             match *it.kind {
                 clean::ModuleItem(..) => "Module ",
@@ -146,8 +166,15 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
     } else {
         "".into()
     };
-    let sidebar =
-        Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path };
+    let sidebar = Sidebar {
+        title_prefix,
+        title,
+        is_mod: it.is_mod(),
+        is_crate: it.is_crate(),
+        parent_is_crate: sidebar_path.len() == 1,
+        blocks,
+        path,
+    };
     sidebar.render_into(buffer).unwrap();
 }
 
@@ -163,30 +190,80 @@ fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec<Link<'a>> {
     fields
 }
 
+fn docblock_toc<'a>(
+    cx: &'a Context<'_>,
+    it: &'a clean::Item,
+    ids: &mut IdMap,
+) -> Option<LinkBlock<'a>> {
+    let (toc, _) = MarkdownWithToc {
+        content: &it.doc_value(),
+        links: &it.links(cx),
+        ids,
+        error_codes: cx.shared.codes,
+        edition: cx.shared.edition(),
+        playground: &cx.shared.playground,
+    }
+    .into_parts();
+    let links: Vec<Link<'_>> = toc
+        .entries
+        .into_iter()
+        .map(|entry| {
+            Link {
+                name_html: if entry.html == entry.name { None } else { Some(entry.html.into()) },
+                name: entry.name.into(),
+                href: entry.id.into(),
+                children: entry
+                    .children
+                    .entries
+                    .into_iter()
+                    .map(|entry| Link {
+                        name_html: if entry.html == entry.name {
+                            None
+                        } else {
+                            Some(entry.html.into())
+                        },
+                        name: entry.name.into(),
+                        href: entry.id.into(),
+                        // Only a single level of nesting is shown here.
+                        // Going the full six could break the layout,
+                        // so we have to cut it off somewhere.
+                        children: vec![],
+                    })
+                    .collect(),
+            }
+        })
+        .collect();
+    if links.is_empty() {
+        None
+    } else {
+        Some(LinkBlock::new(Link::new("", "Sections"), "top-toc", links))
+    }
+}
+
 fn sidebar_struct<'a>(
     cx: &'a Context<'_>,
     it: &'a clean::Item,
     s: &'a clean::Struct,
-) -> Vec<LinkBlock<'a>> {
+    items: &mut Vec<LinkBlock<'a>>,
+) {
     let fields = get_struct_fields_name(&s.fields);
     let field_name = match s.ctor_kind {
         Some(CtorKind::Fn) => Some("Tuple Fields"),
         None => Some("Fields"),
         _ => None,
     };
-    let mut items = vec![];
     if let Some(name) = field_name {
         items.push(LinkBlock::new(Link::new("fields", name), "structfield", fields));
     }
-    sidebar_assoc_items(cx, it, &mut items);
-    items
+    sidebar_assoc_items(cx, it, items);
 }
 
 fn sidebar_trait<'a>(
     cx: &'a Context<'_>,
     it: &'a clean::Item,
     t: &'a clean::Trait,
-) -> Vec<LinkBlock<'a>> {
+    blocks: &mut Vec<LinkBlock<'a>>,
+) {
     fn filter_items<'a>(
         items: &'a [clean::Item],
         filt: impl Fn(&clean::Item) -> bool,
@@ -223,19 +300,20 @@ fn sidebar_trait<'a>(
         foreign_impls.sort();
     }
 
-    let mut blocks: Vec<LinkBlock<'_>> = [
-        ("required-associated-types", "Required Associated Types", req_assoc),
-        ("provided-associated-types", "Provided Associated Types", prov_assoc),
-        ("required-associated-consts", "Required Associated Constants", req_assoc_const),
-        ("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
-        ("required-methods", "Required Methods", req_method),
-        ("provided-methods", "Provided Methods", prov_method),
-        ("foreign-impls", "Implementations on Foreign Types", foreign_impls),
-    ]
-    .into_iter()
-    .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items))
-    .collect();
-    sidebar_assoc_items(cx, it, &mut blocks);
+    blocks.extend(
+        [
+            ("required-associated-types", "Required Associated Types", req_assoc),
+            ("provided-associated-types", "Provided Associated Types", prov_assoc),
+            ("required-associated-consts", "Required Associated Constants", req_assoc_const),
+            ("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
+            ("required-methods", "Required Methods", req_method),
+            ("provided-methods", "Provided Methods", prov_method),
+            ("foreign-impls", "Implementations on Foreign Types", foreign_impls),
+        ]
+        .into_iter()
+        .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)),
+    );
+    sidebar_assoc_items(cx, it, blocks);
 
     if !t.is_object_safe(cx.tcx()) {
         blocks.push(LinkBlock::forced(
@@ -251,20 +329,17 @@ fn sidebar_trait<'a>(
             "impl-auto",
         ));
     }
-    blocks
 }
 
-fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> {
+fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item, items: &mut Vec<LinkBlock<'a>>) {
     if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
-        let mut items = vec![];
-        sidebar_assoc_items(cx, it, &mut items);
-        items
+        sidebar_assoc_items(cx, it, items);
     } else {
         let shared = Rc::clone(&cx.shared);
         let (concrete, synthetic, blanket_impl) =
             super::get_filtered_impls_for_reference(&shared, it);
 
-        sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl).into()
+        sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl, items);
     }
 }
 
@@ -272,8 +347,8 @@ fn sidebar_type_alias<'a>(
     cx: &'a Context<'_>,
     it: &'a clean::Item,
     t: &'a clean::TypeAlias,
-) -> Vec<LinkBlock<'a>> {
-    let mut items = vec![];
+    items: &mut Vec<LinkBlock<'a>>,
+) {
     if let Some(inner_type) = &t.inner_type {
         items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type"));
         match inner_type {
@@ -295,19 +370,18 @@ fn sidebar_type_alias<'a>(
             }
         }
     }
-    sidebar_assoc_items(cx, it, &mut items);
-    items
+    sidebar_assoc_items(cx, it, items);
 }
 
 fn sidebar_union<'a>(
     cx: &'a Context<'_>,
     it: &'a clean::Item,
     u: &'a clean::Union,
-) -> Vec<LinkBlock<'a>> {
+    items: &mut Vec<LinkBlock<'a>>,
+) {
     let fields = get_struct_fields_name(&u.fields);
-    let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)];
-    sidebar_assoc_items(cx, it, &mut items);
-    items
+    items.push(LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields));
+    sidebar_assoc_items(cx, it, items);
 }
 
 /// Adds trait implementations into the blocks of links
@@ -346,21 +420,22 @@ fn sidebar_assoc_items<'a>(
             methods.sort();
         }
 
-        let mut deref_methods = Vec::new();
-        let [concrete, synthetic, blanket] = if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
+        let mut blocks = vec![
+            LinkBlock::new(
+                Link::new("implementations", "Associated Constants"),
+                "associatedconstant",
+                assoc_consts,
+            ),
+            LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
+        ];
+
+        if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
             if let Some(impl_) =
                 v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
             {
                 let mut derefs = DefIdSet::default();
                 derefs.insert(did);
-                sidebar_deref_methods(
-                    cx,
-                    &mut deref_methods,
-                    impl_,
-                    v,
-                    &mut derefs,
-                    &mut used_links,
-                );
+                sidebar_deref_methods(cx, &mut blocks, impl_, v, &mut derefs, &mut used_links);
             }
 
             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
@@ -368,21 +443,15 @@ fn sidebar_assoc_items<'a>(
             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
                 concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
 
-            sidebar_render_assoc_items(cx, &mut id_map, concrete, synthetic, blanket_impl)
-        } else {
-            std::array::from_fn(|_| LinkBlock::new(Link::empty(), "", vec![]))
-        };
-
-        let mut blocks = vec![
-            LinkBlock::new(
-                Link::new("implementations", "Associated Constants"),
-                "associatedconstant",
-                assoc_consts,
-            ),
-            LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
-        ];
-        blocks.append(&mut deref_methods);
-        blocks.extend([concrete, synthetic, blanket]);
+            sidebar_render_assoc_items(
+                cx,
+                &mut id_map,
+                concrete,
+                synthetic,
+                blanket_impl,
+                &mut blocks,
+            );
+        }
         links.append(&mut blocks);
     }
 }
@@ -472,7 +541,8 @@ fn sidebar_enum<'a>(
     cx: &'a Context<'_>,
     it: &'a clean::Item,
     e: &'a clean::Enum,
-) -> Vec<LinkBlock<'a>> {
+    items: &mut Vec<LinkBlock<'a>>,
+) {
     let mut variants = e
         .variants()
         .filter_map(|v| v.name)
@@ -480,24 +550,37 @@ fn sidebar_enum<'a>(
         .collect::<Vec<_>>();
     variants.sort_unstable();
 
-    let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)];
-    sidebar_assoc_items(cx, it, &mut items);
-    items
+    items.push(LinkBlock::new(Link::new("variants", "Variants"), "variant", variants));
+    sidebar_assoc_items(cx, it, items);
 }
 
 pub(crate) fn sidebar_module_like(
     item_sections_in_use: FxHashSet<ItemSection>,
+    ids: &mut IdMap,
+    module_like: ModuleLike,
 ) -> LinkBlock<'static> {
-    let item_sections = ItemSection::ALL
+    let item_sections: Vec<Link<'_>> = ItemSection::ALL
         .iter()
         .copied()
         .filter(|sec| item_sections_in_use.contains(sec))
-        .map(|sec| Link::new(sec.id(), sec.name()))
+        .map(|sec| Link::new(ids.derive(sec.id()), sec.name()))
         .collect();
-    LinkBlock::new(Link::empty(), "", item_sections)
+    let header = if let Some(first_section) = item_sections.get(0) {
+        Link::new(
+            first_section.href.to_owned(),
+            if module_like.is_crate() { "Crate Items" } else { "Module Items" },
+        )
+    } else {
+        Link::empty()
+    };
+    LinkBlock::new(header, "", item_sections)
 }
 
-fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> {
+fn sidebar_module(
+    items: &[clean::Item],
+    ids: &mut IdMap,
+    module_like: ModuleLike,
+) -> LinkBlock<'static> {
     let item_sections_in_use: FxHashSet<_> = items
         .iter()
         .filter(|it| {
@@ -518,13 +601,15 @@ fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> {
         .map(|it| item_ty_to_section(it.type_()))
         .collect();
 
-    sidebar_module_like(item_sections_in_use)
+    sidebar_module_like(item_sections_in_use, ids, module_like)
 }
 
-fn sidebar_foreign_type<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> {
-    let mut items = vec![];
-    sidebar_assoc_items(cx, it, &mut items);
-    items
+fn sidebar_foreign_type<'a>(
+    cx: &'a Context<'_>,
+    it: &'a clean::Item,
+    items: &mut Vec<LinkBlock<'a>>,
+) {
+    sidebar_assoc_items(cx, it, items);
 }
 
 /// Renders the trait implementations for this type
@@ -534,7 +619,8 @@ fn sidebar_render_assoc_items(
     concrete: Vec<&Impl>,
     synthetic: Vec<&Impl>,
     blanket_impl: Vec<&Impl>,
-) -> [LinkBlock<'static>; 3] {
+    items: &mut Vec<LinkBlock<'_>>,
+) {
     let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
         let mut links = FxHashSet::default();
 
@@ -559,7 +645,7 @@ fn sidebar_render_assoc_items(
     let concrete = format_impls(concrete, id_map);
     let synthetic = format_impls(synthetic, id_map);
     let blanket = format_impls(blanket_impl, id_map);
-    [
+    items.extend([
         LinkBlock::new(
             Link::new("trait-implementations", "Trait Implementations"),
             "trait-implementation",
@@ -575,7 +661,7 @@ fn sidebar_render_assoc_items(
             "blanket-implementation",
             blanket,
         ),
-    ]
+    ]);
 }
 
 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 1e483062289..271de1b1ccf 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -568,12 +568,16 @@ img {
 	width: 48px;
 }
 
-ul.block, .block li {
+ul.block, .block li, .block ul {
 	padding: 0;
 	margin: 0;
 	list-style: none;
 }
 
+.block ul a {
+	padding-left: 1rem;
+}
+
 .sidebar-elems a,
 .sidebar > h2 a {
 	display: block;
@@ -585,6 +589,14 @@ ul.block, .block li {
 	background-clip: border-box;
 }
 
+.hide-toc #rustdoc-toc, .hide-toc .in-crate {
+	display: none;
+}
+
+.hide-modnav #rustdoc-modnav {
+	display: none;
+}
+
 .sidebar h2 {
 	text-wrap: balance;
 	overflow-wrap: anywhere;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index c3e219f2c87..0291b6ed6f5 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -499,7 +499,7 @@ function preLoadCss(cssUrl) {
         if (!window.SIDEBAR_ITEMS) {
             return;
         }
-        const sidebar = document.getElementsByClassName("sidebar-elems")[0];
+        const sidebar = document.getElementById("rustdoc-modnav");
 
         /**
          * Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
@@ -885,7 +885,7 @@ function preLoadCss(cssUrl) {
         if (!window.ALL_CRATES) {
             return;
         }
-        const sidebarElems = document.getElementsByClassName("sidebar-elems")[0];
+        const sidebarElems = document.getElementById("rustdoc-modnav");
         if (!sidebarElems) {
             return;
         }
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2b42fbebb80..c52a19ef987 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -36,6 +36,20 @@
                     removeClass(document.documentElement, "hide-sidebar");
                 }
                 break;
+            case "hide-toc":
+                if (value === true) {
+                    addClass(document.documentElement, "hide-toc");
+                } else {
+                    removeClass(document.documentElement, "hide-toc");
+                }
+                break;
+            case "hide-modnav":
+                if (value === true) {
+                    addClass(document.documentElement, "hide-modnav");
+                } else {
+                    removeClass(document.documentElement, "hide-modnav");
+                }
+                break;
         }
     }
 
@@ -102,6 +116,11 @@
         let output = "";
 
         for (const setting of settings) {
+            if (setting === "hr") {
+                output += "<hr>";
+                continue;
+            }
+
             const js_data_name = setting["js_name"];
             const setting_name = setting["name"];
 
@@ -199,6 +218,16 @@
                 "default": false,
             },
             {
+                "name": "Hide table of contents",
+                "js_name": "hide-toc",
+                "default": false,
+            },
+            {
+                "name": "Hide module navigation",
+                "js_name": "hide-modnav",
+                "default": false,
+            },
+            {
                 "name": "Disable keyboard shortcuts",
                 "js_name": "disable-shortcuts",
                 "default": false,
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 4a27ca92fff..d75fb7a7fb5 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -196,16 +196,21 @@ updateTheme();
 // This needs to be done here because this JS is render-blocking,
 // so that the sidebar doesn't "jump" after appearing on screen.
 // The user interaction to change this is set up in main.js.
+//
+// At this point in page load, `document.body` is not available yet.
+// Set a class on the `<html>` element instead.
 if (getSettingValue("source-sidebar-show") === "true") {
-    // At this point in page load, `document.body` is not available yet.
-    // Set a class on the `<html>` element instead.
     addClass(document.documentElement, "src-sidebar-expanded");
 }
 if (getSettingValue("hide-sidebar") === "true") {
-    // At this point in page load, `document.body` is not available yet.
-    // Set a class on the `<html>` element instead.
     addClass(document.documentElement, "hide-sidebar");
 }
+if (getSettingValue("hide-toc") === "true") {
+    addClass(document.documentElement, "hide-toc");
+}
+if (getSettingValue("hide-modnav") === "true") {
+    addClass(document.documentElement, "hide-modnav");
+}
 function updateSidebarWidth() {
     const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
     if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html
index 0990c2716b8..fccf65cbefc 100644
--- a/src/librustdoc/html/templates/sidebar.html
+++ b/src/librustdoc/html/templates/sidebar.html
@@ -1,8 +1,3 @@
-{% if !title.is_empty() %}
-    <h2 class="location"> {# #}
-        <a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
-    </h2>
-{% endif %}
 <div class="sidebar-elems">
     {% if is_crate %}
         <ul class="block"> {# #}
@@ -11,18 +6,46 @@
     {% endif %}
 
     {% if self.should_render_blocks() %}
-        <section>
+        <section id="rustdoc-toc">
+            {% if !title.is_empty() %}
+            <h2 class="location"> {# #}
+                <a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
+            </h2>
+            {% endif %}
             {% for block in blocks %}
                 {% if block.should_render() %}
                     {% if !block.heading.name.is_empty() %}
-                        <h3><a href="#{{block.heading.href|safe}}"> {# #}
-                            {{block.heading.name|wrapped|safe}} {# #}
-                        </a></h3> {# #}
+                        <h3> {# #}
+                            <a href="#{{block.heading.href|safe}}">{{block.heading.name|wrapped|safe}}</a> {# #}
+                        </h3>
                     {% endif %}
                     {% if !block.links.is_empty() %}
                         <ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}">
                             {% for link in block.links %}
-                                <li><a href="#{{link.href|safe}}">{{link.name}}</a></li>
+                                <li> {# #}
+                                    <a href="#{{link.href|safe}}" title="{{link.name}}">
+                                        {% match link.name_html %}
+                                            {% when Some with (html) %}
+                                                {{html|safe}}
+                                            {% else %}
+                                                {{link.name}}
+                                        {% endmatch %}
+                                    </a> {# #}
+                                    {% if !link.children.is_empty() %}
+                                        <ul>
+                                            {% for child in link.children %}
+                                                <li><a href="#{{child.href|safe}}" title="{{child.name}}">
+                                                    {% match child.name_html %}
+                                                        {% when Some with (html) %}
+                                                            {{html|safe}}
+                                                        {% else %}
+                                                            {{child.name}}
+                                                    {% endmatch %}
+                                                </a></li>
+                                            {% endfor %}
+                                        </ul>
+                                    {% endif %}
+                                </li>
                             {% endfor %}
                         </ul>
                     {% endif %}
@@ -30,7 +53,11 @@
             {% endfor %}
         </section>
     {% endif %}
+    <div id="rustdoc-modnav">
     {% if !path.is_empty() %}
-        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a></h2>
+        <h2{% if parent_is_crate +%} class="in-crate"{% endif %}> {# #}
+            <a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a> {# #}
+        </h2>
     {% endif %}
+    </div> {# #}
 </div>
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index a12c2a6a16c..7fdce41a634 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -1,4 +1,5 @@
 //! Table-of-contents creation.
+use crate::html::escape::Escape;
 
 /// A (recursive) table of contents
 #[derive(Debug, PartialEq)]
@@ -16,7 +17,7 @@ pub(crate) struct Toc {
     /// ### A
     /// ## B
     /// ```
-    entries: Vec<TocEntry>,
+    pub(crate) entries: Vec<TocEntry>,
 }
 
 impl Toc {
@@ -27,11 +28,16 @@ impl Toc {
 
 #[derive(Debug, PartialEq)]
 pub(crate) struct TocEntry {
-    level: u32,
-    sec_number: String,
-    name: String,
-    id: String,
-    children: Toc,
+    pub(crate) level: u32,
+    pub(crate) sec_number: String,
+    // name is a plain text header that works in a `title` tag
+    // html includes `<code>` tags
+    // the tooltip is used so that, when a toc is truncated,
+    // you can mouse over it to see the whole thing
+    pub(crate) name: String,
+    pub(crate) html: String,
+    pub(crate) id: String,
+    pub(crate) children: Toc,
 }
 
 /// Progressive construction of a table of contents.
@@ -115,7 +121,7 @@ impl TocBuilder {
     /// Push a level `level` heading into the appropriate place in the
     /// hierarchy, returning a string containing the section number in
     /// `<num>.<num>.<num>` format.
-    pub(crate) fn push(&mut self, level: u32, name: String, id: String) -> &str {
+    pub(crate) fn push(&mut self, level: u32, name: String, html: String, id: String) -> &str {
         assert!(level >= 1);
 
         // collapse all previous sections into their parents until we
@@ -149,6 +155,7 @@ impl TocBuilder {
         self.chain.push(TocEntry {
             level,
             name,
+            html,
             sec_number,
             id,
             children: Toc { entries: Vec::new() },
@@ -170,10 +177,11 @@ impl Toc {
             // recursively format this table of contents
             let _ = write!(
                 v,
-                "\n<li><a href=\"#{id}\">{num} {name}</a>",
+                "\n<li><a href=\"#{id}\" title=\"{name}\">{num} {html}</a>",
                 id = entry.id,
                 num = entry.sec_number,
-                name = entry.name
+                name = Escape(&entry.name),
+                html = &entry.html,
             );
             entry.children.print_inner(&mut *v);
             v.push_str("</li>");
diff --git a/src/librustdoc/html/toc/tests.rs b/src/librustdoc/html/toc/tests.rs
index 014f346862b..81aca737baf 100644
--- a/src/librustdoc/html/toc/tests.rs
+++ b/src/librustdoc/html/toc/tests.rs
@@ -9,7 +9,10 @@ fn builder_smoke() {
     // there's been no macro mistake.
     macro_rules! push {
         ($level: expr, $name: expr) => {
-            assert_eq!(builder.push($level, $name.to_string(), "".to_string()), $name);
+            assert_eq!(
+                builder.push($level, $name.to_string(), $name.to_string(), "".to_string()),
+                $name
+            );
         };
     }
     push!(2, "0.1");
@@ -48,6 +51,7 @@ fn builder_smoke() {
                         TocEntry {
                             level: $level,
                             name: $name.to_string(),
+                            html: $name.to_string(),
                             sec_number: $name.to_string(),
                             id: "".to_string(),
                             children: toc!($($sub),*)
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index a98f81d011e..581ebbbe58d 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -72,6 +72,7 @@ pub(crate) fn render<P: AsRef<Path>>(
     let text = if !options.markdown_no_toc {
         MarkdownWithToc {
             content: text,
+            links: &[],
             ids: &mut ids,
             error_codes,
             edition,
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index da84569c778..cc48a8964a3 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -159,3 +159,37 @@ pub fn get_git_untracked_files(
         .collect();
     Ok(Some(files))
 }
+
+/// Print a warning if the branch returned from `updated_master_branch` is old
+///
+/// For certain configurations of git repository, this remote will not be
+/// updated when running `git pull`.
+///
+/// This can result in formatting thousands of files instead of a dozen,
+/// so we should warn the user something is wrong.
+pub fn warn_old_master_branch(
+    config: &GitConfig<'_>,
+    git_dir: &Path,
+) -> Result<(), Box<dyn std::error::Error>> {
+    use std::time::Duration;
+    const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10);
+    let updated_master = updated_master_branch(config, Some(git_dir))?;
+    let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master);
+    match std::fs::metadata(branch_path) {
+        Ok(meta) => {
+            if meta.modified()?.elapsed()? > WARN_AFTER {
+                eprintln!("warning: {updated_master} has not been updated in 10 days");
+            } else {
+                return Ok(());
+            }
+        }
+        Err(err) => {
+            eprintln!("warning: unable to check if {updated_master} is old due to error: {err}")
+        }
+    }
+    eprintln!(
+        "warning: {updated_master} is used to determine if files have been modified\n\
+               warning: if it is not updated, this may cause files to be needlessly reformatted"
+    );
+    Ok(())
+}
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index a559d6f81a2..865aa76ddb0 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -136,6 +136,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "min-llvm-version",
     "min-system-llvm-version",
     "needs-asm-support",
+    "needs-deterministic-layouts",
     "needs-dlltool",
     "needs-dynamic-linking",
     "needs-force-clang-based-tests",
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 5831f7c3cf2..773d795f75a 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -274,6 +274,9 @@ pub struct Config {
     /// Flags to pass to the compiler when building for the target
     pub target_rustcflags: Vec<String>,
 
+    /// Whether the compiler and stdlib has been built with randomized struct layouts
+    pub rust_randomized_layout: bool,
+
     /// Whether tests should be optimized by default. Individual test-suites and test files may
     /// override this setting.
     pub optimize_tests: bool,
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 72b1b9c6d48..e903f60ceb3 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -135,6 +135,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without PIC relocation model",
         },
         Need {
+            name: "needs-deterministic-layouts",
+            condition: !config.rust_randomized_layout,
+            ignore_reason: "ignored when randomizing layouts",
+        },
+        Need {
             name: "needs-wasmtime",
             condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")),
             ignore_reason: "ignored when wasmtime runner is not available",
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 7018362af54..5402e69bc66 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -99,6 +99,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
         .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optflag(
+            "",
+            "rust-randomized-layout",
+            "set this when rustc/stdlib were compiled with randomized layouts",
+        )
         .optflag("", "optimize-tests", "run tests with optimizations enabled")
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
@@ -286,6 +291,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         host_rustcflags: matches.opt_strs("host-rustcflags"),
         target_rustcflags: matches.opt_strs("target-rustcflags"),
         optimize_tests: matches.opt_present("optimize-tests"),
+        rust_randomized_layout: matches.opt_present("rust-randomized-layout"),
         target,
         host: opt_str2(matches.opt_str("host")),
         cdb,
diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
index 6be13b155f4..dc2b9e4491b 100644
--- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
+++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
@@ -1,6 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
+#![feature(arbitrary_self_types_pointers, unsize, coerce_unsized, dispatch_from_dyn)]
 #![feature(rustc_attrs)]
 
 fn pin_box_dyn() {
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index b0c5eec1fe4..c8610e03939 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -129,6 +129,9 @@
 //@ revisions: armv7_linux_androideabi
 //@ [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi
 //@ [armv7_linux_androideabi] needs-llvm-components: arm
+//@ revisions: armv7_rtems_eabihf
+//@ [armv7_rtems_eabihf] compile-flags: --target armv7-rtems-eabihf
+//@ [armv7_rtems_eabihf] needs-llvm-components: arm
 //@ revisions: armv7_sony_vita_newlibeabihf
 //@ [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf
 //@ [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm
diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs
index e8164c5c380..8d1ce116d26 100644
--- a/tests/codegen/issues/issue-86106.rs
+++ b/tests/codegen/issues/issue-86106.rs
@@ -1,5 +1,6 @@
 //@ only-64bit llvm appears to use stores instead of memset on 32bit
 //@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+//@ needs-deterministic-layouts
 
 // The below two functions ensure that both `String::new()` and `"".to_string()`
 // produce the identical code.
diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs
index d5eadda4469..e62f1a953df 100644
--- a/tests/codegen/mem-replace-big-type.rs
+++ b/tests/codegen/mem-replace-big-type.rs
@@ -5,6 +5,7 @@
 
 //@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no
 //@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining
+//@ needs-deterministic-layouts
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs
index c960688b00c..eda807d3682 100644
--- a/tests/codegen/slice-iter-nonnull.rs
+++ b/tests/codegen/slice-iter-nonnull.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -O
+//@ needs-deterministic-layouts
 #![crate_type = "lib"]
 #![feature(exact_size_is_empty)]
 
diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs
index 31fcf035f11..fca1ed367e6 100644
--- a/tests/codegen/vecdeque-drain.rs
+++ b/tests/codegen/vecdeque-drain.rs
@@ -1,6 +1,7 @@
 // Check that draining at the front or back doesn't copy memory.
 
 //@ compile-flags: -O
+//@ needs-deterministic-layouts
 //@ ignore-debug: FIXME: checks for call detect scoped noalias metadata
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/building/receiver_ptr_mutability.rs b/tests/mir-opt/building/receiver_ptr_mutability.rs
index 4bb3b4cade5..1ddb8b71a5a 100644
--- a/tests/mir-opt/building/receiver_ptr_mutability.rs
+++ b/tests/mir-opt/building/receiver_ptr_mutability.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
 // EMIT_MIR receiver_ptr_mutability.main.built.after.mir
 
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 struct Test {}
 
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.rs b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.rs
index c92424f2983..08347f71b42 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.rs
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.rs
@@ -1,3 +1,4 @@
+//@needs-deterministic-layouts
 // Verify that we do not ICE when printing an invalid constant.
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
diff --git a/tests/rustdoc-gui/sidebar-modnav-position.goml b/tests/rustdoc-gui/sidebar-modnav-position.goml
new file mode 100644
index 00000000000..eb86d118ab2
--- /dev/null
+++ b/tests/rustdoc-gui/sidebar-modnav-position.goml
@@ -0,0 +1,44 @@
+// Verifies that, when TOC is hidden, modnav is always in exactly the same spot
+// This is driven by a reasonably common use case:
+//
+// - There are three or more items that might meet my needs.
+// - I open the first one, decide it's not what I want, switch to the second one using the sidebar.
+// - The second one also doesn't meet my needs, so I switch to the third.
+// - The third also doesn't meet my needs, so...
+//
+// because the sibling module nav is in exactly the same place every time,
+// it's very easy to find and switch between pages that way.
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+show-text: true
+set-local-storage: {"rustdoc-hide-toc": "true"}
+
+define-function: (
+    "check-positions",
+    [url],
+    block {
+        go-to: "file://" + |DOC_PATH| + |url|
+        // Checking results colors.
+        assert-position: ("#rustdoc-modnav > h2", {"x": |h2_x|, "y": |h2_y|})
+        assert-position: (
+            "#rustdoc-modnav > ul:first-of-type > li:first-of-type",
+            {"x": |x|, "y": |y|}
+        )
+    },
+)
+
+// First, at test_docs root
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
+store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
+call-function: ("check-positions", {"url": "/test_docs/enum.WhoLetTheDogOut.html"})
+call-function: ("check-positions", {"url": "/test_docs/struct.StructWithPublicUndocumentedFields.html"})
+call-function: ("check-positions", {"url": "/test_docs/codeblock_sub/index.html"})
+
+// Now in a submodule
+go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
+store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
+store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
+call-function: ("check-positions", {"url": "/test_docs/fields/struct.Struct.html"})
+call-function: ("check-positions", {"url": "/test_docs/fields/union.Union.html"})
+call-function: ("check-positions", {"url": "/test_docs/fields/enum.Enum.html"})
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index e499c159c6c..7794cdbe9e2 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -118,7 +118,7 @@ assert-false: ".sidebar-elems > .crate"
 go-to: "./module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
 assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
-assert-text: (".sidebar > .location", "Module module")
+assert-text: (".sidebar .location", "Module module")
 assert-count: (".sidebar .location", 1)
 assert-text: (".sidebar-elems ul.block > li.current > a", "module")
 // Module page requires three headings:
@@ -126,8 +126,8 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "module")
 //   - Module name, followed by TOC for module headings
 //   - "In crate [name]" parent pointer, followed by sibling navigation
 assert-count: (".sidebar h2", 3)
-assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2")
-assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In crate lib2")
+assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", {
     "href": "/lib2/index.html",
 }, ENDS_WITH)
 // We check that we don't have the crate list.
@@ -136,9 +136,9 @@ assert-false: ".sidebar-elems > .crate"
 go-to: "./sub_module/sub_sub_module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
 assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
-assert-text: (".sidebar > .location", "Module sub_sub_module")
-assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module")
-assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+assert-text: (".sidebar .location", "Module sub_sub_module")
+assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In lib2::module::sub_module")
+assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", {
     "href": "/module/sub_module/index.html",
 }, ENDS_WITH)
 assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module")
@@ -198,3 +198,36 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3})
 // when line-wrapped, see that it becomes flush-left again
 drag-and-drop: ((205, 100), (108, 100))
 assert-position: (".sidebar-crate > h2 > a", {"x": -3})
+
+// Configuration option to show TOC in sidebar.
+set-local-storage: {"rustdoc-hide-toc": "true"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+assert-css: ("#rustdoc-toc", {"display": "none"})
+assert-css: (".sidebar .in-crate", {"display": "none"})
+set-local-storage: {"rustdoc-hide-toc": "false"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+assert-css: ("#rustdoc-toc", {"display": "block"})
+assert-css: (".sidebar .in-crate", {"display": "block"})
+
+set-local-storage: {"rustdoc-hide-modnav": "true"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+assert-css: ("#rustdoc-modnav", {"display": "none"})
+set-local-storage: {"rustdoc-hide-modnav": "false"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
+assert-css: ("#rustdoc-modnav", {"display": "block"})
+
+set-local-storage: {"rustdoc-hide-toc": "true"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+assert-css: ("#rustdoc-toc", {"display": "none"})
+assert-false: ".sidebar .in-crate"
+set-local-storage: {"rustdoc-hide-toc": "false"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+assert-css: ("#rustdoc-toc", {"display": "block"})
+assert-false: ".sidebar .in-crate"
+
+set-local-storage: {"rustdoc-hide-modnav": "true"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+assert-css: ("#rustdoc-modnav", {"display": "none"})
+set-local-storage: {"rustdoc-hide-modnav": "false"}
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+assert-css: ("#rustdoc-modnav", {"display": "block"})
diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc/sidebar/module.rs
new file mode 100644
index 00000000000..b5bcb9f232c
--- /dev/null
+++ b/tests/rustdoc/sidebar/module.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+//@ has 'foo/index.html'
+//@ has - '//section[@id="rustdoc-toc"]/h3' 'Crate Items'
+
+//@ has 'foo/bar/index.html'
+//@ has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
+pub mod bar {
+    //@ has 'foo/bar/struct.Baz.html'
+    //@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
+    pub struct Baz;
+}
+
+//@ has 'foo/baz/index.html'
+//@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
+pub mod baz {}
diff --git a/tests/rustdoc/sidebar-all-page.rs b/tests/rustdoc/sidebar/sidebar-all-page.rs
index 1f97a414048..1f97a414048 100644
--- a/tests/rustdoc/sidebar-all-page.rs
+++ b/tests/rustdoc/sidebar/sidebar-all-page.rs
diff --git a/tests/rustdoc/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs
index f3812143a7d..f3812143a7d 100644
--- a/tests/rustdoc/sidebar-items.rs
+++ b/tests/rustdoc/sidebar/sidebar-items.rs
diff --git a/tests/rustdoc/sidebar-link-generation.rs b/tests/rustdoc/sidebar/sidebar-link-generation.rs
index ee868ec75d3..ee868ec75d3 100644
--- a/tests/rustdoc/sidebar-link-generation.rs
+++ b/tests/rustdoc/sidebar/sidebar-link-generation.rs
diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs
index 7c039eeb39f..7c039eeb39f 100644
--- a/tests/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs
diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs
new file mode 100644
index 00000000000..0f603960434
--- /dev/null
+++ b/tests/rustdoc/sidebar/top-toc-html.rs
@@ -0,0 +1,23 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+//! # Basic [link](https://example.com), *emphasis*, **_very emphasis_** and `code`
+//!
+//! This test case covers TOC entries with rich text inside.
+//! Rustdoc normally supports headers with links, but for the
+//! TOC, that would break the layout.
+//!
+//! For consistency, emphasis is also filtered out.
+
+//@ has foo/index.html
+// User header
+//@ has - '//section[@id="rustdoc-toc"]/h3' 'Sections'
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`'
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code'
+//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0
+//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0
+//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code'
diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs
new file mode 100644
index 00000000000..af07cb4179b
--- /dev/null
+++ b/tests/rustdoc/sidebar/top-toc-idmap.rs
@@ -0,0 +1,44 @@
+#![crate_name = "foo"]
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+//! # Structs
+//!
+//! This header has the same name as a built-in header,
+//! and we need to make sure they're disambiguated with
+//! suffixes.
+//!
+//! Module-like headers get derived from the internal ID map,
+//! so the *internal* one gets a suffix here. To make sure it
+//! works right, the one in the `top-toc` needs to match the one
+//! in the `top-doc`, and the one that's not in the `top-doc`
+//! needs to match the one that isn't in the `top-toc`.
+
+//@ has foo/index.html
+// User header
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs'
+//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs'
+// Built-in header
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs'
+//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs'
+
+/// # Fields
+/// ## Fields
+/// ### Fields
+///
+/// The difference between struct-like headers and module-like headers
+/// is strange, but not actually a problem as long as we're consistent.
+
+//@ has foo/struct.MyStruct.html
+// User header
+//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields'
+//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields'
+// Only one level of nesting
+//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]//a' 2
+// Built-in header
+//@ has - '//section[@id="rustdoc-toc"]/h3/a[@href="#fields"]' 'Fields'
+//@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields'
+
+pub struct MyStruct {
+    pub fields: i32,
+}
diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs
new file mode 100644
index 00000000000..d72d41abf88
--- /dev/null
+++ b/tests/rustdoc/sidebar/top-toc-nil.rs
@@ -0,0 +1,7 @@
+#![crate_name = "foo"]
+
+//! This test case covers missing top TOC entries.
+
+//@ has foo/index.html
+// User header
+//@ !has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]' 'Basic link and emphasis'
diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/strip-enum-variant.no-not-shown.html
index e072335297d..d7a36cc631a 100644
--- a/tests/rustdoc/strip-enum-variant.no-not-shown.html
+++ b/tests/rustdoc/strip-enum-variant.no-not-shown.html
@@ -1 +1 @@
-<ul class="block variant"><li><a href="#variant.Shown">Shown</a></li></ul>
\ No newline at end of file
+<ul class="block variant"><li><a href="#variant.Shown" title="Shown">Shown</a></li></ul>
\ No newline at end of file
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
index 96345de01c9..be2b89aab08 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
@@ -2,7 +2,7 @@
 //
 // issue: <https://github.com/rust-lang/rust/issues/120217>
 
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 trait Static<'a> {
     fn proof(self: *const Self, s: &'a str) -> &'static str;
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 0530e1c34c9..144a67025b3 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -210,7 +210,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -294,7 +294,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 30 warnings emitted
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs
new file mode 100644
index 00000000000..79ceb05662b
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs
@@ -0,0 +1,15 @@
+trait Foo {
+    fn foo(self: *const Self); //~ ERROR `*const Self` cannot be used as the type of `self`
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(self: *const Self) {} //~ ERROR `*const Bar` cannot be used as the type of `self`
+}
+
+impl Bar {
+    fn bar(self: *mut Self) {} //~ ERROR `*mut Bar` cannot be used as the type of `self`
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr
new file mode 100644
index 00000000000..3bb93cf2ea0
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr
@@ -0,0 +1,36 @@
+error[E0658]: `*const Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
+  --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:8:18
+   |
+LL |     fn foo(self: *const Self) {}
+   |                  ^^^^^^^^^^^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0658]: `*mut Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
+  --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:12:18
+   |
+LL |     fn bar(self: *mut Self) {}
+   |                  ^^^^^^^^^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
+  --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:2:18
+   |
+LL |     fn foo(self: *const Self);
+   |                  ^^^^^^^^^^^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
index 711025ff93b..856e0595331 100644
--- a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
+++ b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
@@ -1,33 +1,33 @@
-error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18
    |
 LL |     fn foo(self: *const Self) {}
    |                  ^^^^^^^^^^^
    |
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
-   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18
    |
 LL |     fn bar(self: *const Self) {}
    |                  ^^^^^^^^^^^
    |
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
-   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18
    |
 LL |     fn bar(self: *const Self);
    |                  ^^^^^^^^^^^
    |
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
-   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
diff --git a/tests/ui/inference/auxiliary/inference_unstable_iterator.rs b/tests/ui/inference/auxiliary/inference_unstable_iterator.rs
index 04bc0b1a8ac..8ba6fc89f16 100644
--- a/tests/ui/inference/auxiliary/inference_unstable_iterator.rs
+++ b/tests/ui/inference/auxiliary/inference_unstable_iterator.rs
@@ -1,5 +1,5 @@
 #![feature(staged_api)]
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 #![stable(feature = "ipu_iterator", since = "1.0.0")]
 
diff --git a/tests/ui/inference/auxiliary/inference_unstable_itertools.rs b/tests/ui/inference/auxiliary/inference_unstable_itertools.rs
index fa1efbcfefc..32ca3a45119 100644
--- a/tests/ui/inference/auxiliary/inference_unstable_itertools.rs
+++ b/tests/ui/inference/auxiliary/inference_unstable_itertools.rs
@@ -1,4 +1,4 @@
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 pub trait IpuItertools {
     fn ipu_flatten(&self) -> u32 {
diff --git a/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs b/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs
index 1f45d91847f..7f76ed7fd2a 100644
--- a/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs
+++ b/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 use std::rc::Rc;
 
diff --git a/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs b/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs
index 43f596659b9..6f34c9281b0 100644
--- a/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs
+++ b/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
 
 use std::ptr;
 
diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/hir-stats.rs
index 249413d80e8..7c5da8cf554 100644
--- a/tests/ui/stats/hir-stats.rs
+++ b/tests/ui/stats/hir-stats.rs
@@ -1,12 +1,15 @@
 //@ check-pass
 //@ compile-flags: -Zhir-stats
 //@ only-x86_64
+// layout randomization affects the hir stat output
+//@ needs-deterministic-layouts
 
 // Type layouts sometimes change. When that happens, until the next bootstrap
 // bump occurs, stage1 and stage2 will give different outputs for this test.
 // Add an `ignore-stage1` comment marker to work around that problem during
 // that time.
 
+
 // The aim here is to include at least one of every different type of top-level
 // AST/HIR node reported by `-Zhir-stats`.
 
diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs
index 9c933a9ef1c..5ca9c8678b7 100644
--- a/tests/ui/structs-enums/type-sizes.rs
+++ b/tests/ui/structs-enums/type-sizes.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+//@ needs-deterministic-layouts
 
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]