about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-24 06:02:43 +0000
committerbors <bors@rust-lang.org>2024-09-24 06:02:43 +0000
commit4cadeda932d5c261a9a0b1bbd25c4486e4e0a4c6 (patch)
tree661cc7d8f6423f0caa9628e648059f6dadab121f
parentf5cd2c5888011d4d80311e5b771c6da507d860dd (diff)
parent64aa4c6e2546b88de8dbb098158839b30dc04ac6 (diff)
downloadrust-4cadeda932d5c261a9a0b1bbd25c4486e4e0a4c6.tar.gz
rust-4cadeda932d5c261a9a0b1bbd25c4486e4e0a4c6.zip
Auto merge of #130768 - compiler-errors:rollup-8ncjy55, r=compiler-errors
Rollup of 7 pull requests

Successful merges:

 - #129545 (rustdoc: redesign toolbar and disclosure widgets)
 - #130618 (Skip query in get_parent_item when possible.)
 - #130727 (Check vtable projections for validity in miri)
 - #130750 (Add new Tier-3 target: `loongarch64-unknown-linux-ohos`)
 - #130758 (Revert "Add recursion limit to FFI safety lint")
 - #130759 (Update books)
 - #130762 (stabilize const_intrinsic_copy)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_const_eval/messages.ftl4
-rw-r--r--compiler/rustc_const_eval/src/errors.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs67
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs8
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/types.rs20
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs5
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs12
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs16
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs7
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_passes/src/reachable.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs5
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs24
-rw-r--r--library/core/src/intrinsics.rs8
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ptr/const_ptr.rs4
-rw-r--r--library/core/src/ptr/mod.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs8
-rw-r--r--library/core/src/ptr/non_null.rs8
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs2
-rw-r--r--library/std/src/lib.rs18
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/reference0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/openharmony.md8
-rw-r--r--src/librustdoc/html/sources.rs35
-rw-r--r--src/librustdoc/html/static/css/noscript.css5
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css259
-rw-r--r--src/librustdoc/html/static/js/main.js141
-rw-r--r--src/librustdoc/html/static/js/search.js12
-rw-r--r--src/librustdoc/html/static/js/settings.js19
-rw-r--r--src/librustdoc/html/static/js/storage.js29
-rw-r--r--src/librustdoc/html/templates/print_item.html29
-rw-r--r--src/librustdoc/html/templates/source.html13
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/tools/compiletest/src/runtest.rs2
-rw-r--r--src/tools/html-checker/main.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr4
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr4
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs18
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr15
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr4
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/crashes/130310.rs15
-rw-r--r--tests/rustdoc-gui/anchors.goml5
-rw-r--r--tests/rustdoc-gui/help-page.goml8
-rw-r--r--tests/rustdoc-gui/item-info.goml2
-rw-r--r--tests/rustdoc-gui/mobile.goml15
-rw-r--r--tests/rustdoc-gui/notable-trait.goml5
-rw-r--r--tests/rustdoc-gui/pocket-menu.goml3
-rw-r--r--tests/rustdoc-gui/scrape-examples-layout.goml8
-rw-r--r--tests/rustdoc-gui/search-filter.goml5
-rw-r--r--tests/rustdoc-gui/search-form-elements.goml40
-rw-r--r--tests/rustdoc-gui/search-result-display.goml15
-rw-r--r--tests/rustdoc-gui/search-result-go-to-first.goml3
-rw-r--r--tests/rustdoc-gui/settings-button.goml8
-rw-r--r--tests/rustdoc-gui/settings.goml2
-rw-r--r--tests/rustdoc-gui/shortcuts.goml10
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml2
-rw-r--r--tests/rustdoc-gui/sidebar.goml6
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml8
-rw-r--r--tests/rustdoc-gui/source-code-page.goml16
-rw-r--r--tests/rustdoc-gui/src/theme_css/custom-theme.css2
-rw-r--r--tests/rustdoc-gui/toggle-click-deadspace.goml3
-rw-r--r--tests/rustdoc-gui/toggle-docs-mobile.goml12
-rw-r--r--tests/rustdoc-gui/toggle-docs.goml12
-rw-r--r--tests/rustdoc-gui/type-declation-overflow.goml17
-rw-r--r--tests/rustdoc/empty-mod-private.rs9
-rw-r--r--tests/rustdoc/empty-mod-public.rs9
-rw-r--r--tests/rustdoc/html-no-source.rs8
-rw-r--r--tests/rustdoc/inline_cross/renamed-via-module.rs12
-rw-r--r--tests/rustdoc/keyword.rs1
-rw-r--r--tests/rustdoc/primitive-reference.rs1
-rw-r--r--tests/rustdoc/primitive-slice-auto-trait.rs3
-rw-r--r--tests/rustdoc/primitive-tuple-auto-trait.rs3
-rw-r--r--tests/rustdoc/primitive-unit-auto-trait.rs3
-rw-r--r--tests/rustdoc/source-version-separator.rs4
-rw-r--r--tests/rustdoc/titles.rs44
-rw-r--r--tests/rustdoc/version-separator-without-source.rs8
-rw-r--r--tests/ui/consts/const-eval/raw-pointer-ub.rs3
-rw-r--r--tests/ui/consts/const-eval/raw-pointer-ub.stderr10
-rw-r--r--tests/ui/lint/improper-types-stack-overflow-130310.rs20
-rw-r--r--tests/ui/lint/improper-types-stack-overflow-130310.stderr11
-rw-r--r--tests/ui/lint/lint-ctypes-non-recursion-limit.rs32
96 files changed, 794 insertions, 506 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 6ba6a64c544..ab78584332a 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -161,13 +161,13 @@ pub(crate) fn codegen_const_value<'tcx>(
                             fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
                         fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
                     }
