about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_arena/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs3
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_fluent_macro/src/lib.rs3
-rw-r--r--compiler/rustc_graphviz/src/lib.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs3
-rw-r--r--compiler/rustc_incremental/src/lib.rs3
-rw-r--r--compiler/rustc_infer/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_metadata/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs13
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs3
-rw-r--r--compiler/rustc_privacy/src/lib.rs3
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/src/lib.rs3
-rw-r--r--compiler/rustc_smir/src/lib.rs3
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs3
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs3
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs3
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/test/src/lib.rs2
-rw-r--r--src/doc/rustdoc/src/unstable-features.md15
-rw-r--r--src/librustdoc/html/layout.rs37
-rw-r--r--src/librustdoc/html/render/context.rs19
-rw-r--r--src/librustdoc/html/render/mod.rs1
-rw-r--r--src/librustdoc/html/render/sidebar.rs24
-rw-r--r--src/librustdoc/html/render/write_shared.rs3
-rw-r--r--src/librustdoc/html/sources.rs3
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css86
-rw-r--r--src/librustdoc/html/static/js/main.js40
-rw-r--r--src/librustdoc/html/templates/page.html51
-rw-r--r--src/librustdoc/html/templates/sidebar.html5
-rw-r--r--src/tools/compiletest/src/header.rs10
-rw-r--r--tests/rustdoc-gui/anchors.goml2
-rw-r--r--tests/rustdoc-gui/huge-logo.goml4
-rw-r--r--tests/rustdoc-gui/rust-logo.goml15
-rw-r--r--tests/rustdoc-gui/sidebar-mobile.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml4
-rw-r--r--tests/rustdoc-gui/sidebar.goml37
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml8
-rw-r--r--tests/rustdoc-gui/source-code-page.goml21
-rw-r--r--tests/rustdoc-gui/src/staged_api/lib.rs2
-rw-r--r--tests/rustdoc/crate-version-escape.rs2
-rw-r--r--tests/rustdoc/crate-version-extra.rs7
-rw-r--r--tests/rustdoc/crate-version.rs2
-rw-r--r--tests/rustdoc/logo-class-default.rs6
-rw-r--r--tests/rustdoc/logo-class-rust.rs7
-rw-r--r--tests/rustdoc/logo-class.rs2
-rw-r--r--tests/rustdoc/titles.rs3
-rw-r--r--tests/ui/feature-gates/doc-rust-logo.rs5
-rw-r--r--tests/ui/feature-gates/doc-rust-logo.stderr12
64 files changed, 433 insertions, 99 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index bf8a7eb293e..54274f15356 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -11,6 +11,8 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(no_crate_inject, attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(new_uninit)]
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index b07ed1d1c74..ddc7c8ee825 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -8,6 +8,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(const_trait_impl)]
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index f6186a290f8..b4728ac2aa6 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 1b3f39e69e1..17556c45296 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -5,6 +5,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(lazy_cell)]
 #![feature(decl_macro)]
 #![feature(panic_update_hook)]
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 665b5d6adec..63226504d37 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -3,6 +3,8 @@
 //! This module contains the code for creating and emitting diagnostics.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs
index a01643cd67d..191fb787f70 100644
--- a/compiler/rustc_fluent_macro/src/lib.rs
+++ b/compiler/rustc_fluent_macro/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_span)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 5d86d895817..9cb279e3efd 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -273,6 +273,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 03963925d3d..c7b3648099c 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -57,6 +57,9 @@ This API is completely unstable and subject to change.
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 220ea194a6d..472dfe3dc4a 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,6 +2,9 @@
 
 #![deny(missing_docs)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index e92ba05aa67..4a6d1bc682b 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -13,6 +13,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index af2132fb899..d7a666aa72b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -27,6 +27,8 @@
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index eb70961503d..518c20c9fa8 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,6 +1,9 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 // NOTE: This crate only exists to allow linking on mingw targets.
 
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index fa77b36c4c5..ddeb39669dc 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(decl_macro)]
 #![feature(extract_if)]
 #![feature(generators)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fe4fc3761b3..dee18dc1162 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -23,6 +23,8 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 90ac436a91f..7b6153eea09 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -9,6 +9,9 @@
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 // We want to be able to build this crate with a stable compiler, so no
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 52fb193f3da..fbf3dff7560 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1108,6 +1108,7 @@ impl CheckAttrVisitor<'_> {
                         | sym::html_root_url
                         | sym::html_no_source
                         | sym::test
