about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-05 12:32:28 +0000
committerbors <bors@rust-lang.org>2022-01-05 12:32:28 +0000
commit181e91567c9f347e055b33b1d7e9894f769aafe3 (patch)
treebf1b9bc743d4e9c0be2ccf6d2ef4beb70cc24c8e
parent936ce3dab7fd042101767c439362310f8355e859 (diff)
parenta0673468ae2a1953cfe7799e1755abfb2abd8339 (diff)
Auto merge of #92580 - matthiaskrgr:rollup-nzyn65y, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #92182 (Label more build steps)
 - #92188 (rustdoc: Clean up NestedAttributesExt trait/implementation)
 - #92322 (Add another implementation example to Debug trait)
 - #92448 (Set font size proportional to user's font size)
 - #92517 (Explicitly pass `PATH` to the Windows exe resolver)
 - #92545 (Extract init_env_logger to crate)
 - #92579 (update Miri)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock28
-rw-r--r--compiler/rustc_driver/Cargo.toml6
-rw-r--r--compiler/rustc_driver/src/lib.rs57
-rw-r--r--compiler/rustc_log/Cargo.toml16
-rw-r--r--compiler/rustc_log/src/lib.rs115
-rw-r--r--library/core/src/fmt/mod.rs23
-rw-r--r--library/std/src/sys/windows/process.rs31
-rw-r--r--library/std/src/sys/windows/process/tests.rs39
-rw-r--r--src/bootstrap/bootstrap.py3
-rw-r--r--src/bootstrap/flags.rs34
-rw-r--r--src/librustdoc/clean/types.rs25
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css111
m---------src/tools/miri16
13 files changed, 306 insertions, 198 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1fe03a06c79..f3553c37903 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -368,7 +368,7 @@ version = "0.1.0"
 dependencies = [
  "directories",
  "rustc-workspace-hack",
- "rustc_version 0.3.3",
+ "rustc_version",
  "serde",
  "serde_json",
  "vergen",
@@ -2276,7 +2276,7 @@ dependencies = [
  "measureme 9.1.2",
  "rand 0.8.4",
  "rustc-workspace-hack",
- "rustc_version 0.4.0",
+ "rustc_version",
  "shell-escape",
  "smallvec",
 ]
@@ -3808,7 +3808,6 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
- "atty",
  "libc",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -3822,6 +3821,7 @@ dependencies = [
  "rustc_hir_pretty",
  "rustc_interface",
  "rustc_lint",
+ "rustc_log",
  "rustc_metadata",
  "rustc_middle",
  "rustc_parse",
@@ -3833,8 +3833,6 @@ dependencies = [
  "rustc_target",
  "rustc_typeck",
  "tracing",
- "tracing-subscriber",
- "tracing-tree",
  "winapi",
 ]
 
@@ -4078,6 +4076,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_log"
+version = "0.0.0"
+dependencies = [
+ "atty",
+ "rustc_span",
+ "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
+]
+
+[[package]]
 name = "rustc_macros"
 version = "0.1.0"
 dependencies = [
@@ -4579,15 +4588,6 @@ dependencies = [
 
 [[package]]
 name = "rustc_version"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
-dependencies = [
- "semver 0.11.0",
-]
-
-[[package]]
-name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 2383a000687..872f946bf7d 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -8,10 +8,8 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
-atty = "0.2"
 tracing = { version = "0.1.28" }
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -40,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"]
 
 [features]
 llvm = ['rustc_interface/llvm']
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['rustc_log/max_level_info']
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 12e0b7a4977..3d58b27f839 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -24,6 +24,7 @@ use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
+use rustc_log::stdout_isatty;
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -514,14 +515,6 @@ impl Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-fn stdout_isatty() -> bool {
-    atty::is(atty::Stream::Stdout)
-}
-
-fn stderr_isatty() -> bool {
-    atty::is(atty::Stream::Stderr)
-}
-
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised = if upper_cased_code.starts_with('E') {
@@ -1254,54 +1247,18 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG")
+    if let Err(error) = rustc_log::init_rustc_env_logger() {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) {
-    use tracing_subscriber::{
-        filter::{self, EnvFilter, LevelFilter},
-        layer::SubscriberExt,
-    };
-
-    let filter = match std::env::var(env) {
-        Ok(env) => EnvFilter::new(env),
-        _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
-    };
-
-    let color_logs = match std::env::var(String::from(env) + "_COLOR") {
-        Ok(value) => match value.as_ref() {
-            "always" => true,
-            "never" => false,
-            "auto" => stderr_isatty(),
-            _ => early_error(
-                ErrorOutputType::default(),
-                &format!(
-                    "invalid log color value '{}': expected one of always, never, or auto",
-                    value
-                ),
-            ),
-        },
-        Err(std::env::VarError::NotPresent) => stderr_isatty(),
-        Err(std::env::VarError::NotUnicode(_value)) => early_error(
-            ErrorOutputType::default(),
-            "non-Unicode log color value: expected one of always, never, or auto",
-        ),
-    };
-
-    let layer = tracing_tree::HierarchicalLayer::default()
-        .with_writer(io::stderr)
-        .with_indent_lines(true)
-        .with_ansi(color_logs)
-        .with_targets(true)
-        .with_indent_amount(2);
-    #[cfg(parallel_compiler)]
-    let layer = layer.with_thread_ids(true).with_thread_names(true);
-
-    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    if let Err(error) = rustc_log::init_env_logger(env) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
new file mode 100644
index 00000000000..1b2cde60555
--- /dev/null
+++ b/compiler/rustc_log/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "rustc_log"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+atty = "0.2"
+tracing = "0.1.28"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.2.0"
+
+[dev-dependencies]
+rustc_span = { path = "../rustc_span" }
+
+[features]
+max_level_info = ['tracing/max_level_info']
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
new file mode 100644
index 00000000000..f5e7435d36e
--- /dev/null
+++ b/compiler/rustc_log/src/lib.rs
@@ -0,0 +1,115 @@
+//! This crate allows tools to enable rust logging without having to magically
+//! match rustc's tracing crate version.
+//!
+//! For example if someone is working on rustc_ast and wants to write some
+//! minimal code against it to run in a debugger, with access to the `debug!`
+//! logs emitted by rustc_ast, that can be done by writing:
+//!
+//! ```toml
+//! [dependencies]
+//! rustc_ast = { path = "../rust/compiler/rustc_ast" }
+//! rustc_log = { path = "../rust/compiler/rustc_log" }
+//! rustc_span = { path = "../rust/compiler/rustc_span" }
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     rustc_log::init_rustc_env_logger().unwrap();
+//!
+//!     let edition = rustc_span::edition::Edition::Edition2021;
+//!     rustc_span::create_session_globals_then(edition, || {
+//!         /* ... */
+//!     });
+//! }
+//! ```
+//!
+//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! rustc's debug logging. In a workflow like this, one might also add
+//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! run` by itself is sufficient to get logs.
+//!
+//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
+//! same things in rustc_driver only, is to enable the above workflow. If you
+//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
+//! an enormously bigger dependency tree; every change you make to rustc_ast (or
+//! whichever piece of the compiler you are interested in) would involve
+//! rebuilding all the rest of rustc up to rustc_driver in order to run your
+//! main.rs. Whereas by depending only on rustc_log and the few crates you are
+//! debugging, you can make changes inside those crates and quickly run main.rs
+//! to read the debug logs.
+
+use std::env::{self, VarError};
+use std::fmt::{self, Display};
+use std::io;
+use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::layer::SubscriberExt;
+
+pub fn init_rustc_env_logger() -> Result<(), Error> {
+    init_env_logger("RUSTC_LOG")
+}
+
+/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    let filter = match env::var(env) {
+        Ok(env) => EnvFilter::new(env),
+        _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
+    };
+
+    let color_logs = match env::var(String::from(env) + "_COLOR") {
+        Ok(value) => match value.as_ref() {
+            "always" => true,
+            "never" => false,
+            "auto" => stderr_isatty(),
+            _ => return Err(Error::InvalidColorValue(value)),
+        },
+        Err(VarError::NotPresent) => stderr_isatty(),
+        Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
+    };
+
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_writer(io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(color_logs)
+        .with_targets(true)
+        .with_indent_amount(2);
+    #[cfg(parallel_compiler)]
+    let layer = layer.with_thread_ids(true).with_thread_names(true);
+
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
+
+    Ok(())
+}
+
+pub fn stdout_isatty() -> bool {
+    atty::is(atty::Stream::Stdout)
+}
+
+pub fn stderr_isatty() -> bool {
+    atty::is(atty::Stream::Stderr)
+}
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidColorValue(String),
+    NonUnicodeColorValue,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::InvalidColorValue(value) => write!(
+                formatter,
+                "invalid log color value '{}': expected one of always, never, or auto",
+                value,
+            ),
+            Error::NonUnicodeColorValue => write!(
+                formatter,
+                "non-Unicode log color value: expected one of always, never, or auto",
+            ),
+        }
+    }
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 6fc3cd0b7c4..8a2a64f8dc9 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -570,11 +570,30 @@ impl Display for Arguments<'_> {
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
 /// implementations, such as [`debug_struct`].
 ///
+/// [`debug_struct`]: Formatter::debug_struct
+///
+/// Types that do not wish to use the standard suite of debug representations
+/// provided by the `Formatter` trait (`debug_struct`, `debug_tuple`,
+/// `debut_list`, `debug_set`, `debug_map`) can do something totally custom by
+/// manually writing an arbitrary representation to the `Formatter`.
+///
+/// ```
+/// # use std::fmt;
+/// # struct Point {
+/// #     x: i32,
+/// #     y: i32,
+/// # }
+/// #
+/// impl fmt::Debug for Point {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "Point [{} {}]", self.x, self.y)
+///     }
+/// }
+/// ```
+///
 /// `Debug` implementations using either `derive` or the debug builder API
 /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`.
 ///
-/// [`debug_struct`]: Formatter::debug_struct
-///
 /// Pretty-printing with `#?`:
 ///
 /// ```
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index e84dfbce4a7..5ad57042797 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -268,7 +268,7 @@ impl Command {
         } else {
             None
         };
-        let program = resolve_exe(&self.program, child_paths)?;
+        let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
         let mut cmd_str =
             make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
@@ -362,7 +362,11 @@ impl fmt::Debug for Command {
 // Therefore this functions first assumes `.exe` was intended.
 // It falls back to the plain file name if a full path is given and the extension is omitted
 // or if only a file name is given and it already contains an extension.
-fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Result<PathBuf> {
+fn resolve_exe<'a>(
+    exe_path: &'a OsStr,
+    parent_paths: impl FnOnce() -> Option<OsString>,
+    child_paths: Option<&OsStr>,
+) -> io::Result<PathBuf> {
     // Early return if there is no filename.
     if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
         return Err(io::Error::new_const(
@@ -406,7 +410,7 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
         let has_extension = exe_path.bytes().contains(&b'.');
 
         // Search the directories given by `search_paths`.
-        let result = search_paths(child_paths, |mut path| {
+        let result = search_paths(parent_paths, child_paths, |mut path| {
             path.push(&exe_path);
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
@@ -423,15 +427,20 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
 
 // Calls `f` for every path that should be used to find an executable.
 // Returns once `f` returns the path to an executable or all paths have been searched.
-fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
+fn search_paths<Paths, Exists>(
+    parent_paths: Paths,
+    child_paths: Option<&OsStr>,
+    mut exists: Exists,
+) -> Option<PathBuf>
 where
-    F: FnMut(PathBuf) -> Option<PathBuf>,
+    Paths: FnOnce() -> Option<OsString>,
+    Exists: FnMut(PathBuf) -> Option<PathBuf>,
 {
     // 1. Child paths
     // This is for consistency with Rust's historic behaviour.
     if let Some(paths) = child_paths {
         for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
@@ -440,7 +449,7 @@ where
     // 2. Application path
     if let Ok(mut app_path) = env::current_exe() {
         app_path.pop();
-        if let Some(path) = f(app_path) {
+        if let Some(path) = exists(app_path) {
             return Some(path);
         }
     }
@@ -450,7 +459,7 @@ where
     unsafe {
         if let Ok(Some(path)) = super::fill_utf16_buf(
             |buf, size| c::GetSystemDirectoryW(buf, size),
-            |buf| f(PathBuf::from(OsString::from_wide(buf))),
+            |buf| exists(PathBuf::from(OsString::from_wide(buf))),
         ) {
             return Some(path);
         }
@@ -458,7 +467,7 @@ where
         {
             if let Ok(Some(path)) = super::fill_utf16_buf(
                 |buf, size| c::GetWindowsDirectoryW(buf, size),
-                |buf| f(PathBuf::from(OsString::from_wide(buf))),
+                |buf| exists(PathBuf::from(OsString::from_wide(buf))),
             ) {
                 return Some(path);
             }
@@ -466,9 +475,9 @@ where
     }
 
     // 5. Parent paths
-    if let Some(parent_paths) = env::var_os("PATH") {
+    if let Some(parent_paths) = parent_paths() {
         for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index 6159a679c0e..f1221767af3 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -136,51 +136,46 @@ fn windows_exe_resolver() {
     use super::resolve_exe;
     use crate::io;
 
+    let env_paths = || env::var_os("PATH");
+
     // Test a full path, with and without the `exe` extension.
     let mut current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
     current_exe.set_extension("");
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
 
     // Test lone file names.
-    assert!(resolve_exe(OsStr::new("cmd"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.EXE"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("fc"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
 
     // Invalid file names should return InvalidInput.
-    assert_eq!(resolve_exe(OsStr::new(""), None).unwrap_err().kind(), io::ErrorKind::InvalidInput);
     assert_eq!(
-        resolve_exe(OsStr::new("\0"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
+        io::ErrorKind::InvalidInput
+    );
+    assert_eq!(
+        resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
     // Trailing slash, therefore there's no file name component.
     assert_eq!(
-        resolve_exe(OsStr::new(r"C:\Path\to\"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
 
-    /* FIXME: fix and re-enable these tests before making changes to the resolver.
-
     /*
     Some of the following tests may need to be changed if you are deliberately
     changing the behaviour of `resolve_exe`.
     */
 
-    let paths = env::var_os("PATH").unwrap();
-    env::set_var("PATH", "");
-
-    assert_eq!(resolve_exe(OsStr::new("rustc"), None).unwrap_err().kind(), io::ErrorKind::NotFound);
-
-    let child_paths = Some(paths.as_os_str());
-    assert!(resolve_exe(OsStr::new("rustc"), child_paths).is_ok());
+    let empty_paths = || None;
 
     // The resolver looks in system directories even when `PATH` is empty.
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
 
     // The application's directory is also searched.
     let current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), None).is_ok());
-
-    */
+    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
 }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5a33073e6b0..5235a6b8180 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -974,6 +974,7 @@ class RustBuild(object):
 
     def build_bootstrap(self):
         """Build bootstrap"""
+        print("Building rustbuild")
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
@@ -1133,7 +1134,7 @@ class RustBuild(object):
             recorded_submodules[data[3]] = data[2]
         for module in filtered_submodules:
             self.update_submodule(module[0], module[1], recorded_submodules)
-        print("Submodules updated in %.2f seconds" % (time() - start_time))
+        print("  Submodules updated in %.2f seconds" % (time() - start_time))
 
     def set_dist_environment(self, url):
         """Set download URL for normal environment"""
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 2fddda74a28..9180c5f03af 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -401,26 +401,19 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                     "\n
 Arguments:
     This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to compile. For example:
-
-        ./x.py build library/core
-        ./x.py build library/core library/proc_macro
-        ./x.py build library/std --stage 1
-
-    If no arguments are passed then the complete artifacts for that stage are
-    also compiled.
+    and/or artifacts to compile. For example, for a quick build of a usable
+    compiler:
 
-        ./x.py build
-        ./x.py build --stage 1
+        ./x.py build --stage 1 library/std
 
-    For a quick build of a usable compiler, you can pass:
+    This will build a compiler and standard library from the local source code.
+    Once this is done, build/$ARCH/stage1 contains a usable compiler.
 
-        ./x.py build --stage 1 library/test
+    If no arguments are passed then the default artifacts for that stage are
+    compiled. For example:
 
-    This will first build everything once (like `--stage 0` without further
-    arguments would), and then use the compiler built in stage 0 to build
-    library/test and its dependencies.
-    Once this is done, build/$ARCH/stage1 contains a usable compiler.",
+        ./x.py build --stage 0
+        ./x.py build ",
                 );
             }
             "check" | "c" => {
@@ -430,14 +423,9 @@ Arguments:
     This subcommand accepts a number of paths to directories to the crates
     and/or artifacts to compile. For example:
 
-        ./x.py check library/core
-        ./x.py check library/core library/proc_macro
+        ./x.py check library/std
 
-    If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
-    also that since we use `cargo check`, by default this will automatically enable incremental
-    compilation, so there's no need to pass it separately, though it won't hurt. We also completely
-    ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
-    the compiler.",
+    If no arguments are passed then many artifacts are checked.",
                 );
             }
             "clippy" => {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2ee5de24687..f0f61bb94c8 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -889,20 +889,25 @@ impl AttributesExt for [ast::Attribute] {
 }
 
 crate trait NestedAttributesExt {
-    /// Returns `true` if the attribute list contains a specific `Word`
-    fn has_word(self, word: Symbol) -> bool;
+    /// Returns `true` if the attribute list contains a specific `word`
+    fn has_word(self, word: Symbol) -> bool
+    where
+        Self: std::marker::Sized,
+    {
+        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
+    }
+
+    /// Returns `Some(attr)` if the attribute list contains 'attr'
+    /// corresponding to a specific `word`
     fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
 }
 
-impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
-    NestedAttributesExt for I
+impl<I> NestedAttributesExt for I
+where
+    I: IntoIterator<Item = ast::NestedMetaItem>,
 {
-    fn has_word(self, word: Symbol) -> bool {
-        self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
-    }
-
-    fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
-        self.find(|attr| attr.is_word() && attr.has_name(word))
+    fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
+        self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index e5c667a37c6..d82c65398b8 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -108,7 +108,7 @@ html {
 /* General structure and fonts */
 
 body {
-	font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
+	font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
 	margin: 0;
 	position: relative;
 
@@ -118,13 +118,13 @@ body {
 }
 
 h1 {
-	font-size: 1.5em;
+	font-size: 1.5rem;
 }
 h2 {
-	font-size: 1.4em;
+	font-size: 1.4rem;
 }
 h3 {
-	font-size: 1.3em;
+	font-size: 1.3rem;
 }
 h1, h2, h3, h4, h5, h6 {
 	font-weight: 500;
@@ -160,10 +160,10 @@ h2,
 	border-bottom: 1px solid;
 }
 h3.code-header {
-	font-size: 1.1em;
+	font-size: 1.1rem;
 }
 h4.code-header {
-	font-size: 1em;
+	font-size: 1rem;
 }
 h3.code-header, h4.code-header {
 	font-weight: 600;
@@ -206,7 +206,7 @@ div.impl-items > div:not(.docblock):not(.item-info),
 }
 
 .content ul.crate a.crate {
-	font-size: 16px/1.6;
+	font-size: 1rem/1.6;
 }
 
 ol, ul {
@@ -317,7 +317,7 @@ li {
 
 nav.sub {
 	position: relative;
-	font-size: 16px;
+	font-size: 1rem;
 	text-transform: uppercase;
 }
 
@@ -423,7 +423,7 @@ nav.sub {
 
 .sidebar .location {
 	border: 1px solid;
-	font-size: 17px;
+	font-size: 1.0625rem;
 	margin: 30px 10px 20px 10px;
 	text-align: center;
 	word-wrap: break-word;
@@ -432,7 +432,7 @@ nav.sub {
 }
 
 .sidebar .version {
-	font-size: 15px;
+	font-size: 0.9375rem;
 	text-align: center;
 	border-bottom: 1px solid;
 	overflow-wrap: break-word;
@@ -470,7 +470,7 @@ nav.sub {
 	overflow: hidden;
 	line-height: 15px;
 	padding: 7px 5px;
-	font-size: 14px;
+	font-size: 0.875rem;
 	font-weight: 300;
 	transition: border 500ms ease-out;
 }
@@ -479,7 +479,7 @@ nav.sub {
 	border-top: 1px solid;
 	border-bottom: 1px solid;
 	text-align: center;
-	font-size: 17px;
+	font-size: 1.0625rem;
 	margin-bottom: 5px;
 	font-weight: inherit;
 	padding: 0;
@@ -579,18 +579,18 @@ nav.sub {
 	white-space: pre-wrap;
 }
 
-.top-doc .docblock h2 { font-size: 1.3em; }
-.top-doc .docblock h3 { font-size: 1.15em; }
+.top-doc .docblock h2 { font-size: 1.3rem; }
+.top-doc .docblock h3 { font-size: 1.15rem; }
 .top-doc .docblock h4,
 .top-doc .docblock h5 {
-	font-size: 1.1em;
+	font-size: 1.1rem;
 }
 .top-doc .docblock h6 {
-	font-size: 1em;
+	font-size: 1rem;
 }
 
-.docblock h5 { font-size: 1em; }
-.docblock h6 { font-size: 0.95em; }
+.docblock h5 { font-size: 1rem; }
+.docblock h6 { font-size: 0.95rem; }
 
 .docblock {
 	margin-left: 24px;
@@ -605,7 +605,7 @@ nav.sub {
 .content .out-of-band {
 	flex-grow: 0;
 	text-align: right;
-	font-size: 23px;
+	font-size: 1.4375rem;
 	margin: 0px;
 	padding: 0 0 0 12px;
 	font-weight: normal;
@@ -646,7 +646,7 @@ nav.sub {
 .content td { vertical-align: top; }
 .content td:first-child { padding-right: 20px; }
 .content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; }
 .content tr:first-child td { border-top: 0; }
 
 .docblock table {
@@ -687,7 +687,7 @@ nav.sub {
 .content .multi-column li { width: 100%; display: inline-block; }
 
 .content > .methods > .method {
-	font-size: 1em;
+	font-size: 1rem;
 	position: relative;
 }
 /* Shift "where ..." part of method or fn definition down a line */
@@ -695,7 +695,7 @@ nav.sub {
 .content .fn .where,
 .content .where.fmt-newline {
 	display: block;
-	font-size: 0.8em;
+	font-size: 0.8rem;
 }
 
 .content .methods > div:not(.notable-traits):not(.method) {
@@ -718,7 +718,7 @@ nav.sub {
 }
 
 .content .item-info code {
-	font-size: 90%;
+	font-size: 0.81rem;
 }
 
 .content .item-info {
@@ -732,7 +732,7 @@ nav.sub {
 
 .content .item-info::before {
 	content: '⬑';
-	font-size: 25px;
+	font-size: 1.5625rem;
 	position: absolute;
 	top: -6px;
 	left: -19px;
@@ -835,7 +835,7 @@ h2.small-section-header > .anchor {
 	position: absolute;
 	top: 0;
 	right: 0;
-	font-size: 17px;
+	font-size: 1.0625rem;
 	font-weight: normal;
 }
 
@@ -905,7 +905,7 @@ h2.small-section-header > .anchor {
 	border-radius: 1px;
 	margin-top: 5px;
 	padding: 10px 16px;
-	font-size: 17px;
+	font-size: 1.0625rem;
 	transition: border-color 300ms ease;
 	transition: border-radius 300ms ease-in-out;
 	transition: box-shadow 300ms ease-in-out;
@@ -1000,7 +1000,7 @@ body.blur > :not(#help) {
 #help span.top, #help span.bottom {
 	text-align: center;
 	display: block;
-	font-size: 18px;
+	font-size: 1.125rem;
 
 }
 #help span.top {
@@ -1030,7 +1030,7 @@ body.blur > :not(#help) {
 .stab {
 	padding: 3px;
 	margin-bottom: 5px;
-	font-size: 90%;
+	font-size: 0.9rem;
 	font-weight: normal;
 }
 .stab p {
@@ -1038,7 +1038,7 @@ body.blur > :not(#help) {
 }
 
 .stab .emoji {
-	font-size: 1.2em;
+	font-size: 1.2rem;
 }
 
 /* Black one-pixel outline around emoji shapes */
@@ -1054,7 +1054,7 @@ body.blur > :not(#help) {
 .import-item .stab {
 	border-radius: 3px;
 	display: inline-block;
-	font-size: 80%;
+	font-size: 0.8rem;
 	line-height: 1.2;
 	margin-bottom: 0;
 	margin-left: .3em;
@@ -1080,7 +1080,7 @@ body.blur > :not(#help) {
 
 .impl-items .srclink, .impl .srclink, .methods .srclink {
 	/* Override header settings otherwise it's too bold */
-	font-size: 17px;
+	font-size: 1.0625rem;
 	font-weight: normal;
 }
 
@@ -1089,7 +1089,7 @@ body.blur > :not(#help) {
 }
 
 .has-srclink {
-	font-size: 16px;
+	font-size: 1rem;
 	margin-bottom: 12px;
 	/* Push the src link out to the right edge consistently */
 	justify-content: space-between;
@@ -1120,7 +1120,7 @@ a.test-arrow {
 	position: absolute;
 	padding: 5px 10px 5px 10px;
 	border-radius: 5px;
-	font-size: 130%;
+	font-size: 1.3rem;
 	top: 5px;
 	right: 5px;
 	z-index: 1;
@@ -1155,19 +1155,19 @@ a.test-arrow:hover{
 
 .out-of-band > span.since {
 	position: initial;
-	font-size: 20px;
+	font-size: 1.25rem;
 	margin-right: 5px;
 }
 
 h3.variant {
 	font-weight: 600;
-	font-size: 1.1em;
+	font-size: 1.1rem;
 	margin-bottom: 10px;
 	border-bottom: none;
 }
 
 .sub-variant h4 {
-	font-size: 1em;
+	font-size: 1rem;
 	font-weight: 400;
 	border-bottom: none;
 	margin-top: 0;
@@ -1227,7 +1227,7 @@ h3.variant {
 	padding: 5px 3px 3px 3px;
 	border-radius: 6px;
 	margin-left: 5px;
-	font-size: 16px;
+	font-size: 1rem;
 }
 
 .tooltip.ignore::after {
@@ -1260,7 +1260,7 @@ h3.variant {
 
 .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
 	font-weight: bold;
-	font-size: 20px;
+	font-size: 1.25rem;
 }
 
 .notable-traits-tooltip {
@@ -1279,7 +1279,7 @@ h3.variant {
 	border-radius: 6px;
 	margin-left: 5px;
 	z-index: 10;
-	font-size: 16px;
+	font-size: 1rem;
 	cursor: default;
 	position: absolute;
 	border: 1px solid;
@@ -1299,14 +1299,14 @@ h3.variant {
 .notable-traits .notable {
 	margin: 0;
 	margin-bottom: 13px;
-	font-size: 19px;
+	font-size: 1.1875rem;
 	font-weight: 600;
 }
 
 .notable-traits .docblock code.content{
 	margin: 0;
 	padding: 0;
-	font-size: 20px;
+	font-size: 1.25rem;
 }
 
 /* Example code has the "Run" button that needs to be positioned relative to the pre */
@@ -1344,7 +1344,7 @@ pre.rust {
 	float: left;
 	width: 33.3%;
 	text-align: center;
-	font-size: 18px;
+	font-size: 1.125rem;
 	cursor: pointer;
 	border: 0;
 	border-top: 2px solid;
@@ -1357,7 +1357,7 @@ pre.rust {
 
 #titles > button > div.count {
 	display: inline-block;
-	font-size: 16px;
+	font-size: 1rem;
 }
 
 .notable-traits {
@@ -1384,7 +1384,7 @@ pre.rust {
 	left: 0;
 	cursor: pointer;
 	font-weight: bold;
-	font-size: 1.2em;
+	font-size: 1.2rem;
 	border-bottom: 1px solid;
 	display: flex;
 	height: 40px;
@@ -1398,7 +1398,7 @@ pre.rust {
 	overflow: auto;
 }
 #source-sidebar > .title {
-	font-size: 1.5em;
+	font-size: 1.5rem;
 	text-align: center;
 	border-bottom: 1px solid;
 	margin-bottom: 6px;
@@ -1426,6 +1426,9 @@ pre.rust {
 
 #theme-picker, #settings-menu, #help-button, #copy-path {
 	padding: 4px;
+	/* Rare exception to specifying font sizes in rem. Since these are acting
+	   as icons, it's okay to specify their sizes in pixels. */
+	font-size: 16px;
 	width: 27px;
 	height: 29px;
 	border: 1px solid;
@@ -1437,7 +1440,9 @@ pre.rust {
 	right: 30px;
 	font-family: "Fira Sans", Arial, sans-serif;
 	text-align: center;
-	font-size: 17px;
+	/* Rare exception to specifying font sizes in rem. Since this is acting
+	   as an icon, it's okay to specify their sizes in pixels. */
+	font-size: 16px;
 	padding-top: 2px;
 }
 
@@ -1499,7 +1504,7 @@ kbd {
 	border: 0;
 	border-collapse: collapse;
 	border-spacing: 0;
-	font-size: 16px;
+	font-size: 1rem;
 }
 
 .table-display tr td:first-child {
@@ -1511,11 +1516,11 @@ kbd {
 }
 .table-display .out-of-band {
 	position: relative;
-	font-size: 19px;
+	font-size: 1.1875rem;
 	display: block;
 }
 #implementors-list > .impl-items .table-display .out-of-band {
-	font-size: 17px;
+	font-size: 1.0625rem;
 }
 
 .table-display td:hover .anchor {
@@ -1557,7 +1562,7 @@ div.name.expand + .children {
 div.name::before {
 	content: "\25B6";
 	padding-left: 4px;
-	font-size: 0.7em;
+	font-size: 0.7rem;
 	position: absolute;
 	left: -16px;
 	top: 4px;
@@ -1624,7 +1629,7 @@ details.rustdoc-toggle.top-doc > summary::before,
 details.rustdoc-toggle.non-exhaustive > summary,
 details.rustdoc-toggle.non-exhaustive > summary::before {
 	font-family: 'Fira Sans';
-	font-size: 16px;
+	font-size: 1rem;
 }
 
 details.non-exhaustive {
@@ -1768,7 +1773,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		min-height: 39px;
 		background: inherit;
 		text-align: left;
-		font-size: 24px;
+		font-size: 1.5rem;
 	}
 
 	.sidebar .location:empty {
@@ -1909,7 +1914,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	}
 
 	.show-it > .block.items > ul > li > a {
-		font-size: 21px;
+		font-size: 1.3125rem;
 	}
 
 	/* Because of ios, we need to actually have a full height sidebar title so the
diff --git a/src/tools/miri b/src/tools/miri
-Subproject d307e6c1970d1edb63d6a08d332e0acdb72c5cc
+Subproject 824816c973a3fd0596ae3a9a38c6fb6299b913b