-                    GlobalAlloc::VTable(ty, trait_ref) => {
+                    GlobalAlloc::VTable(ty, dyn_ty) => {
                         let data_id = data_id_for_vtable(
                             fx.tcx,
                             &mut fx.constants_cx,
                             fx.module,
                             ty,
-                            trait_ref,
+                            dyn_ty.principal(),
                         );
                         let local_data_id =
                             fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
@@ -456,8 +456,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 GlobalAlloc::Memory(target_alloc) => {
                     data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
                 }
-                GlobalAlloc::VTable(ty, trait_ref) => {
-                    data_id_for_vtable(tcx, cx, module, ty, trait_ref)
+                GlobalAlloc::VTable(ty, dyn_ty) => {
+                    data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal())
                 }
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index c7cf73f1992..726b126e727 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -224,10 +224,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                         value
                     }
                     GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
-                    GlobalAlloc::VTable(ty, trait_ref) => {
+                    GlobalAlloc::VTable(ty, dyn_ty) => {
                         let alloc = self
                             .tcx
-                            .global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
+                            .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
                             .unwrap_memory();
                         let init = const_alloc_to_gcc(self, alloc);
                         self.static_addr_of(init, alloc.inner().align, None)
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 508c2d1a820..6e37aead835 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -290,10 +290,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         self.get_fn_addr(instance.polymorphize(self.tcx)),
                         self.data_layout().instruction_address_space,
                     ),
-                    GlobalAlloc::VTable(ty, trait_ref) => {
+                    GlobalAlloc::VTable(ty, dyn_ty) => {
                         let alloc = self
                             .tcx
-                            .global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
+                            .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
                             .unwrap_memory();
                         let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
                         let value = self.static_addr_of(init, alloc.inner().align, None);
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 2dc9d57e3b5..73a9a1569f6 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -198,7 +198,7 @@ const_eval_invalid_vtable_pointer =
     using {$pointer} as vtable pointer but it does not point to a vtable
 
 const_eval_invalid_vtable_trait =
-    using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected
+    using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected
 
 const_eval_lazy_lock =
     consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
@@ -459,7 +459,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
 const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
 const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
 const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
-const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}`
+const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`
 const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
 const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
 const_eval_validation_null_box = {$front_matter}: encountered a null box
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c38d7f3d03c..c60bacb8506 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -522,12 +522,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
                 diag.arg("pointer", ptr);
             }
-            InvalidVTableTrait { expected_trait, vtable_trait } => {
-                diag.arg("expected_trait", expected_trait.to_string());
-                diag.arg(
-                    "vtable_trait",
-                    vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
-                );
+            InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => {
+                diag.arg("expected_dyn_type", expected_dyn_type.to_string());
+                diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
             }
             PointerUseAfterFree(alloc_id, msg) => {
                 diag.arg("alloc_id", alloc_id)
@@ -777,12 +774,9 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             DanglingPtrNoProvenance { pointer, .. } => {
                 err.arg("pointer", pointer);
             }
-            InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => {
-                err.arg("ref_trait", ref_trait.to_string());
-                err.arg(
-                    "vtable_trait",
-                    vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
-                );
+            InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
+                err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
+                err.arg("expected_dyn_type", expected_dyn_type.to_string());
             }
             NullPtr { .. }
             | ConstRefToMutable
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 198aa1bbd5b..70d074cfdc5 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -128,7 +128,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             CastKind::DynStar => {
                 if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() {
                     // Initial cast from sized to dyn trait
-                    let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
+                    let vtable = self.get_vtable_ptr(src.layout.ty, data)?;
                     let vtable = Scalar::from_maybe_pointer(vtable, self);
                     let data = self.read_immediate(src)?.to_scalar();
                     let _assert_pointer_like = data.to_pointer(self)?;
@@ -446,12 +446,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
 
                 // Get the destination trait vtable and return that.
-                let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
+                let new_vptr = self.get_vtable_ptr(ty, data_b)?;
                 self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
             }
             (_, &ty::Dynamic(data, _, ty::Dyn)) => {
                 // Initial cast from sized to dyn trait
-                let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
+                let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
                 let ptr = self.read_pointer(src)?;
                 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
                 self.write_immediate(val, dest)
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index e5fdf592ec9..c3b506d848c 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -943,12 +943,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if offset.bytes() != 0 {
             throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
         }
-        let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
+        let Some(GlobalAlloc::VTable(ty, vtable_dyn_type)) =
+            self.tcx.try_get_global_alloc(alloc_id)
         else {
             throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
         };
-        if let Some(expected_trait) = expected_trait {
-            self.check_vtable_for_type(vtable_trait, expected_trait)?;
+        if let Some(expected_dyn_type) = expected_trait {
+            self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?;
         }
         Ok(ty)
     }
@@ -1113,11 +1114,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
                         Some(GlobalAlloc::Function { instance, .. }) => {
                             write!(fmt, " (fn: {instance})")?;
                         }
-                        Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
-                            write!(fmt, " (vtable: impl {trait_ref} for {ty})")?;
-                        }
-                        Some(GlobalAlloc::VTable(ty, None)) => {
-                            write!(fmt, " (vtable: impl <auto trait> for {ty})")?;
+                        Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
+                            write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?;
                         }
                         Some(GlobalAlloc::Static(did)) => {
                             write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index b5eef0fd8c9..8eead6018ac 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::interpret::{InterpResult, Pointer};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Ty, TyCtxt, VtblEntry};
+use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
 use rustc_target::abi::{Align, Size};
 use tracing::trace;
 
@@ -11,26 +11,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
     /// objects.
     ///
-    /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo<Trait>`
-    /// from a value of type `Foo<T>`, then `trait_ref` would map `T: Trait`. `None` here means that
-    /// this is an auto trait without any methods, so we only need the basic vtable (drop, size,
-    /// align).
+    /// The `dyn_ty` encodes the erased self type. Hence, if we are making an object
+    /// `Foo<dyn Trait<Assoc = A> + Send>` from a value of type `Foo<T>`, then `dyn_ty`
+    /// would be `Trait<Assoc = A> + Send`. If this list doesn't have a principal trait ref,
+    /// we only need the basic vtable prefix (drop, size, align).
     pub fn get_vtable_ptr(
         &self,
         ty: Ty<'tcx>,
-        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        dyn_ty: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
-        trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
+        trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");
 
-        let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
+        let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty));
 
         // All vtables must be monomorphic, bail out otherwise.
         ensure_monomorphic_enough(*self.tcx, ty)?;
-        ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
+        ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
 
         let salt = M::get_global_alloc_salt(self, None);
-        let vtable_symbolic_allocation =
-            self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref, salt);
+        let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
         let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
         Ok(vtable_ptr.into())
     }
@@ -64,17 +63,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// expected trait type.
     pub(super) fn check_vtable_for_type(
         &self,
-        vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
-        expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     ) -> InterpResult<'tcx> {
-        let eq = match (expected_trait.principal(), vtable_trait) {
-            (Some(a), Some(b)) => self.eq_in_param_env(a, b),
-            (None, None) => true,
-            _ => false,
-        };
-        if !eq {
-            throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
+        // We check validity by comparing the lists of predicates for equality. We *could* instead
+        // check that the dynamic type to which the vtable belongs satisfies all the expected
+        // predicates, but that would likely be a lot slower and seems unnecessarily permissive.
+
+        // FIXME: we are skipping auto traits for now, but might revisit this in the future.
+        let mut sorted_vtable: Vec<_> = vtable_dyn_type.without_auto_traits().collect();
+        let mut sorted_expected: Vec<_> = expected_dyn_type.without_auto_traits().collect();
+        // `skip_binder` here is okay because `stable_cmp` doesn't look at binders
+        sorted_vtable.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
+        sorted_vtable.dedup();
+        sorted_expected.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
+        sorted_expected.dedup();
+
+        if sorted_vtable.len() != sorted_expected.len() {
+            throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
+        }
+
+        for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) {
+            let is_eq = match (a_pred.skip_binder(), b_pred.skip_binder()) {
+                (
+                    ty::ExistentialPredicate::Trait(a_data),
+                    ty::ExistentialPredicate::Trait(b_data),
+                ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)),
+
+                (
+                    ty::ExistentialPredicate::Projection(a_data),
+                    ty::ExistentialPredicate::Projection(b_data),
+                ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)),
+
+                _ => false,
+            };
+            if !is_eq {
+                throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
+            }
         }
+
         Ok(())
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index ff3c6120f0c..203cceccd9d 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -452,8 +452,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     self.path,
                     Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) =>
                         InvalidVTablePtr { value: format!("{vtable}") },
-                    Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
-                        InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
+                    Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => {
+                        InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type }
                     },
                 );
             }
@@ -1281,8 +1281,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                     self.path,
                     // It's not great to catch errors here, since we can't give a very good path,
                     // but it's better than ICEing.
-                    Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
-                        InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
+                    Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => {
+                        InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type }
                     },
                 );
             }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index edfc7e547e5..375cfccbe9f 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -395,8 +395,6 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent
 lint_improper_ctypes_pat_help = consider using the base type instead
 
 lint_improper_ctypes_pat_reason = pattern types have no C equivalent
-
-lint_improper_ctypes_recursion_limit_reached = type is infinitely recursive
 lint_improper_ctypes_slice_help = consider using a raw pointer instead
 
 lint_improper_ctypes_slice_reason = slices have no C equivalent
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index f5a24f9808d..15fe18adbfb 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -592,8 +592,6 @@ struct CTypesVisitorState<'tcx> {
     /// The original type being checked, before we recursed
     /// to any other types it contains.
     base_ty: Ty<'tcx>,
-    /// Number of times we recursed while checking the type
-    recursion_depth: usize,
 }
 
 enum FfiResult<'tcx> {
@@ -899,23 +897,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
         // Protect against infinite recursion, for example
         // `struct S(*mut S);`.
+        // FIXME: A recursion limit is necessary as well, for irregular
+        // recursive types.
         if !acc.cache.insert(ty) {
             return FfiSafe;
         }
 
-        // Additional recursion check for more complex types like
-        // `struct A<T> { v: *const A<A<T>>, ... }` for which the
-        // cache check above won't be enough (fixes #130310)
-        if !tcx.recursion_limit().value_within_limit(acc.recursion_depth) {
-            return FfiUnsafe {
-                ty: acc.base_ty,
-                reason: fluent::lint_improper_ctypes_recursion_limit_reached,
-                help: None,
-            };
-        }
-
-        acc.recursion_depth += 1;
-
         match *ty.kind() {
             ty::Adt(def, args) => {
                 if let Some(boxed) = ty.boxed_ty()
@@ -1261,8 +1248,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             return;
         }
 
-        let mut acc =
-            CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty, recursion_depth: 0 };
+        let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
         match self.check_type_for_ffi(&mut acc, ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 167b5aef68b..e11361a615f 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -598,7 +598,10 @@ impl<'hir> Map<'hir> {
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
     pub fn get_parent_item(self, hir_id: HirId) -> OwnerId {
-        if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
+        if hir_id.local_id != ItemLocalId::ZERO {
+            // If this is a child of a HIR owner, return the owner.
+            hir_id.owner
+        } else if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
             def_id
         } else {
             CRATE_OWNER_ID
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 89507f1049a..46646e759d5 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -365,8 +365,10 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     InvalidVTablePointer(Pointer<AllocId>),
     /// Using a vtable for the wrong trait.
     InvalidVTableTrait {
-        expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-        vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        /// The vtable that was actually referenced by the wide pointer metadata.
+        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        /// The vtable that was expected at the point in MIR that it was accessed.
+        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     },
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
@@ -479,8 +481,10 @@ pub enum ValidationErrorKind<'tcx> {
         value: String,
     },
     InvalidMetaWrongTrait {
-        expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-        vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        /// The vtable that was actually referenced by the wide pointer metadata.
+        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        /// The vtable that was expected at the point in MIR that it was accessed.
+        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     },
     InvalidMetaSliceTooLarge {
         ptr_kind: PointerKind,
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 3af8f0db3f7..d7809cc4343 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -232,9 +232,8 @@ impl<'s> AllocDecodingSession<'s> {
             }
             AllocDiscriminant::VTable => {
                 trace!("creating vtable alloc ID");
-                let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
-                let poly_trait_ref =
-                    <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
+                let ty = Decodable::decode(decoder);
+                let poly_trait_ref = Decodable::decode(decoder);
                 trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
                 decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT)
             }
@@ -259,7 +258,10 @@ pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
     Function { instance: Instance<'tcx> },
     /// This alloc ID points to a symbolic (not-reified) vtable.
-    VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+    /// We remember the full dyn type, not just the principal trait, so that
+    /// const-eval and Miri can detect UB due to invalid transmutes of
+    /// `dyn Trait` types.
+    VTable(Ty<'tcx>, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>),
     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
     /// This is also used to break the cycle in recursive statics.
     Static(DefId),
@@ -293,7 +295,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
     #[inline]
     pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
         match *self {
-            GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
+            GlobalAlloc::VTable(ty, dyn_ty) => (ty, dyn_ty.principal()),
             _ => bug!("expected vtable, got {:?}", self),
         }
     }
@@ -398,10 +400,10 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn reserve_and_set_vtable_alloc(
         self,
         ty: Ty<'tcx>,
-        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        dyn_ty: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         salt: usize,
     ) -> AllocId {
-        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref), salt)
+        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt)
     }
 
     /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 612055eb879..119aed1106d 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1536,11 +1536,8 @@ pub fn write_allocations<'tcx>(
             // gracefully handle it and allow buggy rustc to be debugged via allocation printing.
             None => write!(w, " (deallocated)")?,
             Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?,
-            Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
-                write!(w, " (vtable: impl {trait_ref} for {ty})")?
-            }
-            Some(GlobalAlloc::VTable(ty, None)) => {
-                write!(w, " (vtable: impl <auto trait> for {ty})")?
+            Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
+                write!(w, " (vtable: impl {dyn_ty} for {ty})")?
             }
             Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
                 match tcx.eval_static_initializer(did) {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 0cdd237dc00..8d137b8d8f9 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1175,8 +1175,8 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
                 output.push(create_fn_mono_item(tcx, instance, DUMMY_SP));
             }
         }
-        GlobalAlloc::VTable(ty, trait_ref) => {
-            let alloc_id = tcx.vtable_allocation((ty, trait_ref));
+        GlobalAlloc::VTable(ty, dyn_ty) => {
+            let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal()));
             collect_alloc(tcx, alloc_id, output)
         }
     }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index d3e852b6b8f..925ee262022 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -318,10 +318,10 @@ impl<'tcx> ReachableContext<'tcx> {
                     ));
                     self.visit(instance.args);
                 }
-                GlobalAlloc::VTable(ty, trait_ref) => {
+                GlobalAlloc::VTable(ty, dyn_ty) => {
                     self.visit(ty);
                     // Manually visit to actually see the trait's `DefId`. Type visitors won't see it
-                    if let Some(trait_ref) = trait_ref {
+                    if let Some(trait_ref) = dyn_ty.principal() {
                         let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
                         self.visit_def_id(def_id, "", &"");
                         self.visit(args);
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index d228bbf51c2..f4c7fd7c900 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -712,8 +712,9 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
             mir::interpret::GlobalAlloc::Function { instance, .. } => {
                 GlobalAlloc::Function(instance.stable(tables))
             }
-            mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => {
-                GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables))
+            mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => {
+                // FIXME: Should we record the whole vtable?
+                GlobalAlloc::VTable(ty.stable(tables), dyn_ty.principal().stable(tables))
             }
             mir::interpret::GlobalAlloc::Static(def) => {
                 GlobalAlloc::Static(tables.static_def(*def))
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index fbf1c8d6010..3f0b23a595c 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1882,6 +1882,7 @@ supported_targets! {
 
     ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
     ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
+    ("loongarch64-unknown-linux-ohos", loongarch64_unknown_linux_ohos),
     ("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
 
     ("x86_64-unknown-linux-none", x86_64_unknown_linux_none),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs
new file mode 100644
index 00000000000..f9f7098684e
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs
@@ -0,0 +1,24 @@
+use crate::spec::{Target, TargetOptions, base};
+
+pub(crate) fn target() -> Target {
+    Target {
+        // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
+        llvm_target: "loongarch64-unknown-linux-musl".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("LoongArch64 OpenHarmony".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
+        arch: "loongarch64".into(),
+        options: TargetOptions {
+            cpu: "generic".into(),
+            features: "+f,+d".into(),
+            llvm_abiname: "lp64d".into(),
+            max_atomic_width: Some(64),
+            ..base::linux_ohos::opts()
+        },
+    }
+}
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 3b2a6e820c6..881a89f4d10 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -3286,13 +3286,13 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
 #[doc(alias = "memcpy")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules]
-#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
 #[inline(always)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_nounwind]
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
@@ -3388,13 +3388,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
 #[doc(alias = "memmove")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules]
-#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
 #[inline(always)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_copy"]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_nounwind]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index d9b03c97072..4c620bef6b3 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -128,7 +128,6 @@
 #![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_index_range_slice_index)]
-#![feature(const_intrinsic_copy)]
 #![feature(const_intrinsic_forget)]
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 3b45d46b31d..1146ca6ef43 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1192,7 +1192,7 @@ impl<T: ?Sized> *const T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1212,7 +1212,7 @@ impl<T: ?Sized> *const T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index d4b505c6ae3..cac33a329b9 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1516,11 +1516,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
-#[rustc_allow_const_fn_unstable(
-    const_mut_refs,
-    const_maybe_uninit_as_mut_ptr,
-    const_intrinsic_copy
-)]
+#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_read_unaligned"]
 pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5fa3b9bf61f..8e33cf081ba 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1269,7 +1269,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1289,7 +1289,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1309,7 +1309,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1329,7 +1329,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 673acc2972f..daa40b3c9d2 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -924,7 +924,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize)
     where
         T: Sized,
@@ -944,7 +944,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize)
     where
         T: Sized,
@@ -964,7 +964,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize)
     where
         T: Sized,
@@ -984,7 +984,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize)
     where
         T: Sized,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 5315ac856f6..604c0d48743 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -21,7 +21,6 @@
 #![feature(const_cell_into_inner)]
 #![feature(const_hash)]
 #![feature(const_heap)]
-#![feature(const_intrinsic_copy)]
 #![feature(const_ip)]
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index 331b6626249..cc6246b4a0d 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -1,8 +1,6 @@
 #![no_std]
 #![feature(
-    const_intrinsic_copy,
     const_refs_to_cell,
-    const_maybe_uninit_as_mut_ptr,
     const_mut_refs,
     convert_float_to_int,
     core_intrinsics,
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index e6b2f15a7a6..4d93af6ea65 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -32,13 +32,17 @@
 //!
 //! Once you are familiar with the contents of the standard library you may
 //! begin to find the verbosity of the prose distracting. At this stage in your
-//! development you may want to press the `[-]` button near the top of the
-//! page to collapse it into a more skimmable view.
-//!
-//! While you are looking at that `[-]` button also notice the `source`
-//! link. Rust's API documentation comes with the source code and you are
-//! encouraged to read it. The standard library source is generally high
-//! quality and a peek behind the curtains is often enlightening.
+//! development you may want to press the <code>
+//! <svg style="width:0.75rem;height:0.75rem" viewBox="0 0 12 12"
+//! stroke="currentColor" fill="none">
+//! <path d="M2,2l4,4l4,-4M2,6l4,4l4,-4"/></svg> Summary</code> button near the
+//! top of the page to collapse it into a more skimmable view.
+//!
+//! While you are looking at the top of the page, also notice the
+//! <code>source</code> link. Rust's API documentation comes with the source
+//! code and you are encouraged to read it. The standard library source is
+//! generally high quality and a peek behind the curtains is
+//! often enlightening.
 //!
 //! # What is in the standard library documentation?
 //!
diff --git a/src/doc/book b/src/doc/book
-Subproject e7d217be2a75ef1753f0988d6ccaba4d7e37625
+Subproject 99cf75a5414fa8adbe3974bd0836661ca901708
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject b3ca7ade0f87d7e3fb538776defc5b2cc418817
+Subproject c7ebae25cb4801a31b6f05353f6d85bfa6feedd
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 687faf9958c52116d003b41dfd29cc1cf44f531
+Subproject 24fb2687cdbc54fa18ae4acf5d879cfceca77b2
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 0ed9229f5b6f7824b333beabd7e3d5ba4b9bd97
+Subproject 555f3de2fa0d61c4294b74d245f1cbad6fcbf58
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 3728d1f5160..999eb9b8a7c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -313,6 +313,7 @@ target | std | host | notes
 `i686-uwp-windows-msvc` | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
 [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | [^x86_32-floats-return-ABI]
+[`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |   | LoongArch64 OpenHarmony
 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? |  | Motorola 680x0 Linux
 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
 `mips-unknown-linux-musl` | ✓ |  | MIPS Linux with musl 1.2.3
diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md
index b2ddbfdfa29..1632f44aeec 100644
--- a/src/doc/rustc/src/platform-support/openharmony.md
+++ b/src/doc/rustc/src/platform-support/openharmony.md
@@ -2,6 +2,14 @@
 
 **Tier: 2**
 
+* aarch64-unknown-linux-ohos
+* armv7-unknown-linux-ohos
+* x86_64-unknown-linux-ohos
+
+**Tier: 3**
+
+* loongarch64-unknown-linux-ohos
+
 Targets for the [OpenHarmony](https://gitee.com/openharmony/docs/) operating
 system.
 
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index c8c45b8fa32..9ba0fb7b83c 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -26,8 +26,11 @@ pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), E
 
     let dst = cx.dst.join("src").join(krate.name(cx.tcx()).as_str());
     cx.shared.ensure_dir(&dst)?;
+    let crate_name = krate.name(cx.tcx());
+    let crate_name = crate_name.as_str();
 
-    let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
+    let mut collector =
+        SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default(), crate_name };
     collector.visit_crate(krate);
     Ok(())
 }
@@ -115,6 +118,8 @@ struct SourceCollector<'a, 'tcx> {
     /// Root destination to place all HTML output into
     dst: PathBuf,
     emitted_local_sources: FxHashSet<PathBuf>,
+
+    crate_name: &'a str,
 }
 
 impl DocVisitor for SourceCollector<'_, '_> {
@@ -210,6 +215,9 @@ impl SourceCollector<'_, '_> {
             },
         );
 
+        let src_fname = p.file_name().expect("source has no filename").to_os_string();
+        let mut fname = src_fname.clone();
+
         let root_path = PathBuf::from("../../").join(root_path.into_inner());
         let mut root_path = root_path.to_string_lossy();
         if let Some(c) = root_path.as_bytes().last()
@@ -217,12 +225,12 @@ impl SourceCollector<'_, '_> {
         {
             root_path += "/";
         }
+        let mut file_path = Path::new(&self.crate_name).join(&*cur.borrow());
+        file_path.push(&fname);
+        fname.push(".html");
         let mut cur = self.dst.join(cur.into_inner());
         shared.ensure_dir(&cur)?;
 
-        let src_fname = p.file_name().expect("source has no filename").to_os_string();
-        let mut fname = src_fname.clone();
-        fname.push(".html");
         cur.push(&fname);
 
         let title = format!("{} - source", src_fname.to_string_lossy());
@@ -250,7 +258,7 @@ impl SourceCollector<'_, '_> {
                     cx,
                     &root_path,
                     highlight::DecorationInfo::default(),
-                    SourceContext::Standalone,
+                    SourceContext::Standalone { file_path },
                 )
             },
             &shared.style_files,
@@ -312,10 +320,11 @@ struct ScrapedSource<'a, Code: std::fmt::Display> {
 struct Source<Code: std::fmt::Display> {
     lines: RangeInclusive<usize>,
     code_html: Code,
+    file_path: Option<(String, String)>,
 }
 
 pub(crate) enum SourceContext<'a> {
-    Standalone,
+    Standalone { file_path: PathBuf },
     Embedded(ScrapedInfo<'a>),
 }
 
@@ -344,9 +353,19 @@ pub(crate) fn print_src(
     });
     let lines = s.lines().count();
     match source_context {
-        SourceContext::Standalone => {
-            Source { lines: (1..=lines), code_html: code }.render_into(&mut writer).unwrap()
+        SourceContext::Standalone { file_path } => Source {
+            lines: (1..=lines),
+            code_html: code,
+            file_path: if let Some(file_name) = file_path.file_name()
+                && let Some(file_path) = file_path.parent()
+            {
+                Some((file_path.display().to_string(), file_name.display().to_string()))
+            } else {
+                None
+            },
         }
+        .render_into(&mut writer)
+        .unwrap(),
         SourceContext::Embedded(info) => {
             let lines = (1 + info.offset)..=(lines + info.offset);
             ScrapedSource { info, lines, code_html: code }.render_into(&mut writer).unwrap();
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index e62b16267f1..477a79d63e9 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -61,6 +61,8 @@ nav.sub {
 	--copy-path-img-hover-filter: invert(35%);
 	--code-example-button-color: #7f7f7f;
 	--code-example-button-hover-color: #595959;
+	--settings-menu-filter: invert(50%);
+	--settings-menu-hover-filter: invert(35%);
 	--codeblock-error-hover-color: rgb(255, 0, 0);
 	--codeblock-error-color: rgba(255, 0, 0, .5);
 	--codeblock-ignore-hover-color: rgb(255, 142, 0);
@@ -87,7 +89,6 @@ nav.sub {
 	--search-tab-button-not-selected-background: #e6e6e6;
 	--search-tab-button-selected-border-top-color: #0089ff;
 	--search-tab-button-selected-background: #fff;
-	--settings-menu-filter: none;
 	--stab-background-color: #fff5d6;
 	--stab-code-color: #000;
 	--code-highlight-kw-color: #8959a8;
@@ -192,6 +193,8 @@ nav.sub {
 		--search-tab-button-not-selected-background: #252525;
 		--search-tab-button-selected-border-top-color: #0089ff;
 		--search-tab-button-selected-background: #353535;
+		--settings-menu-filter: invert(50%);
+		--settings-menu-hover-filter: invert(65%);
 		--stab-background-color: #314559;
 		--stab-code-color: #e6e1cf;
 		--code-highlight-kw-color: #ab8ac1;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 04b0eba7450..ae9727a4d4f 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -34,6 +34,8 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 </g></svg>');
 	--button-left-margin: 4px;
 	--button-border-radius: 2px;
+	--toolbar-button-border-radius: 6px;
+	--code-block-border-radius: 6px;
 }
 
 /* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -165,7 +167,7 @@ h1, h2, h3, h4 {
 .main-heading h1 {
 	margin: 0;
 	padding: 0;
-	flex-grow: 1;
+	grid-area: main-heading-h1;
 	/* We use overflow-wrap: break-word for Safari, which doesn't recognize
 	   `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
 	overflow-wrap: break-word;
@@ -174,10 +176,28 @@ h1, h2, h3, h4 {
 	overflow-wrap: anywhere;
 }
 .main-heading {
-	display: flex;
-	flex-wrap: wrap;
+	position: relative;
+	display: grid;
+	grid-template-areas:
+		"main-heading-breadcrumbs main-heading-breadcrumbs"
+		"main-heading-h1 main-heading-toolbar"
+		"main-heading-sub-heading main-heading-toolbar";
+	grid-template-columns: 1fr max-content;
+	grid-template-rows: 25px min-content min-content;
 	padding-bottom: 6px;
-	margin-bottom: 15px;
+	margin-bottom: 11px;
+}
+.rustdoc-breadcrumbs {
+	grid-area: main-heading-breadcrumbs;
+	height: 25px;
+	line-height: 1.25;
+	display: flex;
+	align-items: end;
+}
+.rustdoc-breadcrumbs a {
+	padding: 4px 0;
+	margin: -4px 0;
+	z-index: 1;
 }
 /* The only headings that get underlines are:
 	 Markdown-generated headings within the top-doc
@@ -218,11 +238,13 @@ h1, h2, h3, h4, h5, h6,
 .search-results .result-name,
 .item-name > a,
 .out-of-band,
+.sub-heading,
 span.since,
 a.src,
-#help-button > a,
+rustdoc-toolbar,
 summary.hideme,
 .scraped-example-list,
+.rustdoc-breadcrumbs,
 /* This selector is for the items listed in the "all items" page. */
 ul.all-items {
 	font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@@ -891,14 +913,27 @@ both the code example and the line numbers, so we need to remove the radius in t
 	overflow-x: auto;
 }
 
-.out-of-band {
+.sub-heading {
+	font-size: 1rem;
 	flex-grow: 0;
-	font-size: 1.125rem;
+	grid-area: main-heading-sub-heading;
+	line-height: 1.25;
+	padding-bottom: 4px;
+}
+
+.main-heading rustdoc-toolbar, .main-heading .out-of-band {
+	grid-area: main-heading-toolbar;
+}
+rustdoc-toolbar {
+	display: flex;
+	flex-direction: row;
+	flex-wrap: nowrap;
 }
 
 .docblock code, .docblock-short code,
 pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	background-color: var(--code-block-background-color);
+	border-radius: var(--code-block-border-radius);
 }
 
 #main-content {
@@ -945,7 +980,7 @@ div.where {
 nav.sub {
 	flex-grow: 1;
 	flex-flow: row nowrap;
-	margin: 4px 0 25px 0;
+	margin: 4px 0 0 0;
 	display: flex;
 	align-items: center;
 }
@@ -956,7 +991,7 @@ nav.sub {
 	flex-grow: 1;
 }
 .src nav.sub {
-	margin: 0 0 15px 0;
+	margin: 0 0 -10px 0;
 }
 
 .section-header {
@@ -1066,6 +1101,11 @@ table,
 	with boxes (i.e. from the flex layout) */
 	align-items: baseline;
 }
+.search-results-title + .sub-heading {
+	color: var(--main-color);
+	display: flex;
+	align-items: center;
+}
 #crate-search-div {
 	/* ensures that 100% in properties of #crate-search-div:after
 	are relative to the size of this div */
@@ -1289,10 +1329,16 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	border-color: var(--settings-input-color) !important;
 }
 
+#settings.popover {
+	--popover-arrow-offset: 202px;
+	top: calc(100% - 16px);
+}
+
 /* use larger max-width for help popover, but not for help.html */
 #help.popover {
 	max-width: 600px;
-	--popover-arrow-offset: 48px;
+	--popover-arrow-offset: 118px;
+	top: calc(100% - 16px);
 }
 
 #help dt {
@@ -1300,10 +1346,15 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	clear: left;
 	margin-right: 0.5rem;
 }
+#help dd {
+	margin-bottom: 0.5rem;
+}
 #help span.top, #help span.bottom {
 	text-align: center;
 	display: block;
 	font-size: 1.125rem;
+	padding: 0 0.5rem;
+	text-wrap-style: balance;
 }
 #help span.top {
 	margin: 10px 0;
@@ -1315,10 +1366,13 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	clear: both;
 	border-top: 1px solid var(--border-color);
 }
+.side-by-side {
+	display: flex;
+	margin-bottom: 20px;
+}
 .side-by-side > div {
 	width: 50%;
-	float: left;
-	padding: 0 20px 20px 17px;
+	padding: 0 20px 0 17px;
 }
 
 .item-info .stab {
@@ -1381,7 +1435,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
 }
 
 .rightside:not(a),
-.out-of-band {
+.out-of-band,
+.sub-heading,
+rustdoc-toolbar {
 	color: var(--right-side-color);
 }
 
@@ -1595,8 +1651,8 @@ instead, we check that it's not a "finger" cursor.
 	display: block;
 }
 
-.out-of-band > span.since {
-	font-size: 1.25rem;
+.main-heading span.since::before {
+	content: "Since ";
 }
 
 .sub-variant h4 {
@@ -1698,6 +1754,7 @@ a.tooltip:hover::after {
 }
 
 #search-tabs {
+	margin-top: 0.25rem;
 	display: flex;
 	flex-direction: row;
 	gap: 1px;
@@ -1759,9 +1816,10 @@ a.tooltip:hover::after {
 	border-bottom: 1px solid var(--border-color);
 }
 
-#settings-menu, #help-button {
+#settings-menu, #help-button, button#toggle-all-docs {
 	margin-left: var(--button-left-margin);
 	display: flex;
+	line-height: 1.25;
 }
 #sidebar-button {
 	display: none;
@@ -1785,33 +1843,36 @@ a.tooltip:hover::after {
 .hide-sidebar .src #sidebar-button {
 	position: static;
 }
-#settings-menu > a, #help-button > a, #sidebar-button > a {
+#settings-menu > a, #help-button > a, #sidebar-button > a, button#toggle-all-docs {
 	display: flex;
 	align-items: center;
 	justify-content: center;
-	background-color: var(--button-background-color);
-	border: 1px solid var(--border-color);
+	flex-direction: column;
+	border: 1px solid transparent;
 	border-radius: var(--button-border-radius);
-	color: var(--settings-button-color);
-	/* Rare exception to specifying font sizes in rem. Since this is acting
-	   as an icon, it's okay to specify their sizes in pixels. */
-	font-size: 20px;
+	color: var(--main-color);
+}
+#settings-menu > a, #help-button > a, button#toggle-all-docs {
+	width: 80px;
+	border-radius: var(--toolbar-button-border-radius);
+}
+#sidebar-button > a {
+	background-color: var(--button-background-color);
+	border-color: var(--border-color);
 	width: 33px;
 }
 