+                        | sym::rust_logo
                             if !self.check_attr_crate_level(attr, meta, hir_id) =>
                         {
                             is_valid = false;
@@ -1166,6 +1167,18 @@ impl CheckAttrVisitor<'_> {
                         | sym::plugins
                         | sym::fake_variadic => {}
 
+                        sym::rust_logo => {
+                            if !self.tcx.features().rustdoc_internals {
+                                feature_err(
+                                    &self.tcx.sess.parse_sess,
+                                    sym::rustdoc_internals,
+                                    meta.span(),
+                                    "the `#[doc(rust_logo)]` attribute is used for Rust branding",
+                                )
+                                .emit();
+                            }
+                        }
+
                         sym::test => {
                             if !self.check_test_attr(meta, hir_id) {
                                 is_valid = false;
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 51f3c9ad76f..946a9e68da6 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,6 +6,9 @@
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index faa7495ef9f..0e1c80a1f64 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -7,6 +7,9 @@
 //! of the Unstable Book for some examples.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ab85f680fcf..21d7bcbed5e 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_defaults)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 30621a135eb..a1465dabed6 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,6 +1,8 @@
 //! Support for serializing the dep-graph and reloading it.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 // this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref
 #![feature(const_mut_refs)]
 #![feature(const_refs_to_cell)]
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 5f012ec29fe..0bc45967e3d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -7,6 +7,8 @@
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(extract_if)]
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 5360aa9ea6a..cfa54072eb9 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -5,6 +5,9 @@
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(allocator_api)]
 #![feature(associated_type_bounds)]
 #![feature(const_option)]
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index d10f46fad9e..c24b9efe865 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -10,6 +10,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 pub mod rustc_internal;
 
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 6fd61e45fcc..e62efab5793 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -14,6 +14,8 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(if_let_guard)]
 #![feature(negative_impls)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a62fa246ac4..ea261923c65 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1327,6 +1327,7 @@ symbols! {
         rust_cold_cc,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
