about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
12 files changed, 233 insertions, 61 deletions
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`");