-#settings-menu > a:hover, #settings-menu > a:focus,
-#help-button > a:hover, #help-button > a:focus,
-#sidebar-button > a:hover, #sidebar-button > a:focus {
+#settings-menu > a:hover, #settings-menu > a:focus-visible,
+#help-button > a:hover, #help-button > a:focus-visible,
+#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
+button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
 	border-color: var(--settings-button-border-focus);
+	text-decoration: none;
 }
 
-#settings-menu > a {
-	line-height: 0;
-	font-size: 0;
-}
 #settings-menu > a:before {
 	/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
-	content: url('data:image/svg+xml,<svg width="22" height="22" viewBox="0 0 12 12" \
+	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
 	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
 	<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\
 	-1.25-2.1650391  c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\
@@ -1824,16 +1885,70 @@ a.tooltip:hover::after {
 	-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915  C10.2238159,6.241333,\
 	10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\
 	,5.1715698,7.5,6  S6.8284302,7.5,6,7.5z" fill="black"/></svg>');
-	width: 22px;
-	height: 22px;
+	width: 18px;
+	height: 18px;
+	filter: var(--settings-menu-filter);
+}
+
+button#toggle-all-docs:before {
+	/* Custom arrow icon */
+	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
+	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
+	<path d="M2,2l4,4l4,-4M2,6l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
+	width: 18px;
+	height: 18px;
+	filter: var(--settings-menu-filter);
+}
+
+#help-button > a:before {
+	/* Question mark with circle */
+	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
+	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg" fill="none">\
+	<circle r="5.25" cx="6" cy="6" stroke-width="1.25" stroke="black"/>\
+	<text x="6" y="7" style="font:8px sans-serif;font-weight:1000" text-anchor="middle" \
+		dominant-baseline="middle" fill="black">?</text></svg>');
+	width: 18px;
+	height: 18px;
+	filter: var(--settings-menu-filter);
+}
+
+button#toggle-all-docs:before,
+#help-button > a:before,
+#settings-menu > a:before {
 	filter: var(--settings-menu-filter);