+        rust_logo,
         rustc,
         rustc_abi,
         rustc_allocator,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 535a3ea2d7e..6ade2d777c7 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -88,6 +88,9 @@
 //! DefPaths which are much more robust in the face of changes to the code base.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index e838e11131f..9c5ce889418 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -8,6 +8,8 @@
 //! LLVM.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 56d37d58de7..5ba29f87855 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,6 +11,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 147b600f7ba..1a9de150041 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(assert_matches)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cd3648214a4..d47f9de941c 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -78,6 +78,8 @@
     not(no_sync),
     target_has_atomic = "ptr"
 ))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![no_std]
 #![needs_allocator]
 // Lints:
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 7fa7e83a744..906421327cb 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -68,6 +68,7 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(cfg_hide(
     not(test),
     any(not(feature = "miri-test-libstd"), test, doctest),
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 0a70c488aec..991fdb1256d 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -17,6 +17,8 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 // This library is copied into rust-analyzer to allow loading rustc compiled proc macros.
 // Please avoid unstable features where possible to minimize the amount of changes necessary
 // to make it compile with rust-analyzer on stable.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 02f4d5bc7ae..aaf20875129 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -227,6 +227,7 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(cfg_hide(
     not(test),
     not(any(test, bootstrap)),
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 413f0fba342..bddf75dffbb 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -16,6 +16,8 @@
 
 #![unstable(feature = "test", issue = "50297")]
 #![doc(test(attr(deny(warnings))))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(internal_output_capture)]
 #![feature(staged_api)]
 #![feature(process_exitcode_internals)]
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 7473b09920f..199b5d69a1c 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -207,6 +207,21 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
 mod empty_mod {}
 ```
 
+### Use the Rust logo as the crate logo
+
+This is for official Rust project use only.
+
+Internal Rustdoc pages like settings.html and scrape-examples-help.html show the Rust logo.
+This logo is tracked as a static resource. The attribute `#![doc(rust_logo)]` makes this same
+built-in resource act as the main logo.
+
+```rust
+#![feature(rustdoc_internals)]
+#![allow(internal_features)]
+#![doc(rust_logo)]
+//! This crate has the Rust(tm) branding on it.
+```
+
 ## Effects of other nightly features
 
 These nightly-only features are not primarily related to Rustdoc,
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 8c5871d9126..d4b4db0f3fd 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -17,6 +17,7 @@ pub(crate) struct Layout {
     pub(crate) external_html: ExternalHtml,
     pub(crate) default_settings: FxHashMap<String, String>,
     pub(crate) krate: String,
+    pub(crate) krate_version: String,
     /// The given user css file which allow to customize the generated
     /// documentation theme.
     pub(crate) css_file_extension: Option<PathBuf>,
@@ -31,6 +32,7 @@ pub(crate) struct Page<'a> {
     pub(crate) static_root_path: Option<&'a str>,
     pub(crate) description: &'a str,
     pub(crate) resource_suffix: &'a str,
+    pub(crate) rust_logo: bool,
 }
 
 impl<'a> Page<'a> {
@@ -54,9 +56,19 @@ struct PageLayout<'a> {
     themes: Vec<String>,
     sidebar: String,
     content: String,
-    krate_with_trailing_slash: String,
     rust_channel: &'static str,
     pub(crate) rustdoc_version: &'a str,
+    // same as layout.krate, except on top-level pages like
+    // Settings, Help, All Crates, and About Scraped Examples,
+    // where these things instead give Rustdoc name and version.
+    //
+    // These are separate from the variables used for the search
+    // engine, because "Rustdoc" isn't necessarily a crate in
+    // the current workspace.
+    display_krate: &'a str,
+    display_krate_with_trailing_slash: String,
+    display_krate_version_number: &'a str,
+    display_krate_version_extra: &'a str,
 }
 
 pub(crate) fn render<T: Print, S: Print>(
@@ -66,12 +78,26 @@ pub(crate) fn render<T: Print, S: Print>(
     t: T,
     style_files: &[StylePath],
 ) -> String {
+    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
+
+    let (display_krate, display_krate_version, display_krate_with_trailing_slash) =
+        if page.root_path == "./" {
+            // top level pages use Rust branding
+            ("Rustdoc", rustdoc_version, String::new())
+        } else {
+            let display_krate_with_trailing_slash =
+                ensure_trailing_slash(&layout.krate).to_string();
+            (&layout.krate[..], &layout.krate_version[..], display_krate_with_trailing_slash)
+        };
     let static_root_path = page.get_static_root_path();
-    let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
+
+    // bootstrap passes in parts of the version separated by tabs, but other stuff might use spaces
+    let (display_krate_version_number, display_krate_version_extra) =
+        display_krate_version.split_once([' ', '\t']).unwrap_or((display_krate_version, ""));
+
     let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
     themes.sort();
 
-    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
     let sidebar = Buffer::html().to_display(sidebar);
     PageLayout {
@@ -82,7 +108,10 @@ pub(crate) fn render<T: Print, S: Print>(
         themes,
         sidebar,
         content,
-        krate_with_trailing_slash,
+        display_krate,
+        display_krate_with_trailing_slash,
+        display_krate_version_number,
+        display_krate_version_extra,
         rust_channel: *crate::clean::utils::DOC_CHANNEL,
         rustdoc_version,
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 97714afaa45..bf8d1a80337 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -24,6 +24,7 @@ use super::{
     sidebar::{sidebar_module_like, Sidebar},
     AllTypes, LinkFromSrc, StylePath,
 };
+use crate::clean::utils::has_doc_flag;
 use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem};
 use crate::config::{ModuleSorting, RenderOptions};
 use crate::docfs::{DocFS, PathError};
@@ -277,6 +278,7 @@ impl<'tcx> Context<'tcx> {
                 title: &title,
                 description: &desc,
                 resource_suffix: &clone_shared.resource_suffix,
+                rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
             };
             let mut page_buffer = Buffer::html();
             print_item(self, it, &mut page_buffer, &page);
@@ -528,12 +530,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         if let Some(url) = playground_url {
             playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
         }
+        let krate_version = cache.crate_version.as_deref().unwrap_or_default();
         let mut layout = layout::Layout {
             logo: String::new(),
             favicon: String::new(),
             external_html,
             default_settings,
             krate: krate.name(tcx).to_string(),
+            krate_version: krate_version.to_string(),
             css_file_extension: extension_css,
             scrape_examples_extension: !call_locations.is_empty(),
         };
@@ -658,21 +662,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let shared = Rc::clone(&self.shared);
         let mut page = layout::Page {
             title: "List of all items in this crate",
-            css_class: "mod",
+            css_class: "mod sys",
             root_path: "../",
             static_root_path: shared.static_root_path.as_deref(),
             description: "List of all items in this crate",
             resource_suffix: &shared.resource_suffix,
+            rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
         let all = shared.all.replace(AllTypes::new());
         let mut sidebar = Buffer::html();
 
         let blocks = sidebar_module_like(all.item_sections());
         let bar = Sidebar {
-            title_prefix: "Crate ",
-            title: crate_name.as_str(),
+            title_prefix: "",
+            title: "",
             is_crate: false,
-            version: "",
+            is_mod: false,
             blocks: vec![blocks],
             path: String::new(),
         };
@@ -689,9 +694,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         shared.fs.write(final_file, v)?;
 
         // Generating settings page.
-        page.title = "Rustdoc settings";
+        page.title = "Settings";
         page.description = "Settings of Rustdoc";
         page.root_path = "./";
+        page.rust_logo = true;
 
         let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
         let v = layout::render(
@@ -739,9 +745,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         shared.fs.write(settings_file, v)?;
 
         // Generating help page.
-        page.title = "Rustdoc help";
+        page.title = "Help";
         page.description = "Documentation for Rustdoc";
         page.root_path = "./";
+        page.rust_logo = true;
 
         let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
         let v = layout::render(
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index b0ce475850c..49817f5eb64 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2094,6 +2094,7 @@ impl ItemSection {
     const ALL: &'static [Self] = {
         use ItemSection::*;
         // NOTE: The order here affects the order in the UI.
+        // Keep this synchronized with addSidebarItems in main.js
         &[
             Reexports,
             PrimitiveTypes,
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 3f8b22050c8..fb429f237e3 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -19,7 +19,7 @@ pub(super) struct Sidebar<'a> {
     pub(super) title_prefix: &'static str,
     pub(super) title: &'a str,
     pub(super) is_crate: bool,
-    pub(super) version: &'a str,
+    pub(super) is_mod: bool,
     pub(super) blocks: Vec<LinkBlock<'a>>,
     pub(super) path: String,
 }
@@ -99,12 +99,12 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
         || it.is_primitive()
         || it.is_union()
         || it.is_enum()
-        || it.is_mod()
+        // crate title is displayed as part of logo lockup
+        || (it.is_mod() && !it.is_crate())
         || it.is_type_alias()
     {
         (
             match *it.kind {
-                clean::ModuleItem(..) if it.is_crate() => "Crate ",
                 clean::ModuleItem(..) => "Module ",
                 _ => "",
             },
@@ -113,14 +113,22 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
     } else {
         ("", "")
     };
-    let version =
-        if it.is_crate() { cx.cache().crate_version.as_deref().unwrap_or_default() } else { "" };
-    let path: String = if !it.is_mod() {
-        cx.current.iter().map(|s| s.as_str()).intersperse("::").collect()
+    // need to show parent path header if:
+    //   - it's a child module, instead of the crate root
+    //   - there's a sidebar section for the item itself
+    //
+    // otherwise, the parent path header is redundant with the big crate
+    // branding area at the top of the sidebar
+    let sidebar_path =
+        if it.is_mod() { &cx.current[..cx.current.len() - 1] } else { &cx.current[..] };
+    let path: String = if sidebar_path.len() > 1 || !title.is_empty() {
+        let path = sidebar_path.iter().map(|s| s.as_str()).intersperse("::").collect();
+        if sidebar_path.len() == 1 { format!("crate {path}") } else { path }
     } else {
         "".into()
     };
-    let sidebar = Sidebar { title_prefix, title, is_crate: it.is_crate(), version, blocks, path };
+    let sidebar =
+        Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path };
     sidebar.render_into(buffer).unwrap();
 }
 
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e824651e727..e68d5ab2fbd 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -336,11 +336,12 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
             let dst = cx.dst.join("index.html");
             let page = layout::Page {
                 title: "Index of crates",
-                css_class: "mod",
+                css_class: "mod sys",
                 root_path: "./",
                 static_root_path: shared.static_root_path.as_deref(),
                 description: "List of crates",
                 resource_suffix: &shared.resource_suffix,
+                rust_logo: true,
             };
 
             let content = format!(
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 1d6eafe51b9..4a218b9b37c 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -1,4 +1,5 @@
 use crate::clean;
+use crate::clean::utils::has_doc_flag;
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::html::format;
@@ -13,6 +14,7 @@ use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::FileName;
+use rustc_span::sym;
 
 use std::cell::RefCell;
 use std::ffi::OsStr;
@@ -231,6 +233,7 @@ impl SourceCollector<'_, '_> {
             static_root_path: shared.static_root_path.as_deref(),
             description: &desc,
             resource_suffix: &shared.resource_suffix,
+            rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
         let v = layout::render(
             &shared.layout,
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 47f9e650281..e2b4cc50dd5 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -461,19 +461,9 @@ img {
 	display: none !important;
 }
 
-.sidebar .logo-container {
-	margin-top: 10px;
-	margin-bottom: 10px;
-	text-align: center;
-}
-
-.version {
-	overflow-wrap: break-word;
-}
-
 .logo-container > img {
-	height: 100px;
-	width: 100px;
+	height: 48px;
+	width: 48px;
 }
 
 ul.block, .block li {
@@ -502,6 +492,7 @@ ul.block, .block li {
 }
 
 .sidebar-elems,
+.sidebar > .version,
 .sidebar > h2 {
 	padding-left: 24px;
 }
@@ -510,6 +501,8 @@ ul.block, .block li {
 	color: var(--sidebar-link-color);
 }
 .sidebar .current,
+.sidebar .current a,
+.sidebar-crate a.logo-container:hover + h2 a,
 .sidebar a:hover:not(.logo-container) {
 	background-color: var(--sidebar-current-link-background-color);
 }
@@ -524,6 +517,75 @@ ul.block, .block li {
 	overflow: hidden;
 }
 
+.sidebar-crate {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	/* there's a 10px padding at the top of <main>, and a 4px margin at the
+		top of the search form. To line them up, add them. */
+	margin: 14px 32px 1rem;
+	row-gap: 10px;
+	column-gap: 32px;
+	flex-wrap: wrap;
+}
+
+.sidebar-crate h2 {
+	flex-grow: 1;
+	/* This setup with the margins and row-gap is designed to make flex-wrap
+		work the way we want. If they're in the side-by-side lockup, there
+		should be a 16px margin to the left of the logo (visually the same as
+		the 24px one on everything else, which are not giant circles) and 8px
+		between it and the crate's name and version. When they're line wrapped,
+		the logo needs to have the same margin on both sides of itself (to
+		center properly) and the crate name and version need 24px on their
+		left margin. */
+	margin: 0 -8px;
+	/* To align this with the search bar, it should not be centered, even when
+		the logo is. */
+	align-self: start;
+}
+
+.sidebar-crate .logo-container {
+	/* The logo is expected to have 8px "slop" along its edges, so we can optically
+		center it. */
+	margin: 0 -16px 0 -16px;
+	text-align: center;
+}
+
+.sidebar-crate h2 a {
+	display: block;
+	margin: 0 calc(-24px + 0.25rem) 0 -0.5rem;
+	/* Align the sidebar crate link with the search bar, which have different
+		font sizes.
+
+		|        | font-size | line-height | total line-height | padding-y |     total    |
+		|:-------|----------:|------------:|------------------:|----------:|-------------:|
+		| crate  |  1.375rem |        1.25 |           1.72rem |         x |   2x+1.72rem |
+		| search |      1rem |        1.15 |           1.15rem |       8px | 1.15rem+16px |
+
+		2x + 1.72rem = 1.15rem + 16px
+		2x = 1.15rem + 16px - 1.72rem
+		2x = 16px - 0.57rem
+		x = ( 16px - 0.57rem ) / 2
+	*/
+	padding: calc( ( 16px - 0.57rem ) / 2 ) 0.25rem;
+	padding-left: 0.5rem;
+}
+
+.sidebar-crate h2 .version {
+	display: block;
+	font-weight: normal;
+	font-size: 1rem;
+	overflow-wrap: break-word;
+	/* opposite of the link padding, cut in half again */
+	margin-top: calc( ( -16px + 0.57rem ) / 2 );
+}
+
+.sidebar-crate + .version {
+	margin-top: -1rem;
+	margin-bottom: 1rem;
+}
+
 .mobile-topbar {
 	display: none;
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 43c4f2b6ff5..2e9897ef82b 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -51,9 +51,14 @@ function setMobileTopbar() {
     // but with the current code it's hard to get the right information in the right place.
     const mobileTopbar = document.querySelector(".mobile-topbar");
     const locationTitle = document.querySelector(".sidebar h2.location");
-    if (mobileTopbar && locationTitle) {
+    if (mobileTopbar) {
         const mobileTitle = document.createElement("h2");
-        mobileTitle.innerHTML = locationTitle.innerHTML;
+        mobileTitle.className = "location";
+        if (hasClass(document.body, "crate")) {
+            mobileTitle.innerText = `Crate ${window.currentCrate}`;
+        } else if (locationTitle) {
+            mobileTitle.innerHTML = locationTitle.innerHTML;
+        }
         mobileTopbar.appendChild(mobileTitle);
     }
 }
@@ -480,22 +485,27 @@ function preLoadCss(cssUrl) {
                 return;
             }
 
+            const modpath = hasClass(document.body, "mod") ? "../" : "";
+
             const h3 = document.createElement("h3");
-            h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
+            h3.innerHTML = `<a href="${modpath}index.html#${id}">${longty}</a>`;
             const ul = document.createElement("ul");
             ul.className = "block " + shortty;
 
             for (const name of filtered) {
                 let path;
                 if (shortty === "mod") {
-                    path = name + "/index.html";
+                    path = `${modpath}${name}/index.html`;
                 } else {
-                    path = shortty + "." + name + ".html";
+                    path = `${modpath}${shortty}.${name}.html`;
+                }
+                let current_page = document.location.href.toString();
+                if (current_page.endsWith("/")) {
+                    current_page += "index.html";
                 }
-                const current_page = document.location.href.split("/").pop();
                 const link = document.createElement("a");
                 link.href = path;
-                if (path === current_page) {
+                if (link.href === current_page) {
                     link.className = "current";
                 }
                 link.textContent = name;
@@ -508,19 +518,33 @@ function preLoadCss(cssUrl) {
         }
 
         if (sidebar) {
+            // keep this synchronized with ItemSection::ALL in html/render/mod.rs
+            // Re-exports aren't shown here, because they don't have child pages
+            //block("reexport", "reexports", "Re-exports");
             block("primitive", "primitives", "Primitive Types");
             block("mod", "modules", "Modules");
             block("macro", "macros", "Macros");
             block("struct", "structs", "Structs");
             block("enum", "enums", "Enums");
-            block("union", "unions", "Unions");
             block("constant", "constants", "Constants");
             block("static", "static", "Statics");
             block("trait", "traits", "Traits");
             block("fn", "functions", "Functions");
             block("type", "types", "Type Aliases");
+            block("union", "unions", "Unions");
+            // No point, because these items don't appear in modules
+            //block("impl", "impls", "Implementations");
+            //block("tymethod", "tymethods", "Type Methods");
+            //block("method", "methods", "Methods");
+            //block("structfield", "fields", "Fields");
+            //block("variant", "variants", "Variants");
+            //block("associatedtype", "associated-types", "Associated Types");
+            //block("associatedconstant", "associated-consts", "Associated Constants");
             block("foreigntype", "foreign-types", "Foreign Types");
             block("keyword", "keywords", "Keywords");
+            block("opaque", "opaque-types", "Opaque Types");
+            block("attr", "attributes", "Attribute Macros");
+            block("derive", "derives", "Derive Macros");
             block("traitalias", "trait-aliases", "Trait Aliases");
         }
     }
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 579c782be09..ebf817673bf 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -42,6 +42,8 @@
     <script defer src="{{page.root_path|safe}}src-files{{page.resource_suffix}}.js"></script> {# #}
     {% else if !page.css_class.contains("mod") %}
     <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {# #}
+    {% else if !page.css_class.contains("sys") %}
+    <script defer src="../sidebar-items{{page.resource_suffix}}.js"></script> {# #}
     {% endif %}
     <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {# #}
     {% if layout.scrape_examples_extension %}
@@ -77,36 +79,51 @@
     {% if page.css_class != "src" %}
     <nav class="mobile-topbar"> {# #}
         <button class="sidebar-menu-toggle">&#9776;</button> {# #}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-        {% if !layout.logo.is_empty() %}
-            <img src="{{layout.logo}}" alt="logo"> {# #}
-        {% else %}
-            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+        {% if !layout.logo.is_empty() || page.rust_logo %}
+        <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+        {% if page.rust_logo %}
+            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt=""> {# #}
+        {% else if !layout.logo.is_empty() %}
+            <img src="{{layout.logo}}" alt=""> {# #}
         {% endif %}
         </a> {# #}
+        {% endif %}
     </nav>
     {% endif %}
     <nav class="sidebar"> {# #}
         {% if page.css_class != "src" %}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-            {% if !layout.logo.is_empty() %}
-                <img src="{{layout.logo}}" alt="logo"> {# #}
-            {% else %}
-                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+        <div class="sidebar-crate">
+            {% if !layout.logo.is_empty() || page.rust_logo %}
+            <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+                {% if page.rust_logo %}
+                    <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+                {% else if !layout.logo.is_empty() %}
+                    <img src="{{layout.logo}}" alt="logo"> {# #}
+                {% endif %}
+            </a> {# #}
             {% endif %}
-        </a> {# #}
+            <h2> {# #}
+                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
+                {% if !display_krate_version_number.is_empty() %}
+                    <span class="version">{{+ display_krate_version_number}}</span>
+                {% endif %}
+            </h2> {# #}
+        </div> {# #}
+        {% if !display_krate_version_extra.is_empty() %}
+        <div class="version">{{+ display_krate_version_extra}}</div> {# #}
+        {% endif %}
         {% endif %}
         {{ sidebar|safe }}
     </nav> {# #}
     <main> {# #}
         {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
             <nav class="sub"> {# #}
-                {% if page.css_class == "src" %}
-                <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-                    {% if !layout.logo.is_empty() %}
-                        <img src="{{layout.logo}}" alt="logo"> {# #}
-                    {% else %}
-                        <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+                {% if page.css_class == "src" && (!layout.logo.is_empty() || page.rust_logo) %}
+                <a class="sub-logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+                    {% if page.rust_logo %}
+                    <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="{{display_krate}}"> {# #}
+                    {% else if !layout.logo.is_empty() %}
+                        <img src="{{layout.logo}}" alt="{{display_krate}}"> {# #}
                     {% endif %}
                 </a> {# #}
                 {% endif %}
diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html
index 01d476ad29f..a99198141e2 100644
--- a/src/librustdoc/html/templates/sidebar.html
+++ b/src/librustdoc/html/templates/sidebar.html
@@ -6,9 +6,6 @@
 <div class="sidebar-elems">
     {% if is_crate %}
         <ul class="block">
-            {% if !version.is_empty() %}
-                <li class="version">Version {{+ version}}</li>
-            {% endif %}
             <li><a id="all-types" href="all.html">All Items</a></li> {# #}
         </ul>
     {% endif %}
@@ -32,6 +29,6 @@
         </section>
     {% endif %}
     {% if !path.is_empty() %}
-        <h2><a href="index.html">In {{+ path}}</a></h2>
+        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a></h2>
     {% endif %}
 </div>
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 269d9384376..948439d6e79 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -322,7 +322,15 @@ impl TestProps {
                 );
 
                 if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
-                    self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
+                    self.compile_flags.extend(
+                        flags
+                            .split("'")
+                            .enumerate()
+                            .flat_map(|(i, f)| {
+                                if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
+                            })
+                            .map(|s| s.to_owned()),
+                    );
                 }
                 if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
                     panic!("`compiler-flags` directive should be spelled `compile-flags`");
diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml
index 30b83f0da38..72e0bcd77e0 100644
--- a/tests/rustdoc-gui/anchors.goml
+++ b/tests/rustdoc-gui/anchors.goml
@@ -56,7 +56,7 @@ define-function: (
 
         assert-css: ("#top-doc-prose-title", {"color": |title_color|})
 
-        assert-css: (".sidebar a", {"color": |sidebar_link_color|})
+        assert-css: (".sidebar .block a", {"color": |sidebar_link_color|})
         assert-css: (".main-heading h1 a", {"color": |title_color|})
 
         // We move the cursor over the "Implementations" title so the anchor is displayed.
diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml
index 6d3eb66068c..bfc24c3260d 100644
--- a/tests/rustdoc-gui/huge-logo.goml
+++ b/tests/rustdoc-gui/huge-logo.goml
@@ -4,8 +4,8 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html"
 
 set-window-size: (1280, 1024)
 // offsetWidth = width of sidebar
-assert-property: (".sidebar .logo-container", {"offsetWidth": "200", "offsetHeight": 100})
-assert-property: (".sidebar .logo-container img", {"offsetWidth": "100", "offsetHeight": 100})
+assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "48", "offsetHeight": 48})
+assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48})
 
 set-window-size: (400, 600)
 // offset = size + margin
diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml
index cd453aea276..696cab34dcc 100644
--- a/tests/rustdoc-gui/rust-logo.goml
+++ b/tests/rustdoc-gui/rust-logo.goml
@@ -1,18 +1,18 @@
 // This test ensures that the correct style is applied to the rust logo in the sidebar.
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
 
 define-function: (
     "check-logo",
     (theme, filter),
     block {
         // Going to the doc page.
-        go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
         // Changing theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
         assert-css: (".rust-logo", {"filter": |filter|})
         // Going to the source code page.
-        go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+        go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html"
         // Changing theme (since it's local files, the local storage works by folder).
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -26,6 +26,15 @@ define-function: (
         assert-false: ".rust-logo"
         // Check there is no filter.
         assert-css: (".sidebar .logo-container img", {"filter": "none"})
+        // Now we check that this page has no logo at all
+        go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        assert-false: ".rust-logo"
+        assert-false: ".logo-container"
+        assert-false: ".sub-logo-container"
+        go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+        assert-false: ".rust-logo"
+        assert-false: ".logo-container"
+        assert-false: ".sub-logo-container"
     },
 )
 
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index 4b8337ace3a..d3a82d9ebe6 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -26,7 +26,7 @@ assert-css: (".sidebar", {"left": "0px"})
 // Make sure the "struct Foo" header is hidden, since the mobile topbar already does it.
 assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='Foo']/parent::h2", {"display": "none"})
 // Make sure the global navigation is still here.
-assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In test_docs']/parent::h2", {"display": "block"})
+assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In crate test_docs']/parent::h2", {"display": "block"})
 
 // Click elsewhere.
 click: "body"
@@ -50,7 +50,7 @@ assert-position: ("#method\.must_use", {"y": 46})
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
-compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543.19})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544})
 
 // Now checking the background color of the sidebar.
 show-text: true
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 88546ed2549..cea4db1466b 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -174,14 +174,14 @@ click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-assert-window-property: {"pageYOffset": "2542"}
+assert-window-property: {"pageYOffset": "2516"}
 // Expanding the sidebar...
 click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "0px"})
 click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
 // The "scrollTop" property should be the same.
-assert-window-property: {"pageYOffset": "2542"}
+assert-window-property: {"pageYOffset": "2516"}
 
 // We now check that opening the sidebar and clicking a link will close it.
 // The behavior here on mobile is different than the behavior on desktop,
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 520481d3bba..eff66d803d2 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -50,9 +50,9 @@ set-local-storage: {"rustdoc-theme": "light"}
 // We reload the page so the local storage settings are being used.
 reload:
 
-assert-text: (".sidebar > .location", "Crate test_docs")
-// In modules, we only have one "location" element.
-assert-count: (".sidebar .location", 1)
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs")
+// Crate root has no "location" element
+assert-count: (".sidebar .location", 0)
 assert-count: (".sidebar h2", 1)
 assert-text: ("#all-types", "All Items")
 assert-css: ("#all-types", {"color": "#356da4"})
@@ -74,8 +74,9 @@ assert-text: ("#structs + .item-table .item-name > a", "Foo")
 click: "#structs + .item-table .item-name > a"
 
 // PAGE: struct.Foo.html
+assert-count: (".sidebar .sidebar-crate", 1)
 assert-count: (".sidebar .location", 1)
-assert-count: (".sidebar h2", 2)
+assert-count: (".sidebar h2", 3)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
 
@@ -94,7 +95,8 @@ click: ".sidebar-elems ul.crate > li:first-child > a"
 // PAGE: lib2/index.html
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
-assert-text: (".sidebar > .location", "Crate lib2")
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
+assert-count: (".sidebar .location", 0)
 // We check that we have the crates list and that the "current" on is now "lib2".
 assert-text: (".sidebar-elems ul.crate > li > a.current", "lib2")
 // We now go to the "foobar" function page.
@@ -108,22 +110,39 @@ click: "#functions + .item-table .item-name > a"
 
 // PAGE: fn.foobar.html
 // In items containing no items (like functions or constants) and in modules, we have no
-// "location" elements. Only the parent module h2.
+// "location" elements. Only the crate and optional parent module.
+// This page, being directly below the crate, only has its heading.
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-count: (".sidebar .location", 0)
 assert-count: (".sidebar h2", 1)
-assert-text: (".sidebar .sidebar-elems h2", "In lib2")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar > .location", "Module module")
+assert-count: (".sidebar .location", 1)
+// Module page requires three headings:
+//   - Presistent crate branding (name and version)
+//   - Module name, followed by TOC for module headings
+//   - "In crate [name]" parent pointer, followed by sibling navigation
+assert-count: (".sidebar h2", 3)
+assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2")
+assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+    "href": "/lib2/index.html",
+}, ENDS_WITH)
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./sub_module/sub_sub_module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar > .location", "Module sub_sub_module")
+assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module")
+assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+    "href": "/module/sub_module/index.html",
+}, ENDS_WITH)
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems .crate"
 assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions")
@@ -152,14 +171,14 @@ assert-property: (".sidebar", {"clientWidth": "200"})
 
 // Checks that all.html and index.html have their sidebar link in the same place.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-store-property: (".sidebar .location a", {
+store-property: (".sidebar .sidebar-crate h2 a", {
     "clientWidth": index_sidebar_width,
     "clientHeight": index_sidebar_height,
     "offsetTop": index_sidebar_y,
     "offsetLeft": index_sidebar_x,
 })
 go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
-assert-property: (".sidebar .location a", {
+assert-property: (".sidebar .sidebar-crate h2 a", {
     "clientWidth": |index_sidebar_width|,
     "clientHeight": |index_sidebar_height|,
     "offsetTop": |index_sidebar_y|,
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 0e4913cafb2..940851ea146 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": "149"})
+assert-property: ("html", {"scrollTop": "123"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "180"})
+assert-property: ("html", {"scrollTop": "154"})
 click: '//a[text() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "77"})
+assert-property: ("html", {"scrollTop": "51"})
 
 // 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": "77"})
+assert-property: ("html", {"scrollTop": "51"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index f19e3ce80e1..ad57380ae25 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": 112})
+assert-position: ("//*[@id='1']", {"x": 88, "y": 86})
 // We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
-click: (87, 103)
+click: (87, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
 // Checking the source code sidebar.
@@ -163,16 +163,16 @@ assert-css: ("nav.sub", {"flex-direction": "row"})
 // 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": 28, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 90})
-// 28 = 90 - 34 - 28
+assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 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": 21, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 76})
-// 21 = 76 - 34 - 21
+assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 50})
+// 8 = 50 - 34 - 8
 
 // Check the sidebar directory entries have a marker and spacing (tablet).
 store-property: ("#src-sidebar > .title", {
@@ -198,7 +198,12 @@ call-function: ("check-sidebar-dir-entry", {
     "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
 })
 
+// The logo is not present on this page.
+assert-false: ".sub-logo-container > img"
+
+// Check the staged-api page instead, which does.
 // Now we check that the logo has a bottom margin so it's not stuck to the search input.
+go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html"
 assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"})
 store-property: (".sub-logo-container", {"clientHeight": logo_height})
 assert-position: (".search-form", {"y": |logo_height| + 8})
diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs
index 0c914470e28..9b5ad1c5ff3 100644
--- a/tests/rustdoc-gui/src/staged_api/lib.rs
+++ b/tests/rustdoc-gui/src/staged_api/lib.rs
@@ -1,6 +1,8 @@
 #![feature(staged_api)]
+#![feature(rustdoc_internals)]
 #![allow(internal_features)]
 #![stable(feature = "some_feature", since = "1.3.5")]
+#![doc(rust_logo)]
 
 #[stable(feature = "some_feature", since = "1.3.5")]
 pub struct Foo {}
diff --git a/tests/rustdoc/crate-version-escape.rs b/tests/rustdoc/crate-version-escape.rs
index 8413709f15e..f134d9baa7d 100644
--- a/tests/rustdoc/crate-version-escape.rs
+++ b/tests/rustdoc/crate-version-escape.rs
@@ -2,4 +2,4 @@
 
 #![crate_name = "foo"]
 
-// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>'
+// @has 'foo/index.html' '//*[@class="version"]' '<script>alert("hi")</script>'
diff --git a/tests/rustdoc/crate-version-extra.rs b/tests/rustdoc/crate-version-extra.rs
new file mode 100644
index 00000000000..72a2c4ba5f7
--- /dev/null
+++ b/tests/rustdoc/crate-version-extra.rs
@@ -0,0 +1,7 @@
+// compile-flags: '--crate-version=1.3.37-nightly (203c57dbe 2023-09-17)'
+
+#![crate_name="foo"]
+
+// main version next to logo, extra version data below it
+// @has 'foo/index.html' '//h2/span[@class="version"]' '1.3.37-nightly'
+// @has 'foo/index.html' '//nav[@class="sidebar"]/div[@class="version"]' '(203c57dbe 2023-09-17)'
diff --git a/tests/rustdoc/crate-version.rs b/tests/rustdoc/crate-version.rs
index 2592c98530f..d4be845b71e 100644
--- a/tests/rustdoc/crate-version.rs
+++ b/tests/rustdoc/crate-version.rs
@@ -1,3 +1,3 @@
 // compile-flags: --crate-version=1.3.37
 
-// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37'
+// @has 'crate_version/index.html' '//*[@class="version"]' '1.3.37'
diff --git a/tests/rustdoc/logo-class-default.rs b/tests/rustdoc/logo-class-default.rs
index d2d4391997f..6b46b46051f 100644
--- a/tests/rustdoc/logo-class-default.rs
+++ b/tests/rustdoc/logo-class-default.rs
@@ -1,4 +1,4 @@
-// Note: this test is paired with logo-class.rs.
-// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
-// @has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+// Note: this test is paired with logo-class.rs and logo-class-rust.rs.
+// @!has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img' ''
+// @!has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img' ''
 pub struct SomeStruct;
diff --git a/tests/rustdoc/logo-class-rust.rs b/tests/rustdoc/logo-class-rust.rs
new file mode 100644
index 00000000000..d4f6113c0c0
--- /dev/null
+++ b/tests/rustdoc/logo-class-rust.rs
@@ -0,0 +1,7 @@
+#![feature(rustdoc_internals)]
+#![allow(internal_features)]
+#![doc(rust_logo)]
+// Note: this test is paired with logo-class.rs and logo-class-default.rs.
+// @has logo_class_rust/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+// @has src/logo_class_rust/logo-class-rust.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/tests/rustdoc/logo-class.rs b/tests/rustdoc/logo-class.rs
index d3aa446dab9..d15ce134cd1 100644
--- a/tests/rustdoc/logo-class.rs
+++ b/tests/rustdoc/logo-class.rs
@@ -1,6 +1,6 @@
 #![doc(html_logo_url =
     "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")]
-// Note: this test is paired with logo-class-default.rs.
+// Note: this test is paired with logo-class-default.rs and logo-class-rust.rs.
 
 // @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
 // @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs
index f6a059de620..f9da5a81375 100644
--- a/tests/rustdoc/titles.rs
+++ b/tests/rustdoc/titles.rs
@@ -2,7 +2,8 @@
 #![feature(rustc_attrs)]
 
 // @matches 'foo/index.html' '//h1' 'Crate foo'
-// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
+// @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'
diff --git a/tests/ui/feature-gates/doc-rust-logo.rs b/tests/ui/feature-gates/doc-rust-logo.rs
new file mode 100644
index 00000000000..e6a58512944
--- /dev/null
+++ b/tests/ui/feature-gates/doc-rust-logo.rs
@@ -0,0 +1,5 @@
+#![doc(rust_logo)]
+//~^ ERROR the `#[doc(rust_logo)]` attribute is used for Rust branding
+//! This is not an official rust crate
+
+fn main() {}
diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr
new file mode 100644
index 00000000000..ff5855290d4
--- /dev/null
+++ b/tests/ui/feature-gates/doc-rust-logo.stderr
@@ -0,0 +1,12 @@
+error[E0658]: the `#[doc(rust_logo)]` attribute is used for Rust branding
+  --> $DIR/doc-rust-logo.rs:1:8
+   |
+LL | #![doc(rust_logo)]
+   |        ^^^^^^^^^
+   |
+   = note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
+   = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.