+	margin: 8px;
+}
+
+@media not (pointer: coarse) {
+	button#toggle-all-docs:hover:before,
+	#help-button > a:hover:before,
+	#settings-menu > a:hover:before {
+		filter: var(--settings-menu-hover-filter);
+	}
+}
+
+button[disabled]#toggle-all-docs {
+	opacity: 0.25;
+	border: solid 1px var(--main-background-color);
+	background-size: cover;
+}
+
+button[disabled]#toggle-all-docs:hover {
+	border: solid 1px var(--main-background-color);
+	cursor: not-allowed;
+}
+
+rustdoc-toolbar span.label {
+	font-size: 1rem;
+	flex-grow: 1;
+	padding-bottom: 4px;
 }
 
 #sidebar-button > a:before {
 	/* sidebar resizer image */
 	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
 		fill="none" stroke="black">\
-		<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
+		<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
 		<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
 		<path d="m7.6121 3v16 M5.375 7.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
 	width: 22px;
@@ -1948,10 +2063,10 @@ details.toggle > summary.hideme > span {
 }
 
 details.toggle > summary::before {
-	/* toggle plus */
-	background: url('data:image/svg+xml,<svg width="17" height="17" \
-shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
-d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>') no-repeat top left;
+	/* arrow pointing left */
+	background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
+	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
+	<path d="M4,2l4,4l-4,4" stroke="black" fill="none" stroke-width="1px"/></svg>');
 	content: "";
 	cursor: pointer;
 	width: 16px;
@@ -2034,10 +2149,10 @@ details.toggle[open] > summary.hideme > span {
 }
 
 details.toggle[open] > summary::before {
-	/* toggle minus */
-	background: url('data:image/svg+xml,<svg width="17" height="17" \
-shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
-d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>') no-repeat top left;
+	/* arrow pointing down */
+	background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
+	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
+	<path d="M2,4l4,4l4,-4" stroke="black" fill="none" stroke-width="1px"/></svg>');
 }
 
 details.toggle[open] > summary::after {
@@ -2090,6 +2205,12 @@ However, it's not needed with smaller screen width because the doc/code block is
 	#search-tabs .count {
 		display: block;
 	}
+	.side-by-side {
+		flex-direction: column-reverse;
+	}
+	.side-by-side > div {
+		width: auto;
+	}
 }
 
 /*
@@ -2106,6 +2227,25 @@ in src-script.js and main.js
 		scroll-margin-top: 45px;
 	}
 
+	/* We don't display this button on mobile devices. */
+	#copy-path {
+		display: none;
+	}
+
+	/* Text label takes up too much space at this size. */
+	rustdoc-toolbar span.label {
+		display: none;
+	}
+	#settings-menu > a, #help-button > a, button#toggle-all-docs {
+		width: 33px;
+	}
+	#settings.popover {
+		--popover-arrow-offset: 86px;
+	}
+	#help.popover {
+		--popover-arrow-offset: 48px;
+	}
+
 	.rustdoc {
 		/* Sidebar should overlay main content, rather than pushing main content to the right.
 		   Turn off `display: flex` on the body element. */
@@ -2117,20 +2257,6 @@ in src-script.js and main.js
 		padding-top: 0px;
 	}
 
-	.main-heading {
-		flex-direction: column;
-	}
-
-	.out-of-band {
-		text-align: left;
-		margin-left: initial;
-		padding: initial;
-	}
-
-	.out-of-band .since::before {
-		content: "Since ";
-	}
-
 	/* Hide the logo and item name from the sidebar. Those are displayed
 	   in the mobile-topbar instead. */
 	.sidebar .logo-container,
@@ -2163,6 +2289,9 @@ in src-script.js and main.js
 	.src .search-form {
 		margin-left: 40px;
 	}
+	.src .main-heading {
+		margin-left: 8px;
+	}
 	.hide-sidebar .search-form {
 		margin-left: 32px;
 	}
@@ -2234,16 +2363,11 @@ in src-script.js and main.js
 		left: -11px;
 	}
 
-	/* We don't display these buttons on mobile devices. */
-	#copy-path, #help-button {
-		display: none;
-	}
-
 	/* sidebar button becomes topbar button */
 	#sidebar-button > a:before {
 		content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
 			viewBox="0 0 22 22" fill="none" stroke="black">\
-			<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
+			<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
 			<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
 			<path d="m3 7.375h16m0-3h-4" stroke-width="1.25"/></svg>');
 		width: 22px;
@@ -2305,7 +2429,7 @@ in src-script.js and main.js
 	}
 
 	.src nav.sub {
-		margin: 0;
+		margin: 0 0 -25px 0;
 		padding: var(--nav-sub-mobile-padding);
 	}
 }
@@ -2543,6 +2667,8 @@ by default.
 	--copy-path-img-hover-filter: invert(35%);
 	--code-example-button-color: #7f7f7f;
 	--code-example-button-hover-color: #595959;
+	--settings-menu-filter: invert(50%);
+	--settings-menu-hover-filter: invert(35%);
 	--codeblock-error-hover-color: rgb(255, 0, 0);
 	--codeblock-error-color: rgba(255, 0, 0, .5);
 	--codeblock-ignore-hover-color: rgb(255, 142, 0);
@@ -2569,7 +2695,6 @@ by default.
 	--search-tab-button-not-selected-background: #e6e6e6;
 	--search-tab-button-selected-border-top-color: #0089ff;
 	--search-tab-button-selected-background: #fff;
-	--settings-menu-filter: none;
 	--stab-background-color: #fff5d6;
 	--stab-code-color: #000;
 	--code-highlight-kw-color: #8959a8;
@@ -2673,7 +2798,8 @@ by default.
 	--search-tab-button-not-selected-background: #252525;
 	--search-tab-button-selected-border-top-color: #0089ff;
 	--search-tab-button-selected-background: #353535;
-	--settings-menu-filter: none;
+	--settings-menu-filter: invert(50%);
+	--settings-menu-hover-filter: invert(65%);
 	--stab-background-color: #314559;
 	--stab-code-color: #e6e1cf;
 	--code-highlight-kw-color: #ab8ac1;
@@ -2784,7 +2910,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--search-tab-button-not-selected-background: transparent !important;
 	--search-tab-button-selected-border-top-color: none;
 	--search-tab-button-selected-background: #141920 !important;
-	--settings-menu-filter: invert(100%);
+	--settings-menu-filter: invert(70%);
+	--settings-menu-hover-filter: invert(100%);
 	--stab-background-color: #314559;
 	--stab-code-color: #e6e1cf;
 	--code-highlight-kw-color: #ff7733;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0eba80133df..0d556e0a682 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1,6 +1,6 @@
 // Local js definitions:
 /* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */
-/* global onEach, onEachLazy, removeClass, getVar */
+/* global onEachLazy, removeClass, getVar */
 
 "use strict";
 
@@ -19,17 +19,25 @@ function resourcePath(basename, extension) {
 
 function hideMain() {
     addClass(document.getElementById(MAIN_ID), "hidden");
+    const toggle = document.getElementById("toggle-all-docs");
+    if (toggle) {
+        toggle.setAttribute("disabled", "disabled");
+    }
 }
 
 function showMain() {
-    removeClass(document.getElementById(MAIN_ID), "hidden");
-}
-
-function blurHandler(event, parentElem, hideCallback) {
-    if (!parentElem.contains(document.activeElement) &&
-        !parentElem.contains(event.relatedTarget)
-    ) {
-        hideCallback();
+    const main = document.getElementById(MAIN_ID);
+    removeClass(main, "hidden");
+    const mainHeading = main.querySelector(".main-heading");
+    if (mainHeading && searchState.rustdocToolbar) {
+        if (searchState.rustdocToolbar.parentElement) {
+            searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
+        }
+        mainHeading.appendChild(searchState.rustdocToolbar);
+    }
+    const toggle = document.getElementById("toggle-all-docs");
+    if (toggle) {
+        toggle.removeAttribute("disabled");
     }
 }
 
@@ -167,6 +175,14 @@ function switchDisplayedElement(elemToDisplay) {
     el.appendChild(elemToDisplay);
     hideMain();
     removeClass(el, "hidden");
+
+    const mainHeading = elemToDisplay.querySelector(".main-heading");
+    if (mainHeading && searchState.rustdocToolbar) {
+        if (searchState.rustdocToolbar.parentElement) {
+            searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
+        }
+        mainHeading.appendChild(searchState.rustdocToolbar);
+    }
 }
 
 function browserSupportsHistoryApi() {
@@ -194,33 +210,36 @@ function preLoadCss(cssUrl) {
         document.head.append(script);
     }
 
-    getSettingsButton().onclick = event => {
-        if (event.ctrlKey || event.altKey || event.metaKey) {
-            return;
-        }
-        window.hideAllModals(false);
-        addClass(getSettingsButton(), "rotate");
-        event.preventDefault();
-        // Sending request for the CSS and the JS files at the same time so it will
-        // hopefully be loaded when the JS will generate the settings content.
-        loadScript(getVar("static-root-path") + getVar("settings-js"));
-        // Pre-load all theme CSS files, so that switching feels seamless.
-        //
-        // When loading settings.html as a standalone page, the equivalent HTML is
-        // generated in context.rs.
-        setTimeout(() => {
-            const themes = getVar("themes").split(",");
-            for (const theme of themes) {
-                // if there are no themes, do nothing
-                // "".split(",") == [""]
-                if (theme !== "") {
-                    preLoadCss(getVar("root-path") + theme + ".css");
-                }
+    if (getSettingsButton()) {
+        getSettingsButton().onclick = event => {
+            if (event.ctrlKey || event.altKey || event.metaKey) {
+                return;
             }
-        }, 0);
-    };
+            window.hideAllModals(false);
+            addClass(getSettingsButton(), "rotate");
+            event.preventDefault();
+            // Sending request for the CSS and the JS files at the same time so it will
+            // hopefully be loaded when the JS will generate the settings content.
+            loadScript(getVar("static-root-path") + getVar("settings-js"));
+            // Pre-load all theme CSS files, so that switching feels seamless.
+            //
+            // When loading settings.html as a standalone page, the equivalent HTML is
+            // generated in context.rs.
+            setTimeout(() => {
+                const themes = getVar("themes").split(",");
+                for (const theme of themes) {
+                    // if there are no themes, do nothing
+                    // "".split(",") == [""]
+                    if (theme !== "") {
+                        preLoadCss(getVar("root-path") + theme + ".css");
+                    }
+                }
+            }, 0);
+        };
+    }
 
     window.searchState = {
+        rustdocToolbar: document.querySelector("rustdoc-toolbar"),
         loadingText: "Loading search results...",
         input: document.getElementsByClassName("search-input")[0],
         outputElement: () => {
@@ -919,8 +938,7 @@ function preLoadCss(cssUrl) {
                 e.open = true;
             }
         });
-        innerToggle.title = "collapse all docs";
-        innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "−" minus sign
+        innerToggle.children[0].innerText = "Summary";
     }
 
     function collapseAllDocs() {
@@ -934,8 +952,7 @@ function preLoadCss(cssUrl) {
                 e.open = false;
             }
         });
-        innerToggle.title = "expand all docs";
-        innerToggle.children[0].innerText = "+";
+        innerToggle.children[0].innerText = "Show all";
     }
 
     function toggleAllDocs() {
@@ -1330,7 +1347,13 @@ function preLoadCss(cssUrl) {
     }
 
     function helpBlurHandler(event) {
-        blurHandler(event, getHelpButton(), window.hidePopoverMenus);
+        if (!getHelpButton().contains(document.activeElement) &&
+            !getHelpButton().contains(event.relatedTarget) &&
+            !getSettingsButton().contains(document.activeElement) &&
+            !getSettingsButton().contains(event.relatedTarget)
+        ) {
+            window.hidePopoverMenus();
+        }
     }
 
     function buildHelpMenu() {
@@ -1433,9 +1456,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      * Hide all the popover menus.
      */
     window.hidePopoverMenus = () => {
-        onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
+        onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
             elem.style.display = "none";
         });
+        const button = getHelpButton();
+        if (button) {
+            removeClass(button, "help-open");
+        }
     };
 
     /**
@@ -1460,7 +1487,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     function showHelp() {
         // Prevent `blur` events from being dispatched as a result of closing
         // other modals.
-        getHelpButton().querySelector("a").focus();
+        const button = getHelpButton();
+        addClass(button, "help-open");
+        button.querySelector("a").focus();
         const menu = getHelpMenu(true);
         if (menu.style.display === "none") {
             window.hideAllModals();
@@ -1468,28 +1497,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         }
     }
 
+    const helpLink = document.querySelector(`#${HELP_BUTTON_ID} > a`);
     if (isHelpPage) {
-        showHelp();
-        document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
-            // Already on the help page, make help button a no-op.
-            const target = event.target;
-            if (target.tagName !== "A" ||
-                target.parentElement.id !== HELP_BUTTON_ID ||
-                event.ctrlKey ||
-                event.altKey ||
-                event.metaKey) {
-                return;
-            }
-            event.preventDefault();
-        });
-    } else {
-        document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
+        buildHelpMenu();
+    } else if (helpLink) {
+        helpLink.addEventListener("click", event => {
             // By default, have help button open docs in a popover.
             // If user clicks with a moderator, though, use default browser behavior,
             // probably opening in a new window or tab.
-            const target = event.target;
-            if (target.tagName !== "A" ||
-                target.parentElement.id !== HELP_BUTTON_ID ||
+            if (!helpLink.contains(helpLink) ||
                 event.ctrlKey ||
                 event.altKey ||
                 event.metaKey) {
@@ -1812,14 +1828,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         return;
     }
     but.onclick = () => {
-        const parent = but.parentElement;
         const path = [];
-
-        onEach(parent.childNodes, child => {
-            if (child.tagName === "A") {
-                path.push(child.textContent);
-            }
+        onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => {
+            path.push(a.textContent);
         });
+        path.push(document.querySelector("title").textContent.split(" ")[0]);
 
         copyContentToClipboard(path.join("::"));
         copyButtonAnimation(but);
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 4da0bbc787d..eed64d024c0 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3597,15 +3597,16 @@ async function showResults(results, go_to_first, filterCrates) {
 
     let crates = "";
     if (rawSearchIndex.size > 1) {
-        crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
-            "<option value=\"all crates\">all crates</option>";
+        crates = "<div class=\"sub-heading\"> in&nbsp;<div id=\"crate-search-div\">" +
+            "<select id=\"crate-search\"><option value=\"all crates\">all crates</option>";
         for (const c of rawSearchIndex.keys()) {
             crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
         }
-        crates += "</select></div>";
+        crates += "</select></div></div>";
     }
 
-    let output = `<h1 class="search-results-title">Results${crates}</h1>`;
+    let output = `<div class="main-heading">\
+        <h1 class="search-results-title">Results</h1>${crates}</div>`;
     if (results.query.error !== null) {
         const error = results.query.error;
         error.forEach((value, index) => {
@@ -3662,6 +3663,9 @@ async function showResults(results, go_to_first, filterCrates) {
     resultsElem.appendChild(ret_returned[0]);
 
     search.innerHTML = output;
+    if (searchState.rustdocToolbar) {
+        search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
+    }
     const crateSearch = document.getElementById("crate-search");
     if (crateSearch) {
         crateSearch.addEventListener("input", updateCrate);
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index c52a19ef987..183663b94fc 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,7 +1,7 @@
 // Local js definitions:
 /* global getSettingValue, updateLocalStorage, updateTheme */
-/* global addClass, removeClass, onEach, onEachLazy, blurHandler */
-/* global MAIN_ID, getVar, getSettingsButton */
+/* global addClass, removeClass, onEach, onEachLazy */
+/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
 
 "use strict";
 
@@ -267,15 +267,16 @@
     }
 
     function settingsBlurHandler(event) {
-        blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
+        if (!getHelpButton().contains(document.activeElement) &&
+            !getHelpButton().contains(event.relatedTarget) &&
+            !getSettingsButton().contains(document.activeElement) &&
+            !getSettingsButton().contains(event.relatedTarget)
+        ) {
+            window.hidePopoverMenus();
+        }
     }
 
-    if (isSettingsPage) {
-        // We replace the existing "onclick" callback to do nothing if clicked.
-        getSettingsButton().onclick = event => {
-            event.preventDefault();
-        };
-    } else {
+    if (!isSettingsPage) {
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
         const settingsMenu = document.getElementById("settings");
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index d75fb7a7fb5..d77804d045e 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -274,16 +274,29 @@ class RustdocSearchElement extends HTMLElement {
                     spellcheck="false"
                     placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…"
                     type="search">
-                <div id="help-button" tabindex="-1">
-                    <a href="${rootPath}help.html" title="help">?</a>
-                </div>
-                <div id="settings-menu" tabindex="-1">
-                    <a href="${rootPath}settings.html" title="settings">
-                        Settings
-                    </a>
-                </div>
             </form>
         </nav>`;
     }
 }
 window.customElements.define("rustdoc-search", RustdocSearchElement);
+class RustdocToolbarElement extends HTMLElement {
+    constructor() {
+        super();
+    }
+    connectedCallback() {
+        // Avoid replacing the children after they're already here.
+        if (this.firstElementChild) {
+            return;
+        }
+        const rootPath = getVar("root-path");
+        this.innerHTML = `
+        <div id="settings-menu" tabindex="-1">
+            <a href="${rootPath}settings.html"><span class="label">Settings</span></a>
+        </div>
+        <div id="help-button" tabindex="-1">
+            <a href="${rootPath}help.html"><span class="label">Help</span></a>
+        </div>
+        <button id="toggle-all-docs"><span class="label">Summary</span></button>`;
+    }
+}
+window.customElements.define("rustdoc-toolbar", RustdocToolbarElement);
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 76e770453b6..32ded1fbe42 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -1,26 +1,33 @@
 <div class="main-heading"> {# #}
+    {% if !path_components.is_empty() %}
+    <span class="rustdoc-breadcrumbs">
+        {% for (i, component) in path_components.iter().enumerate() %}
+            {% if i != 0 %}
+                ::<wbr>
+            {% endif %}
+            <a href="{{component.path|safe}}index.html">{{component.name}}</a>
+        {% endfor %}
+    </span>
+    {% endif %}
     <h1>
         {{typ}}
-        {# The breadcrumbs of the item path, like std::string #}
-        {% for component in path_components %}
-            <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
-        {% endfor %}
-        <a class="{{item_type}}" href="#">{{name}}</a> {# #}
+        <span{% if item_type != "mod" +%} class="{{item_type}}"{% endif %}>
+        {{name}}
+        </span> {# #}
         <button id="copy-path" title="Copy item path to clipboard"> {# #}
             Copy item path {# #}
         </button> {# #}
     </h1> {# #}
-    <span class="out-of-band">
+    <rustdoc-toolbar></rustdoc-toolbar> {# #}
+    <span class="sub-heading">
         {% if !stability_since_raw.is_empty() %}
-        {{ stability_since_raw|safe +}} · {#+ #}
+        {{ stability_since_raw|safe +}}
         {% endif %}
         {% match src_href %}
             {% when Some with (href) %}
-                <a class="src" href="{{href|safe}}">source</a> · {#+ #}
+                {% if !stability_since_raw.is_empty() +%} · {%+ endif %}
+                <a class="src" href="{{href|safe}}">source</a> {#+ #}
             {% else %}
         {% endmatch %}
-        <button id="toggle-all-docs" title="collapse all docs"> {# #}
-            [<span>&#x2212;</span>] {# #}
-        </button> {# #}
     </span> {# #}
 </div> {# #}
diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html
index 60a47f1b5de..9daa0cf8ff6 100644
--- a/src/librustdoc/html/templates/source.html
+++ b/src/librustdoc/html/templates/source.html
@@ -1,4 +1,15 @@
-<div class="example-wrap">
+{% match file_path %}
+{% when Some with ((path, name)) %}
+<div class="main-heading"> {# #}
+    <h1> {# #}
+        <div class="sub-heading">{{path}}/</div>
+        {{name}}
+    </h1> {# #}
+    <rustdoc-toolbar></rustdoc-toolbar> {# #}
+</div>
+{% else %}
+{% endmatch %}
+<div class="example-wrap"> {# #}
     {# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
        Do not show "1 2 3 4 5 ..." in web search results. #}
     <div data-nosnippet><pre class="src-line-numbers">
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index f210873e696..dd75f4d7928 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -10,6 +10,7 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
+#![feature(os_str_display)]
 #![feature(round_char_boundary)]
 #![feature(test)]
 #![feature(type_alias_impl_trait)]
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 177d4044ec2..25a135aa320 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1963,7 +1963,7 @@ impl<'test> TestCx<'test> {
 
         #[rustfmt::skip]
         let tidy_args = [
-            "--new-blocklevel-tags", "rustdoc-search",
+            "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar",
             "--indent", "yes",
             "--indent-spaces", "2",
             "--wrap", "0",
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index ecfbb1955e7..5cdc4d53ab5 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -31,7 +31,7 @@ fn check_html_file(file: &Path) -> usize {
         .arg("--mute-id") // this option is useful in case we want to mute more warnings
         .arg("yes")
         .arg("--new-blocklevel-tags")
-        .arg("rustdoc-search") // custom elements
+        .arg("rustdoc-search,rustdoc-toolbar") // custom elements
         .arg("--mute")
         .arg(&to_mute_s)
         .arg(file);
diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
index 982d57b7372..7ac619e09ab 100644
--- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
@@ -16,5 +16,5 @@ impl T1 for i32 {
 fn main() {
     let r = Box::new(0) as Box<dyn T1>;
     let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
-    r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected
+    r2.method2(); //~ERROR: using vtable for `T1` but `T2` was expected
 }
diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
index 3680a84fac2..37d102c8713 100644
--- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
+++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected
+error: Undefined Behavior: using vtable for `T1` but `T2` was expected
   --> tests/fail/dyn-call-trait-mismatch.rs:LL:CC
    |
 LL |     r2.method2();
-   |     ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected
+   |     ^^^^^^^^^^^^ using vtable for `T1` but `T2` was expected
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index 85d7582d112..f450e7e652c 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -63,6 +63,6 @@ fn main() {
         let baz: &dyn Baz = &1;
         let baz_fake: *const dyn Bar = std::mem::transmute(baz);
         let _err = baz_fake as *const dyn Foo;
-        //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected
+        //~^ERROR: using vtable for `Baz` but `Bar` was expected
     }
 }
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
index 2129fe66e9c..b40f83e8654 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected
+error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected
   --> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC
    |
 LL |         let _err = baz_fake as *const dyn Foo;
-   |                    ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected
+   |                    ^^^^^^^^ using vtable for `Baz` but `Bar` was expected
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
new file mode 100644
index 00000000000..1478abedee0
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
@@ -0,0 +1,18 @@
+trait Trait {
+    type Assoc;
+    fn foo(&self) -> Self::Assoc;
+}
+
+impl<T: Copy> Trait for T {
+    type Assoc = T;
+    fn foo(&self) -> T { *self }
+}
+
+fn main() {
+    let v: Box<dyn Trait<Assoc = u8>> = Box::new(2);
+    let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) }; //~ERROR: wrong trait
+
+    if v.foo() {
+        println!("huh");
+    }
+}
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr
new file mode 100644
index 00000000000..44939a5a838
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
+  --> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
+   |
+LL |     let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) };
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
index 4be3fb52bdb..45c882bebdf 100644
--- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
+error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
   --> tests/fail/validity/wrong-dyn-trait.rs:LL:CC
    |
 LL |     let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) };
-   |                                              ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
+   |                                              ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 6ffa34f802e..e0f8e9cab79 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -249,6 +249,9 @@
 //@ revisions: loongarch64_unknown_linux_musl
 //@ [loongarch64_unknown_linux_musl] compile-flags: --target loongarch64-unknown-linux-musl
 //@ [loongarch64_unknown_linux_musl] needs-llvm-components: loongarch
+//@ revisions: loongarch64_unknown_linux_ohos
+//@ [loongarch64_unknown_linux_ohos] compile-flags: --target loongarch64-unknown-linux-ohos
+//@ [loongarch64_unknown_linux_ohos] needs-llvm-components: loongarch
 //@ revisions: loongarch64_unknown_none
 //@ [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none
 //@ [loongarch64_unknown_none] needs-llvm-components: loongarch
diff --git a/tests/crashes/130310.rs b/tests/crashes/130310.rs
new file mode 100644
index 00000000000..d59dd39983c
--- /dev/null
+++ b/tests/crashes/130310.rs
@@ -0,0 +1,15 @@
+//@ known-bug: rust-lang/rust#130310
+
+use std::marker::PhantomData;
+
+#[repr(C)]
+struct A<T> {
+    a: *const A<A<T>>,
+    p: PhantomData<T>,
+}
+
+extern "C" {
+    fn f(a: *const A<()>);
+}
+
+fn main() {}
diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml
index 61b2e8880c6..3168c8e17c5 100644
--- a/tests/rustdoc-gui/anchors.goml
+++ b/tests/rustdoc-gui/anchors.goml
@@ -12,8 +12,7 @@ define-function: (
         call-function: ("switch-theme", {"theme": |theme|})
 
         assert-css: ("#toggle-all-docs", {"color": |main_color|})
-        assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|})
-        assert-css: (".main-heading a:nth-of-type(2)", {"color": |main_heading_type_color|})
+        assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|})
         assert-css: (
              ".rightside a.src",
              {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
@@ -55,7 +54,7 @@ define-function: (
         assert-css: ("#top-doc-prose-title", {"color": |title_color|})
 
         assert-css: (".sidebar .block a", {"color": |sidebar_link_color|})
-        assert-css: (".main-heading h1 a", {"color": |title_color|})
+        assert-css: (".main-heading h1", {"color": |title_color|})
 
         // We move the cursor over the "Implementations" title so the anchor is displayed.
         move-cursor-to: "h2#implementations"
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index f1a2675128c..6d6e353ae36 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -4,7 +4,7 @@ set-window-size: (1000, 1000) // Try desktop size first.
 wait-for: "#help"
 assert-css: ("#help", {"display": "block"})
 assert-css: ("#help dd", {"font-size": "16px"})
-click: "#help-button > a"
+assert-false: "#help-button > a"
 assert-css: ("#help", {"display": "block"})
 compare-elements-property: (".sub", "#help", ["offsetWidth"])
 compare-elements-position: (".sub", "#help", ["x"])
@@ -50,7 +50,8 @@ call-function: ("check-colors", {
 })
 
 // This test ensures that opening the help popover without switching pages works.
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
+wait-for: "#search-tabs" // Waiting for the search.js to load.
 set-window-size: (1000, 1000) // Only supported on desktop.
 assert-false: "#help"
 click: "#help-button > a"
@@ -62,7 +63,8 @@ compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
 compare-elements-position-false: (".sub", "#help", ["x"])
 
 // This test ensures that the "the rustdoc book" anchor link within the help popover works.
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
+wait-for: "#search-tabs" // Waiting for the search.js to load.
 set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px.
 assert-false: "#help"
 click: "#help-button > a"
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index 7a0194c6cc1..c8aa7b31cad 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -20,7 +20,7 @@ store-position: (
     {"x": second_line_x, "y": second_line_y},
 )
 assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
-assert: |first_line_y| != |second_line_y| && |first_line_y| == 688 && |second_line_y| == 711
+assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737
 
 // Now we ensure that they're not rendered on the same line.
 set-window-size: (1100, 800)
diff --git a/tests/rustdoc-gui/mobile.goml b/tests/rustdoc-gui/mobile.goml
index e576385cd53..a9eee53dd1d 100644
--- a/tests/rustdoc-gui/mobile.goml
+++ b/tests/rustdoc-gui/mobile.goml
@@ -5,23 +5,8 @@ set-window-size: (400, 600)
 set-font-size: 18
 wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
 
-// The out-of-band info (source, stable version, collapse) should be below the
-// h1 when the screen gets narrow enough.
-assert-css: (".main-heading", {
-  "display": "flex",
-  "flex-direction": "column"
-})
-
 assert-property: (".mobile-topbar h2", {"offsetHeight": 33})
 
-// Note: We can't use assert-text here because the 'Since' is set by CSS and
-// is therefore not part of the DOM.
-assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
-
-set-window-size: (1000, 1000)
-wait-for: 100 // wait a bit for the resize to be fully taken into account.
-assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
-
 // On the settings page, the theme buttons should not line-wrap. Instead, they should
 // all be placed as a group on a line below the setting name "Theme."
 go-to: "file://" + |DOC_PATH| + "/settings.html"
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index e2a8a43007e..b8fa26b17f6 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -248,12 +248,13 @@ click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 assert-count: ("//*[@class='tooltip popover']", 1)
 assert-false: "//*[@class='sidebar shown']"
 
-// Also check the focus handling for the help button.
+// Also check the focus handling for the settings button.
 set-window-size: (1100, 600)
 reload:
 assert-count: ("//*[@class='tooltip popover']", 0)
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 assert-count: ("//*[@class='tooltip popover']", 1)
-click: "#help-button a"
+click: "#settings-menu a"
+wait-for: "#settings"
 assert-count: ("//*[@class='tooltip popover']", 0)
 assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml
index ec31f492abe..4a062fec751 100644
--- a/tests/rustdoc-gui/pocket-menu.goml
+++ b/tests/rustdoc-gui/pocket-menu.goml
@@ -1,6 +1,7 @@
 // This test ensures that the "pocket menus" are working as expected.
 include: "utils.goml"
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
+wait-for: "#crate-search"
 // First we check that the help menu doesn't exist yet.
 assert-false: "#help-button .popover"
 // Then we display the help menu.
diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml
index be14e202b37..fd0774c91b6 100644
--- a/tests/rustdoc-gui/scrape-examples-layout.goml
+++ b/tests/rustdoc-gui/scrape-examples-layout.goml
@@ -80,8 +80,8 @@ click: ".scraped-example .button-holder .expand"
 store-value: (offset_y, 4)
 
 // First with desktop
-assert-position: (".scraped-example", {"y": 226})
-assert-position: (".scraped-example .prev", {"y": 226 + |offset_y|})
+assert-position: (".scraped-example", {"y": 252})
+assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|})
 
 // Gradient background should be at the top of the code block.
 assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@@ -90,8 +90,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"})
 // Then with mobile
 set-window-size: (600, 600)
 store-size: (".scraped-example .scraped-example-title", {"height": title_height})
-assert-position: (".scraped-example", {"y": 284})
-assert-position: (".scraped-example .prev", {"y": 284 + |offset_y| + |title_height|})
+assert-position: (".scraped-example", {"y": 281})
+assert-position: (".scraped-example .prev", {"y": 281 + |offset_y| + |title_height|})
 
 define-function: (
     "check_title_and_code_position",
diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml
index d6421599a20..c5038e0892b 100644
--- a/tests/rustdoc-gui/search-filter.goml
+++ b/tests/rustdoc-gui/search-filter.goml
@@ -56,7 +56,8 @@ assert-property: ("#crate-search", {"value": "lib2"})
 assert-false: "#results .externcrate"
 
 // Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
-assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
+assert-text: (".search-results-title", "Results", STARTS_WITH)
+assert-text: (".search-results-title + .sub-heading", " in all crates", STARTS_WITH)
 
 // Checking the display of the crate filter.
 // We start with the light theme.
@@ -84,6 +85,6 @@ wait-for-css: ("#crate-search", {
 click: "#theme-ayu"
 wait-for-css: ("#crate-search", {
     "border": "1px solid #5c6773",
-    "color": "#fff",
+    "color": "#c5c5c5",
     "background-color": "#0f1419",
 })
diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml
index 63d2ceb3e7c..efe39f7a9d1 100644
--- a/tests/rustdoc-gui/search-form-elements.goml
+++ b/tests/rustdoc-gui/search-form-elements.goml
@@ -1,13 +1,14 @@
 // This test ensures that the elements in ".search-form" have the expected display.
 include: "utils.goml"
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
+wait-for: "#search-tabs" // Waiting for the search.js to load.
 show-text: true
 
 define-function: (
     "check-search-colors",
     [
         theme, border, background, search_input_color, search_input_border_focus,
-        menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
+        menu_button_a_color, menu_button_a_border_hover, menu_a_color,
     ],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
@@ -30,29 +31,21 @@ define-function: (
             },
         )
         assert-css: (
-            "#help-button",
-            {"border-color": |menu_button_border|},
-        )
-        assert-css: (
             "#help-button > a",
             {
                 "color": |menu_button_a_color|,
-                "border-color": |border|,
-                "background-color": |background|,
+                "border-color": "transparent",
+                "background-color": "transparent",
             },
         )
         // Hover help button.
         move-cursor-to: "#help-button"
         assert-css: (
-            "#help-button:hover",
-            {"border-color": |menu_button_border|},
-        )
-        assert-css: (
             "#help-button > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": |menu_button_a_border_hover|,
-                "background-color": |background|,
+                "background-color": "transparent",
             },
         )
         // Link color inside
@@ -64,29 +57,21 @@ define-function: (
             },
         )
         assert-css: (
-            "#settings-menu",
-            {"border-color": |menu_button_border|},
-        )
-        assert-css: (
             "#settings-menu > a",
             {
                 "color": |menu_button_a_color|,
-                "border-color": |border|,
-                "background-color": |background|,
+                "border-color": "transparent",
+                "background-color": "transparent",
             },
         )
         // Hover settings menu.
         move-cursor-to: "#settings-menu"
         assert-css: (
-            "#settings-menu:hover",
-            {"border-color": |menu_button_border|},
-        )
-        assert-css: (
             "#settings-menu:hover > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": |menu_button_a_border_hover|,
-                "background-color": |background|,
+                "background-color": "transparent",
             },
         )
     },
@@ -100,8 +85,7 @@ call-function: (
         "background": "#141920",
         "search_input_color": "#fff",
         "search_input_border_focus": "#5c6773",
-        "menu_button_border": "#c5c5c5",
-        "menu_button_a_color": "#fff",
+        "menu_button_a_color": "#c5c5c5",
         "menu_button_a_border_hover": "#e0e0e0",
         "menu_a_color": "#39afd7",
     }
@@ -114,8 +98,7 @@ call-function: (
         "background": "#f0f0f0",
         "search_input_color": "#111",
         "search_input_border_focus": "#008dfd",
-        "menu_button_border": "#ddd",
-        "menu_button_a_color": "#000",
+        "menu_button_a_color": "#ddd",
         "menu_button_a_border_hover": "#ffb900",
         "menu_a_color": "#d2991d",
     }
@@ -128,7 +111,6 @@ call-function: (
         "background": "#fff",
         "search_input_color": "#000",
         "search_input_border_focus": "#66afe9",
-        "menu_button_border": "#000",
         "menu_button_a_color": "#000",
         "menu_button_a_border_hover": "#717171",
         "menu_a_color": "#3873ad",
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index 3ca46f3c569..156244f92b4 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -50,8 +50,11 @@ compare-elements-size-near: (
 set-window-size: (900, 900)
 
 // First we check the current width, height and position.
-assert-css: ("#crate-search", {"width": "223px"})
-assert-css: (".search-results-title", {"height": "50px", "width": "640px"})
+assert-css: ("#crate-search", {"width": "159px"})
+store-size: (".search-results-title", {
+    "height": search_results_title_height,
+    "width": search_results_title_width,
+})
 assert-css: ("#search", {"width": "640px"})
 
 // Then we update the text of one of the `<option>`.
@@ -61,10 +64,12 @@ set-text: (
 )
 
 // Then we compare again to confirm the height didn't change.
-assert-size: ("#crate-search", {"width": 527})
-assert-size: (".search-results-title", {"height": 50, "width": 640})
-// And we check that the `<select>` isn't bigger than its container (".search-results-title").
+assert-size: ("#crate-search", {"width": 509})
+assert-size: (".search-results-title", {
+    "height": |search_results_title_height|,
+})
 assert-css: ("#search", {"width": "640px"})
+assert: |search_results_title_width| <= 640
 
 // Now checking that the crate filter is working as expected too.
 show-text: true
diff --git a/tests/rustdoc-gui/search-result-go-to-first.goml b/tests/rustdoc-gui/search-result-go-to-first.goml
index f4cfe096386..136213c517e 100644
--- a/tests/rustdoc-gui/search-result-go-to-first.goml
+++ b/tests/rustdoc-gui/search-result-go-to-first.goml
@@ -16,4 +16,5 @@ assert-css: ("#main-content", {"display": "none"})
 // Now we can check that the feature is working as expected!
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
 // Waiting for the page to load...
-wait-for-text: (".main-heading h1", "Struct test_docs::FooCopy item path")
+wait-for-text: (".main-heading .rustdoc-breadcrumbs", "test_docs")
+wait-for-text: (".main-heading h1", "Struct FooCopy item path")
diff --git a/tests/rustdoc-gui/settings-button.goml b/tests/rustdoc-gui/settings-button.goml
index c38a537e047..d78034769e2 100644
--- a/tests/rustdoc-gui/settings-button.goml
+++ b/tests/rustdoc-gui/settings-button.goml
@@ -11,8 +11,8 @@ define-function: (
         call-function: ("switch-theme", {"theme": |theme|})
         assert-css: ("#settings-menu > a::before", {
             "filter": |filter|,
-            "width": "22px",
-            "height": "22px",
+            "width": "18px",
+            "height": "18px",
         })
     }
 )
@@ -23,9 +23,9 @@ call-function: ("check-image", {
 })
 call-function: ("check-image", {
     "theme": "dark",
-    "filter": "none",
+    "filter": "invert(0.65)",
 })
 call-function: ("check-image", {
     "theme": "light",
-    "filter": "none",
+    "filter": "invert(0.35)",
 })
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index 3f4f2946bf5..1d93c07f9ec 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -305,6 +305,7 @@ wait-for-css: ("#help-button .popover", {"display": "block"})
 // Now we go to the settings page to check that the CSS is loaded as expected.
 go-to: "file://" + |DOC_PATH| + "/settings.html"
 wait-for: "#settings"
+assert-false: "#settings-menu"
 assert-css: (".setting-radio", {"cursor": "pointer"})
 
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
@@ -324,6 +325,5 @@ javascript: true
 show-text: true
 reload:
 set-window-size: (300, 1000)
-click: "#settings-menu"
 wait-for: "#settings"
 assert-css: (".setting-radio", {"cursor": "pointer"})
diff --git a/tests/rustdoc-gui/shortcuts.goml b/tests/rustdoc-gui/shortcuts.goml
index 2c61ee5428b..5a6171d6f76 100644
--- a/tests/rustdoc-gui/shortcuts.goml
+++ b/tests/rustdoc-gui/shortcuts.goml
@@ -13,19 +13,19 @@ press-key: "Escape"
 assert-css: ("#help-button .popover", {"display": "none"})
 // Checking doc collapse and expand.
 // It should be displaying a "-":
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 press-key: "-"
-wait-for-text: ("#toggle-all-docs", "[+]")
+wait-for-text: ("#toggle-all-docs", "Show all")
 assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
 // Pressing it again shouldn't do anything.
 press-key: "-"
-assert-text: ("#toggle-all-docs", "[+]")
+assert-text: ("#toggle-all-docs", "Show all")
 assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
 // Expanding now.
 press-key: "+"
-wait-for-text: ("#toggle-all-docs", "[−]")
+wait-for-text: ("#toggle-all-docs", "Summary")
 assert-attribute: ("#toggle-all-docs", {"class": ""})
 // Pressing it again shouldn't do anything.
 press-key: "+"
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 assert-attribute: ("#toggle-all-docs", {"class": ""})
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 67152afbbaa..c3e02c4e9b4 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@ click: "#sidebar-button"
 wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-store-value: (y_offset, "2493")
+store-value: (y_offset, "2564")
 assert-window-property: {"pageYOffset": |y_offset|}
 // Expanding the sidebar...
 click: "#sidebar-button"
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 7794cdbe9e2..bb7453fdeac 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -160,12 +160,12 @@ click: "//ul[@class='block mod']/preceding-sibling::h3/a"
 // PAGE: index.html
 assert-css: ("#modules", {"background-color": "#fdffd3"})
 
-// Finally, assert that the `[+]/[−]` toggle doesn't affect sidebar width.
+// Finally, assert that the Summary toggle doesn't affect sidebar width.
 click: "#toggle-all-docs"
-assert-text: ("#toggle-all-docs", "[+]")
+assert-text: ("#toggle-all-docs", "Show all")
 assert-property: (".sidebar", {"clientWidth": "200"})
 click: "#toggle-all-docs"
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 assert-property: (".sidebar", {"clientWidth": "200"})
 
 // Checks that all.html and index.html have their sidebar link in the same place.
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 3508b26a0bf..166890abe4b 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@ set-window-size: (600, 800)
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "123"})
+assert-property: ("html", {"scrollTop": "194"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "154"})
+assert-property: ("html", {"scrollTop": "225"})
 click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "51"})
+assert-property: ("html", {"scrollTop": "122"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "51"})
+assert-property: ("html", {"scrollTop": "122"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 619d2b37d8d..095354c2f4c 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -89,9 +89,9 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
 // do anything (and certainly not add a `#NaN` to the URL!).
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 88, "y": 86})
+assert-position: ("//*[@id='1']", {"x": 88, "y": 163})
 // We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
-click: (87, 77)
+click: (163, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
 // Checking the source code sidebar.
@@ -159,19 +159,21 @@ call-function: ("check-sidebar-dir-entry", {
 // Check the search form
 assert-css: ("nav.sub", {"flex-direction": "row"})
 // The goal of this test is to ensure the search input is perfectly centered
-// between the top of the page and the top of the gray code block.
+// between the top of the page and the header.
 // To check this, we maintain the invariant:
 //
 // offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
-assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 64})
+assert-position: ("nav.sub form", {"y": 15})
+assert-property: ("nav.sub form", {"offsetHeight": 34})
+assert-position: ("h1", {"y": 64})
 // 15 = 64 - 34 - 15
 
 // Now do the same check on moderately-sized, tablet mobile.
 set-window-size: (700, 700)
 assert-css: ("nav.sub", {"flex-direction": "row"})
-assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 50})
+assert-position: ("nav.sub form", {"y": 8})
+assert-property: ("nav.sub form", {"offsetHeight": 34})
+assert-position: ("h1", {"y": 50})
 // 8 = 50 - 34 - 8
 
 // Check the sidebar directory entries have a marker and spacing (tablet).
diff --git a/tests/rustdoc-gui/src/theme_css/custom-theme.css b/tests/rustdoc-gui/src/theme_css/custom-theme.css
index 366f09f22b2..5ea5009fb2e 100644
--- a/tests/rustdoc-gui/src/theme_css/custom-theme.css
+++ b/tests/rustdoc-gui/src/theme_css/custom-theme.css
@@ -52,6 +52,8 @@
 	--search-tab-button-selected-border-top-color: #0089ff;
 	--search-tab-button-selected-background: #fff;
 	--settings-menu-filter: none;
+	--settings-menu-hover-filter: invert(35%);
+	--settings-menu-disabled-filter: invert(14%) sepia(11%) saturate(14%) hue-rotate(337deg);
 	--stab-background-color: #fff5d6;
 	--stab-code-color: #000;
 	--code-highlight-kw-color: #8959a8;
diff --git a/tests/rustdoc-gui/toggle-click-deadspace.goml b/tests/rustdoc-gui/toggle-click-deadspace.goml
index 37bc3f7c372..caca1b61493 100644
--- a/tests/rustdoc-gui/toggle-click-deadspace.goml
+++ b/tests/rustdoc-gui/toggle-click-deadspace.goml
@@ -12,4 +12,5 @@ assert-attribute-false: (".impl-items .toggle", {"open": ""})
 
 // Click the "Trait" part of "impl Trait" and verify it navigates.
 click: "#impl-Trait-for-Foo h3 a:first-of-type"
-assert-text: (".main-heading h1", "Trait lib2::TraitCopy item path")
+assert-text: (".main-heading .rustdoc-breadcrumbs", "lib2")
+assert-text: (".main-heading h1", "Trait TraitCopy item path")
diff --git a/tests/rustdoc-gui/toggle-docs-mobile.goml b/tests/rustdoc-gui/toggle-docs-mobile.goml
index b69aa6e30ca..59233d94fcc 100644
--- a/tests/rustdoc-gui/toggle-docs-mobile.goml
+++ b/tests/rustdoc-gui/toggle-docs-mobile.goml
@@ -3,12 +3,12 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 set-window-size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 270) // This is the position of the top doc comment toggle
+click: (4, 260) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 270)
+click: (4, 260)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 270)
+click: (3, 260)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
@@ -24,10 +24,10 @@ assert-position: (
 // Now we do the same but with a little bigger width
 set-window-size: (600, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 270) // New Y position since all search elements are back on one line.
+click: (4, 260) // New Y position since all search elements are back on one line.
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 270)
+click: (4, 260)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 270)
+click: (3, 260)
 assert-attribute: (".top-doc", {"open": ""})
diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml
index 1235ee4b754..4607c604eeb 100644
--- a/tests/rustdoc-gui/toggle-docs.goml
+++ b/tests/rustdoc-gui/toggle-docs.goml
@@ -2,12 +2,12 @@
 include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-attribute: ("#main-content > details.top-doc", {"open": ""})
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 click: "#toggle-all-docs"
 wait-for: 50
 // This is now collapsed so there shouldn't be the "open" attribute on details.
 assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
-assert-text: ("#toggle-all-docs", "[+]")
+assert-text: ("#toggle-all-docs", "Show all")
 assert-css: (
     "#main-content > details.top-doc > summary",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
@@ -15,12 +15,12 @@ assert-css: (
 click: "#toggle-all-docs"
 // Not collapsed anymore so the "open" attribute should be back.
 wait-for-attribute: ("#main-content > details.top-doc", {"open": ""})
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 
 // Check that it works on non-module pages as well.
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 // We first check that everything is visible.
-assert-text: ("#toggle-all-docs", "[−]")
+assert-text: ("#toggle-all-docs", "Summary")
 assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
 assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
 assert-attribute-false: (
@@ -31,7 +31,7 @@ assert-attribute-false: (
 
 // We collapse them all.
 click: "#toggle-all-docs"
-wait-for-text: ("#toggle-all-docs", "[+]")
+wait-for-text: ("#toggle-all-docs", "Show all")
 // We check that all <details> are collapsed (except for the impl block ones).
 assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
 assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
@@ -43,7 +43,7 @@ assert-attribute-false: (
 )
 // We open them all again.
 click: "#toggle-all-docs"
-wait-for-text: ("#toggle-all-docs", "[−]")
+wait-for-text: ("#toggle-all-docs", "Summary")
 assert-attribute: ("details.toggle", {"open": ""}, ALL)
 
 // Checking the toggles style.
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index 8df946c6f39..4f8fe78ea4d 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -51,22 +51,23 @@ store-property: (".mobile-topbar", {"scrollWidth": scrollWidth})
 assert-property: (".mobile-topbar", {"clientWidth": |scrollWidth|})
 assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
 
-// Check wrapping for top main-heading h1 and out-of-band.
-// On desktop, they wrap when too big.
+// Check that main heading and toolbar go side-by-side, both on desktop and on mobile.
 set-window-size: (1100, 800)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
-// make sure there is a gap between them
-compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
 
 // On mobile, they always wrap.
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
 
 // Now we will check that the scrolling is working.
 // First on an item with "hidden methods".
diff --git a/tests/rustdoc/empty-mod-private.rs b/tests/rustdoc/empty-mod-private.rs
index 4e408e3d424..5a8638cd5f5 100644
--- a/tests/rustdoc/empty-mod-private.rs
+++ b/tests/rustdoc/empty-mod-private.rs
@@ -2,15 +2,18 @@
 
 //@ has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
 //@ hasraw 'empty_mod_private/sidebar-items.js' 'foo'
-//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo'
+//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module foo'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
 mod foo {}
 
 //@ has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar'
 //@ hasraw 'empty_mod_private/sidebar-items.js' 'bar'
-//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar'
+//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module bar'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
 mod bar {
     //@ has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
     //@ hasraw 'empty_mod_private/bar/sidebar-items.js' 'baz'
-    //@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz'
+    //@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module baz'
+    //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private::bar'
     mod baz {}
 }
diff --git a/tests/rustdoc/empty-mod-public.rs b/tests/rustdoc/empty-mod-public.rs
index b5a63525524..f06ac69f3ed 100644
--- a/tests/rustdoc/empty-mod-public.rs
+++ b/tests/rustdoc/empty-mod-public.rs
@@ -1,14 +1,17 @@
 //@ has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo'
 //@ hasraw 'empty_mod_public/sidebar-items.js' 'foo'
-//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo'
+//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module foo'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
 pub mod foo {}
 
 //@ has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar'
 //@ hasraw 'empty_mod_public/sidebar-items.js' 'bar'
-//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar'
+//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module bar'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
 pub mod bar {
     //@ has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
     //@ hasraw 'empty_mod_public/bar/sidebar-items.js' 'baz'
-    //@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz'
+    //@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module baz'
+    //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public::bar'
     pub mod baz {}
 }
diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/html-no-source.rs
index 100ab0031f7..248afbd00ef 100644
--- a/tests/rustdoc/html-no-source.rs
+++ b/tests/rustdoc/html-no-source.rs
@@ -11,14 +11,14 @@
 //@ files 'src/foo' '[]'
 
 //@ has foo/fn.foo.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
-//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
+//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "bar", since = "1.0")]
 pub fn foo() {}
 
 //@ has foo/struct.Bar.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
-//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
+//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "bar", since = "1.0")]
 pub struct Bar;
 
diff --git a/tests/rustdoc/inline_cross/renamed-via-module.rs b/tests/rustdoc/inline_cross/renamed-via-module.rs
index bdaf2cf1f62..8bcdd9f7a39 100644
--- a/tests/rustdoc/inline_cross/renamed-via-module.rs
+++ b/tests/rustdoc/inline_cross/renamed-via-module.rs
@@ -10,15 +10,19 @@ extern crate foo;
 //@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
 //@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
 //@ has foo/iter/struct.DeprecatedStepBy.html
-//@ has - '//h1' "Struct foo::iter::DeprecatedStepBy"
+//@ has - '//h1' "Struct DeprecatedStepBy"
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
 //@ has foo/iter/struct.StepBy.html
-//@ has - '//h1' "Struct foo::iter::StepBy"
+//@ has - '//h1' "Struct StepBy"
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
 
 //@ has bar/iter/index.html
 //@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
 //@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
 //@ has bar/iter/struct.DeprecatedStepBy.html
-//@ has - '//h1' "Struct bar::iter::DeprecatedStepBy"
+//@ has - '//h1' "Struct DeprecatedStepBy"
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
 //@ has bar/iter/struct.StepBy.html
-//@ has - '//h1' "Struct bar::iter::StepBy"
+//@ has - '//h1' "Struct StepBy"
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
 pub use foo::iter;
diff --git a/tests/rustdoc/keyword.rs b/tests/rustdoc/keyword.rs
index 0157c35288e..519e1944bc7 100644
--- a/tests/rustdoc/keyword.rs
+++ b/tests/rustdoc/keyword.rs
@@ -6,7 +6,6 @@
 //@ has foo/index.html '//a[@href="keyword.match.html"]' 'match'
 //@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
 //@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
-//@ has foo/keyword.match.html '//a[@class="keyword"]' 'match'
 //@ has foo/keyword.match.html '//h1' 'Keyword match'
 //@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 //@ has foo/index.html '//a/@href' '../foo/index.html'
diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs
index c12d65ee0c5..bd6b2a32f75 100644
--- a/tests/rustdoc/primitive-reference.rs
+++ b/tests/rustdoc/primitive-reference.rs
@@ -8,7 +8,6 @@
 //@ has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
 //@ has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
 //@ has foo/primitive.reference.html
-//@ has - '//a[@class="primitive"]' 'reference'
 //@ has - '//h1' 'Primitive Type reference'
 //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 
diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive-slice-auto-trait.rs
index a877b73cf9f..e78d1d94614 100644
--- a/tests/rustdoc/primitive-slice-auto-trait.rs
+++ b/tests/rustdoc/primitive-slice-auto-trait.rs
@@ -3,8 +3,7 @@
 #![crate_name = "foo"]
 #![feature(rustc_attrs)]
 
-//@ has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
-//@ has - '//h1' 'Primitive Type slice'
+//@ has foo/primitive.slice.html '//h1' 'Primitive Type slice'
 //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive-tuple-auto-trait.rs
index 060c4ecfbdc..045478e6b4f 100644
--- a/tests/rustdoc/primitive-tuple-auto-trait.rs
+++ b/tests/rustdoc/primitive-tuple-auto-trait.rs
@@ -3,8 +3,7 @@
 #![crate_name = "foo"]
 #![feature(rustc_attrs)]
 
-//@ has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
-//@ has - '//h1' 'Primitive Type tuple'
+//@ has foo/primitive.tuple.html '//h1' 'Primitive Type tuple'
 //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive-unit-auto-trait.rs
index 7751a2bf1d0..6cae094c21c 100644
--- a/tests/rustdoc/primitive-unit-auto-trait.rs
+++ b/tests/rustdoc/primitive-unit-auto-trait.rs
@@ -3,8 +3,7 @@
 #![crate_name = "foo"]
 #![feature(rustc_attrs)]
 
-//@ has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
-//@ has - '//h1' 'Primitive Type unit'
+//@ has foo/primitive.unit.html '//h1' 'Primitive Type unit'
 //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'
diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs
index a998c538eed..9709bbe3c71 100644
--- a/tests/rustdoc/source-version-separator.rs
+++ b/tests/rustdoc/source-version-separator.rs
@@ -3,7 +3,7 @@
 #![feature(staged_api)]
 
 //@ has foo/trait.Bar.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "bar", since = "1.0")]
 pub trait Bar {
     //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
@@ -14,7 +14,7 @@ pub trait Bar {
 //@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
 
 //@ has foo/struct.Foo.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "baz", since = "1.0")]
 pub struct Foo;
 
diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs
index bdf950b0a62..922068adc59 100644
--- a/tests/rustdoc/titles.rs
+++ b/tests/rustdoc/titles.rs
@@ -5,53 +5,65 @@
 //@ matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo'
 //@ count 'foo/index.html' '//h2[@class="location"]' 0
 
-//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
-//@ matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
+//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo_mod'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
+//@ matches - '//h2[@class="location"]' 'Module foo_mod'
 pub mod foo_mod {
     pub struct __Thing {}
 }
 
 extern "C" {
-    //@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn'
+    //@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo_ffn'
+    //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
     pub fn foo_ffn();
 }
 
-//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn'
+//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo_fn'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
 pub fn foo_fn() {}
 
-//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
-//@ matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
+//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait FooTrait'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
+//@ matches - '//h2[@class="location"]' 'FooTrait'
 pub trait FooTrait {}
 
-//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
-//@ matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
+//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct FooStruct'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
+//@ matches - '//h2[@class="location"]' 'FooStruct'
 pub struct FooStruct;
 
-//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
-//@ matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
+//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum FooEnum'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
+//@ matches - '//h2[@class="location"]' 'FooEnum'
 pub enum FooEnum {}
 
-//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias foo::FooType'
-//@ matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
+//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias FooType'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
+//@ matches - '//h2[@class="location"]' 'FooType'
 pub type FooType = FooStruct;
 
-//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
+//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo_macro'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
 #[macro_export]
 macro_rules! foo_macro {
     () => {};
 }
 
 //@ matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
+//@ count - '//*[@class="rustdoc-breadcrumbs"]' 0
 #[rustc_doc_primitive = "bool"]
 mod bool {}
 
-//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'
+//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static FOO_STATIC'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
 pub static FOO_STATIC: FooStruct = FooStruct;
 
 extern "C" {
-    //@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC'
+    //@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static FOO_FSTATIC'
+    //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
     pub static FOO_FSTATIC: FooStruct;
 }
 
-//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT'
+//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant FOO_CONSTANT'
+//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
 pub const FOO_CONSTANT: FooStruct = FooStruct;
diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/version-separator-without-source.rs
index e439681484c..7cd1780f1d3 100644
--- a/tests/rustdoc/version-separator-without-source.rs
+++ b/tests/rustdoc/version-separator-without-source.rs
@@ -4,14 +4,14 @@
 #![crate_name = "foo"]
 
 //@ has foo/fn.foo.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
-//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
+//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "bar", since = "1.0")]
 pub fn foo() {}
 
 //@ has foo/struct.Bar.html
-//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
-//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
+//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
 #[stable(feature = "bar", since = "1.0")]
 pub struct Bar;
 
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs
index 3320e627812..5724293f145 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.rs
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs
@@ -1,6 +1,3 @@
-#![feature(const_intrinsic_copy)]
-
-
 const MISALIGNED_LOAD: () = unsafe {
     let mem = [0u32; 8];
     let ptr = mem.as_ptr().byte_add(1);
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
index aeb46725c06..3426a768cb6 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
@@ -1,11 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-pointer-ub.rs:7:16
+  --> $DIR/raw-pointer-ub.rs:4:16
    |
 LL |     let _val = *ptr;
    |                ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-pointer-ub.rs:14:5
+  --> $DIR/raw-pointer-ub.rs:11:5
    |
 LL |     *ptr = 0;
    |     ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
@@ -20,19 +20,19 @@ note: inside `copy_nonoverlapping::<u32>`
 note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `MISALIGNED_COPY`
-  --> $DIR/raw-pointer-ub.rs:22:5
+  --> $DIR/raw-pointer-ub.rs:19:5
    |
 LL |     y.copy_to_nonoverlapping(&mut z, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-pointer-ub.rs:34:16
+  --> $DIR/raw-pointer-ub.rs:31:16
    |
 LL |     let _val = (*ptr).0;
    |                ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-pointer-ub.rs:41:16
+  --> $DIR/raw-pointer-ub.rs:38:16
    |
 LL |     let _val = *ptr;
    |                ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 which is only 4 bytes from the end of the allocation
diff --git a/tests/ui/lint/improper-types-stack-overflow-130310.rs b/tests/ui/lint/improper-types-stack-overflow-130310.rs
deleted file mode 100644
index 60eb8739817..00000000000
--- a/tests/ui/lint/improper-types-stack-overflow-130310.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Regression test for #130310
-// Tests that we do not fall into infinite
-// recursion while checking FFI safety of
-// recursive types like `A<T>` below
-
-//@ build-pass
-use std::marker::PhantomData;
-
-#[repr(C)]
-struct A<T> {
-    a: *const A<A<T>>, // Recursive because of this field
-    p: PhantomData<T>,
-}
-
-extern "C" {
-    fn f(a: *const A<()>);
-    //~^ WARN `extern` block uses type `*const A<()>`, which is not FFI-safe
-}
-
-fn main() {}
diff --git a/tests/ui/lint/improper-types-stack-overflow-130310.stderr b/tests/ui/lint/improper-types-stack-overflow-130310.stderr
deleted file mode 100644
index 6981bb25755..00000000000
--- a/tests/ui/lint/improper-types-stack-overflow-130310.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: `extern` block uses type `*const A<()>`, which is not FFI-safe
-  --> $DIR/improper-types-stack-overflow-130310.rs:16:13
-   |
-LL |     fn f(a: *const A<()>);
-   |             ^^^^^^^^^^^^ not FFI-safe
-   |
-   = note: type is infinitely recursive
-   = note: `#[warn(improper_ctypes)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs b/tests/ui/lint/lint-ctypes-non-recursion-limit.rs
new file mode 100644
index 00000000000..61e95dc5a46
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-non-recursion-limit.rs
@@ -0,0 +1,32 @@
+//@ check-pass
+
+#![recursion_limit = "5"]
+#![allow(unused)]
+#![deny(improper_ctypes)]
+
+#[repr(C)]
+struct F1(*const ());
+#[repr(C)]
+struct F2(*const ());
+#[repr(C)]
+struct F3(*const ());
+#[repr(C)]
+struct F4(*const ());
+#[repr(C)]
+struct F5(*const ());
+#[repr(C)]
+struct F6(*const ());
+
+#[repr(C)]
+struct B {
+    f1: F1,
+    f2: F2,
+    f3: F3,
+    f4: F4,
+    f5: F5,
+    f6: F6,
+}
+
+extern "C" fn foo(_: B) {}
+
+fn main() {}