]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #56832 - alexcrichton:external-demangle, r=Mark-Simulacrum
authorMazdak Farrokhzad <twingoow@gmail.com>
Sun, 16 Dec 2018 13:08:33 +0000 (14:08 +0100)
committerGitHub <noreply@github.com>
Sun, 16 Dec 2018 13:08:33 +0000 (14:08 +0100)
std: Use `rustc_demangle` from crates.io

No more need to duplicate the demangling routine between crates.io and
the standard library, we can use the exact same one!

121 files changed:
Cargo.lock
README.md
src/bootstrap/Cargo.toml
src/bootstrap/builder.rs
src/bootstrap/cache.rs
src/bootstrap/cc_detect.rs
src/bootstrap/channel.rs
src/bootstrap/check.rs
src/bootstrap/clean.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/install.rs
src/bootstrap/job.rs
src/bootstrap/lib.rs
src/bootstrap/metadata.rs
src/bootstrap/native.rs
src/bootstrap/sanity.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/ci/docker/dist-various-1/Dockerfile
src/doc/rustc/src/targets/built-in.md
src/doc/rustc/src/targets/index.md
src/doc/unstable-book/src/language-features/unsized-locals.md
src/liballoc/Cargo.toml
src/liballoc/collections/btree/node.rs
src/liballoc/collections/linked_list.rs
src/liballoc/tests/vec.rs
src/libcore/fmt/mod.rs
src/libcore/future/future.rs
src/libcore/iter/iterator.rs
src/libcore/num/mod.rs
src/libcore/ops/function.rs
src/libcore/ptr.rs
src/libcore/sync/atomic.rs
src/librustc/infer/canonical/query_response.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/lint/builtin.rs
src/librustc/middle/liveness.rs
src/librustc/middle/stability.rs
src/librustc/mir/interpret/error.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/llvm_util.rs
src/librustc_lint/lib.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/invalidation.rs
src/librustc_mir/borrow_check/places_conflict.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_passes/lib.rs
src/librustc_passes/mir_stats.rs [deleted file]
src/librustc_resolve/lib.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/uefi_base.rs [new file with mode: 0644]
src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
src/librustc_target/spec/x86_64_unknown_uefi.rs [new file with mode: 0644]
src/librustc_typeck/check/method/suggest.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/noscript.css [new file with mode: 0644]
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/storage.js
src/librustdoc/html/static_files.rs
src/librustdoc/test.rs
src/libstd/ffi/mod.rs
src/libstd/fs.rs
src/libstd/os/raw/mod.rs
src/libsyntax/ext/expand.rs
src/libsyntax/parse/parser.rs
src/llvm
src/rustllvm/llvm-rebuild-trigger
src/stdsimd
src/test/compile-fail/must_use-in-stdlib-traits.rs [new file with mode: 0644]
src/test/run-pass/ctfe/references.rs
src/test/rustdoc/comment-in-doctest.rs [new file with mode: 0644]
src/test/ui/anon-params-denied-2018.stderr
src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr
src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr
src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs
src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr
src/test/ui/deprecation/deprecation-in-future.rs [new file with mode: 0644]
src/test/ui/deprecation/deprecation-in-future.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0424.rs
src/test/ui/error-codes/E0424.stderr
src/test/ui/extern/auxiliary/invalid-utf8.txt [new file with mode: 0644]
src/test/ui/extern/external-doc-error.rs
src/test/ui/extern/external-doc-error.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-35677.rs [new file with mode: 0644]
src/test/ui/issues/issue-35677.stderr [new file with mode: 0644]
src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr
src/test/ui/lint/lint-unexported-no-mangle.stderr
src/test/ui/liveness/liveness-dead.stderr
src/test/ui/liveness/liveness-unused.stderr
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/nll/match-on-borrowed.rs
src/test/ui/nll/match-on-borrowed.stderr
src/test/ui/pattern/const-pat-ice.rs [new file with mode: 0644]
src/test/ui/pattern/slice-pattern-const-2.rs
src/test/ui/pattern/slice-pattern-const-2.stderr [new file with mode: 0644]
src/test/ui/pattern/slice-pattern-const-3.rs
src/test/ui/pattern/slice-pattern-const-3.stderr [new file with mode: 0644]
src/test/ui/pattern/slice-pattern-const.rs
src/test/ui/pattern/slice-pattern-const.stderr [new file with mode: 0644]
src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs [new file with mode: 0644]
src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
src/test/ui/suggestions/path-display.rs [new file with mode: 0644]
src/test/ui/suggestions/path-display.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed [new file with mode: 0644]
src/test/ui/suggestions/suggest-impl-trait-lifetime.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr [new file with mode: 0644]
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/util.rs

index 472470de1de7e26d81b07b7fd991cfe9e85896b4..7e03474565d857a8b4af3ebc7cc48107076162b4 100644 (file)
@@ -81,7 +81,7 @@ dependencies = [
 
 [[package]]
 name = "backtrace"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -728,7 +728,7 @@ name = "error-chain"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -736,7 +736,7 @@ name = "error-chain"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -751,7 +751,7 @@ name = "failure"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2060,7 +2060,7 @@ name = "rustc"
 version = "0.0.0"
 dependencies = [
  "arena 0.0.0",
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3385,7 +3385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
 "checksum assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51"
 "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
-"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
+"checksum backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782"
 "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
 "checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
 "checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
index 37442661bcbc1f73daab687a1e2e97f25ce263a3..dc013a1ad2be66985b47fc5d0a8313cdd1169bed 100644 (file)
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ standard library, and documentation.
 
 Read ["Installation"] from [The Book].
 
-["Installation"]: https://doc.rust-lang.org/book/second-edition/ch01-01-installation.html
+["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html
 [The Book]: https://doc.rust-lang.org/book/index.html
 
 ## Building from Source
index 3e91c2b3e86c8316bf4e9e6a769b1f7e8b2d289c..0f7b6c22e1cc52ff8632881b195b831f8d4d3aca 100644 (file)
@@ -2,6 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "bootstrap"
 version = "0.0.0"
+edition = "2018"
 
 [lib]
 name = "bootstrap"
index 32f3e573d6845bdf597e9b9e32ba88083e9c3fb7..405fc871eef76e6f22763c3b510261a9d134f80d 100644 (file)
 use std::process::Command;
 use std::time::{Duration, Instant};
 
-use cache::{Cache, Interned, INTERNER};
-use check;
-use compile;
-use dist;
-use doc;
-use flags::Subcommand;
-use install;
-use native;
-use test;
-use tool;
-use util::{add_lib_path, exe, libdir};
-use {Build, DocTests, Mode, GitRepo};
-
-pub use Compiler;
+use crate::cache::{Cache, Interned, INTERNER};
+use crate::check;
+use crate::compile;
+use crate::dist;
+use crate::doc;
+use crate::flags::Subcommand;
+use crate::install;
+use crate::native;
+use crate::test;
+use crate::tool;
+use crate::util::{add_lib_path, exe, libdir};
+use crate::{Build, DocTests, Mode, GitRepo};
+
+pub use crate::Compiler;
 
 use petgraph::graph::NodeIndex;
 use petgraph::Graph;
@@ -416,6 +416,7 @@ macro_rules! describe {
                 test::Rustfmt,
                 test::Miri,
                 test::Clippy,
+                test::CompiletestTest,
                 test::RustdocJS,
                 test::RustdocTheme,
                 // Run bootstrap close to the end as it's unlikely to fail
@@ -1251,7 +1252,7 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
 #[cfg(test)]
 mod __test {
     use super::*;
-    use config::Config;
+    use crate::config::Config;
     use std::thread;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
index 0b561a3523f2b483460d8549b75f4913d7a6bcd0..165cffa4587d370bbddf7567c5509c566e480605 100644 (file)
@@ -23,7 +23,7 @@
 use std::sync::Mutex;
 use std::cmp::{PartialOrd, Ord, Ordering};
 
-use builder::Step;
+use crate::builder::Step;
 
 pub struct Interned<T>(usize, PhantomData<*const T>);
 
index d5da0cabec84aa7d5fc61cb3f65011831ca91761..3d2b3a2c9de498ee7bc69bb1f14b5bed96bf82de 100644 (file)
@@ -39,9 +39,9 @@
 use build_helper::output;
 use cc;
 
-use {Build, GitRepo};
-use config::Target;
-use cache::Interned;
+use crate::{Build, GitRepo};
+use crate::config::Target;
+use crate::cache::Interned;
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
 // so use some simplified logic here. First we respect the environment variable `AR`, then
index 878b6ed73a3125712e6034aa151188cafa8aa989..8756ec944c25704da8a5dc9e3a3a00aa6c61e7b6 100644 (file)
@@ -20,8 +20,8 @@
 
 use build_helper::output;
 
-use Build;
-use config::Config;
+use crate::Build;
+use crate::config::Config;
 
 // The version number
 pub const CFG_RELEASE_NUM: &str = "1.33.0";
index 0c6dbb06bb8821053171421780a0e556983b5b88..84e7c40e4559e479a94d2b71257ea0bc9fdff3c3 100644 (file)
 
 //! Implementation of compiling the compiler and standard library, in "check" mode.
 
-use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot};
-use builder::{RunConfig, Builder, ShouldRun, Step};
-use tool::{prepare_tool_cargo, SourceType};
-use {Compiler, Mode};
-use cache::{INTERNER, Interned};
+use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env,
+                     add_to_sysroot};
+use crate::builder::{RunConfig, Builder, ShouldRun, Step};
+use crate::tool::{prepare_tool_cargo, SourceType};
+use crate::{Compiler, Mode};
+use crate::cache::{INTERNER, Interned};
 use std::path::PathBuf;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
index 87f194fb7d2f85d4ae3eed1e32efd0390331975b..dc42159d068b1e6bff46bfed57290fc5fc716d15 100644 (file)
@@ -19,7 +19,7 @@
 use std::io::{self, ErrorKind};
 use std::path::Path;
 
-use Build;
+use crate::Build;
 
 pub fn clean(build: &Build, all: bool) {
     rm_rf("tmp".as_ref());
index c84abe42a637225a3f7d25c682f74093a40354e4..61a04b97206029fbb3679f7e17358dc893456bb5 100644 (file)
 use filetime::FileTime;
 use serde_json;
 
-use util::{exe, libdir, is_dylib};
-use {Compiler, Mode, GitRepo};
-use native;
+use crate::util::{exe, libdir, is_dylib};
+use crate::{Compiler, Mode, GitRepo};
+use crate::native;
 
-use cache::{INTERNER, Interned};
-use builder::{Step, RunConfig, ShouldRun, Builder};
+use crate::cache::{INTERNER, Interned};
+use crate::builder::{Step, RunConfig, ShouldRun, Builder};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -155,7 +155,9 @@ pub fn std_cargo(builder: &Builder,
         cargo
             .args(&["-p", "alloc"])
             .arg("--manifest-path")
-            .arg(builder.src.join("src/liballoc/Cargo.toml"));
+            .arg(builder.src.join("src/liballoc/Cargo.toml"))
+            .arg("--features")
+            .arg("compiler-builtins-mem");
     } else {
         let features = builder.std_features();
 
index 1dafbe148afdafd503f1f640e36c4749d1e69b6d..2ae9da9c085d4397811f30051d9cd8ee5879d26e 100644 (file)
@@ -22,9 +22,9 @@
 
 use num_cpus;
 use toml;
-use cache::{INTERNER, Interned};
-use flags::Flags;
-pub use flags::Subcommand;
+use crate::cache::{INTERNER, Interned};
+use crate::flags::Flags;
+pub use crate::flags::Subcommand;
 
 /// Global configuration for the entire build and/or bootstrap.
 ///
index f03eefb7a129bd3c869006822b6004c1c4eaea48..927f9bf8ddbca36ce57320793902ae916c95b518 100644 (file)
 
 use build_helper::output;
 
-use {Compiler, Mode, LLVM_TOOLS};
-use channel;
-use util::{libdir, is_dylib, exe};
-use builder::{Builder, RunConfig, ShouldRun, Step};
-use compile;
-use tool::{self, Tool};
-use cache::{INTERNER, Interned};
+use crate::{Compiler, Mode, LLVM_TOOLS};
+use crate::channel;
+use crate::util::{libdir, is_dylib, exe};
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::compile;
+use crate::tool::{self, Tool};
+use crate::cache::{INTERNER, Interned};
 use time;
 
 pub fn pkgname(builder: &Builder, component: &str) -> String {
index 2d0625b26dbe3cf19de5a655fcafad2d0669f40a..217328adfbf66403925f23a05a112ef6916a0667 100644 (file)
 use std::io;
 use std::path::{PathBuf, Path};
 
-use Mode;
+use crate::Mode;
 use build_helper::up_to_date;
 
-use util::symlink_dir;
-use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
-use tool::{self, prepare_tool_cargo, Tool, SourceType};
-use compile;
-use cache::{INTERNER, Interned};
-use config::Config;
+use crate::util::symlink_dir;
+use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
+use crate::tool::{self, prepare_tool_cargo, Tool, SourceType};
+use crate::compile;
+use crate::cache::{INTERNER, Interned};
+use crate::config::Config;
 
 macro_rules! book {
     ($($name:ident, $path:expr, $book_name:expr;)+) => {
index c49da8fc734892042d4f70c03e2e8a39600461bb..14e2f69432dac21d96753c6e1eeb1d78cb0b1591 100644 (file)
 
 use getopts::Options;
 
-use builder::Builder;
-use config::Config;
-use metadata;
-use {Build, DocTests};
+use crate::builder::Builder;
+use crate::config::Config;
+use crate::metadata;
+use crate::{Build, DocTests};
 
-use cache::{Interned, INTERNER};
+use crate::cache::{Interned, INTERNER};
 
 /// Deserialized version of all flags for this compile.
 pub struct Flags {
index cb28698aa3d6d22b2b7495550a40868c413a90fc..aebcfb4519543abbea8e271b402f66a807c3fbb9 100644 (file)
 use std::path::{Path, PathBuf, Component};
 use std::process::Command;
 
-use dist::{self, pkgname, sanitize_sh, tmpdir};
+use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
 
-use builder::{Builder, RunConfig, ShouldRun, Step};
-use cache::Interned;
-use config::Config;
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::cache::Interned;
+use crate::config::Config;
 
 pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) {
     install_sh(builder, "docs", "rust-docs", stage, Some(host));
index f7b1c50f0fd67de61b24743c87b99118a331be59..a9da2c491da53992774affa8f2c2d63660e027ca 100644 (file)
@@ -42,7 +42,7 @@
 use std::env;
 use std::io;
 use std::mem;
-use Build;
+use crate::Build;
 
 type HANDLE = *mut u8;
 type BOOL = i32;
index c8792918db2e2654e95b3c208ca05373f5514cf3..c5b8f19eee6fb0b27a41c2c010cffaf7729b52b1 100644 (file)
 use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
 use filetime::FileTime;
 
-use util::{exe, libdir, OutputFolder, CiEnv};
+use crate::util::{exe, libdir, OutputFolder, CiEnv};
 
 mod cc_detect;
 mod channel;
 mod job {
     use libc;
 
-    pub unsafe fn setup(build: &mut ::Build) {
+    pub unsafe fn setup(build: &mut crate::Build) {
         if build.config.low_priority {
             libc::setpriority(libc::PRIO_PGRP as _, 0, 10);
         }
@@ -197,14 +197,14 @@ pub unsafe fn setup(build: &mut ::Build) {
 
 #[cfg(any(target_os = "haiku", not(any(unix, windows))))]
 mod job {
-    pub unsafe fn setup(_build: &mut ::Build) {
+    pub unsafe fn setup(_build: &mut crate::Build) {
     }
 }
 
-pub use config::Config;
-use flags::Subcommand;
-use cache::{Interned, INTERNER};
-use toolstate::ToolState;
+pub use crate::config::Config;
+use crate::flags::Subcommand;
+use crate::cache::{Interned, INTERNER};
+use crate::toolstate::ToolState;
 
 const LLVM_TOOLS: &[&str] = &[
     "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
index fa0b1983510b90075b44b6ff0175a5cf58ada47a..bb503e8b8d3d1bf8d6bb1bd145297312af3903a2 100644 (file)
@@ -16,8 +16,8 @@
 use build_helper::output;
 use serde_json;
 
-use {Build, Crate};
-use cache::INTERNER;
+use crate::{Build, Crate};
+use crate::cache::INTERNER;
 
 #[derive(Deserialize)]
 struct Output {
index 8ff175b01875688582f1aaec820d5be546b898a9..2da800f19c07b8b804a7222dab1983aedb543cc1 100644 (file)
 use cmake;
 use cc;
 
-use util::{self, exe};
+use crate::util::{self, exe};
 use build_helper::up_to_date;
-use builder::{Builder, RunConfig, ShouldRun, Step};
-use cache::Interned;
-use GitRepo;
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::cache::Interned;
+use crate::GitRepo;
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
index 7a9e6d4fd387b8a7fa3b0a6b7954c457b0191fda..f585495b0aa947f573a11ccc16875411032b5d80 100644 (file)
@@ -27,7 +27,7 @@
 
 use build_helper::output;
 
-use Build;
+use crate::Build;
 
 struct Finder {
     cache: HashMap<OsString, Option<PathBuf>>,
index dc061fe5099a590a8cb38ec3a3352c84c3d6faeb..11932d58ceac623011357f60652b4a15f26a2cea 100644 (file)
 
 use build_helper::{self, output};
 
-use builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
-use cache::{Interned, INTERNER};
-use compile;
-use dist;
-use flags::Subcommand;
-use native;
-use tool::{self, Tool, SourceType};
-use toolstate::ToolState;
-use util::{self, dylib_path, dylib_path_var};
-use Crate as CargoCrate;
-use {DocTests, Mode, GitRepo};
+use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
+use crate::cache::{Interned, INTERNER};
+use crate::compile;
+use crate::dist;
+use crate::flags::Subcommand;
+use crate::native;
+use crate::tool::{self, Tool, SourceType};
+use crate::toolstate::ToolState;
+use crate::util::{self, dylib_path, dylib_path_var};
+use crate::Crate as CargoCrate;
+use crate::{DocTests, Mode, GitRepo};
 
 const ADB_TEST_DIR: &str = "/data/tmp/work";
 
@@ -429,6 +429,45 @@ fn run(self, builder: &Builder) {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CompiletestTest {
+    stage: u32,
+    host: Interned<String>,
+}
+
+impl Step for CompiletestTest {
+    type Output = ();
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/compiletest")
+    }
+
+    fn make_run(run: RunConfig) {
+        run.builder.ensure(CompiletestTest {
+            stage: run.builder.top_stage,
+            host: run.target,
+        });
+    }
+
+    /// Runs `cargo test` for compiletest.
+    fn run(self, builder: &Builder) {
+        let stage = self.stage;
+        let host = self.host;
+        let compiler = builder.compiler(stage, host);
+
+        let mut cargo = tool::prepare_tool_cargo(builder,
+                                                 compiler,
+                                                 Mode::ToolBootstrap,
+                                                 host,
+                                                 "test",
+                                                 "src/tools/compiletest",
+                                                 SourceType::InTree,
+                                                 &[]);
+
+        try_run(builder, &mut cargo);
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Clippy {
     stage: u32,
@@ -577,7 +616,7 @@ fn run(self, builder: &Builder) {
         if let Some(ref nodejs) = builder.config.nodejs {
             let mut command = Command::new(nodejs);
             command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]);
-            builder.ensure(::doc::Std {
+            builder.ensure(crate::doc::Std {
                 target: self.target,
                 stage: builder.top_stage,
             });
index 1bd4403a66ffa9aea6888d9f02f7fefd6086f77a..4335359e11589c7295c18e2f4832f615d61d7b2e 100644 (file)
 use std::process::{Command, exit};
 use std::collections::HashSet;
 
-use Mode;
-use Compiler;
-use builder::{Step, RunConfig, ShouldRun, Builder};
-use util::{exe, add_lib_path};
-use compile;
-use native;
-use channel::GitInfo;
-use channel;
-use cache::Interned;
-use toolstate::ToolState;
+use crate::Mode;
+use crate::Compiler;
+use crate::builder::{Step, RunConfig, ShouldRun, Builder};
+use crate::util::{exe, add_lib_path};
+use crate::compile;
+use crate::native;
+use crate::channel::GitInfo;
+use crate::channel;
+use crate::cache::Interned;
+use crate::toolstate::ToolState;
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum SourceType {
index be24ae0ce664815e96f42e65c00cd094e2bd6a47..b18e38e471efff47672d499e91ce736aca49c1c2 100644 (file)
@@ -21,8 +21,8 @@
 use std::process::Command;
 use std::time::{SystemTime, Instant};
 
-use config::Config;
-use builder::Builder;
+use crate::config::Config;
+use crate::builder::Builder;
 
 /// Returns the `name` as the filename of a static library for `target`.
 pub fn staticlib(name: &str, target: &str) -> String {
index c7e6af28f9d4fbb385c4d8f21394eea12f492ac8..4f8a3c0240e1a19b50938da2acf7b5f5e2740b97 100644 (file)
@@ -52,8 +52,8 @@ RUN env \
     CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv6 -marm" \
     bash musl.sh arm && \
     env \
-    CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv6 -marm" \
-    CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv6 -marm" \
+    CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv6 -marm -mfpu=vfp" \
+    CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv6 -marm -mfpu=vfp" \
     bash musl.sh armhf && \
     env \
     CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv7-a" \
index 8620346e5b7480fcb5eb5240fdfc9ee6c9c42a17..2e94ebe345adbbb791cb9d66bf18786c015f45fa 100644 (file)
@@ -6,5 +6,5 @@ the team is supporting directly.
 
 To see the list of built-in targets, you can run `rustc --print target-list`,
 or look at [the API
-docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/#modules).
+docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/index.html#modules).
 Each module there defines a builder for a particular target.
\ No newline at end of file
index 07e3a79471f5b5f4d877ed2129ef782df76fbdc9..3d63d072befe0ae46979c8d8ffcc5b90d8dc325a 100644 (file)
@@ -4,7 +4,7 @@
 architecture. The list of *targets* are the possible architectures that you can build for.
 
 To see all the options that you can set with a target, see the docs
-[here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/struct.Target.html).
+[here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html).
 
 To compile to a particular target, use the `--target` flag:
 
index 1165ab93a146953da8d37096e9c226edb492ca5b..edc039f896b2c528318706b233dde801c8214806 100644 (file)
@@ -8,7 +8,7 @@ The tracking issue for this feature is: [#48055]
 
 This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
 
-[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-coercions.md
+[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
 
 ```rust
 #![feature(unsized_locals)]
index b7faee1bc7da440e39dd7c79c067957171df4ba1..b2eb3566c04a7285ce117e509d9c804d884ef108 100644 (file)
@@ -28,3 +28,6 @@ path = "../liballoc/benches/lib.rs"
 name = "vec_deque_append_bench"
 path = "../liballoc/benches/vec_deque_append.rs"
 harness = false
+
+[features]
+compiler-builtins-mem = ['compiler_builtins/mem']
index 215689dfc48c99c007d06ce4ec16f91877a2d704..a2d2d3c74be9dd261813b56a42eaa19f8527df2a 100644 (file)
 /// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned
 /// case.
 ///
-/// We put the metadata first so that its position is the same for every `K` and `V`, in order
-/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
-/// prevent them from being reordered.
+/// We have a separate type for the header and rely on it matching the prefix of `LeafNode`, in
+/// order to statically allocate a single dummy node to avoid allocations. This struct is
+/// `repr(C)` to prevent them from being reordered.  `LeafNode` does not just contain a
+/// `NodeHeader` because we do not want unnecessary padding between `len` and the keys.
+/// Crucially, `NodeHeader` can be safely transmuted to different K and V.  (This is exploited
+/// by `as_header`.)
+/// See `into_key_slice` for an explanation of K2.  K2 cannot be safely transmuted around
+/// because the size of `NodeHeader` depends on its alignment!
+#[repr(C)]
+struct NodeHeader<K, V, K2 = ()> {
+    /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
+    /// This either points to an actual node or is null.
+    parent: *const InternalNode<K, V>,
+
+    /// This node's index into the parent node's `edges` array.
+    /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
+    /// This is only guaranteed to be initialized when `parent` is non-null.
+    parent_idx: MaybeUninit<u16>,
+
+    /// The number of keys and values this node stores.
+    ///
+    /// This next to `parent_idx` to encourage the compiler to join `len` and
+    /// `parent_idx` into the same 32-bit word, reducing space overhead.
+    len: u16,
+
+    /// See `into_key_slice`.
+    keys_start: [K2; 0],
+}
 #[repr(C)]
 struct LeafNode<K, V> {
     /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
@@ -98,24 +123,25 @@ unsafe fn new() -> Self {
             len: 0
         }
     }
+}
 
+impl<K, V> NodeHeader<K, V> {
     fn is_shared_root(&self) -> bool {
         ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _)
     }
 }
 
 // We need to implement Sync here in order to make a static instance.
-unsafe impl Sync for LeafNode<(), ()> {}
+unsafe impl Sync for NodeHeader<(), ()> {}
 
 // An empty node used as a placeholder for the root node, to avoid allocations.
-// We use () in order to save space, since no operation on an empty tree will
+// We use just a header in order to save space, since no operation on an empty tree will
 // ever take a pointer past the first key.
-static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
+static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader {
     parent: ptr::null(),
     parent_idx: MaybeUninit::uninitialized(),
     len: 0,
-    keys: MaybeUninit::uninitialized(),
-    vals: MaybeUninit::uninitialized(),
+    keys_start: [],
 };
 
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
@@ -281,7 +307,7 @@ pub fn pop_level(&mut self) {
                                     .node)
         };
         self.height -= 1;
-        self.as_mut().as_leaf_mut().parent = ptr::null();
+        unsafe { (*self.as_mut().as_leaf_mut()).parent = ptr::null(); }
 
         unsafe {
             Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
@@ -306,6 +332,11 @@ pub fn pop_level(&mut self) {
 ///   `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the
 ///   `NodeRef` points to an internal node, and when this is `LeafOrInternal` the
 ///   `NodeRef` could be pointing to either type of node.
+///   Note that in case of a leaf node, this might still be the shared root!  Only turn
+///   this into a `LeafNode` reference if you know it is not a root!  Shared references
+///   must be dereferencable *for the entire size of their pointee*, so `&InternalNode`
+///   pointing to the shared root is UB.
+///   Turning this into a `NodeHeader` is always safe.
 pub struct NodeRef<BorrowType, K, V, Type> {
     height: usize,
     node: NonNull<LeafNode<K, V>>,
@@ -352,7 +383,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     /// Finds the length of the node. This is the number of keys or values. In an
     /// internal node, the number of edges is `len() + 1`.
     pub fn len(&self) -> usize {
-        self.as_leaf().len as usize
+        self.as_header().len as usize
     }
 
     /// Returns the height of this node in the whole tree. Zero height denotes the
@@ -382,14 +413,19 @@ fn reborrow<'a>(&'a self) -> NodeRef<marker::Immut<'a>, K, V, Type> {
         }
     }
 
-    fn as_leaf(&self) -> &LeafNode<K, V> {
+    /// Assert that this is indeed a proper leaf node, and not the shared root.
+    unsafe fn as_leaf(&self) -> &LeafNode<K, V> {
+        self.node.as_ref()
+    }
+
+    fn as_header(&self) -> &NodeHeader<K, V> {
         unsafe {
-            self.node.as_ref()
+            &*(self.node.as_ptr() as *const NodeHeader<K, V>)
         }
     }
 
     pub fn is_shared_root(&self) -> bool {
-        self.as_leaf().is_shared_root()
+        self.as_header().is_shared_root()
     }
 
     pub fn keys(&self) -> &[K] {
@@ -418,7 +454,7 @@ pub fn ascend(self) -> Result<
         >,
         Self
     > {
-        let parent_as_leaf = self.as_leaf().parent as *const LeafNode<K, V>;
+        let parent_as_leaf = self.as_header().parent as *const LeafNode<K, V>;
         if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) {
             Ok(Handle {
                 node: NodeRef {
@@ -427,7 +463,7 @@ pub fn ascend(self) -> Result<
                     root: self.root,
                     _marker: PhantomData
                 },
-                idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) },
+                idx: unsafe { usize::from(*self.as_header().parent_idx.get_ref()) },
                 _marker: PhantomData
             })
         } else {
@@ -534,10 +570,10 @@ unsafe fn reborrow_mut(&mut self) -> NodeRef<marker::Mut, K, V, Type> {
         }
     }
 
-    fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
-        unsafe {
-            self.node.as_mut()
-        }
+    /// Returns a raw ptr to avoid asserting exclusive access to the entire node.
+    fn as_leaf_mut(&mut self) -> *mut LeafNode<K, V> {
+        // We are mutable, so we cannot be the root, so accessing this as a leaf is okay.
+        self.node.as_ptr()
     }
 
     fn keys_mut(&mut self) -> &mut [K] {
@@ -551,28 +587,50 @@ fn vals_mut(&mut self) -> &mut [V] {
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
     fn into_key_slice(self) -> &'a [K] {
-        // When taking a pointer to the keys, if our key has a stricter
-        // alignment requirement than the shared root does, then the pointer
-        // would be out of bounds, which LLVM assumes will not happen. If the
-        // alignment is more strict, we need to make an empty slice that doesn't
-        // use an out of bounds pointer.
+        // We have to be careful here because we might be pointing to the shared root.
+        // In that case, we must not create an `&LeafNode`.  We could just return
+        // an empty slice whenever the length is 0 (this includes the shared root),
+        // but we want to avoid that run-time check.
+        // Instead, we create a slice pointing into the node whenever possible.
+        // We can sometimes do this even for the shared root, as the slice will be
+        // empty.  We cannot *always* do this because if the type is too highly
+        // aligned, the offset of `keys` in a "full node" might be outside the bounds
+        // of the header!  So we do an alignment check first, that will be
+        // evaluated at compile-time, and only do any run-time check in the rare case
+        // that the alignment is very big.
         if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
             &[]
         } else {
-            // Here either it's not the root, or the alignment is less strict,
-            // in which case the keys pointer will point "one-past-the-end" of
-            // the node, which is allowed by LLVM.
+            // Thanks to the alignment check above, we know that `keys` will be
+            // in-bounds of some allocation even if this is the shared root!
+            // (We might be one-past-the-end, but that is allowed by LLVM.)
+            // Getting the pointer is tricky though.  `NodeHeader` does not have a `keys`
+            // field because we want its size to not depend on the alignment of `K`
+            // (needed becuase `as_header` should be safe).  We cannot call `as_leaf`
+            // because we might be the shared root.
+            // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
+            // and hence just adds a size-0-align-1 field, not affecting layout).
+            // We know that we can transmute `NodeHeader<K, V, ()>` to `NodeHeader<K, V, K>`
+            // because we did the alignment check above, and hence `NodeHeader<K, V, K>`
+            // is not bigger than `NodeHeader<K, V, ()>`!  Then we can use `NodeHeader<K, V, K>`
+            // to compute the pointer where the keys start.
+            // This entire hack will become unnecessary once
+            // <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw
+            // pointer to the `keys` field of `*const InternalNode<K, V>`.
+
+            // This is a non-debug-assert because it can be completely compile-time evaluated.
+            assert!(mem::size_of::<NodeHeader<K, V>>() == mem::size_of::<NodeHeader<K, V, K>>());
+            let header = self.as_header() as *const _ as *const NodeHeader<K, V, K>;
+            let keys = unsafe { &(*header).keys_start as *const _ as *const K };
             unsafe {
-                slice::from_raw_parts(
-                    self.as_leaf().keys.as_ptr() as *const K,
-                    self.len()
-                )
+                slice::from_raw_parts(keys, self.len())
             }
         }
     }
 
     fn into_val_slice(self) -> &'a [V] {
         debug_assert!(!self.is_shared_root());
+        // We cannot be the root, so `as_leaf` is okay
         unsafe {
             slice::from_raw_parts(
                 self.as_leaf().vals.as_ptr() as *const V,
@@ -602,7 +660,7 @@ fn into_key_slice_mut(mut self) -> &'a mut [K] {
         } else {
             unsafe {
                 slice::from_raw_parts_mut(
-                    self.as_leaf_mut().keys.as_mut_ptr() as *mut K,
+                    (*self.as_leaf_mut()).keys.as_mut_ptr() as *mut K,
                     self.len()
                 )
             }
@@ -613,7 +671,7 @@ fn into_val_slice_mut(mut self) -> &'a mut [V] {
         debug_assert!(!self.is_shared_root());
         unsafe {
             slice::from_raw_parts_mut(
-                self.as_leaf_mut().vals.as_mut_ptr() as *mut V,
+                (*self.as_leaf_mut()).vals.as_mut_ptr() as *mut V,
                 self.len()
             )
         }
@@ -637,9 +695,9 @@ pub fn push(&mut self, key: K, val: V) {
         unsafe {
             ptr::write(self.keys_mut().get_unchecked_mut(idx), key);
             ptr::write(self.vals_mut().get_unchecked_mut(idx), val);
-        }
 
-        self.as_leaf_mut().len += 1;
+            (*self.as_leaf_mut()).len += 1;
+        }
     }
 
     /// Adds a key/value pair to the beginning of the node.
@@ -651,9 +709,9 @@ pub fn push_front(&mut self, key: K, val: V) {
         unsafe {
             slice_insert(self.keys_mut(), 0, key);
             slice_insert(self.vals_mut(), 0, val);
-        }
 
-        self.as_leaf_mut().len += 1;
+            (*self.as_leaf_mut()).len += 1;
+        }
     }
 }
 
@@ -672,7 +730,7 @@ pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
             ptr::write(self.vals_mut().get_unchecked_mut(idx), val);
             ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node);
 
-            self.as_leaf_mut().len += 1;
+            (*self.as_leaf_mut()).len += 1;
 
             Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
         }
@@ -708,7 +766,7 @@ pub fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
                 edge.node
             );
 
-            self.as_leaf_mut().len += 1;
+            (*self.as_leaf_mut()).len += 1;
 
             self.correct_all_childrens_parent_links();
         }
@@ -732,12 +790,12 @@ pub fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
                 ForceResult::Internal(internal) => {
                     let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1));
                     let mut new_root = Root { node: edge, height: internal.height - 1 };
-                    new_root.as_mut().as_leaf_mut().parent = ptr::null();
+                    (*new_root.as_mut().as_leaf_mut()).parent = ptr::null();
                     Some(new_root)
                 }
             };
 
-            self.as_leaf_mut().len -= 1;
+            (*self.as_leaf_mut()).len -= 1;
             (key, val, edge)
         }
     }
@@ -765,7 +823,7 @@ pub fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
                     );
 
                     let mut new_root = Root { node: edge, height: internal.height - 1 };
-                    new_root.as_mut().as_leaf_mut().parent = ptr::null();
+                    (*new_root.as_mut().as_leaf_mut()).parent = ptr::null();
 
                     for i in 0..old_len {
                         Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link();
@@ -775,7 +833,7 @@ pub fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
                 }
             };
 
-            self.as_leaf_mut().len -= 1;
+            (*self.as_leaf_mut()).len -= 1;
 
             (key, val, edge)
         }
@@ -966,7 +1024,7 @@ fn insert_fit(&mut self, key: K, val: V) -> *mut V {
             slice_insert(self.node.keys_mut(), self.idx, key);
             slice_insert(self.node.vals_mut(), self.idx, val);
 
-            self.node.as_leaf_mut().len += 1;
+            (*self.node.as_leaf_mut()).len += 1;
 
             self.node.vals_mut().get_unchecked_mut(self.idx)
         }
@@ -1009,8 +1067,10 @@ fn correct_parent_link(mut self) {
         let idx = self.idx as u16;
         let ptr = self.node.as_internal_mut() as *mut _;
         let mut child = self.descend();
-        child.as_leaf_mut().parent = ptr;
-        child.as_leaf_mut().parent_idx.set(idx);
+        unsafe {
+            (*child.as_leaf_mut()).parent = ptr;
+            (*child.as_leaf_mut()).parent_idx.set(idx);
+        }
     }
 
     /// Unsafely asserts to the compiler some static information about whether the underlying
@@ -1158,7 +1218,7 @@ pub fn split(mut self)
                 new_len
             );
 
-            self.node.as_leaf_mut().len = self.idx as u16;
+            (*self.node.as_leaf_mut()).len = self.idx as u16;
             new_node.len = new_len as u16;
 
             (
@@ -1180,7 +1240,7 @@ pub fn remove(mut self)
         unsafe {
             let k = slice_remove(self.node.keys_mut(), self.idx);
             let v = slice_remove(self.node.vals_mut(), self.idx);
-            self.node.as_leaf_mut().len -= 1;
+            (*self.node.as_leaf_mut()).len -= 1;
             (self.left_edge(), k, v)
         }
     }
@@ -1221,7 +1281,7 @@ pub fn split(mut self)
                 new_len + 1
             );
 
-            self.node.as_leaf_mut().len = self.idx as u16;
+            (*self.node.as_leaf_mut()).len = self.idx as u16;
             new_node.data.len = new_len as u16;
 
             let mut new_root = Root {
@@ -1295,9 +1355,9 @@ pub fn merge(mut self)
             for i in self.idx+1..self.node.len() {
                 Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link();
             }
-            self.node.as_leaf_mut().len -= 1;
+            (*self.node.as_leaf_mut()).len -= 1;
 
-            left_node.as_leaf_mut().len += right_len as u16 + 1;
+            (*left_node.as_leaf_mut()).len += right_len as u16 + 1;
 
             if self.node.height > 1 {
                 ptr::copy_nonoverlapping(
@@ -1407,8 +1467,8 @@ pub fn bulk_steal_left(&mut self, count: usize) {
                 move_kv(left_kv, new_left_len, parent_kv, 0, 1);
             }
 
-            left_node.reborrow_mut().as_leaf_mut().len -= count as u16;
-            right_node.reborrow_mut().as_leaf_mut().len += count as u16;
+            (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16;
+            (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16;
 
             match (left_node.force(), right_node.force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
@@ -1468,8 +1528,8 @@ pub fn bulk_steal_right(&mut self, count: usize) {
                           new_right_len);
             }
 
-            left_node.reborrow_mut().as_leaf_mut().len += count as u16;
-            right_node.reborrow_mut().as_leaf_mut().len -= count as u16;
+            (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16;
+            (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16;
 
             match (left_node.force(), right_node.force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
@@ -1560,8 +1620,8 @@ pub fn move_suffix(&mut self,
 
             move_kv(left_kv, left_new_len, right_kv, 0, right_new_len);
 
-            left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16;
-            right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16;
+            (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16;
+            (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16;
 
             match (left_node.force(), right_node.force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(right)) => {
index 2ef84dbade0fbc480f96529db85988407f45e241..ba46fafaf169f6d09bb46a700773dab490639811 100644 (file)
@@ -627,7 +627,9 @@ pub fn pop_front(&mut self) -> Option<T> {
         self.pop_front_node().map(Node::into_element)
     }
 
-    /// Appends an element to the back of a list
+    /// Appends an element to the back of a list.
+    ///
+    /// This operation should compute in O(1) time.
     ///
     /// # Examples
     ///
@@ -647,6 +649,8 @@ pub fn push_back(&mut self, elt: T) {
     /// Removes the last element from a list and returns it, or `None` if
     /// it is empty.
     ///
+    /// This operation should compute in O(1) time.
+    ///
     /// # Examples
     ///
     /// ```
index e329b45a6175d8641532e4d71d6c1e0a7f05cc3a..509195cd047d4846427df0efa53cc7ed9c29124e 100644 (file)
@@ -79,6 +79,11 @@ fn test_reserve() {
     assert!(v.capacity() >= 33)
 }
 
+#[test]
+fn test_zst_capacity() {
+    assert_eq!(Vec::<()>::new().capacity(), usize::max_value());
+}
+
 #[test]
 fn test_extend() {
     let mut v = Vec::new();
index 0c5256b981e5cc63d1cb9abc9d348b5b9f1c0162..8e0caa5ae330deb3f771b2055bae935b0aec9542 100644 (file)
@@ -609,10 +609,15 @@ pub trait Debug {
 /// println!("The origin is: {}", origin);
 /// ```
 #[rustc_on_unimplemented(
+    on(
+        _Self="std::path::Path",
+        label="`{Self}` cannot be formatted with the default formatter; call `.display()` on it",
+        note="call `.display()` or `.to_string_lossy()` to safely print paths, \
+              as they may contain non-Unicode data"
+    ),
     message="`{Self}` doesn't implement `{Display}`",
     label="`{Self}` cannot be formatted with the default formatter",
-    note="in format strings you may be able to use `{{:?}}` \
-          (or {{:#?}} for pretty-print) instead",
+    note="in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead",
 )]
 #[doc(alias = "{}")]
 #[stable(feature = "rust1", since = "1.0.0")]
index 0c870f9e404a26ca59147ea840bb30760bb16a67..5dee1d6dd3a39dcb66115401481d41e23eb7341c 100644 (file)
@@ -33,6 +33,7 @@
 ///
 /// When using a future, you generally won't call `poll` directly, but instead
 /// `await!` the value.
+#[must_use]
 pub trait Future {
     /// The result of the `Future`.
     type Output;
index 92a4aed4e27e586c2eced47623495fc93b40694e..c0b83a6868b383aab4b4df2a8529e234f54051ba 100644 (file)
@@ -98,6 +98,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item=()>) {}
     message="`{Self}` is not an iterator"
 )]
 #[doc(spotlight)]
+#[must_use]
 pub trait Iterator {
     /// The type of the elements being iterated over.
     #[stable(feature = "rust1", since = "1.0.0")]
index 4acf3a15ebf0dbf5de22104cd667ce00a73e0d26..fd74e713416d6099b48ad8cbd380c13bf3458b6b 100644 (file)
@@ -70,7 +70,7 @@ impl $Ty {
                 #[stable(feature = "nonzero", since = "1.28.0")]
                 #[inline]
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
-                    $Ty(unsafe { NonZero(n) })
+                    $Ty(NonZero(n))
                 }
 
                 /// Create a non-zero if the given value is not zero.
index d1be724c3264e6c1a7430d94878bb8d1d55eee8b..3b356b9a1e7b4ee73206f66895da7c99ee7fc041 100644 (file)
@@ -72,6 +72,7 @@
     label="expected an `Fn<{Args}>` closure, found `{Self}`",
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use]
 pub trait Fn<Args> : FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -150,6 +151,7 @@ pub trait Fn<Args> : FnMut<Args> {
     label="expected an `FnMut<{Args}>` closure, found `{Self}`",
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use]
 pub trait FnMut<Args> : FnOnce<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -228,6 +230,7 @@ pub trait FnMut<Args> : FnOnce<Args> {
     label="expected an `FnOnce<{Args}>` closure, found `{Self}`",
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
     #[stable(feature = "fn_once_output", since = "1.12.0")]
index f61e582f7641b21e3fb0bd07cc53b59b0e134042..b3c93ae1fa7b24b5a25f862ccb38ec987e75f925 100644 (file)
@@ -2544,7 +2544,7 @@ pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
 /// assert_eq!(actual, expected);
 /// ```
 #[unstable(feature = "ptr_hash", reason = "newly added", issue = "56286")]
-pub fn hash<T, S: hash::Hasher>(hashee: *const T, into: &mut S) {
+pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
     use hash::Hash;
     hashee.hash(into);
 }
@@ -2928,7 +2928,7 @@ impl<T: ?Sized> NonNull<T> {
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
-        NonNull { pointer: unsafe { NonZero(ptr as _) } }
+        NonNull { pointer: NonZero(ptr as _) }
     }
 
     /// Creates a new `NonNull` if `ptr` is non-null.
index 060983a702f0b79f2e1f2ef87e02442aa9ffc8f3..d2683e31eefb84fc04089034f8cf8d2fdb11a305 100644 (file)
@@ -1072,6 +1072,15 @@ pub fn compare_exchange_weak(&self,
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "atomic_bool_from", since = "1.24.0")]
 impl From<bool> for AtomicBool {
+    /// Converts a `bool` into an `AtomicBool`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::atomic::AtomicBool;
+    /// let atomic_bool = AtomicBool::from(true);
+    /// assert_eq!(format!("{:?}", atomic_bool), "true")
+    /// ```
     #[inline]
     fn from(b: bool) -> Self { Self::new(b) }
 }
@@ -1126,8 +1135,12 @@ fn default() -> Self {
 
         #[$stable_from]
         impl From<$int_type> for $atomic_type {
-            #[inline]
-            fn from(v: $int_type) -> Self { Self::new(v) }
+            doc_comment! {
+                concat!(
+"Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`."),
+                #[inline]
+                fn from(v: $int_type) -> Self { Self::new(v) }
+            }
         }
 
         #[$stable_debug]
index 8d2b1d74c554b0f62839a3056f9b04341c3a36ab..43bc9d88895d7e74af0c63c4f4432bd5d40a9972 100644 (file)
@@ -36,6 +36,7 @@
 use ty::fold::TypeFoldable;
 use ty::subst::{Kind, UnpackedKind};
 use ty::{self, BoundVar, Lift, Ty, TyCtxt};
+use util::captures::Captures;
 
 impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
     /// The "main method" for a canonicalized trait query. Given the
@@ -527,32 +528,30 @@ fn query_region_constraints_into_obligations<'a>(
         param_env: ty::ParamEnv<'tcx>,
         unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
         result_subst: &'a CanonicalVarValues<'tcx>,
-    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
-        Box::new(
-            unsubstituted_region_constraints
-                .iter()
-                .map(move |constraint| {
-                    let constraint = substitute_value(self.tcx, result_subst, constraint);
-                    let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
-
-                    Obligation::new(
-                        cause.clone(),
-                        param_env,
-                        match k1.unpack() {
-                            UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
-                                ty::Binder::bind(
-                                    ty::OutlivesPredicate(r1, r2)
-                                )
-                            ),
-                            UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
-                                ty::Binder::bind(
-                                    ty::OutlivesPredicate(t1, r2)
-                                )
-                            ),
-                        }
-                    )
-                })
-        ) as Box<dyn Iterator<Item = _>>
+    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'gcx> {
+        unsubstituted_region_constraints
+            .iter()
+            .map(move |constraint| {
+                let constraint = substitute_value(self.tcx, result_subst, constraint);
+                let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
+
+                Obligation::new(
+                    cause.clone(),
+                    param_env,
+                    match k1.unpack() {
+                        UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
+                            ty::Binder::bind(
+                                ty::OutlivesPredicate(r1, r2)
+                            )
+                        ),
+                        UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
+                            ty::Binder::bind(
+                                ty::OutlivesPredicate(t1, r2)
+                            )
+                        ),
+                    }
+                )
+            })
     }
 
     /// Given two sets of values for the same set of canonical variables, unify them.
index 7d997a01546002f8a6faa2ccbb0d7b5cb38c0230..d213a5c56187141f6f169ca93affa41617bacfbf 100644 (file)
@@ -1095,7 +1095,8 @@ pub fn construct_generic_bound_failure(
                             let sp = hir.span(id);
                             // `sp` only covers `T`, change it so that it covers
                             // `T:` when appropriate
-                            let sp = if has_bounds {
+                            let is_impl_trait = bound_kind.to_string().starts_with("impl ");
+                            let sp = if has_bounds && !is_impl_trait {
                                 sp.to(self.tcx
                                     .sess
                                     .source_map()
@@ -1103,7 +1104,7 @@ pub fn construct_generic_bound_failure(
                             } else {
                                 sp
                             };
-                            (sp, has_bounds)
+                            (sp, has_bounds, is_impl_trait)
                         })
                     } else {
                         None
@@ -1136,25 +1137,33 @@ pub fn construct_generic_bound_failure(
 
         fn binding_suggestion<'tcx, S: fmt::Display>(
             err: &mut DiagnosticBuilder<'tcx>,
-            type_param_span: Option<(Span, bool)>,
+            type_param_span: Option<(Span, bool, bool)>,
             bound_kind: GenericKind<'tcx>,
             sub: S,
         ) {
-            let consider = &format!(
-                "consider adding an explicit lifetime bound `{}: {}`...",
-                bound_kind, sub
+            let consider = format!(
+                "consider adding an explicit lifetime bound {}",
+                if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) {
+                    format!(" `{}` to `{}`...", sub, bound_kind)
+                } else {
+                    format!("`{}: {}`...", bound_kind, sub)
+                },
             );
-            if let Some((sp, has_lifetimes)) = type_param_span {
-                let tail = if has_lifetimes { " + " } else { "" };
-                let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
+            if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
+                let suggestion = if is_impl_trait {
+                    format!("{} + {}", bound_kind, sub)
+                } else {
+                    let tail = if has_lifetimes { " + " } else { "" };
+                    format!("{}: {}{}", bound_kind, sub, tail)
+                };
                 err.span_suggestion_short_with_applicability(
                     sp,
-                    consider,
+                    &consider,
                     suggestion,
                     Applicability::MaybeIncorrect, // Issue #41966
                 );
             } else {
-                err.help(consider);
+                err.help(&consider);
             }
         }
 
index b7759a8c92b07ef64a461f0c7f3bf590e9c8c400..82145f61b26b18ea8c77144acca6f9ca14219f5d 100644 (file)
@@ -365,6 +365,13 @@ pub mod parser {
     }
 }
 
+declare_lint! {
+    pub DEPRECATED_IN_FUTURE,
+    Allow,
+    "detects use of items that will be deprecated in a future version",
+    report_in_external_macro: true
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// that are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -427,6 +434,7 @@ fn get_lints(&self) -> LintArray {
             MACRO_USE_EXTERN_CRATE,
             MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
             parser::QUESTION_MARK_MACRO_SEP,
+            DEPRECATED_IN_FUTURE,
         )
     }
 }
index e576951417f93b27026c2dbe17169871dedf5e81..31a75bd106e2cb36c6a9b13deabcb7c6a4375ab7 100644 (file)
@@ -1657,11 +1657,15 @@ fn warn_about_dead_assign(&self,
     fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) {
         if let Some(name) = self.should_warn(var) {
             if is_argument {
-                self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
-                    &format!("value passed to `{}` is never read", name));
+                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
+                &format!("value passed to `{}` is never read", name))
+                .help("maybe it is overwritten before being read?")
+                .emit();
             } else {
-                self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
-                    &format!("value assigned to `{}` is never read", name));
+                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
+                &format!("value assigned to `{}` is never read", name))
+                .help("maybe it is overwritten before being read?")
+                .emit();
             }
         }
     }
index ab379c910f7764b645e45803c875497b2a99c2d4..61341cbc30ce45ca3ef5f17c4676bf67dd482d70 100644 (file)
@@ -13,7 +13,7 @@
 
 pub use self::StabilityLevel::*;
 
-use lint;
+use lint::{self, Lint};
 use hir::{self, Item, Generics, StructField, Variant, HirId};
 use hir::def::Def;
 use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
@@ -562,18 +562,20 @@ pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> Ev
             return EvalResult::Allow;
         }
 
-        let lint_deprecated = |def_id: DefId, id: NodeId, note: Option<Symbol>| {
-            let path = self.item_path_str(def_id);
-
+        let lint_deprecated = |def_id: DefId,
+                               id: NodeId,
+                               note: Option<Symbol>,
+                               message: &str,
+                               lint: &'static Lint| {
             let msg = if let Some(note) = note {
-                format!("use of deprecated item '{}': {}", path, note)
+                format!("{}: {}", message, note)
             } else {
-                format!("use of deprecated item '{}'", path)
+                format!("{}", message)
             };
 
-            self.lint_node(lint::builtin::DEPRECATED, id, span, &msg);
+            self.lint_node(lint, id, span, &msg);
             if id == ast::DUMMY_NODE_ID {
-                span_bug!(span, "emitted a deprecated lint with dummy node id: {:?}", def_id);
+                span_bug!(span, "emitted a {} lint with dummy node id: {:?}", lint.name, def_id);
             }
         };
 
@@ -584,17 +586,39 @@ pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> Ev
                 // version, then we should display no warning message.
                 let deprecated_in_future_version = if let Some(sym) = depr_entry.attr.since {
                     let since = sym.as_str();
-                    !deprecation_in_effect(&since)
+                    if !deprecation_in_effect(&since) {
+                        Some(since)
+                    } else {
+                        None
+                    }
                 } else {
-                    false
+                    None
                 };
 
                 let parent_def_id = self.hir().local_def_id(self.hir().get_parent(id));
-                let skip = deprecated_in_future_version ||
-                           self.lookup_deprecation_entry(parent_def_id)
+                let skip = self.lookup_deprecation_entry(parent_def_id)
                                .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
-                if !skip {
-                    lint_deprecated(def_id, id, depr_entry.attr.note);
+
+                if let Some(since) = deprecated_in_future_version {
+                    let path = self.item_path_str(def_id);
+                    let message = format!("use of item '{}' \
+                                           that will be deprecated in future version {}",
+                                          path,
+                                          since);
+
+                    lint_deprecated(def_id,
+                                    id,
+                                    depr_entry.attr.note,
+                                    &message,
+                                    lint::builtin::DEPRECATED_IN_FUTURE);
+                } else if !skip {
+                    let path = self.item_path_str(def_id);
+                    let message = format!("use of deprecated item '{}'", path);
+                    lint_deprecated(def_id,
+                                    id,
+                                    depr_entry.attr.note,
+                                    &message,
+                                    lint::builtin::DEPRECATED);
                 }
             };
         }
@@ -614,8 +638,24 @@ pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> Ev
         if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, since }), ..})
                 = stability {
             if let Some(id) = id {
+                let path = self.item_path_str(def_id);
                 if deprecation_in_effect(&since.as_str()) {
-                    lint_deprecated(def_id, id, Some(reason));
+                    let message = format!("use of deprecated item '{}'", path);
+                    lint_deprecated(def_id,
+                                    id,
+                                    Some(reason),
+                                    &message,
+                                    lint::builtin::DEPRECATED);
+                } else {
+                    let message = format!("use of item '{}' \
+                                           that will be deprecated in future version {}",
+                                          path,
+                                          since);
+                    lint_deprecated(def_id,
+                                    id,
+                                    Some(reason),
+                                    &message,
+                                    lint::builtin::DEPRECATED_IN_FUTURE);
                 }
             }
         }
index 289f693df244d0d43728cc2bbd9a6960a598fd42..8b16aafd314d7d0d53a20c652d85c2214a54a875 100644 (file)
@@ -183,50 +183,14 @@ pub struct EvalError<'tcx> {
 impl<'tcx> EvalError<'tcx> {
     pub fn print_backtrace(&mut self) {
         if let Some(ref mut backtrace) = self.backtrace {
-            eprintln!("{}", print_backtrace(&mut *backtrace));
+            print_backtrace(&mut *backtrace);
         }
     }
 }
 
-fn print_backtrace(backtrace: &mut Backtrace) -> String {
-    use std::fmt::Write;
-
+fn print_backtrace(backtrace: &mut Backtrace) {
     backtrace.resolve();
-
-    let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
-    write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
-    'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
-        if frame.symbols().is_empty() {
-            write!(trace_text, "  {}: no symbols\n", i).unwrap();
-        }
-        let mut first = true;
-        for symbol in frame.symbols() {
-            if first {
-                write!(trace_text, "  {}: ", i).unwrap();
-                first = false;
-            } else {
-                let len = i.to_string().len();
-                write!(trace_text, "  {}  ", " ".repeat(len)).unwrap();
-            }
-            if let Some(name) = symbol.name() {
-                write!(trace_text, "{}\n", name).unwrap();
-            } else {
-                write!(trace_text, "<unknown>\n").unwrap();
-            }
-            write!(trace_text, "           at ").unwrap();
-            if let Some(file_path) = symbol.filename() {
-                write!(trace_text, "{}", file_path.display()).unwrap();
-            } else {
-                write!(trace_text, "<unknown_file>").unwrap();
-            }
-            if let Some(line) = symbol.lineno() {
-                write!(trace_text, ":{}\n", line).unwrap();
-            } else {
-                write!(trace_text, "\n").unwrap();
-            }
-        }
-    }
-    trace_text
+    eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
 }
 
 impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
@@ -238,7 +202,7 @@ fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
 
                 if val == "immediate" {
                     // Print it now
-                    eprintln!("{}", print_backtrace(&mut backtrace));
+                    print_backtrace(&mut backtrace);
                     None
                 } else {
                     Some(Box::new(backtrace))
index 8b26ada1576063db231af8f977c05bb6b89447a3..e229f8d95cd5b566d09c8ef47cc9f6e445fa8cc3 100644 (file)
@@ -1192,7 +1192,7 @@ macro_rules! require_simd {
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
-    // every intrinsic takes a SIMD vector as its first argument
+    // every intrinsic below takes a SIMD vector as its first argument
     require_simd!(arg_tys[0], "input");
     let in_ty = arg_tys[0];
     let in_elem = arg_tys[0].simd_type(tcx);
@@ -1296,6 +1296,7 @@ macro_rules! require_simd {
     if name == "simd_select" {
         let m_elem_ty = in_elem;
         let m_len = in_len;
+        require_simd!(arg_tys[1], "argument");
         let v_len = arg_tys[1].simd_size(tcx);
         require!(m_len == v_len,
                  "mismatched lengths: mask length `{}` != other vector length `{}`",
index 12109ae1662ff5364b8fe79de6f0e9f3c16fb507..82b1d7e8b40e4554adb485776992b7aa04924d64 100644 (file)
@@ -140,6 +140,7 @@ unsafe fn configure_llvm(sess: &Session) {
     ("avx512vpopcntdq", Some("avx512_target_feature")),
     ("bmi1", None),
     ("bmi2", None),
+    ("cmpxchg16b", Some("cmpxchg16b_target_feature")),
     ("fma", None),
     ("fxsr", None),
     ("lzcnt", None),
@@ -212,6 +213,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
         ("x86", "pclmulqdq") => "pclmul",
         ("x86", "rdrand") => "rdrnd",
         ("x86", "bmi1") => "bmi",
+        ("x86", "cmpxchg16b") => "cx16",
         ("aarch64", "fp") => "fp-armv8",
         ("aarch64", "fp16") => "fullfp16",
         (_, s) => s,
index b1e44ea761c8664e4d2d1c72b36328ac4988b78e..66364ff88b38dce963a368511cbb1a951dbe107e 100644 (file)
@@ -376,7 +376,7 @@ macro_rules! add_lint_group {
     store.register_removed("resolve_trait_on_defaulted_unit",
         "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
     store.register_removed("private_no_mangle_fns",
-        "no longer an warning, #[no_mangle] functions always exported");
+        "no longer a warning, #[no_mangle] functions always exported");
     store.register_removed("private_no_mangle_statics",
-        "no longer an warning, #[no_mangle] statics always exported");
+        "no longer a warning, #[no_mangle] statics always exported");
 }
index e3029c6a19d499d057268af5c690546fcf731554..5eca62938f7a8c821cbe68b18930779f7c770b12 100644 (file)
@@ -545,7 +545,7 @@ fn visit_statement_entry(
                 self.mutate_place(
                     ContextKind::SetDiscrim.new(location),
                     (place, span),
-                    Shallow(Some(ArtificialField::Discriminant)),
+                    Shallow(None),
                     JustWrite,
                     flow_state,
                 );
@@ -782,7 +782,6 @@ enum MutateMode {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum ArtificialField {
-    Discriminant,
     ArrayLength,
     ShallowBorrow,
 }
@@ -1191,14 +1190,14 @@ fn consume_rvalue(
 
             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
                 let af = match *rvalue {
-                    Rvalue::Len(..) => ArtificialField::ArrayLength,
-                    Rvalue::Discriminant(..) => ArtificialField::Discriminant,
+                    Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
+                    Rvalue::Discriminant(..) => None,
                     _ => unreachable!(),
                 };
                 self.access_place(
                     context,
                     (place, span),
-                    (Shallow(Some(af)), Read(ReadKind::Copy)),
+                    (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
                     flow_state,
                 );
index 8af23a8813a9e6d8eac91be8c07d60a2e0461433..07bda8af62618a6191df91d1533277641add6939 100644 (file)
@@ -99,7 +99,7 @@ fn visit_statement(&mut self,
                 self.mutate_place(
                     ContextKind::SetDiscrim.new(location),
                     place,
-                    Shallow(Some(ArtificialField::Discriminant)),
+                    Shallow(None),
                     JustWrite,
                 );
             }
@@ -360,14 +360,14 @@ fn consume_rvalue(
 
             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
                 let af = match *rvalue {
-                    Rvalue::Len(..) => ArtificialField::ArrayLength,
-                    Rvalue::Discriminant(..) => ArtificialField::Discriminant,
+                    Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
+                    Rvalue::Discriminant(..) => None,
                     _ => unreachable!(),
                 };
                 self.access_place(
                     context,
                     place,
-                    (Shallow(Some(af)), Read(ReadKind::Copy)),
+                    (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
                 );
             }
index eeac915cff37eb79b6a33619917d96f057016454..e24586cca0929ba372e8e084253a839f6e3b4c13 100644 (file)
@@ -165,15 +165,12 @@ fn place_components_conflict<'gcx, 'tcx>(
                 let base_ty = base.ty(mir, tcx).to_ty(tcx);
 
                 match (elem, &base_ty.sty, access) {
-                    (_, _, Shallow(Some(ArtificialField::Discriminant)))
-                    | (_, _, Shallow(Some(ArtificialField::ArrayLength)))
+                    (_, _, Shallow(Some(ArtificialField::ArrayLength)))
                     | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
-                        // The discriminant and array length are like
-                        // additional fields on the type; they do not
-                        // overlap any existing data there. Furthermore,
-                        // they cannot actually be a prefix of any
-                        // borrowed place (at least in MIR as it is
-                        // currently.)
+                        // The array length is like  additional fields on the
+                        // type; it does not overlap any existing data there.
+                        // Furthermore, if cannot actually be a prefix of any
+                        // borrowed place (at least in MIR as it is currently.)
                         //
                         // e.g., a (mutable) borrow of `a[5]` while we read the
                         // array length of `a`.
index ab52d9be6b81bc7255f5aeb2e0530a298886a061..451034fd153341c89c8513ca37432dd067f185a9 100644 (file)
@@ -111,13 +111,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
 
             let safety = match fn_sig.unsafety {
                 hir::Unsafety::Normal => Safety::Safe,
-                hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => {
-                    // As specified in #55607, a `const unsafe fn` differs
-                    // from an `unsafe fn` in that its body is still considered
-                    // safe code by default.
-                    assert!(implicit_argument.is_none());
-                    Safety::Safe
-                },
                 hir::Unsafety::Unsafe => Safety::FnUnsafe,
             };
 
index 4c77350f10ecd7182b8d058fade9b5a02978e614..5cfcc16162ee2bb2426315be0ff18efa3e281d2c 100644 (file)
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::RangeEnd;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::{Integer, IntegerExt, VariantIdx};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
+use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
 
 use rustc::mir::Field;
-use rustc::mir::interpret::ConstValue;
+use rustc::mir::interpret::{ConstValue, Pointer, Scalar};
 use rustc::util::common::ErrorReported;
 
 use syntax::attr::{SignedInt, UnsignedInt};
 pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
                                 -> &'a Pattern<'tcx>
 {
-    cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
+    cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat))
 }
 
-struct LiteralExpander;
-impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
+struct LiteralExpander<'a, 'tcx> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
+    /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
+    ///
+    /// `crty` and `rty` can differ because you can use array constants in the presence of slice
+    /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
+    /// the array to a slice in that case.
+    fn fold_const_value_deref(
+        &mut self,
+        val: ConstValue<'tcx>,
+        // the pattern's pointee type
+        rty: Ty<'tcx>,
+        // the constant's pointee type
+        crty: Ty<'tcx>,
+    ) -> ConstValue<'tcx> {
+        match (val, &crty.sty, &rty.sty) {
+            // the easy case, deref a reference
+            (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef(
+                p.alloc_id,
+                self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
+                p.offset,
+            ),
+            // unsize array to slice if pattern is array but match value or other patterns are slice
+            (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
+                assert_eq!(t, u);
+                ConstValue::ScalarPair(
+                    Scalar::Ptr(p),
+                    n.val.try_to_scalar().unwrap(),
+                )
+            },
+            // fat pointers stay the same
+            (ConstValue::ScalarPair(..), _, _) => val,
+            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
+            _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
+        }
+    }
+}
+
+impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> {
     fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
         match (&pat.ty.sty, &*pat.kind) {
-            (&ty::Ref(_, rty, _), &PatternKind::Constant { ref value }) => {
+            (
+                &ty::Ref(_, rty, _),
+                &PatternKind::Constant { value: Const {
+                    val,
+                    ty: ty::TyS { sty: ty::Ref(_, crty, _), .. },
+                } },
+            ) => {
                 Pattern {
                     ty: pat.ty,
                     span: pat.span,
@@ -215,7 +261,11 @@ fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
                         subpattern: Pattern {
                             ty: rty,
                             span: pat.span,
-                            kind: box PatternKind::Constant { value: value.clone() },
+                            kind: box PatternKind::Constant { value: Const::from_const_value(
+                                self.tcx,
+                                self.fold_const_value_deref(*val, rty, crty),
+                                rty,
+                            ) },
                         }
                     }
                 }
@@ -732,15 +782,17 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     for row in patterns {
         match *row.kind {
             PatternKind::Constant { value } => {
-                if let Some(ptr) = value.to_ptr() {
-                    let is_array_ptr = value.ty
-                        .builtin_deref(true)
-                        .and_then(|t| t.ty.builtin_index())
-                        .map_or(false, |t| t == cx.tcx.types.u8);
-                    if is_array_ptr {
-                        let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
-                        max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
-                    }
+                // extract the length of an array/slice from a constant
+                match (value.val, &value.ty.sty) {
+                    (_, ty::Array(_, n)) => max_fixed_len = cmp::max(
+                        max_fixed_len,
+                        n.unwrap_usize(cx.tcx),
+                    ),
+                    (ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
+                        max_fixed_len,
+                        n.to_usize(&cx.tcx).unwrap(),
+                    ),
+                    _ => {},
                 }
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
@@ -1348,28 +1400,62 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-fn slice_pat_covered_by_constructor<'tcx>(
+// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
+// meaning all other types will compare unequal and thus equal patterns often do not cause the
+// second pattern to lint about unreachable match arms.
+fn slice_pat_covered_by_const<'tcx>(
     tcx: TyCtxt<'_, 'tcx, '_>,
     _span: Span,
-    ctor: &Constructor,
+    const_val: &ty::Const<'tcx>,
     prefix: &[Pattern<'tcx>],
     slice: &Option<Pattern<'tcx>>,
     suffix: &[Pattern<'tcx>]
 ) -> Result<bool, ErrorReported> {
-    let data: &[u8] = match *ctor {
-        ConstantValue(const_val) => {
-            let val = match const_val.val {
-                ConstValue::Unevaluated(..) |
-                ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val),
-                ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val,
-            };
-            if let Ok(ptr) = val.to_ptr() {
-                tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref()
-            } else {
-                bug!("unexpected non-ptr ConstantValue")
+    let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
+        (ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
+            if *t != tcx.types.u8 {
+                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
+                // any sort of exhaustiveness/unreachable check yet
+                // This solely means that we don't lint about unreachable patterns, even if some
+                // are definitely unreachable.
+                return Ok(false);
             }
-        }
-        _ => bug!()
+            let ptr = Pointer::new(id, offset);
+            let n = n.assert_usize(tcx).unwrap();
+            alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
+        },
+        // a slice fat pointer to a zero length slice
+        (ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => {
+            if *t != tcx.types.u8 {
+                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
+                // any sort of exhaustiveness/unreachable check yet
+                // This solely means that we don't lint about unreachable patterns, even if some
+                // are definitely unreachable.
+                return Ok(false);
+            }
+            assert_eq!(n.to_usize(&tcx).unwrap(), 0);
+            &[]
+        },
+        //
+        (ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
+            if *t != tcx.types.u8 {
+                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
+                // any sort of exhaustiveness/unreachable check yet
+                // This solely means that we don't lint about unreachable patterns, even if some
+                // are definitely unreachable.
+                return Ok(false);
+            }
+            let n = n.to_usize(&tcx).unwrap();
+            tcx.alloc_map
+                .lock()
+                .unwrap_memory(ptr.alloc_id)
+                .get_bytes(&tcx, ptr, Size::from_bytes(n))
+                .unwrap()
+        },
+        _ => bug!(
+            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
+            const_val, prefix, slice, suffix,
+        ),
     };
 
     let pat_len = prefix.len() + suffix.len();
@@ -1675,22 +1761,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                     // necessarily point to memory, they are usually just integers. The only time
                     // they should be pointing to memory is when they are subslices of nonzero
                     // slices
-                    let (opt_ptr, n, ty) = match value.ty.builtin_deref(false).unwrap().ty.sty {
-                        ty::TyKind::Array(t, n) => (value.to_ptr(), n.unwrap_usize(cx.tcx), t),
-                        ty::TyKind::Slice(t) => {
-                            match value.val {
-                                ConstValue::ScalarPair(ptr, n) => (
-                                    ptr.to_ptr().ok(),
-                                    n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
-                                    t,
-                                ),
-                                _ => span_bug!(
-                                    pat.span,
-                                    "slice pattern constant must be scalar pair but is {:?}",
-                                    value,
-                                ),
-                            }
-                        },
+                    let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) {
+                        (ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => (
+                            Some((
+                                Pointer::new(id, offset),
+                                alloc,
+                            )),
+                            n.unwrap_usize(cx.tcx),
+                            t,
+                        ),
+                        (ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => (
+                            ptr.to_ptr().ok().map(|ptr| (
+                                ptr,
+                                cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
+                            )),
+                            n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
+                            t,
+                        ),
                         _ => span_bug!(
                             pat.span,
                             "unexpected const-val {:?} with ctor {:?}",
@@ -1702,8 +1789,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         // convert a constant slice/array pattern to a list of patterns.
                         match (n, opt_ptr) {
                             (0, _) => Some(SmallVec::new()),
-                            (_, Some(ptr)) => {
-                                let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
+                            (_, Some((ptr, alloc))) => {
                                 let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
                                 (0..n).map(|i| {
                                     let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
@@ -1766,10 +1852,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         None
                     }
                 }
-                ConstantValue(..) => {
-                    match slice_pat_covered_by_constructor(
-                        cx.tcx, pat.span, constructor, prefix, slice, suffix
-                            ) {
+                ConstantValue(cv) => {
+                    match slice_pat_covered_by_const(cx.tcx, pat.span, cv, prefix, slice, suffix) {
                         Ok(true) => Some(smallvec![]),
                         Ok(false) => None,
                         Err(ErrorReported) => None
index d695a64f62a08e1e2a1a1a211996e5807529cb5f..ddd6a705b04d116a8d1135d91d4342ef19e20552 100644 (file)
@@ -1259,34 +1259,32 @@ pub fn compare_const_vals<'a, 'tcx>(
         }
     }
 
-    if let ty::Ref(_, rty, _) = ty.value.sty {
-        if let ty::Str = rty.sty {
-            match (a.val, b.val) {
-                (
-                    ConstValue::ScalarPair(
-                        Scalar::Ptr(ptr_a),
-                        len_a,
-                    ),
-                    ConstValue::ScalarPair(
-                        Scalar::Ptr(ptr_b),
-                        len_b,
-                    ),
-                ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
-                    if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
-                        if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
-                            if len_a == len_b {
-                                let map = tcx.alloc_map.lock();
-                                let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
-                                let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
-                                if alloc_a.bytes.len() as u128 == len_a {
-                                    return from_bool(alloc_a == alloc_b);
-                                }
+    if let ty::Str = ty.value.sty {
+        match (a.val, b.val) {
+            (
+                ConstValue::ScalarPair(
+                    Scalar::Ptr(ptr_a),
+                    len_a,
+                ),
+                ConstValue::ScalarPair(
+                    Scalar::Ptr(ptr_b),
+                    len_b,
+                ),
+            ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
+                if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
+                    if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
+                        if len_a == len_b {
+                            let map = tcx.alloc_map.lock();
+                            let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
+                            let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
+                            if alloc_a.bytes.len() as u128 == len_a {
+                                return from_bool(alloc_a == alloc_b);
                             }
                         }
                     }
                 }
-                _ => (),
             }
+            _ => (),
         }
     }
 
index 6af29b74c1c4fab1e535a8b8ee492e47202b66ad..3607869384077656bcc6591ceb6ee520d9f1bae4 100644 (file)
@@ -311,13 +311,9 @@ fn register_violations(&mut self,
                            violations: &[UnsafetyViolation],
                            unsafe_blocks: &[(ast::NodeId, bool)]) {
         let safety = self.source_scope_local_data[self.source_info.scope].safety;
-        let within_unsafe = match (safety, self.min_const_fn) {
-            // Erring on the safe side, pun intended
-            (Safety::BuiltinUnsafe, true) |
-            // mir building encodes const fn bodies as safe, even for `const unsafe fn`
-            (Safety::FnUnsafe, true) => bug!("const unsafe fn body treated as inherently unsafe"),
+        let within_unsafe = match safety {
             // `unsafe` blocks are required in safe code
-            (Safety::Safe, _) => {
+            Safety::Safe => {
                 for violation in violations {
                     let mut violation = violation.clone();
                     match violation.kind {
@@ -342,9 +338,9 @@ fn register_violations(&mut self,
                 }
                 false
             }
-            // regular `unsafe` function bodies allow unsafe without additional unsafe blocks
-            (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true,
-            (Safety::ExplicitUnsafe(node_id), _) => {
+            // `unsafe` function bodies allow unsafe without additional unsafe blocks
+            Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
+            Safety::ExplicitUnsafe(node_id) => {
                 // mark unsafe block as used if there are any unsafe operations inside
                 if !violations.is_empty() {
                     self.used_unsafe.insert(node_id);
@@ -616,21 +612,6 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
     } in violations.iter() {
         // Report an error.
         match kind {
-            UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => {
-                let mut err = tcx.sess.struct_span_err(
-                    source_info.span,
-                    &format!("{} is unsafe and unsafe operations \
-                            are not allowed in const fn", description));
-                err.span_label(source_info.span, &description.as_str()[..])
-                    .note(&details.as_str()[..]);
-                if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe {
-                    err.note(
-                        "unsafe action within a `const unsafe fn` still require an `unsafe` \
-                        block in contrast to regular `unsafe fn`."
-                    );
-                }
-                err.emit();
-            }
             UnsafetyViolationKind::GeneralAndConstFn |
             UnsafetyViolationKind::General => {
                 struct_span_err!(
index 42ead92783d7af2a424e713bdf92df85fc7510c5..a5d2edbc5d4396f286688ded2938246aa7dbf509 100644 (file)
@@ -41,7 +41,6 @@
 pub mod rvalue_promotion;
 pub mod hir_stats;
 pub mod loops;
-mod mir_stats;
 
 __build_diagnostic_array! { librustc_passes, DIAGNOSTICS }
 
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
deleted file mode 100644 (file)
index fb37f03..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// The visitors in this module collect sizes and counts of the most important
-// pieces of MIR. The resulting numbers are good approximations but not
-// completely accurate (some things might be counted twice, others missed).
-
-use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
-use rustc::mir::{Constant, Location, Local, LocalDecl};
-use rustc::mir::{Place, PlaceElem, PlaceProjection};
-use rustc::mir::{Mir, Operand, ProjectionElem};
-use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
-use rustc::mir::{Terminator, TerminatorKind, SourceScope, SourceScopeData};
-use rustc::mir::interpret::EvalErrorKind;
-use rustc::mir::visit as mir_visit;
-use rustc::ty::{self, ClosureSubsts, TyCtxt};
-use rustc::util::nodemap::{FxHashMap};
-
-struct NodeData {
-    count: usize,
-    size: usize,
-}
-
-struct StatCollector<'a, 'tcx: 'a> {
-    _tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    data: FxHashMap<&'static str, NodeData>,
-}
-
-impl<'a, 'tcx> StatCollector<'a, 'tcx> {
-
-    fn record_with_size(&mut self, label: &'static str, node_size: usize) {
-        let entry = self.data.entry(label).or_insert(NodeData {
-            count: 0,
-            size: 0,
-        });
-
-        entry.count += 1;
-        entry.size = node_size;
-    }
-
-    fn record<T>(&mut self, label: &'static str, node: &T) {
-        self.record_with_size(label, ::std::mem::size_of_val(node));
-    }
-}
-
-impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
-    fn visit_mir(&mut self, mir: &Mir<'tcx>) {
-        self.record("Mir", mir);
-
-        // since the `super_mir` method does not traverse the MIR of
-        // promoted rvalues, (but we still want to gather statistics
-        // on the structures represented there) we manually traverse
-        // the promoted rvalues here.
-        for promoted_mir in &mir.promoted {
-            self.visit_mir(promoted_mir);
-        }
-
-        self.super_mir(mir);
-    }
-
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
-        self.record("BasicBlockData", data);
-        self.super_basic_block_data(block, data);
-    }
-
-    fn visit_source_scope_data(&mut self, scope_data: &SourceScopeData) {
-        self.record("SourceScopeData", scope_data);
-        self.super_source_scope_data(scope_data);
-    }
-
-    fn visit_statement(&mut self,
-                       block: BasicBlock,
-                       statement: &Statement<'tcx>,
-                       location: Location) {
-        self.record("Statement", statement);
-        self.record(match statement.kind {
-            StatementKind::Assign(..) => "StatementKind::Assign",
-            StatementKind::FakeRead(..) => "StatementKind::FakeRead",
-            StatementKind::Retag { .. } => "StatementKind::Retag",
-            StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw",
-            StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant",
-            StatementKind::StorageLive(..) => "StatementKind::StorageLive",
-            StatementKind::StorageDead(..) => "StatementKind::StorageDead",
-            StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
-            StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType",
-            StatementKind::Nop => "StatementKind::Nop",
-        }, &statement.kind);
-        self.super_statement(block, statement, location);
-    }
-
-    fn visit_terminator(&mut self,
-                        block: BasicBlock,
-                        terminator: &Terminator<'tcx>,
-                        location: Location) {
-        self.record("Terminator", terminator);
-        self.super_terminator(block, terminator, location);
-    }
-
-    fn visit_terminator_kind(&mut self,
-                             block: BasicBlock,
-                             kind: &TerminatorKind<'tcx>,
-                             location: Location) {
-        self.record("TerminatorKind", kind);
-        self.record(match *kind {
-            TerminatorKind::Goto { .. } => "TerminatorKind::Goto",
-            TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt",
-            TerminatorKind::Resume => "TerminatorKind::Resume",
-            TerminatorKind::Abort => "TerminatorKind::Abort",
-            TerminatorKind::Return => "TerminatorKind::Return",
-            TerminatorKind::Unreachable => "TerminatorKind::Unreachable",
-            TerminatorKind::Drop { .. } => "TerminatorKind::Drop",
-            TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace",
-            TerminatorKind::Call { .. } => "TerminatorKind::Call",
-            TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
-            TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
-            TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
-            TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
-            TerminatorKind::FalseUnwind { .. } => "TerminatorKind::FalseUnwind",
-        }, kind);
-        self.super_terminator_kind(block, kind, location);
-    }
-
-    fn visit_assert_message(&mut self, msg: &AssertMessage<'tcx>, location: Location) {
-        self.record("AssertMessage", msg);
-        self.record(match *msg {
-            EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
-            EvalErrorKind::Overflow(..) => "AssertMessage::Overflow",
-            EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg",
-            EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero",
-            EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero",
-            EvalErrorKind::GeneratorResumedAfterReturn => {
-                "AssertMessage::GeneratorResumedAfterReturn"
-            }
-            EvalErrorKind::GeneratorResumedAfterPanic => {
-                "AssertMessage::GeneratorResumedAfterPanic"
-            }
-            _ => bug!(),
-        }, msg);
-        self.super_assert_message(msg, location);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        self.record("Rvalue", rvalue);
-        let rvalue_kind = match *rvalue {
-            Rvalue::Use(..) => "Rvalue::Use",
-            Rvalue::Repeat(..) => "Rvalue::Repeat",
-            Rvalue::Ref(..) => "Rvalue::Ref",
-            Rvalue::Len(..) => "Rvalue::Len",
-            Rvalue::Cast(..) => "Rvalue::Cast",
-            Rvalue::BinaryOp(..) => "Rvalue::BinaryOp",
-            Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp",
-            Rvalue::UnaryOp(..) => "Rvalue::UnaryOp",
-            Rvalue::Discriminant(..) => "Rvalue::Discriminant",
-            Rvalue::NullaryOp(..) => "Rvalue::NullaryOp",
-            Rvalue::Aggregate(ref kind, ref _operands) => {
-                // AggregateKind is not distinguished by visit API, so
-                // record it. (`super_rvalue` handles `_operands`.)
-                self.record(match **kind {
-                    AggregateKind::Array(_) => "AggregateKind::Array",
-                    AggregateKind::Tuple => "AggregateKind::Tuple",
-                    AggregateKind::Adt(..) => "AggregateKind::Adt",
-                    AggregateKind::Closure(..) => "AggregateKind::Closure",
-                    AggregateKind::Generator(..) => "AggregateKind::Generator",
-                }, kind);
-
-                "Rvalue::Aggregate"
-            }
-        };
-        self.record(rvalue_kind, rvalue);
-        self.super_rvalue(rvalue, location);
-    }
-
-    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        self.record("Operand", operand);
-        self.record(match *operand {
-            Operand::Copy(..) => "Operand::Copy",
-            Operand::Move(..) => "Operand::Move",
-            Operand::Constant(..) => "Operand::Constant",
-        }, operand);
-        self.super_operand(operand, location);
-    }
-
-    fn visit_place(&mut self,
-                    place: &Place<'tcx>,
-                    context: mir_visit::PlaceContext<'tcx>,
-                    location: Location) {
-        self.record("Place", place);
-        self.record(match *place {
-            Place::Local(..) => "Place::Local",
-            Place::Static(..) => "Place::Static",
-            Place::Promoted(..) => "Place::Promoted",
-            Place::Projection(..) => "Place::Projection",
-        }, place);
-        self.super_place(place, context, location);
-    }
-
-    fn visit_projection(&mut self,
-                        place: &PlaceProjection<'tcx>,
-                        context: mir_visit::PlaceContext<'tcx>,
-                        location: Location) {
-        self.record("PlaceProjection", place);
-        self.super_projection(place, context, location);
-    }
-
-    fn visit_projection_elem(&mut self,
-                             place: &PlaceElem<'tcx>,
-                             location: Location) {
-        self.record("PlaceElem", place);
-        self.record(match *place {
-            ProjectionElem::Deref => "PlaceElem::Deref",
-            ProjectionElem::Subslice { .. } => "PlaceElem::Subslice",
-            ProjectionElem::Field(..) => "PlaceElem::Field",
-            ProjectionElem::Index(..) => "PlaceElem::Index",
-            ProjectionElem::ConstantIndex { .. } => "PlaceElem::ConstantIndex",
-            ProjectionElem::Downcast(..) => "PlaceElem::Downcast",
-        }, place);
-        self.super_projection_elem(place, location);
-    }
-
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
-        self.record("Constant", constant);
-        self.super_constant(constant, location);
-    }
-
-    fn visit_source_info(&mut self, source_info: &SourceInfo) {
-        self.record("SourceInfo", source_info);
-        self.super_source_info(source_info);
-    }
-
-    fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, _: Location) {
-        self.record("ClosureSubsts", substs);
-        self.super_closure_substs(substs);
-    }
-
-    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
-        self.record("Const", constant);
-        self.super_const(constant);
-    }
-
-    fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
-        self.record("LocalDecl", local_decl);
-        self.super_local_decl(local, local_decl);
-    }
-
-    fn visit_source_scope(&mut self, scope: &SourceScope) {
-        self.record("VisiblityScope", scope);
-        self.super_source_scope(scope);
-    }
-}
index ebd2c87fa4642e9ff385d26d53a61b630fcae121..e449fece6b474a2b33ccc7ddf9041df7c1deab41 100644 (file)
@@ -3010,6 +3010,7 @@ fn resolve_pattern(&mut self,
         // Visit all direct subpatterns of this pattern.
         let outer_pat_id = pat.id;
         pat.walk(&mut |pat| {
+            debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
             match pat.node {
                 PatKind::Ident(bmode, ident, ref opt_pat) => {
                     // First try to resolve the identifier as some existing
@@ -3166,6 +3167,7 @@ fn smart_resolve_path_fragment(&mut self,
                  format!("not found in {}", mod_str),
                  item_span)
             };
+
             let code = DiagnosticId::Error(code.into());
             let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
 
@@ -3189,11 +3191,22 @@ fn smart_resolve_path_fragment(&mut self,
                 return (err, Vec::new());
             }
             if is_self_value(path, ns) {
+                debug!("smart_resolve_path_fragment E0424 source:{:?}", source);
+
                 __diagnostic_used!(E0424);
                 err.code(DiagnosticId::Error("E0424".into()));
-                err.span_label(span, format!("`self` value is a keyword \
-                                               only available in \
-                                               methods with `self` parameter"));
+                err.span_label(span, match source {
+                    PathSource::Pat => {
+                        format!("`self` value is a keyword \
+                                and may not be bound to \
+                                variables or shadowed")
+                    }
+                    _ => {
+                        format!("`self` value is a keyword \
+                                only available in methods \
+                                with `self` parameter")
+                    }
+                });
                 return (err, Vec::new());
             }
 
index d8e8477f3d06b44a067783cdb7c1628f01aacdd6..aef8770bcc69b3c8dfa51d92893aba2a5f358b2e 100644 (file)
@@ -68,6 +68,7 @@
 mod openbsd_base;
 mod netbsd_base;
 mod solaris_base;
+mod uefi_base;
 mod windows_base;
 mod windows_msvc_base;
 mod thumb_base;
@@ -254,12 +255,12 @@ fn load_specific(target: &str) -> TargetResult {
             }
         }
 
-        pub fn get_targets() -> Box<dyn Iterator<Item=String>> {
-            Box::new(TARGETS.iter().filter_map(|t| -> Option<String> {
+        pub fn get_targets() -> impl Iterator<Item = String> {
+            TARGETS.iter().filter_map(|t| -> Option<String> {
                 load_specific(t)
                     .and(Ok(t.to_string()))
                     .ok()
-            }))
+            })
         }
 
         #[cfg(test)]
@@ -419,6 +420,8 @@ fn $module() {
     ("aarch64-unknown-none", aarch64_unknown_none),
 
     ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
+
+    ("x86_64-unknown-uefi", x86_64_unknown_uefi),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs
new file mode 100644 (file)
index 0000000..9b05158
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This defines a base target-configuration for native UEFI systems. The UEFI specification has
+// quite detailed sections on the ABI of all the supported target architectures. In almost all
+// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
+// documentation.
+// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
+// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
+// by the loader if the pre-chosen memory location is already in use.
+// UEFI forbids running code on anything but the boot-CPU. Not interrupts are allowed other than
+// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
+// code runs in the same environment, no process separation is supported.
+
+use spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    let mut pre_link_args = LinkArgs::new();
+
+    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), vec![
+            // Suppress the verbose logo and authorship debugging output, which would needlessly
+            // clog any log files.
+            "/NOLOGO".to_string(),
+
+            // UEFI is fully compatible to non-executable data pages. Tell the compiler that
+            // non-code sections can be marked as non-executable, including stack pages.
+            "/NXCOMPAT".to_string(),
+
+            // There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
+            // must be freestanding.
+            "/nodefaultlib".to_string(),
+
+            // Non-standard subsystems have no default entry-point in PE+ files. We have to define
+            // one. "efi_main" seems to be a common choice amongst other implementations and the
+            // spec.
+            "/entry:efi_main".to_string(),
+
+            // COFF images have a "Subsystem" field in their header, which defines what kind of
+            // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
+            // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
+            // which is very likely the most common option. Individual projects can override this
+            // with custom linker flags.
+            // The subsystem-type only has minor effects on the application. It defines the memory
+            // regions the application is loaded into (runtime-drivers need to be put into
+            // reserved areas), as well as whether a return from the entry-point is treated as
+            // exit (default for applications).
+            "/subsystem:efi_application".to_string(),
+        ]);
+
+    TargetOptions {
+        dynamic_linking: false,
+        executables: true,
+        disable_redzone: true,
+        exe_suffix: ".efi".to_string(),
+        allows_weak_linkage: false,
+        panic_strategy: PanicStrategy::Abort,
+        singlethread: true,
+        emit_debug_gdb_scripts: false,
+
+        linker: Some("lld-link".to_string()),
+        lld_flavor: LldFlavor::Link,
+        pre_link_args,
+
+        .. Default::default()
+    }
+}
index 07383b3d64862430b332413b5490cad227025756..5b6d8abc5ef3e51c0244e07c971266f1588b7a8f 100644 (file)
@@ -49,6 +49,7 @@ pub fn target() -> Result<Target, String> {
         max_atomic_width: Some(64),
         panic_strategy: PanicStrategy::Abort,
         cpu: "x86-64".into(),
+        features: "+rdrnd,+rdseed".into(),
         position_independent_executables: true,
         pre_link_args: iter::once(
                 (LinkerFlavor::Gcc, PRE_LINK_ARGS.iter().cloned().map(String::from).collect())
diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/src/librustc_target/spec/x86_64_unknown_uefi.rs
new file mode 100644 (file)
index 0000000..ea68afa
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This defines the amd64 target for UEFI systems as described in the UEFI specification. See the
+// uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec)
+// UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a
+// single-CPU execution.
+// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
+// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
+
+use spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::uefi_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.max_atomic_width = Some(64);
+
+    // We disable MMX and SSE for now. UEFI does not prevent these from being used, but there have
+    // been reports to GRUB that some firmware does not initialize the FP exception handlers
+    // properly. Therefore, using FP coprocessors will end you up at random memory locations when
+    // you throw FP exceptions.
+    // To be safe, we disable them for now and force soft-float. This can be revisited when we
+    // have more test coverage. Disabling FP served GRUB well so far, so it should be good for us
+    // as well.
+    base.features = "-mmx,-sse,+soft-float".to_string();
+
+    // UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
+    // LLVM to expect code to reference any address in the address-space. The "large" code-model
+    // places no locality-restrictions, so it fits well here.
+    base.code_model = Some("large".to_string());
+
+    // UEFI mostly mirrors the calling-conventions used on windows. In case of x86-64 this means
+    // small structs will be returned as int. This shouldn't matter much, since the restrictions
+    // placed by the UEFI specifications forbid any ABI to return structures.
+    base.abi_return_struct_as_int = true;
+
+    Ok(Target {
+        llvm_target: "x86_64-unknown-windows".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        target_os: "uefi".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        arch: "x86_64".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+
+        options: base,
+    })
+}
index b76c9101eae02b66f7aa9f565d5af1a4605f0149..09063579c4214b73d0943616820efb3238be4457 100644 (file)
@@ -424,10 +424,12 @@ macro_rules! report_function {
                 }
 
                 if !unsatisfied_predicates.is_empty() {
-                    let bound_list = unsatisfied_predicates.iter()
+                    let mut bound_list = unsatisfied_predicates.iter()
                         .map(|p| format!("`{} : {}`", p.self_ty(), p))
-                        .collect::<Vec<_>>()
-                        .join("\n");
+                        .collect::<Vec<_>>();
+                    bound_list.sort();
+                    bound_list.dedup();  // #35677
+                    let bound_list = bound_list.join("\n");
                     err.note(&format!("the method `{}` exists but the following trait bounds \
                                        were not satisfied:\n{}",
                                       item_name,
index 6ce02c313ee050365ac36fa0703c681046287566..37ff693bdf16794e4d16c71cd49a98171f848b5d 100644 (file)
@@ -54,6 +54,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
     <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
           id=\"themeStyle\">\
     <script src=\"{root_path}storage{suffix}.js\"></script>\
+    <noscript><link rel=\"stylesheet\" href=\"{root_path}noscript{suffix}.css\"></noscript>\
     {css_extension}\
     {favicon}\
     {in_header}\
index 4b10c23fd3f3f219bbed58a7e673b10486adb808..c9f3aa011a1d4987dec7b0602b0c7310f6dbf246 100644 (file)
@@ -772,6 +772,9 @@ fn write_shared(
     write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
                  static_files::SETTINGS_CSS,
                  options.enable_minification)?;
+    write_minify(cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)),
+                 static_files::NOSCRIPT_CSS,
+                 options.enable_minification)?;
 
     // To avoid "light.css" to be overwritten, we'll first run over the received themes and only
     // then we'll run over the "official" styles.
@@ -865,9 +868,8 @@ fn write_shared(
     }
 
     {
-        let mut data = format!("var resourcesSuffix = \"{}\";\n",
-                               cx.shared.resource_suffix);
-        data.push_str(static_files::STORAGE_JS);
+        let mut data = static_files::STORAGE_JS.to_owned();
+        data.push_str(&format!("var resourcesSuffix = \"{}\";", cx.shared.resource_suffix));
         write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
                      &data,
                      options.enable_minification)?;
@@ -3013,6 +3015,22 @@ fn item_trait(
     // Trait documentation
     document(w, cx, it)?;
 
+    fn write_small_section_header(
+        w: &mut fmt::Formatter,
+        id: &str,
+        title: &str,
+        extra_content: &str,
+    ) -> fmt::Result {
+        write!(w, "
+            <h2 id='{0}' class='small-section-header'>\
+              {1}<a href='#{0}' class='anchor'></a>\
+            </h2>{2}", id, title, extra_content)
+    }
+
+    fn write_loading_content(w: &mut fmt::Formatter, extra_content: &str) -> fmt::Result {
+        write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content)
+    }
+
     fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item)
                   -> fmt::Result {
         let name = m.name.as_ref().unwrap();
@@ -3033,74 +3051,45 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
     }
 
     if !types.is_empty() {
-        write!(w, "
-            <h2 id='associated-types' class='small-section-header'>
-              Associated Types<a href='#associated-types' class='anchor'></a>
-            </h2>
-            <div class='methods'>
-        ")?;
+        write_small_section_header(w, "associated-types", "Associated Types",
+                                   "<div class='methods'>")?;
         for t in &types {
             trait_item(w, cx, *t, it)?;
         }
-        write!(w, "</div>")?;
+        write_loading_content(w, "</div>")?;
     }
 
     if !consts.is_empty() {
-        write!(w, "
-            <h2 id='associated-const' class='small-section-header'>
-              Associated Constants<a href='#associated-const' class='anchor'></a>
-            </h2>
-            <div class='methods'>
-        ")?;
+        write_small_section_header(w, "associated-const", "Associated Constants",
+                                   "<div class='methods'>")?;
         for t in &consts {
             trait_item(w, cx, *t, it)?;
         }
-        write!(w, "</div>")?;
+        write_loading_content(w, "</div>")?;
     }
 
     // Output the documentation for each function individually
     if !required.is_empty() {
-        write!(w, "
-            <h2 id='required-methods' class='small-section-header'>
-              Required Methods<a href='#required-methods' class='anchor'></a>
-            </h2>
-            <div class='methods'>
-        ")?;
+        write_small_section_header(w, "required-methods", "Required methods",
+                                   "<div class='methods'>")?;
         for m in &required {
             trait_item(w, cx, *m, it)?;
         }
-        write!(w, "</div>")?;
+        write_loading_content(w, "</div>")?;
     }
     if !provided.is_empty() {
-        write!(w, "
-            <h2 id='provided-methods' class='small-section-header'>
-              Provided Methods<a href='#provided-methods' class='anchor'></a>
-            </h2>
-            <div class='methods'>
-        ")?;
+        write_small_section_header(w, "provided-methods", "Provided methods",
+                                   "<div class='methods'>")?;
         for m in &provided {
             trait_item(w, cx, *m, it)?;
         }
-        write!(w, "</div>")?;
+        write_loading_content(w, "</div>")?;
     }
 
     // If there are methods directly on this trait object, render them here.
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
 
     let cache = cache();
-    let impl_header = "\
-        <h2 id='implementors' class='small-section-header'>\
-          Implementors<a href='#implementors' class='anchor'></a>\
-        </h2>\
-        <div class='item-list' id='implementors-list'>\
-    ";
-
-    let synthetic_impl_header = "\
-        <h2 id='synthetic-implementors' class='small-section-header'>\
-          Auto implementors<a href='#synthetic-implementors' class='anchor'></a>\
-        </h2>\
-        <div class='item-list' id='synthetic-implementors-list'>\
-    ";
 
     let mut synthetic_types = Vec::new();
 
@@ -3137,11 +3126,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
         concrete.sort_by(compare_impl);
 
         if !foreign.is_empty() {
-            write!(w, "
-                <h2 id='foreign-impls' class='small-section-header'>
-                  Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a>
-                </h2>
-            ")?;
+            write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?;
 
             for implementor in foreign {
                 let assoc_link = AssocItemLink::GotoSource(
@@ -3152,33 +3137,38 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
                             RenderMode::Normal, implementor.impl_item.stable_since(), false,
                             None)?;
             }
+            write_loading_content(w, "")?;
         }
 
-        write!(w, "{}", impl_header)?;
+        write_small_section_header(w, "implementors", "Implementors",
+                                   "<div class='item-list' id='implementors-list'>")?;
         for implementor in concrete {
             render_implementor(cx, implementor, w, &implementor_dups)?;
         }
-        write!(w, "</div>")?;
+        write_loading_content(w, "</div>")?;
 
         if t.auto {
-            write!(w, "{}", synthetic_impl_header)?;
+            write_small_section_header(w, "synthetic-implementors", "Auto implementors",
+                                       "<div class='item-list' id='synthetic-implementors-list'>")?;
             for implementor in synthetic {
                 synthetic_types.extend(
                     collect_paths_for_type(implementor.inner_impl().for_.clone())
                 );
                 render_implementor(cx, implementor, w, &implementor_dups)?;
             }
-            write!(w, "</div>")?;
+            write_loading_content(w, "</div>")?;
         }
     } else {
         // even without any implementations to write in, we still want the heading and list, so the
         // implementors javascript file pulled in below has somewhere to write the impls into
-        write!(w, "{}", impl_header)?;
-        write!(w, "</div>")?;
+        write_small_section_header(w, "implementors", "Implementors",
+                                   "<div class='item-list' id='implementors-list'>")?;
+        write_loading_content(w, "</div>")?;
 
         if t.auto {
-            write!(w, "{}", synthetic_impl_header)?;
-            write!(w, "</div>")?;
+            write_small_section_header(w, "synthetic-implementors", "Auto implementors",
+                                       "<div class='item-list' id='synthetic-implementors-list'>")?;
+            write_loading_content(w, "</div>")?;
         }
     }
     write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
index 1869969a5306956171b4026989941a5782b92913..51714c35d6faa2dddb3e0266a23dbe4a846213c7 100644 (file)
@@ -30,6 +30,27 @@ if (!String.prototype.endsWith) {
     };
 }
 
+if (!DOMTokenList.prototype.add) {
+    DOMTokenList.prototype.add = function(className) {
+        if (className && !hasClass(this, className)) {
+            if (this.className && this.className.length > 0) {
+                this.className += " " + className;
+            } else {
+                this.className = className;
+            }
+        }
+    };
+}
+
+if (!DOMTokenList.prototype.remove) {
+    DOMTokenList.prototype.remove = function(className) {
+        if (className && this.className) {
+            this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
+                                                         .trim();
+        }
+    };
+}
+
 (function() {
     "use strict";
 
@@ -61,7 +82,7 @@ if (!String.prototype.endsWith) {
                      "attr",
                      "derive"];
 
-    var search_input = document.getElementsByClassName('search-input')[0];
+    var search_input = document.getElementsByClassName("search-input")[0];
 
     // On the search screen, so you remain on the last tab you opened.
     //
@@ -75,9 +96,9 @@ if (!String.prototype.endsWith) {
     var titleBeforeSearch = document.title;
 
     function getPageId() {
-        var id = document.location.href.split('#')[1];
+        var id = document.location.href.split("#")[1];
         if (id) {
-            return id.split('?')[0].split('&')[0];
+            return id.split("?")[0].split("&")[0];
         }
         return null;
     }
@@ -87,9 +108,9 @@ if (!String.prototype.endsWith) {
         if (elems) {
             addClass(elems, "show-it");
         }
-        var sidebar = document.getElementsByClassName('sidebar')[0];
+        var sidebar = document.getElementsByClassName("sidebar")[0];
         if (sidebar) {
-            addClass(sidebar, 'mobile');
+            addClass(sidebar, "mobile");
             var filler = document.getElementById("sidebar-filler");
             if (!filler) {
                 var div = document.createElement("div");
@@ -108,13 +129,13 @@ if (!String.prototype.endsWith) {
         if (elems) {
             removeClass(elems, "show-it");
         }
-        var sidebar = document.getElementsByClassName('sidebar')[0];
-        removeClass(sidebar, 'mobile');
+        var sidebar = document.getElementsByClassName("sidebar")[0];
+        removeClass(sidebar, "mobile");
         var filler = document.getElementById("sidebar-filler");
         if (filler) {
             filler.remove();
         }
-        document.getElementsByTagName("body")[0].style.marginTop = '';
+        document.getElementsByTagName("body")[0].style.marginTop = "";
         var themePicker = document.getElementsByClassName("theme-picker");
         if (themePicker && themePicker.length > 0) {
             themePicker[0].style.display = null;
@@ -125,8 +146,8 @@ if (!String.prototype.endsWith) {
     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
     var TY_KEYWORD = itemTypes.indexOf("keyword");
 
-    onEach(document.getElementsByClassName('js-only'), function(e) {
-        removeClass(e, 'js-only');
+    onEachLazy(document.getElementsByClassName("js-only"), function(e) {
+        removeClass(e, "js-only");
     });
 
     function getQueryStringParams() {
@@ -145,16 +166,19 @@ if (!String.prototype.endsWith) {
           window.history && typeof window.history.pushState === "function";
     }
 
+    var main = document.getElementById("main");
+
     function highlightSourceLines(ev) {
         // If we're in mobile mode, we should add the sidebar in any case.
         hideSidebar();
+        var elem;
         var search = document.getElementById("search");
         var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
         if (match) {
             from = parseInt(match[1], 10);
             to = Math.min(50000, parseInt(match[2] || match[1], 10));
             from = Math.min(from, to);
-            var elem = document.getElementById(from);
+            elem = document.getElementById(from);
             if (!elem) {
                 return;
             }
@@ -164,22 +188,22 @@ if (!String.prototype.endsWith) {
                     x.scrollIntoView();
                 }
             }
-            onEach(document.getElementsByClassName('line-numbers'), function(e) {
-                onEach(e.getElementsByTagName('span'), function(i_e) {
-                    removeClass(i_e, 'line-highlighted');
+            onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
+                onEachLazy(e.getElementsByTagName("span"), function(i_e) {
+                    removeClass(i_e, "line-highlighted");
                 });
             });
             for (i = from; i <= to; ++i) {
-                addClass(document.getElementById(i), 'line-highlighted');
+                addClass(document.getElementById(i), "line-highlighted");
             }
         } else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
             addClass(search, "hidden");
-            removeClass(document.getElementById("main"), "hidden");
-            var hash = ev.newURL.slice(ev.newURL.indexOf('#') + 1);
+            removeClass(main, "hidden");
+            var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
             if (browserSupportsHistoryApi()) {
                 history.replaceState(hash, "", "?search=#" + hash);
             }
-            var elem = document.getElementById(hash);
+            elem = document.getElementById(hash);
             if (elem) {
                 elem.scrollIntoView();
             }
@@ -190,7 +214,7 @@ if (!String.prototype.endsWith) {
         var elem = document.getElementById(id);
         if (elem && isHidden(elem)) {
             var h3 = elem.parentNode.previousSibling;
-            if (h3 && h3.tagName !== 'H3') {
+            if (h3 && h3.tagName !== "H3") {
                 h3 = h3.previousSibling; // skip div.docblock
             }
 
@@ -236,7 +260,7 @@ if (!String.prototype.endsWith) {
                 removeClass(help, "hidden");
                 addClass(document.body, "blur");
             }
-        } else if (!hasClass(help, "hidden")) {
+        } else if (hasClass(help, "hidden") === false) {
             ev.preventDefault();
             addClass(help, "hidden");
             removeClass(document.body, "blur");
@@ -246,12 +270,12 @@ if (!String.prototype.endsWith) {
     function handleEscape(ev, help) {
         hideModal();
         var search = document.getElementById("search");
-        if (!hasClass(help, "hidden")) {
+        if (hasClass(help, "hidden") === false) {
             displayHelp(false, ev);
-        } else if (!hasClass(search, "hidden")) {
+        } else if (hasClass(search, "hidden") === false) {
             ev.preventDefault();
             addClass(search, "hidden");
-            removeClass(document.getElementById("main"), "hidden");
+            removeClass(main, "hidden");
             document.title = titleBeforeSearch;
         }
         defocusSearchBar();
@@ -305,26 +329,27 @@ if (!String.prototype.endsWith) {
             if (elem && elem.tagName === tagName) {
                 return elem;
             }
-        } while (elem = elem.parentNode);
+            elem = elem.parentNode;
+        } while (elem);
         return null;
     }
 
     document.onkeypress = handleShortcut;
     document.onkeydown = handleShortcut;
     document.onclick = function(ev) {
-        if (hasClass(ev.target, 'collapse-toggle')) {
+        if (hasClass(ev.target, "collapse-toggle")) {
             collapseDocs(ev.target, "toggle");
-        } else if (hasClass(ev.target.parentNode, 'collapse-toggle')) {
+        } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
             collapseDocs(ev.target.parentNode, "toggle");
-        } else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) {
+        } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
             var prev_id = 0;
 
             var set_fragment = function(name) {
                 if (browserSupportsHistoryApi()) {
-                    history.replaceState(null, null, '#' + name);
+                    history.replaceState(null, null, "#" + name);
                     window.hashchange();
                 } else {
-                    location.replace('#' + name);
+                    location.replace("#" + name);
                 }
             };
 
@@ -337,31 +362,31 @@ if (!String.prototype.endsWith) {
                     cur_id = tmp;
                 }
 
-                set_fragment(prev_id + '-' + cur_id);
+                set_fragment(prev_id + "-" + cur_id);
             } else {
                 prev_id = cur_id;
 
                 set_fragment(cur_id);
             }
-        } else if (!hasClass(document.getElementById("help"), "hidden")) {
+        } else if (hasClass(document.getElementById("help"), "hidden") === false) {
             addClass(document.getElementById("help"), "hidden");
             removeClass(document.body, "blur");
         } else {
             // Making a collapsed element visible on onhashchange seems
             // too late
-            var a = findParentElement(ev.target, 'A');
+            var a = findParentElement(ev.target, "A");
             if (a && a.hash) {
-                expandSection(a.hash.replace(/^#/, ''));
+                expandSection(a.hash.replace(/^#/, ""));
             }
         }
     };
 
-    var x = document.getElementsByClassName('version-selector');
+    var x = document.getElementsByClassName("version-selector");
     if (x.length > 0) {
         x[0].onchange = function() {
             var i, match,
                 url = document.location.href,
-                stripped = '',
+                stripped = "",
                 len = rootPath.match(/\.\.\//g).length + 1;
 
             for (i = 0; i < len; ++i) {
@@ -372,7 +397,7 @@ if (!String.prototype.endsWith) {
                 url = url.substring(0, url.length - match[0].length);
             }
 
-            url += '/' + document.getElementsByClassName('version-selector')[0].value + stripped;
+            url += "/" + document.getElementsByClassName("version-selector")[0].value + stripped;
 
             document.location.href = url;
         };
@@ -428,7 +453,7 @@ if (!String.prototype.endsWith) {
         // where you start trying to do a search, and the index loads, and
         // suddenly your search is gone!
         if (search_input.value === "") {
-            search_input.value = params.search || '';
+            search_input.value = params.search || "";
         }
 
         /**
@@ -441,7 +466,8 @@ if (!String.prototype.endsWith) {
          */
         function execQuery(query, searchWords, filterCrates) {
             function itemTypeFromName(typename) {
-                for (var i = 0; i < itemTypes.length; ++i) {
+                var length = itemTypes.length;
+                for (var i = 0; i < length; ++i) {
                     if (itemTypes[i] === typename) {
                         return i;
                     }
@@ -455,7 +481,8 @@ if (!String.prototype.endsWith) {
                 results = {}, results_in_args = {}, results_returned = {},
                 split = valLower.split("::");
 
-            for (var z = 0; z < split.length; ++z) {
+            var length = split.length;
+            for (var z = 0; z < length; ++z) {
                 if (split[z] === "") {
                     split.splice(z, 1);
                     z -= 1;
@@ -464,7 +491,8 @@ if (!String.prototype.endsWith) {
 
             function transformResults(results, isType) {
                 var out = [];
-                for (i = 0; i < results.length; ++i) {
+                var length = results.length;
+                for (var i = 0; i < length; ++i) {
                     if (results[i].id > -1) {
                         var obj = searchIndex[results[i].id];
                         obj.lev = results[i].lev;
@@ -473,7 +501,7 @@ if (!String.prototype.endsWith) {
                             obj.displayPath = pathSplitter(res[0]);
                             obj.fullPath = obj.displayPath + obj.name;
                             // To be sure than it some items aren't considered as duplicate.
-                            obj.fullPath += '|' + obj.ty;
+                            obj.fullPath += "|" + obj.ty;
                             obj.href = res[1];
                             out.push(obj);
                             if (out.length >= MAX_RESULTS) {
@@ -493,8 +521,9 @@ if (!String.prototype.endsWith) {
                     }
                 }
                 results = ar;
+                var i;
                 var nresults = results.length;
-                for (var i = 0; i < nresults; ++i) {
+                for (i = 0; i < nresults; ++i) {
                     results[i].word = searchWords[results[i].id];
                     results[i].item = searchIndex[results[i].id] || {};
                 }
@@ -552,8 +581,8 @@ if (!String.prototype.endsWith) {
                     }
 
                     // sort by description (no description goes later)
-                    a = (aaa.item.desc === '');
-                    b = (bbb.item.desc === '');
+                    a = (aaa.item.desc === "");
+                    b = (bbb.item.desc === "");
                     if (a !== b) { return a - b; }
 
                     // sort by type (later occurrence in `itemTypes` goes later)
@@ -570,7 +599,8 @@ if (!String.prototype.endsWith) {
                     return 0;
                 });
 
-                for (var i = 0; i < results.length; ++i) {
+                var length = results.length;
+                for (i = 0; i < length; ++i) {
                     var result = results[i];
 
                     // this validation does not make sense when searching by types
@@ -592,10 +622,10 @@ if (!String.prototype.endsWith) {
 
             function extractGenerics(val) {
                 val = val.toLowerCase();
-                if (val.indexOf('<') !== -1) {
-                    var values = val.substring(val.indexOf('<') + 1, val.lastIndexOf('>'));
+                if (val.indexOf("<") !== -1) {
+                    var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
                     return {
-                        name: val.substring(0, val.indexOf('<')),
+                        name: val.substring(0, val.indexOf("<")),
                         generics: values.split(/\s*,\s*/),
                     };
                 }
@@ -617,9 +647,11 @@ if (!String.prototype.endsWith) {
                         var done = 0;
                         // We need to find the type that matches the most to remove it in order
                         // to move forward.
-                        for (var y = 0; y < val.generics.length; ++y) {
+                        var vlength = val.generics.length;
+                        for (var y = 0; y < vlength; ++y) {
                             var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
-                            for (var x = 0; x < elems.length; ++x) {
+                            var elength = elems.length;
+                            for (var x = 0; x < elength; ++x) {
                                 var tmp_lev = levenshtein(elems[x], val.generics[y]);
                                 if (tmp_lev < lev.lev) {
                                     lev.lev = tmp_lev;
@@ -644,6 +676,7 @@ if (!String.prototype.endsWith) {
             // Check for type name and type generics (if any).
             function checkType(obj, val, literalSearch) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
+                var x;
                 if (obj[NAME] === val.name) {
                     if (literalSearch === true) {
                         if (val.generics && val.generics.length !== 0) {
@@ -651,7 +684,6 @@ if (!String.prototype.endsWith) {
                                   obj[GENERICS_DATA].length >= val.generics.length) {
                                 var elems = obj[GENERICS_DATA].slice(0);
                                 var allFound = true;
-                                var x;
 
                                 for (var y = 0; allFound === true && y < val.generics.length; ++y) {
                                     allFound = false;
@@ -685,7 +717,8 @@ if (!String.prototype.endsWith) {
                 // Names didn't match so let's check if one of the generic types could.
                 if (literalSearch === true) {
                      if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
-                        for (var x = 0; x < obj[GENERICS_DATA].length; ++x) {
+                        var length = obj[GENERICS_DATA].length;
+                        for (x = 0; x < length; ++x) {
                             if (obj[GENERICS_DATA][x] === val.name) {
                                 return true;
                             }
@@ -693,13 +726,13 @@ if (!String.prototype.endsWith) {
                     }
                     return false;
                 }
-                var lev_distance = Math.min(levenshtein(obj[NAME], val.name),
-                                            lev_distance);
+                lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
                 if (lev_distance <= MAX_LEV_DISTANCE) {
                     lev_distance = Math.min(checkGenerics(obj, val), lev_distance);
                 } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
                     // We can check if the type we're looking for is inside the generics!
-                    for (var x = 0; x < obj[GENERICS_DATA].length; ++x) {
+                    var olength = obj[GENERICS_DATA].length;
+                    for (x = 0; x < olength; ++x) {
                         lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
                                                 lev_distance);
                     }
@@ -714,7 +747,8 @@ if (!String.prototype.endsWith) {
 
                 if (obj && obj.type && obj.type[INPUTS_DATA] &&
                       obj.type[INPUTS_DATA].length > 0) {
-                    for (var i = 0; i < obj.type[INPUTS_DATA].length; i++) {
+                    var length = obj.type[INPUTS_DATA].length;
+                    for (var i = 0; i < length; i++) {
                         var tmp = checkType(obj.type[INPUTS_DATA][i], val, literalSearch);
                         if (literalSearch === true && tmp === true) {
                             return true;
@@ -755,16 +789,18 @@ if (!String.prototype.endsWith) {
                     path.push(ty.parent.name.toLowerCase());
                 }
 
-                if (contains.length > path.length) {
+                var length = path.length;
+                var clength = contains.length;
+                if (clength > length) {
                     return MAX_LEV_DISTANCE + 1;
                 }
-                for (var i = 0; i < path.length; ++i) {
-                    if (i + contains.length > path.length) {
+                for (var i = 0; i < length; ++i) {
+                    if (i + clength > length) {
                         break;
                     }
                     var lev_total = 0;
                     var aborted = false;
-                    for (var x = 0; x < contains.length; ++x) {
+                    for (var x = 0; x < clength; ++x) {
                         var lev = levenshtein(path[i + x], contains[x]);
                         if (lev > MAX_LEV_DISTANCE) {
                             aborted = true;
@@ -773,7 +809,7 @@ if (!String.prototype.endsWith) {
                         lev_total += lev;
                     }
                     if (aborted === false) {
-                        ret_lev = Math.min(ret_lev, Math.round(lev_total / contains.length));
+                        ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
                     }
                 }
                 return ret_lev;
@@ -810,18 +846,23 @@ if (!String.prototype.endsWith) {
 
             // quoted values mean literal search
             var nSearchWords = searchWords.length;
+            var i;
+            var ty;
+            var fullId;
+            var returned;
+            var in_args;
             if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
                 val.charAt(val.length - 1) === val.charAt(0))
             {
                 val = extractGenerics(val.substr(1, val.length - 2));
-                for (var i = 0; i < nSearchWords; ++i) {
+                for (i = 0; i < nSearchWords; ++i) {
                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
                         continue;
                     }
-                    var in_args = findArg(searchIndex[i], val, true);
-                    var returned = checkReturned(searchIndex[i], val, true);
-                    var ty = searchIndex[i];
-                    var fullId = generateId(ty);
+                    in_args = findArg(searchIndex[i], val, true);
+                    returned = checkReturned(searchIndex[i], val, true);
+                    ty = searchIndex[i];
+                    fullId = generateId(ty);
 
                     if (searchWords[i] === val.name) {
                         // filter type: ... queries
@@ -866,27 +907,27 @@ if (!String.prototype.endsWith) {
                 var input = parts[0];
                 // sort inputs so that order does not matter
                 var inputs = input.split(",").map(trimmer).sort();
-                for (var i = 0; i < inputs.length; ++i) {
+                for (i = 0; i < inputs.length; ++i) {
                     inputs[i] = extractGenerics(inputs[i]);
                 }
                 var output = extractGenerics(parts[1]);
 
-                for (var i = 0; i < nSearchWords; ++i) {
+                for (i = 0; i < nSearchWords; ++i) {
                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
                         continue;
                     }
                     var type = searchIndex[i].type;
-                    var ty = searchIndex[i];
+                    ty = searchIndex[i];
                     if (!type) {
                         continue;
                     }
-                    var fullId = generateId(ty);
+                    fullId = generateId(ty);
 
                     // allow searching for void (no output) functions as well
                     var typeOutput = type.length > OUTPUT_DATA ? type[OUTPUT_DATA].name : "";
-                    var returned = checkReturned(ty, output, true);
+                    returned = checkReturned(ty, output, true);
                     if (output.name === "*" || returned === true) {
-                        var in_args = false;
+                        in_args = false;
                         var module = false;
 
                         if (input === "*") {
@@ -946,14 +987,16 @@ if (!String.prototype.endsWith) {
                 var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
 
                 for (j = 0; j < nSearchWords; ++j) {
-                    var ty = searchIndex[j];
+                    var lev;
+                    var lev_distance;
+                    ty = searchIndex[j];
                     if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
                         continue;
                     }
                     var lev_distance;
                     var lev_add = 0;
                     if (paths.length > 1) {
-                        var lev = checkPath(contains, paths[paths.length - 1], ty);
+                        lev = checkPath(contains, paths[paths.length - 1], ty);
                         if (lev > MAX_LEV_DISTANCE) {
                             continue;
                         } else if (lev > 0) {
@@ -961,12 +1004,12 @@ if (!String.prototype.endsWith) {
                         }
                     }
 
-                    var returned = MAX_LEV_DISTANCE + 1;
-                    var in_args = MAX_LEV_DISTANCE + 1;
+                    returned = MAX_LEV_DISTANCE + 1;
+                    in_args = MAX_LEV_DISTANCE + 1;
                     var index = -1;
                     // we want lev results to go lower than others
-                    var lev = MAX_LEV_DISTANCE + 1;
-                    var fullId = generateId(ty);
+                    lev = MAX_LEV_DISTANCE + 1;
+                    fullId = generateId(ty);
 
                     if (searchWords[j].indexOf(split[i]) > -1 ||
                         searchWords[j].indexOf(val) > -1 ||
@@ -1042,14 +1085,14 @@ if (!String.prototype.endsWith) {
             }
 
             var ret = {
-                'in_args': sortResults(results_in_args, true),
-                'returned': sortResults(results_returned, true),
-                'others': sortResults(results),
+                "in_args": sortResults(results_in_args, true),
+                "returned": sortResults(results_returned, true),
+                "others": sortResults(results),
             };
             if (ALIASES && ALIASES[window.currentCrate] &&
                     ALIASES[window.currentCrate][query.raw]) {
                 var aliases = ALIASES[window.currentCrate][query.raw];
-                for (var i = 0; i < aliases.length; ++i) {
+                for (i = 0; i < aliases.length; ++i) {
                     aliases[i].is_alias = true;
                     aliases[i].alias = query.raw;
                     aliases[i].path = aliases[i].p;
@@ -1057,9 +1100,9 @@ if (!String.prototype.endsWith) {
                     aliases[i].displayPath = pathSplitter(res[0]);
                     aliases[i].fullPath = aliases[i].displayPath + aliases[i].name;
                     aliases[i].href = res[1];
-                    ret['others'].unshift(aliases[i]);
-                    if (ret['others'].length > MAX_RESULTS) {
-                        ret['others'].pop();
+                    ret.others.unshift(aliases[i]);
+                    if (ret.others.length > MAX_RESULTS) {
+                        ret.others.pop();
                     }
                 }
             }
@@ -1106,7 +1149,7 @@ if (!String.prototype.endsWith) {
 
             matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
             if (matches) {
-                type = matches[1].replace(/^const$/, 'constant');
+                type = matches[1].replace(/^const$/, "constant");
                 query = query.substring(matches[0].length);
             }
 
@@ -1124,38 +1167,38 @@ if (!String.prototype.endsWith) {
             var click_func = function(e) {
                 var el = e.target;
                 // to retrieve the real "owner" of the event.
-                while (el.tagName !== 'TR') {
+                while (el.tagName !== "TR") {
                     el = el.parentNode;
                 }
-                var dst = e.target.getElementsByTagName('a');
+                var dst = e.target.getElementsByTagName("a");
                 if (dst.length < 1) {
                     return;
                 }
                 dst = dst[0];
                 if (window.location.pathname === dst.pathname) {
-                    addClass(document.getElementById('search'), 'hidden');
-                    removeClass(document.getElementById('main'), 'hidden');
+                    addClass(document.getElementById("search"), "hidden");
+                    removeClass(main, "hidden");
                     document.location.href = dst.href;
                 }
             };
             var mouseover_func = function(e) {
                 var el = e.target;
                 // to retrieve the real "owner" of the event.
-                while (el.tagName !== 'TR') {
+                while (el.tagName !== "TR") {
                     el = el.parentNode;
                 }
                 clearTimeout(hoverTimeout);
                 hoverTimeout = setTimeout(function() {
-                    onEach(document.getElementsByClassName('search-results'), function(e) {
-                        onEach(e.getElementsByClassName('result'), function(i_e) {
-                            removeClass(i_e, 'highlighted');
+                    onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+                        onEachLazy(e.getElementsByClassName("result"), function(i_e) {
+                            removeClass(i_e, "highlighted");
                         });
                     });
-                    addClass(el, 'highlighted');
+                    addClass(el, "highlighted");
                 }, 20);
             };
-            onEach(document.getElementsByClassName('search-results'), function(e) {
-                onEach(e.getElementsByClassName('result'), function(i_e) {
+            onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+                onEachLazy(e.getElementsByClassName("result"), function(i_e) {
                     i_e.onclick = click_func;
                     i_e.onmouseover = mouseover_func;
                 });
@@ -1167,8 +1210,8 @@ if (!String.prototype.endsWith) {
                 var actives = [[], [], []];
                 // "current" is used to know which tab we're looking into.
                 var current = 0;
-                onEach(document.getElementsByClassName('search-results'), function(e) {
-                    onEach(e.getElementsByClassName('highlighted'), function(e) {
+                onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+                    onEachLazy(e.getElementsByClassName("highlighted"), function(e) {
                         actives[current].push(e);
                     });
                     current += 1;
@@ -1180,25 +1223,25 @@ if (!String.prototype.endsWith) {
                         return;
                     }
 
-                    addClass(actives[currentTab][0].previousElementSibling, 'highlighted');
-                    removeClass(actives[currentTab][0], 'highlighted');
+                    addClass(actives[currentTab][0].previousElementSibling, "highlighted");
+                    removeClass(actives[currentTab][0], "highlighted");
                 } else if (e.which === 40) { // down
                     if (!actives[currentTab].length) {
-                        var results = document.getElementsByClassName('search-results');
+                        var results = document.getElementsByClassName("search-results");
                         if (results.length > 0) {
-                            var res = results[currentTab].getElementsByClassName('result');
+                            var res = results[currentTab].getElementsByClassName("result");
                             if (res.length > 0) {
-                                addClass(res[0], 'highlighted');
+                                addClass(res[0], "highlighted");
                             }
                         }
                     } else if (actives[currentTab][0].nextElementSibling) {
-                        addClass(actives[currentTab][0].nextElementSibling, 'highlighted');
-                        removeClass(actives[currentTab][0], 'highlighted');
+                        addClass(actives[currentTab][0].nextElementSibling, "highlighted");
+                        removeClass(actives[currentTab][0], "highlighted");
                     }
                 } else if (e.which === 13) { // return
                     if (actives[currentTab].length) {
                         document.location.href =
-                            actives[currentTab][0].getElementsByTagName('a')[0].href;
+                            actives[currentTab][0].getElementsByTagName("a")[0].href;
                     }
                 } else if (e.which === 9) { // tab
                     if (e.shiftKey) {
@@ -1210,11 +1253,11 @@ if (!String.prototype.endsWith) {
                 } else if (e.which === 16) { // shift
                     // Does nothing, it's just to avoid losing "focus" on the highlighted element.
                 } else if (e.which === 27) { // escape
-                    removeClass(actives[currentTab][0], 'highlighted');
-                    search_input.value = '';
+                    removeClass(actives[currentTab][0], "highlighted");
+                    search_input.value = "";
                     defocusSearchBar();
                 } else if (actives[currentTab].length > 0) {
-                    removeClass(actives[currentTab][0], 'highlighted');
+                    removeClass(actives[currentTab][0], "highlighted");
                 }
             };
         }
@@ -1225,46 +1268,46 @@ if (!String.prototype.endsWith) {
             var type = itemTypes[item.ty];
             var name = item.name;
 
-            if (type === 'mod') {
-                displayPath = item.path + '::';
-                href = rootPath + item.path.replace(/::/g, '/') + '/' +
-                       name + '/index.html';
+            if (type === "mod") {
+                displayPath = item.path + "::";
+                href = rootPath + item.path.replace(/::/g, "/") + "/" +
+                       name + "/index.html";
             } else if (type === "primitive" || type === "keyword") {
                 displayPath = "";
-                href = rootPath + item.path.replace(/::/g, '/') +
-                       '/' + type + '.' + name + '.html';
+                href = rootPath + item.path.replace(/::/g, "/") +
+                       "/" + type + "." + name + ".html";
             } else if (type === "externcrate") {
                 displayPath = "";
-                href = rootPath + name + '/index.html';
+                href = rootPath + name + "/index.html";
             } else if (item.parent !== undefined) {
                 var myparent = item.parent;
-                var anchor = '#' + type + '.' + name;
+                var anchor = "#" + type + "." + name;
                 var parentType = itemTypes[myparent.ty];
                 if (parentType === "primitive") {
-                    displayPath = myparent.name + '::';
+                    displayPath = myparent.name + "::";
                 } else {
-                    displayPath = item.path + '::' + myparent.name + '::';
+                    displayPath = item.path + "::" + myparent.name + "::";
                 }
-                href = rootPath + item.path.replace(/::/g, '/') +
-                       '/' + parentType +
-                       '.' + myparent.name +
-                       '.html' + anchor;
+                href = rootPath + item.path.replace(/::/g, "/") +
+                       "/" + parentType +
+                       "." + myparent.name +
+                       ".html" + anchor;
             } else {
-                displayPath = item.path + '::';
-                href = rootPath + item.path.replace(/::/g, '/') +
-                       '/' + type + '.' + name + '.html';
+                displayPath = item.path + "::";
+                href = rootPath + item.path.replace(/::/g, "/") +
+                       "/" + type + "." + name + ".html";
             }
             return [displayPath, href];
         }
 
         function escape(content) {
-            var h1 = document.createElement('h1');
+            var h1 = document.createElement("h1");
             h1.textContent = content;
             return h1.innerHTML;
         }
 
         function pathSplitter(path) {
-            var tmp = '<span>' + path.replace(/::/g, '::</span><span>');
+            var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
             if (tmp.endsWith("<span>")) {
                 return tmp.slice(0, tmp.length - 6);
             }
@@ -1272,16 +1315,16 @@ if (!String.prototype.endsWith) {
         }
 
         function addTab(array, query, display) {
-            var extraStyle = '';
+            var extraStyle = "";
             if (display === false) {
-                extraStyle = ' style="display: none;"';
+                extraStyle = " style=\"display: none;\"";
             }
 
-            var output = '';
+            var output = "";
             var duplicates = {};
             var length = 0;
             if (array.length > 0) {
-                output = '<table class="search-results"' + extraStyle + '>';
+                output = "<table class=\"search-results\"" + extraStyle + ">";
 
                 array.forEach(function(item) {
                     var name, type;
@@ -1297,50 +1340,50 @@ if (!String.prototype.endsWith) {
                     }
                     length += 1;
 
-                    output += '<tr class="' + type + ' result"><td>' +
-                              '<a href="' + item.href + '">' +
+                    output += "<tr class=\"" + type + " result\"><td>" +
+                              "<a href=\"" + item.href + "\">" +
                               (item.is_alias === true ?
-                               ('<span class="alias"><b>' + item.alias + ' </b></span><span ' +
-                                  'class="grey"><i>&nbsp;- see&nbsp;</i></span>') : '') +
-                              item.displayPath + '<span class="' + type + '">' +
-                              name + '</span></a></td><td>' +
-                              '<a href="' + item.href + '">' +
-                              '<span class="desc">' + escape(item.desc) +
-                              '&nbsp;</span></a></td></tr>';
+                               ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
+                                  "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
+                              item.displayPath + "<span class=\"" + type + "\">" +
+                              name + "</span></a></td><td>" +
+                              "<a href=\"" + item.href + "\">" +
+                              "<span class=\"desc\">" + escape(item.desc) +
+                              "&nbsp;</span></a></td></tr>";
                 });
-                output += '</table>';
+                output += "</table>";
             } else {
-                output = '<div class="search-failed"' + extraStyle + '>No results :(<br/>' +
-                    'Try on <a href="https://duckduckgo.com/?q=' +
-                    encodeURIComponent('rust ' + query.query) +
-                    '">DuckDuckGo</a>?<br/><br/>' +
-                    'Or try looking in one of these:<ul><li>The <a ' +
-                    'href="https://doc.rust-lang.org/reference/index.html">Rust Reference</a> for' +
-                    ' technical details about the language.</li><li><a ' +
-                    'href="https://doc.rust-lang.org/rust-by-example/index.html">Rust By Example' +
-                    '</a> for expository code examples.</a></li><li>The <a ' +
-                    'href="https://doc.rust-lang.org/book/index.html">Rust Book</a> for ' +
-                    'introductions to language features and the language itself.</li><li><a ' +
-                    'href="https://docs.rs">Docs.rs</a> for documentation of crates released on ' +
-                    '<a href="https://crates.io/">crates.io</a>.</li></ul></div>';
+                output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
+                    "Try on <a href=\"https://duckduckgo.com/?q=" +
+                    encodeURIComponent("rust " + query.query) +
+                    "\">DuckDuckGo</a>?<br/><br/>" +
+                    "Or try looking in one of these:<ul><li>The <a " +
+                    "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
+                    " for technical details about the language.</li><li><a " +
+                    "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
+                    "Example</a> for expository code examples.</a></li><li>The <a " +
+                    "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
+                    "introductions to language features and the language itself.</li><li><a " +
+                    "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
+                    " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
             }
             return [output, length];
         }
 
         function makeTabHeader(tabNb, text, nbElems) {
             if (currentTab === tabNb) {
-                return '<div class="selected">' + text +
-                       ' <div class="count">(' + nbElems + ')</div></div>';
+                return "<div class=\"selected\">" + text +
+                       " <div class=\"count\">(" + nbElems + ")</div></div>";
             }
-            return '<div>' + text + ' <div class="count">(' + nbElems + ')</div></div>';
+            return "<div>" + text + " <div class=\"count\">(" + nbElems + ")</div></div>";
         }
 
-        function showResults(results, filterCrates) {
-            if (results['others'].length === 1 &&
-                getCurrentValue('rustdoc-go-to-only-result') === "true") {
-                var elem = document.createElement('a');
-                elem.href = results['others'][0].href;
-                elem.style.display = 'none';
+        function showResults(results) {
+            if (results.others.length === 1 &&
+                getCurrentValue("rustdoc-go-to-only-result") === "true") {
+                var elem = document.createElement("a");
+                elem.href = results.others[0].href;
+                elem.style.display = "none";
                 // For firefox, we need the element to be in the DOM so it can be clicked.
                 document.body.appendChild(elem);
                 elem.click();
@@ -1349,39 +1392,34 @@ if (!String.prototype.endsWith) {
 
             currentResults = query.id;
 
-            var ret_others = addTab(results['others'], query);
-            var ret_in_args = addTab(results['in_args'], query, false);
-            var ret_returned = addTab(results['returned'], query, false);
+            var ret_others = addTab(results.others, query);
+            var ret_in_args = addTab(results.in_args, query, false);
+            var ret_returned = addTab(results.returned, query, false);
 
-            var filter = "";
-            if (filterCrates !== undefined) {
-                filter = " (in <b>" + filterCrates + "</b> crate)";
-            }
-
-            var output = '<h1>Results for ' + escape(query.query) +
-                (query.type ? ' (type: ' + escape(query.type) + ')' : '') + filter + '</h1>' +
-                '<div id="titles">' +
+            var output = "<h1>Results for " + escape(query.query) +
+                (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
+                "<div id=\"titles\">" +
                 makeTabHeader(0, "In Names", ret_others[1]) +
                 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
                 makeTabHeader(2, "In Return Types", ret_returned[1]) +
-                '</div><div id="results">' +
-                ret_others[0] + ret_in_args[0] + ret_returned[0] + '</div>';
+                "</div><div id=\"results\">" +
+                ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
 
-            addClass(document.getElementById('main'), 'hidden');
-            var search = document.getElementById('search');
-            removeClass(search, 'hidden');
+            addClass(main, "hidden");
+            var search = document.getElementById("search");
+            removeClass(search, "hidden");
             search.innerHTML = output;
-            var tds = search.getElementsByTagName('td');
+            var tds = search.getElementsByTagName("td");
             var td_width = 0;
             if (tds.length > 0) {
                 td_width = tds[0].offsetWidth;
             }
             var width = search.offsetWidth - 40 - td_width;
-            onEach(search.getElementsByClassName('desc'), function(e) {
-                e.style.width = width + 'px';
+            onEachLazy(search.getElementsByClassName("desc"), function(e) {
+                e.style.width = width + "px";
             });
             initSearchNav();
-            var elems = document.getElementById('titles').childNodes;
+            var elems = document.getElementById("titles").childNodes;
             elems[0].onclick = function() { printTab(0); };
             elems[1].onclick = function() { printTab(1); };
             elems[2].onclick = function() { printTab(2); };
@@ -1389,74 +1427,74 @@ if (!String.prototype.endsWith) {
         }
 
         function execSearch(query, searchWords, filterCrates) {
+            function getSmallest(arrays, positions, notDuplicates) {
+                var start = null;
+
+                for (var it = 0; it < positions.length; ++it) {
+                    if (arrays[it].length > positions[it] &&
+                        (start === null || start > arrays[it][positions[it]].lev) &&
+                        !notDuplicates[arrays[it][positions[it]].fullPath]) {
+                        start = arrays[it][positions[it]].lev;
+                    }
+                }
+                return start;
+            }
+
+            function mergeArrays(arrays) {
+                var ret = [];
+                var positions = [];
+                var notDuplicates = {};
+
+                for (var x = 0; x < arrays.length; ++x) {
+                    positions.push(0);
+                }
+                while (ret.length < MAX_RESULTS) {
+                    var smallest = getSmallest(arrays, positions, notDuplicates);
+
+                    if (smallest === null) {
+                        break;
+                    }
+                    for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
+                        if (arrays[x].length > positions[x] &&
+                                arrays[x][positions[x]].lev === smallest &&
+                                !notDuplicates[arrays[x][positions[x]].fullPath]) {
+                            ret.push(arrays[x][positions[x]]);
+                            notDuplicates[arrays[x][positions[x]].fullPath] = true;
+                            positions[x] += 1;
+                        }
+                    }
+                }
+                return ret;
+            }
+
             var queries = query.raw.split(",");
             var results = {
-                'in_args': [],
-                'returned': [],
-                'others': [],
+                "in_args": [],
+                "returned": [],
+                "others": [],
             };
 
             for (var i = 0; i < queries.length; ++i) {
-                var query = queries[i].trim();
+                query = queries[i].trim();
                 if (query.length !== 0) {
                     var tmp = execQuery(getQuery(query), searchWords, filterCrates);
 
-                    results['in_args'].push(tmp['in_args']);
-                    results['returned'].push(tmp['returned']);
-                    results['others'].push(tmp['others']);
+                    results.in_args.push(tmp.in_args);
+                    results.returned.push(tmp.returned);
+                    results.others.push(tmp.others);
                 }
             }
             if (queries.length > 1) {
-                function getSmallest(arrays, positions, notDuplicates) {
-                    var start = null;
-
-                    for (var it = 0; it < positions.length; ++it) {
-                        if (arrays[it].length > positions[it] &&
-                            (start === null || start > arrays[it][positions[it]].lev) &&
-                            !notDuplicates[arrays[it][positions[it]].fullPath]) {
-                            start = arrays[it][positions[it]].lev;
-                        }
-                    }
-                    return start;
-                }
-
-                function mergeArrays(arrays) {
-                    var ret = [];
-                    var positions = [];
-                    var notDuplicates = {};
-
-                    for (var x = 0; x < arrays.length; ++x) {
-                        positions.push(0);
-                    }
-                    while (ret.length < MAX_RESULTS) {
-                        var smallest = getSmallest(arrays, positions, notDuplicates);
-
-                        if (smallest === null) {
-                            break;
-                        }
-                        for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
-                            if (arrays[x].length > positions[x] &&
-                                    arrays[x][positions[x]].lev === smallest &&
-                                    !notDuplicates[arrays[x][positions[x]].fullPath]) {
-                                ret.push(arrays[x][positions[x]]);
-                                notDuplicates[arrays[x][positions[x]].fullPath] = true;
-                                positions[x] += 1;
-                            }
-                        }
-                    }
-                    return ret;
-                }
-
                 return {
-                    'in_args': mergeArrays(results['in_args']),
-                    'returned': mergeArrays(results['returned']),
-                    'others': mergeArrays(results['others']),
+                    "in_args": mergeArrays(results.in_args),
+                    "returned": mergeArrays(results.returned),
+                    "others": mergeArrays(results.others),
                 };
             } else {
                 return {
-                    'in_args': results['in_args'][0],
-                    'returned': results['returned'][0],
-                    'others': results['others'][0],
+                    "in_args": results.in_args[0],
+                    "returned": results.returned[0],
+                    "others": results.others[0],
                 };
             }
         }
@@ -1508,6 +1546,8 @@ if (!String.prototype.endsWith) {
         function buildIndex(rawSearchIndex) {
             searchIndex = [];
             var searchWords = [];
+            var i;
+
             for (var crate in rawSearchIndex) {
                 if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
 
@@ -1534,7 +1574,7 @@ if (!String.prototype.endsWith) {
 
                 // convert `paths` into an object form
                 var len = paths.length;
-                for (var i = 0; i < len; ++i) {
+                for (i = 0; i < len; ++i) {
                     paths[i] = {ty: paths[i][0], name: paths[i][1]};
                 }
 
@@ -1545,9 +1585,9 @@ if (!String.prototype.endsWith) {
                 // operation that is cached for the life of the page state so that
                 // all other search operations have access to this cached data for
                 // faster analysis operations
-                var len = items.length;
+                len = items.length;
                 var lastPath = "";
-                for (var i = 0; i < len; ++i) {
+                for (i = 0; i < len; ++i) {
                     var rawRow = items[i];
                     var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
                                path: rawRow[2] || lastPath, desc: rawRow[3],
@@ -1573,13 +1613,12 @@ if (!String.prototype.endsWith) {
                     if (browserSupportsHistoryApi()) {
                         history.replaceState("", "std - Rust", "?search=");
                     }
-                    var main = document.getElementById('main');
-                    if (hasClass(main, 'content')) {
-                        removeClass(main, 'hidden');
+                    if (hasClass(main, "content")) {
+                        removeClass(main, "hidden");
                     }
-                    var search_c = document.getElementById('search');
-                    if (hasClass(search_c, 'content')) {
-                        addClass(search_c, 'hidden');
+                    var search_c = document.getElementById("search");
+                    if (hasClass(search_c, "content")) {
+                        addClass(search_c, "hidden");
                     }
                 } else {
                     searchTimeout = setTimeout(search, 500);
@@ -1620,13 +1659,12 @@ if (!String.prototype.endsWith) {
                     // When browsing back from search results the main page
                     // visibility must be reset.
                     if (!params.search) {
-                        var main = document.getElementById('main');
-                        if (hasClass(main, 'content')) {
-                            removeClass(main, 'hidden');
+                        if (hasClass(main, "content")) {
+                            removeClass(main, "hidden");
                         }
-                        var search_c = document.getElementById('search');
-                        if (hasClass(search_c, 'content')) {
-                            addClass(search_c, 'hidden');
+                        var search_c = document.getElementById("search");
+                        if (hasClass(search_c, "content")) {
+                            addClass(search_c, "hidden");
                         }
                     }
                     // Revert to the previous title manually since the History
@@ -1643,9 +1681,9 @@ if (!String.prototype.endsWith) {
                     if (params.search) {
                         search_input.value = params.search;
                     } else {
-                        search_input.value = '';
+                        search_input.value = "";
                     }
-                    // Some browsers fire 'onpopstate' for every page load
+                    // Some browsers fire "onpopstate" for every page load
                     // (Chrome), while others fire the event only when actually
                     // popping a state (Firefox), which is why search() is
                     // called both here and at the end of the startSearch()
@@ -1660,13 +1698,13 @@ if (!String.prototype.endsWith) {
         startSearch();
 
         // Draw a convenient sidebar of known crates if we have a listing
-        if (rootPath === '../' || rootPath === "./") {
-            var sidebar = document.getElementsByClassName('sidebar-elems')[0];
+        if (rootPath === "../" || rootPath === "./") {
+            var sidebar = document.getElementsByClassName("sidebar-elems")[0];
             if (sidebar) {
-                var div = document.createElement('div');
-                div.className = 'block crate';
-                div.innerHTML = '<h3>Crates</h3>';
-                var ul = document.createElement('ul');
+                var div = document.createElement("div");
+                div.className = "block crate";
+                div.innerHTML = "<h3>Crates</h3>";
+                var ul = document.createElement("ul");
                 div.appendChild(ul);
 
                 var crates = [];
@@ -1678,17 +1716,17 @@ if (!String.prototype.endsWith) {
                 }
                 crates.sort();
                 for (var i = 0; i < crates.length; ++i) {
-                    var klass = 'crate';
+                    var klass = "crate";
                     if (rootPath !== "./" && crates[i] === window.currentCrate) {
-                        klass += ' current';
+                        klass += " current";
                     }
-                    var link = document.createElement('a');
-                    link.href = rootPath + crates[i] + '/index.html';
+                    var link = document.createElement("a");
+                    link.href = rootPath + crates[i] + "/index.html";
                     link.title = rawSearchIndex[crates[i]].doc;
                     link.className = klass;
                     link.textContent = crates[i];
 
-                    var li = document.createElement('li');
+                    var li = document.createElement("li");
                     li.appendChild(link);
                     ul.appendChild(li);
                 }
@@ -1701,41 +1739,44 @@ if (!String.prototype.endsWith) {
 
     // delayed sidebar rendering.
     function initSidebarItems(items) {
-        var sidebar = document.getElementsByClassName('sidebar-elems')[0];
+        var sidebar = document.getElementsByClassName("sidebar-elems")[0];
         var current = window.sidebarCurrent;
 
         function block(shortty, longty) {
             var filtered = items[shortty];
-            if (!filtered) { return; }
+            if (!filtered) {
+                return;
+            }
 
-            var div = document.createElement('div');
-            div.className = 'block ' + shortty;
-            var h3 = document.createElement('h3');
+            var div = document.createElement("div");
+            div.className = "block " + shortty;
+            var h3 = document.createElement("h3");
             h3.textContent = longty;
             div.appendChild(h3);
-            var ul = document.createElement('ul');
+            var ul = document.createElement("ul");
 
-            for (var i = 0; i < filtered.length; ++i) {
+            var length = filtered.length;
+            for (var i = 0; i < length; ++i) {
                 var item = filtered[i];
                 var name = item[0];
                 var desc = item[1]; // can be null
 
                 var klass = shortty;
                 if (name === current.name && shortty === current.ty) {
-                    klass += ' current';
+                    klass += " current";
                 }
                 var path;
-                if (shortty === 'mod') {
-                    path = name + '/index.html';
+                if (shortty === "mod") {
+                    path = name + "/index.html";
                 } else {
-                    path = shortty + '.' + name + '.html';
+                    path = shortty + "." + name + ".html";
                 }
-                var link = document.createElement('a');
+                var link = document.createElement("a");
                 link.href = current.relpath + path;
                 link.title = desc;
                 link.className = klass;
                 link.textContent = name;
-                var li = document.createElement('li');
+                var li = document.createElement("li");
                 li.appendChild(link);
                 ul.appendChild(li);
             }
@@ -1763,22 +1804,25 @@ if (!String.prototype.endsWith) {
     window.initSidebarItems = initSidebarItems;
 
     window.register_implementors = function(imp) {
-        var implementors = document.getElementById('implementors-list');
-        var synthetic_implementors = document.getElementById('synthetic-implementors-list');
+        var implementors = document.getElementById("implementors-list");
+        var synthetic_implementors = document.getElementById("synthetic-implementors-list");
 
         var libs = Object.getOwnPropertyNames(imp);
-        for (var i = 0; i < libs.length; ++i) {
+        var llength = libs.length;
+        for (var i = 0; i < llength; ++i) {
             if (libs[i] === currentCrate) { continue; }
             var structs = imp[libs[i]];
 
+            var slength = structs.length;
             struct_loop:
-            for (var j = 0; j < structs.length; ++j) {
+            for (var j = 0; j < slength; ++j) {
                 var struct = structs[j];
 
                 var list = struct.synthetic ? synthetic_implementors : implementors;
 
                 if (struct.synthetic) {
-                    for (var k = 0; k < struct.types.length; k++) {
+                    var stlength = struct.types.length;
+                    for (var k = 0; k < stlength; k++) {
                         if (window.inlined_types.has(struct.types[k])) {
                             continue struct_loop;
                         }
@@ -1786,21 +1830,22 @@ if (!String.prototype.endsWith) {
                     }
                 }
 
-                var code = document.createElement('code');
+                var code = document.createElement("code");
                 code.innerHTML = struct.text;
 
-                var x = code.getElementsByTagName('a');
-                for (var k = 0; k < x.length; k++) {
-                    var href = x[k].getAttribute('href');
-                    if (href && href.indexOf('http') !== 0) {
-                        x[k].setAttribute('href', rootPath + href);
+                var x = code.getElementsByTagName("a");
+                var xlength = x.length;
+                for (var it = 0; it < xlength; it++) {
+                    var href = x[it].getAttribute("href");
+                    if (href && href.indexOf("http") !== 0) {
+                        x[it].setAttribute("href", rootPath + href);
                     }
                 }
-                var display = document.createElement('h3');
+                var display = document.createElement("h3");
                 addClass(display, "impl");
-                display.innerHTML = '<span class="in-band"><table class="table-display"><tbody>\
-                    <tr><td><code>' + code.outerHTML + '</code></td><td></td></tr></tbody></table>\
-                    </span>';
+                display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
+                    "<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
+                    "</tbody></table></span>";
                 list.appendChild(display);
             }
         }
@@ -1816,47 +1861,49 @@ if (!String.prototype.endsWith) {
         }
         // button will collapse the section
         // note that this text is also set in the HTML template in render.rs
-        return "\u2212"; // "\u2212" is '−' minus sign
+        return "\u2212"; // "\u2212" is "−" minus sign
     }
 
     function onEveryMatchingChild(elem, className, func) {
         if (elem && className && func) {
-            for (var i = 0; i < elem.childNodes.length; i++) {
-                if (hasClass(elem.childNodes[i], className)) {
-                    func(elem.childNodes[i]);
+            var length = elem.childNodes.length;
+            var nodes = elem.childNodes;
+            for (var i = 0; i < length; ++i) {
+                if (hasClass(nodes[i], className)) {
+                    func(nodes[i]);
                 } else {
-                    onEveryMatchingChild(elem.childNodes[i], className, func);
+                    onEveryMatchingChild(nodes[i], className, func);
                 }
             }
         }
     }
 
     function toggleAllDocs(pageId, fromAutoCollapse) {
-        var toggle = document.getElementById("toggle-all-docs");
-        if (!toggle) {
+        var innerToggle = document.getElementById("toggle-all-docs");
+        if (!innerToggle) {
             return;
         }
-        if (hasClass(toggle, "will-expand")) {
+        if (hasClass(innerToggle, "will-expand")) {
             updateLocalStorage("rustdoc-collapse", "false");
-            removeClass(toggle, "will-expand");
-            onEveryMatchingChild(toggle, "inner", function(e) {
+            removeClass(innerToggle, "will-expand");
+            onEveryMatchingChild(innerToggle, "inner", function(e) {
                 e.innerHTML = labelForToggleButton(false);
             });
-            toggle.title = "collapse all docs";
+            innerToggle.title = "collapse all docs";
             if (fromAutoCollapse !== true) {
-                onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
+                onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
                     collapseDocs(e, "show");
                 });
             }
         } else {
             updateLocalStorage("rustdoc-collapse", "true");
-            addClass(toggle, "will-expand");
-            onEveryMatchingChild(toggle, "inner", function(e) {
+            addClass(innerToggle, "will-expand");
+            onEveryMatchingChild(innerToggle, "inner", function(e) {
                 e.innerHTML = labelForToggleButton(true);
             });
-            toggle.title = "expand all docs";
+            innerToggle.title = "expand all docs";
             if (fromAutoCollapse !== true) {
-                onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
+                onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
                     collapseDocs(e, "hide", pageId);
                 });
             }
@@ -1870,27 +1917,58 @@ if (!String.prototype.endsWith) {
 
         function adjustToggle(arg) {
             return function(e) {
-                if (hasClass(e, 'toggle-label')) {
+                if (hasClass(e, "toggle-label")) {
                     if (arg) {
-                        e.style.display = 'inline-block';
+                        e.style.display = "inline-block";
                     } else {
-                        e.style.display = 'none';
+                        e.style.display = "none";
                     }
                 }
-                if (hasClass(e, 'inner')) {
+                if (hasClass(e, "inner")) {
                     e.innerHTML = labelForToggleButton(arg);
                 }
             };
-        };
+        }
 
-        if (!hasClass(toggle.parentNode, "impl")) {
-            var relatedDoc = toggle.parentNode.nextElementSibling;
+        function implHider(addOrRemove) {
+            return function(n) {
+                var is_method = hasClass(n, "method");
+                if (is_method || hasClass(n, "type")) {
+                    if (is_method === true) {
+                        if (addOrRemove) {
+                            addClass(n, "hidden-by-impl-hider");
+                        } else {
+                            removeClass(n, "hidden-by-impl-hider");
+                        }
+                    }
+                    var ns = n.nextElementSibling;
+                    while (true) {
+                        if (ns && (
+                                hasClass(ns, "docblock") ||
+                                hasClass(ns, "stability"))) {
+                            if (addOrRemove) {
+                                addClass(ns, "hidden-by-impl-hider");
+                            } else {
+                                removeClass(ns, "hidden-by-impl-hider");
+                            }
+                            ns = ns.nextElementSibling;
+                            continue;
+                        }
+                        break;
+                    }
+                }
+            };
+        }
+
+        var relatedDoc;
+        var action = mode;
+        if (hasClass(toggle.parentNode, "impl") === false) {
+            relatedDoc = toggle.parentNode.nextElementSibling;
             if (hasClass(relatedDoc, "stability")) {
                 relatedDoc = relatedDoc.nextElementSibling;
             }
             if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
-                var action = mode;
-                if (action === "toggle") {
+                if (mode === "toggle") {
                     if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
                         action = "show";
                     } else {
@@ -1899,67 +1977,35 @@ if (!String.prototype.endsWith) {
                 }
                 if (action === "hide") {
                     addClass(relatedDoc, "hidden-by-usual-hider");
-                    onEach(toggle.childNodes, adjustToggle(true));
-                    addClass(toggle.parentNode, 'collapsed');
+                    onEachLazy(toggle.childNodes, adjustToggle(true));
+                    addClass(toggle.parentNode, "collapsed");
                 } else if (action === "show") {
                     removeClass(relatedDoc, "hidden-by-usual-hider");
-                    removeClass(toggle.parentNode, 'collapsed');
-                    onEach(toggle.childNodes, adjustToggle(false));
+                    removeClass(toggle.parentNode, "collapsed");
+                    onEachLazy(toggle.childNodes, adjustToggle(false));
                 }
             }
         } else {
             // we are collapsing the impl block
-            function implHider(addOrRemove) {
-                return function(n) {
-                    var is_method = hasClass(n, "method");
-                    if (is_method || hasClass(n, "type")) {
-                        if (is_method === true) {
-                            if (addOrRemove) {
-                                addClass(n, "hidden-by-impl-hider");
-                            } else {
-                                removeClass(n, "hidden-by-impl-hider");
-                            }
-                        }
-                        var ns = n.nextElementSibling;
-                        while (true) {
-                            if (ns && (
-                                    hasClass(ns, "docblock") ||
-                                    hasClass(ns, "stability"))) {
-                                if (addOrRemove) {
-                                    addClass(ns, "hidden-by-impl-hider");
-                                } else {
-                                    removeClass(ns, "hidden-by-impl-hider");
-                                }
-                                ns = ns.nextElementSibling;
-                                continue;
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
 
             var parentElem = toggle.parentNode;
-            var relatedDoc = parentElem;
+            relatedDoc = parentElem;
             var docblock = relatedDoc.nextElementSibling;
 
-            while (!hasClass(relatedDoc, "impl-items")) {
+            while (hasClass(relatedDoc, "impl-items") === false) {
                 relatedDoc = relatedDoc.nextElementSibling;
             }
 
-            if ((!relatedDoc && !hasClass(docblock, "docblock")) ||
-                (pageId && onEach(relatedDoc.childNodes, function(e) {
-                    return e.id === pageId;
-                }) === true)) {
+            if ((!relatedDoc && hasClass(docblock, "docblock") === false) ||
+                (pageId && document.getElementById(pageId))) {
                 return;
             }
 
             // Hide all functions, but not associated types/consts
 
-            var action = mode;
-            if (action === "toggle") {
+            if (mode === "toggle") {
                 if (hasClass(relatedDoc, "fns-now-collapsed") ||
-                    hasClass(docblock,  "hidden-by-impl-hider")) {
+                    hasClass(docblock, "hidden-by-impl-hider")) {
                     action = "show";
                 } else {
                     action = "hide";
@@ -1969,13 +2015,25 @@ if (!String.prototype.endsWith) {
             if (action === "show") {
                 removeClass(relatedDoc, "fns-now-collapsed");
                 removeClass(docblock, "hidden-by-usual-hider");
-                onEach(toggle.childNodes, adjustToggle(false));
-                onEach(relatedDoc.childNodes, implHider(false));
+                onEachLazy(toggle.childNodes, adjustToggle(false));
+                onEachLazy(relatedDoc.childNodes, implHider(false));
             } else if (action === "hide") {
                 addClass(relatedDoc, "fns-now-collapsed");
                 addClass(docblock, "hidden-by-usual-hider");
-                onEach(toggle.childNodes, adjustToggle(true));
-                onEach(relatedDoc.childNodes, implHider(true));
+                onEachLazy(toggle.childNodes, adjustToggle(true));
+                onEachLazy(relatedDoc.childNodes, implHider(true));
+            }
+        }
+    }
+
+    function collapser(e, collapse) {
+        // inherent impl ids are like "impl" or impl-<number>'.
+        // they will never be hidden by default.
+        var n = e.parentElement;
+        if (n.id.match(/^impl(?:-\d+)?$/) === null) {
+            // Automatically minimize all non-inherent impls
+            if (collapse || hasClass(n, "impl")) {
+                collapseDocs(e, "hide", pageId);
             }
         }
     }
@@ -1983,88 +2041,112 @@ if (!String.prototype.endsWith) {
     function autoCollapse(pageId, collapse) {
         if (collapse) {
             toggleAllDocs(pageId, true);
-        }
-        var collapser = function(e) {
-                // inherent impl ids are like 'impl' or impl-<number>'.
-                // they will never be hidden by default.
-                var n = e.parentElement;
-                if (n.id.match(/^impl(?:-\d+)?$/) === null) {
-                    // Automatically minimize all non-inherent impls
-                    if (collapse || hasClass(n, 'impl')) {
-                        collapseDocs(e, "hide", pageId);
-                    }
-                }
-        };
-        if (getCurrentValue('rustdoc-trait-implementations') !== "false") {
-            var impl_list = document.getElementById('implementations-list');
+        } else if (getCurrentValue("rustdoc-trait-implementations") !== "false") {
+            var impl_list = document.getElementById("implementations-list");
 
             if (impl_list !== null) {
-                onEach(impl_list.getElementsByClassName("collapse-toggle"), collapser);
-            }
-        }
-        if (getCurrentValue('rustdoc-method-docs') !== "false") {
-            var implItems = document.getElementsByClassName('impl-items');
-
-            if (implItems && implItems.length > 0) {
-                onEach(implItems, function(elem) {
-                    onEach(elem.getElementsByClassName("collapse-toggle"), collapser);
+                onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) {
+                    collapser(e, collapse);
                 });
             }
         }
     }
 
-    var x = document.getElementById('toggle-all-docs');
-    if (x) {
-        x.onclick = toggleAllDocs;
+    var toggles = document.getElementById("toggle-all-docs");
+    if (toggles) {
+        toggles.onclick = toggleAllDocs;
     }
 
     function insertAfter(newNode, referenceNode) {
         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
     }
 
-    function checkIfThereAreMethods(elems) {
-        var areThereMethods = false;
-
-        onEach(elems, function(e) {
-            if (hasClass(e, "method")) {
-                areThereMethods = true;
-                return true;
-            }
-        });
-        return areThereMethods;
+    function createSimpleToggle(sectionIsCollapsed) {
+        var toggle = document.createElement("a");
+        toggle.href = "javascript:void(0)";
+        toggle.className = "collapse-toggle";
+        toggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed) +
+                           "</span>]";
+        return toggle;
     }
 
-    var toggle = document.createElement('a');
-    toggle.href = 'javascript:void(0)';
-    toggle.className = 'collapse-toggle';
-    toggle.innerHTML = "[<span class='inner'>" + labelForToggleButton(false) + "</span>]";
+    var toggle = createSimpleToggle(false);
 
     var func = function(e) {
         var next = e.nextElementSibling;
-        if (hasClass(e, 'impl') && next && hasClass(next, 'docblock')) {
+        if (!next) {
+            return;
+        }
+        if (hasClass(next, "docblock") ||
+            (hasClass(next, "stability") &&
+             hasClass(next.nextElementSibling, "docblock"))) {
+            insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
+        }
+    };
+
+    var funcImpl = function(e) {
+        var next = e.nextElementSibling;
+        if (next && hasClass(next, "docblock")) {
             next = next.nextElementSibling;
         }
         if (!next) {
             return;
         }
-        if ((hasClass(e, 'method') || hasClass(e, 'associatedconstant') ||
-             checkIfThereAreMethods(next.childNodes)) &&
-            (hasClass(next, 'docblock') ||
-             hasClass(e, 'impl') ||
-             (hasClass(next, 'stability') &&
-              hasClass(next.nextElementSibling, 'docblock')))) {
+        if (next.getElementsByClassName("method").length > 0 && hasClass(e, "impl")) {
             insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
         }
     };
-    onEach(document.getElementsByClassName('method'), func);
-    onEach(document.getElementsByClassName('associatedconstant'), func);
-    onEach(document.getElementsByClassName('impl'), func);
-    onEach(document.getElementsByClassName('impl-items'), function(e) {
-        onEach(e.getElementsByClassName('associatedconstant'), func);
-        var hiddenElems = e.getElementsByClassName('hidden');
+
+    onEachLazy(document.getElementsByClassName("method"), func);
+    onEachLazy(document.getElementsByClassName("associatedconstant"), func);
+    onEachLazy(document.getElementsByClassName("impl"), funcImpl);
+    var impl_call = function() {};
+    if (getCurrentValue("rustdoc-method-docs") !== "false") {
+        impl_call = function(e, newToggle, pageId) {
+            if (e.id.match(/^impl(?:-\d+)?$/) === null) {
+                // Automatically minimize all non-inherent impls
+                if (hasClass(e, "impl")) {
+                    collapseDocs(newToggle, "hide", pageId);
+                }
+            }
+        };
+    }
+    var pageId = getPageId();
+    var newToggle = document.createElement("a");
+    newToggle.href = "javascript:void(0)";
+    newToggle.className = "collapse-toggle hidden-default collapsed";
+    newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
+                          "</span>] Show hidden undocumented items";
+    function toggleClicked() {
+        if (hasClass(this, "collapsed")) {
+            removeClass(this, "collapsed");
+            onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
+                if (hasClass(x, "content") === false) {
+                    removeClass(x, "hidden");
+                    addClass(x, "x");
+                }
+            }, true);
+            this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
+                             "</span>] Hide undocumented items";
+        } else {
+            addClass(this, "collapsed");
+            onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
+                if (hasClass(x, "content") === false) {
+                    addClass(x, "hidden");
+                    removeClass(x, "x");
+                }
+            }, true);
+            this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
+                             "</span>] Show hidden undocumented items";
+        }
+    }
+    onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
+        onEachLazy(e.getElementsByClassName("associatedconstant"), func);
+        var hiddenElems = e.getElementsByClassName("hidden");
         var needToggle = false;
 
-        for (var i = 0; i < hiddenElems.length; ++i) {
+        var hlength = hiddenElems.length;
+        for (var i = 0; i < hlength; ++i) {
             if (hasClass(hiddenElems[i], "content") === false &&
                 hasClass(hiddenElems[i], "docblock") === false) {
                 needToggle = true;
@@ -2072,46 +2154,21 @@ if (!String.prototype.endsWith) {
             }
         }
         if (needToggle === true) {
-            var newToggle = document.createElement('a');
-            newToggle.href = 'javascript:void(0)';
-            newToggle.className = 'collapse-toggle hidden-default collapsed';
-            newToggle.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) + "</span>" +
-                                  "] Show hidden undocumented items";
-            newToggle.onclick = function() {
-                if (hasClass(this, "collapsed")) {
-                    removeClass(this, "collapsed");
-                    onEach(this.parentNode.getElementsByClassName("hidden"), function(x) {
-                        if (hasClass(x, "content") === false) {
-                            removeClass(x, "hidden");
-                            addClass(x, "x");
-                        }
-                    }, true);
-                    this.innerHTML = "[<span class='inner'>" + labelForToggleButton(false) +
-                                     "</span>] Hide undocumented items"
-                } else {
-                    addClass(this, "collapsed");
-                    onEach(this.parentNode.getElementsByClassName("x"), function(x) {
-                        if (hasClass(x, "content") === false) {
-                            addClass(x, "hidden");
-                            removeClass(x, "x");
-                        }
-                    }, true);
-                    this.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) +
-                                     "</span>] Show hidden undocumented items";
-                }
-            };
-            e.insertBefore(newToggle, e.firstChild);
+            var inner_toggle = newToggle.cloneNode(true);
+            inner_toggle.onclick = toggleClicked;
+            e.insertBefore(inner_toggle, e.firstChild);
+            impl_call(e, inner_toggle, pageId);
         }
     });
 
     function createToggle(otherMessage, fontSize, extraClass, show) {
-        var span = document.createElement('span');
-        span.className = 'toggle-label';
+        var span = document.createElement("span");
+        span.className = "toggle-label";
         if (show) {
-            span.style.display = 'none';
+            span.style.display = "none";
         }
         if (!otherMessage) {
-            span.innerHTML = '&nbsp;Expand&nbsp;description';
+            span.innerHTML = "&nbsp;Expand&nbsp;description";
         } else {
             span.innerHTML = otherMessage;
         }
@@ -2123,13 +2180,13 @@ if (!String.prototype.endsWith) {
         var mainToggle = toggle.cloneNode(true);
         mainToggle.appendChild(span);
 
-        var wrapper = document.createElement('div');
-        wrapper.className = 'toggle-wrapper';
+        var wrapper = document.createElement("div");
+        wrapper.className = "toggle-wrapper";
         if (!show) {
-            addClass(wrapper, 'collapsed');
-            var inner = mainToggle.getElementsByClassName('inner');
+            addClass(wrapper, "collapsed");
+            var inner = mainToggle.getElementsByClassName("inner");
             if (inner && inner.length > 0) {
-                inner[0].innerHTML = '+';
+                inner[0].innerHTML = "+";
             }
         }
         if (extraClass) {
@@ -2139,21 +2196,21 @@ if (!String.prototype.endsWith) {
         return wrapper;
     }
 
-    var showItemDeclarations = getCurrentValue('rustdoc-item-declarations') === "false";
+    var showItemDeclarations = getCurrentValue("rustdoc-item-declarations") === "false";
     function buildToggleWrapper(e) {
-        if (hasClass(e, 'autohide')) {
+        if (hasClass(e, "autohide")) {
             var wrap = e.previousElementSibling;
-            if (wrap && hasClass(wrap, 'toggle-wrapper')) {
-                var toggle = wrap.childNodes[0];
-                var extra = e.childNodes[0].tagName === 'H3';
+            if (wrap && hasClass(wrap, "toggle-wrapper")) {
+                var inner_toggle = wrap.childNodes[0];
+                var extra = e.childNodes[0].tagName === "H3";
 
-                e.style.display = 'none';
-                addClass(wrap, 'collapsed');
-                onEach(toggle.getElementsByClassName('inner'), function(e) {
+                e.style.display = "none";
+                addClass(wrap, "collapsed");
+                onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) {
                     e.innerHTML = labelForToggleButton(true);
                 });
-                onEach(toggle.getElementsByClassName('toggle-label'), function(e) {
-                    e.style.display = 'inline-block';
+                onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) {
+                    e.style.display = "inline-block";
                     if (extra === true) {
                         i_e.innerHTML = " Show " + e.childNodes[0].innerHTML;
                     }
@@ -2161,28 +2218,28 @@ if (!String.prototype.endsWith) {
             }
         }
         if (e.parentNode.id === "main") {
-            var otherMessage = '';
+            var otherMessage = "";
             var fontSize;
             var extraClass;
 
             if (hasClass(e, "type-decl")) {
                 fontSize = "20px";
-                otherMessage = '&nbsp;Show&nbsp;declaration';
+                otherMessage = "&nbsp;Show&nbsp;declaration";
                 if (showItemDeclarations === false) {
-                    extraClass = 'collapsed';
+                    extraClass = "collapsed";
                 }
             } else if (hasClass(e, "sub-variant")) {
-                otherMessage = '&nbsp;Show&nbsp;fields';
+                otherMessage = "&nbsp;Show&nbsp;fields";
             } else if (hasClass(e, "non-exhaustive")) {
-                otherMessage = '&nbsp;This&nbsp;';
+                otherMessage = "&nbsp;This&nbsp;";
                 if (hasClass(e, "non-exhaustive-struct")) {
-                    otherMessage += 'struct';
+                    otherMessage += "struct";
                 } else if (hasClass(e, "non-exhaustive-enum")) {
-                    otherMessage += 'enum';
+                    otherMessage += "enum";
                 } else if (hasClass(e, "non-exhaustive-type")) {
-                    otherMessage += 'type';
+                    otherMessage += "type";
                 }
-                otherMessage += '&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive';
+                otherMessage += "&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive";
             } else if (hasClass(e.childNodes[0], "impl-items")) {
                 extraClass = "marg-left";
             }
@@ -2199,21 +2256,8 @@ if (!String.prototype.endsWith) {
         }
     }
 
-    onEach(document.getElementsByClassName('docblock'), buildToggleWrapper);
-    onEach(document.getElementsByClassName('sub-variant'), buildToggleWrapper);
-
-    function createToggleWrapper(tog) {
-        var span = document.createElement('span');
-        span.className = 'toggle-label';
-        span.style.display = 'none';
-        span.innerHTML = '&nbsp;Expand&nbsp;attributes';
-        tog.appendChild(span);
-
-        var wrapper = document.createElement('div');
-        wrapper.className = 'toggle-wrapper toggle-attributes';
-        wrapper.appendChild(tog);
-        return wrapper;
-    }
+    onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
+    onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
 
     // In the search display, allows to switch between tabs.
     function printTab(nb) {
@@ -2221,24 +2265,37 @@ if (!String.prototype.endsWith) {
             currentTab = nb;
         }
         var nb_copy = nb;
-        onEach(document.getElementById('titles').childNodes, function(elem) {
+        onEachLazy(document.getElementById("titles").childNodes, function(elem) {
             if (nb_copy === 0) {
-                addClass(elem, 'selected');
+                addClass(elem, "selected");
             } else {
-                removeClass(elem, 'selected');
+                removeClass(elem, "selected");
             }
             nb_copy -= 1;
         });
-        onEach(document.getElementById('results').childNodes, function(elem) {
+        onEachLazy(document.getElementById("results").childNodes, function(elem) {
             if (nb === 0) {
-                elem.style.display = '';
+                elem.style.display = "";
             } else {
-                elem.style.display = 'none';
+                elem.style.display = "none";
             }
             nb -= 1;
         });
     }
 
+    function createToggleWrapper(tog) {
+        var span = document.createElement("span");
+        span.className = "toggle-label";
+        span.style.display = "none";
+        span.innerHTML = "&nbsp;Expand&nbsp;attributes";
+        tog.appendChild(span);
+
+        var wrapper = document.createElement("div");
+        wrapper.className = "toggle-wrapper toggle-attributes";
+        wrapper.appendChild(tog);
+        return wrapper;
+    }
+
     // To avoid checking on "rustdoc-item-attributes" value on every loop...
     var itemAttributesFunc = function() {};
     if (getCurrentValue("rustdoc-item-attributes") !== "false") {
@@ -2246,8 +2303,9 @@ if (!String.prototype.endsWith) {
             collapseDocs(x.previousSibling.childNodes[0], "toggle");
         };
     }
-    onEach(document.getElementById('main').getElementsByClassName('attributes'), function(i_e) {
-        i_e.parentNode.insertBefore(createToggleWrapper(toggle.cloneNode(true)), i_e);
+    var attributesToggle = createToggleWrapper(createSimpleToggle(false));
+    onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
+        i_e.parentNode.insertBefore(attributesToggle.cloneNode(true), i_e);
         itemAttributesFunc(i_e);
     });
 
@@ -2255,45 +2313,45 @@ if (!String.prototype.endsWith) {
     var lineNumbersFunc = function() {};
     if (getCurrentValue("rustdoc-line-numbers") === "true") {
         lineNumbersFunc = function(x) {
-            var count = x.textContent.split('\n').length;
+            var count = x.textContent.split("\n").length;
             var elems = [];
             for (var i = 0; i < count; ++i) {
                 elems.push(i + 1);
             }
-            var node = document.createElement('pre');
-            addClass(node, 'line-number');
-            node.innerHTML = elems.join('\n');
+            var node = document.createElement("pre");
+            addClass(node, "line-number");
+            node.innerHTML = elems.join("\n");
             x.parentNode.insertBefore(node, x);
         };
     }
-    onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {
-        if (hasClass(e, 'compile_fail')) {
+    onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
+        if (hasClass(e, "compile_fail")) {
             e.addEventListener("mouseover", function(event) {
-                this.parentElement.previousElementSibling.childNodes[0].style.color = '#f00';
+                this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
             });
             e.addEventListener("mouseout", function(event) {
-                this.parentElement.previousElementSibling.childNodes[0].style.color = '';
+                this.parentElement.previousElementSibling.childNodes[0].style.color = "";
             });
-        } else if (hasClass(e, 'ignore')) {
+        } else if (hasClass(e, "ignore")) {
             e.addEventListener("mouseover", function(event) {
-                this.parentElement.previousElementSibling.childNodes[0].style.color = '#ff9200';
+                this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
             });
             e.addEventListener("mouseout", function(event) {
-                this.parentElement.previousElementSibling.childNodes[0].style.color = '';
+                this.parentElement.previousElementSibling.childNodes[0].style.color = "";
             });
         }
         lineNumbersFunc(e);
     });
 
     function showModal(content) {
-        var modal = document.createElement('div');
+        var modal = document.createElement("div");
         modal.id = "important";
-        addClass(modal, 'modal');
-        modal.innerHTML = '<div class="modal-content"><div class="close" id="modal-close">✕</div>' +
-                          '<div class="whiter"></div><span class="docblock">' + content +
-                          '</span></div>';
-        document.getElementsByTagName('body')[0].appendChild(modal);
-        document.getElementById('modal-close').onclick = hideModal;
+        addClass(modal, "modal");
+        modal.innerHTML = "<div class=\"modal-content\"><div class=\"close\" id=\"modal-close\">✕" +
+                          "</div><div class=\"whiter\"></div><span class=\"docblock\">" + content +
+                          "</span></div>";
+        document.getElementsByTagName("body")[0].appendChild(modal);
+        document.getElementById("modal-close").onclick = hideModal;
         modal.onclick = hideModal;
     }
 
@@ -2304,7 +2362,7 @@ if (!String.prototype.endsWith) {
         }
     }
 
-    onEach(document.getElementsByClassName('important-traits'), function(e) {
+    onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
         e.onclick = function() {
             showModal(e.lastElementChild.innerHTML);
         };
@@ -2312,7 +2370,7 @@ if (!String.prototype.endsWith) {
 
     function putBackSearch(search_input) {
         if (search_input.value !== "") {
-            addClass(document.getElementById("main"), "hidden");
+            addClass(main, "hidden");
             removeClass(document.getElementById("search"), "hidden");
             if (browserSupportsHistoryApi()) {
                 history.replaceState(search_input.value,
@@ -2330,16 +2388,16 @@ if (!String.prototype.endsWith) {
 
     var params = getQueryStringParams();
     if (params && params.search) {
-        addClass(document.getElementById("main"), "hidden");
+        addClass(main, "hidden");
         var search = document.getElementById("search");
         removeClass(search, "hidden");
-        search.innerHTML = '<h3 style="text-align: center;">Loading search results...</h3>';
+        search.innerHTML = "<h3 style=\"text-align: center;\">Loading search results...</h3>";
     }
 
     var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
     if (sidebar_menu) {
         sidebar_menu.onclick = function() {
-            var sidebar = document.getElementsByClassName('sidebar')[0];
+            var sidebar = document.getElementsByClassName("sidebar")[0];
             if (hasClass(sidebar, "mobile") === true) {
                 hideSidebar();
             } else {
@@ -2355,7 +2413,18 @@ if (!String.prototype.endsWith) {
     autoCollapse(getPageId(), getCurrentValue("rustdoc-collapse") === "true");
 
     if (window.location.hash && window.location.hash.length > 0) {
-        expandSection(window.location.hash.replace(/^#/, ''));
+        expandSection(window.location.hash.replace(/^#/, ""));
+    }
+
+    if (main) {
+        onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
+            e.remove();
+        });
+        onEachLazy(main.childNodes, function(e) {
+            if (e.tagName === "H2" || e.tagName === "H3") {
+                e.nextElementSibling.style.display = "block";
+            }
+        });
     }
 
     function addSearchOptions(crates) {
@@ -2394,10 +2463,10 @@ if (!String.prototype.endsWith) {
 
 // Sets the focus on the search bar at the top of the page
 function focusSearchBar() {
-    document.getElementsByClassName('search-input')[0].focus();
+    document.getElementsByClassName("search-input")[0].focus();
 }
 
 // Removes the focus from the search bar
 function defocusSearchBar() {
-    document.getElementsByClassName('search-input')[0].blur();
+    document.getElementsByClassName("search-input")[0].blur();
 }
diff --git a/src/librustdoc/html/static/noscript.css b/src/librustdoc/html/static/noscript.css
new file mode 100644 (file)
index 0000000..f4de75f
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+ * file at the top-level directory of this distribution and at
+ * http://rust-lang.org/COPYRIGHT.
+ *
+ * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+ * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ * option. This file may not be copied, modified, or distributed
+ * except according to those terms.
+ */
+
+#main > h2 + div, #main > h2 + h3, #main > h3 + div {
+       display: block;
+}
+
+.loading-content {
+       display: none;
+}
index cd5a8a739d16dfac78d3288c9dccb18f28e15bf9..d1336b1e8eb0b7aa510bd30df42795ef893dcd1d 100644 (file)
@@ -368,6 +368,10 @@ body:not(.source) .example-wrap > pre {
 #main > .docblock h2 { font-size: 1.15em; }
 #main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; }
 
+#main > h2 + div, #main > h2 + h3, #main > h3 + div {
+       display: none;
+}
+
 .docblock h1 { font-size: 1em; }
 .docblock h2 { font-size: 0.95em; }
 .docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; }
index e8f0c03d91aa666332503a236f82db9f7cd8b1b2..d1c377bf95ac87e29c6cd117849992d7c7029cdb 100644 (file)
@@ -19,55 +19,38 @@ var mainTheme = document.getElementById("mainThemeStyle");
 var savedHref = [];
 
 function hasClass(elem, className) {
-    if (elem && className && elem.className) {
-        var elemClass = elem.className;
-        var start = elemClass.indexOf(className);
-        if (start === -1) {
-            return false;
-        } else if (elemClass.length === className.length) {
-            return true;
-        } else {
-            if (start > 0 && elemClass[start - 1] !== ' ') {
-                return false;
-            }
-            var end = start + className.length;
-            return !(end < elemClass.length && elemClass[end] !== ' ');
-        }
-    }
-    return false;
+    return elem && elem.classList && elem.classList.contains(className);
 }
 
 function addClass(elem, className) {
-    if (elem && className && !hasClass(elem, className)) {
-        if (elem.className && elem.className.length > 0) {
-            elem.className += ' ' + className;
-        } else {
-            elem.className = className;
-        }
+    if (!elem || !elem.classList) {
+        return;
     }
+    elem.classList.add(className);
 }
 
 function removeClass(elem, className) {
-    if (elem && className && elem.className) {
-        elem.className = (" " + elem.className + " ").replace(" " + className + " ", " ")
-                                                     .trim();
+    if (!elem || !elem.classList) {
+        return;
     }
+    elem.classList.remove(className);
 }
 
 function isHidden(elem) {
-    return (elem.offsetParent === null)
+    return elem.offsetParent === null;
 }
 
 function onEach(arr, func, reversed) {
     if (arr && arr.length > 0 && func) {
+        var length = arr.length;
         if (reversed !== true) {
-            for (var i = 0; i < arr.length; ++i) {
+            for (var i = 0; i < length; ++i) {
                 if (func(arr[i]) === true) {
                     return true;
                 }
             }
         } else {
-            for (var i = arr.length - 1; i >= 0; --i) {
+            for (var i = length - 1; i >= 0; --i) {
                 if (func(arr[i]) === true) {
                     return true;
                 }
@@ -77,6 +60,13 @@ function onEach(arr, func, reversed) {
     return false;
 }
 
+function onEachLazy(lazyArray, func, reversed) {
+    return onEach(
+        Array.prototype.slice.call(lazyArray),
+        func,
+        reversed);
+}
+
 function usableLocalStorage() {
     // Check if the browser supports localStorage at all:
     if (typeof(Storage) === "undefined") {
@@ -133,8 +123,8 @@ function switchTheme(styleElem, mainStyleElem, newTheme) {
     });
     if (found === true) {
         styleElem.href = newHref;
-        updateLocalStorage('rustdoc-theme', newTheme);
+        updateLocalStorage("rustdoc-theme", newTheme);
     }
 }
 
-switchTheme(currentTheme, mainTheme, getCurrentValue('rustdoc-theme') || 'light');
+switchTheme(currentTheme, mainTheme, getCurrentValue("rustdoc-theme") || "light");
index a485facfac2dcb1fb30084aabfd4e44fda6d24ba..f71b2a8728422f4e323962512860f3729ec55a9c 100644 (file)
@@ -23,6 +23,9 @@
 /// The file contents of `settings.css`, responsible for the items on the settings page.
 pub static SETTINGS_CSS: &'static str = include_str!("static/settings.css");
 
+/// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled.
+pub static NOSCRIPT_CSS: &'static str = include_str!("static/noscript.css");
+
 /// The file contents of `normalize.css`, included to even out standard elements between browser
 /// implementations.
 pub static NORMALIZE_CSS: &'static str = include_str!("static/normalize.css");
index 50acde64cf023b32e1f817ab43fe67d2f3d49eeb..84ce9f6d2574d1bc54926aa1c99ff32fb004b94f 100644 (file)
@@ -395,6 +395,7 @@ pub fn make_test(s: &str,
     // Now push any outer attributes from the example, assuming they
     // are intended to be crate attributes.
     prog.push_str(&crate_attrs);
+    prog.push_str(&crates);
 
     // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
     // crate already is included.
@@ -488,37 +489,78 @@ pub fn make_test(s: &str,
         prog.push_str("\n}");
     }
 
+    debug!("final doctest:\n{}", prog);
+
     (prog, line_offset)
 }
 
 // FIXME(aburka): use a real parser to deal with multiline attributes
 fn partition_source(s: &str) -> (String, String, String) {
-    let mut after_header = false;
+    #[derive(Copy, Clone, PartialEq)]
+    enum PartitionState {
+        Attrs,
+        Crates,
+        Other,
+    }
+    let mut state = PartitionState::Attrs;
     let mut before = String::new();
     let mut crates = String::new();
     let mut after = String::new();
 
     for line in s.lines() {
         let trimline = line.trim();
-        let header = trimline.chars().all(|c| c.is_whitespace()) ||
-            trimline.starts_with("#![") ||
-            trimline.starts_with("#[macro_use] extern crate") ||
-            trimline.starts_with("extern crate");
-        if !header || after_header {
-            after_header = true;
-            after.push_str(line);
-            after.push_str("\n");
-        } else {
-            if trimline.starts_with("#[macro_use] extern crate")
-                || trimline.starts_with("extern crate") {
+
+        // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be
+        // shunted into "everything else"
+        match state {
+            PartitionState::Attrs => {
+                state = if trimline.starts_with("#![") ||
+                    trimline.chars().all(|c| c.is_whitespace()) ||
+                    (trimline.starts_with("//") && !trimline.starts_with("///"))
+                {
+                    PartitionState::Attrs
+                } else if trimline.starts_with("extern crate") ||
+                    trimline.starts_with("#[macro_use] extern crate")
+                {
+                    PartitionState::Crates
+                } else {
+                    PartitionState::Other
+                };
+            }
+            PartitionState::Crates => {
+                state = if trimline.starts_with("extern crate") ||
+                    trimline.starts_with("#[macro_use] extern crate") ||
+                    trimline.chars().all(|c| c.is_whitespace()) ||
+                    (trimline.starts_with("//") && !trimline.starts_with("///"))
+                {
+                    PartitionState::Crates
+                } else {
+                    PartitionState::Other
+                };
+            }
+            PartitionState::Other => {}
+        }
+
+        match state {
+            PartitionState::Attrs => {
+                before.push_str(line);
+                before.push_str("\n");
+            }
+            PartitionState::Crates => {
                 crates.push_str(line);
                 crates.push_str("\n");
             }
-            before.push_str(line);
-            before.push_str("\n");
+            PartitionState::Other => {
+                after.push_str(line);
+                after.push_str("\n");
+            }
         }
     }
 
+    debug!("before:\n{}", before);
+    debug!("crates:\n{}", crates);
+    debug!("after:\n{}", after);
+
     (before, after, crates)
 }
 
@@ -1035,8 +1077,8 @@ fn make_test_fake_main() {
 assert_eq!(2+2, 4);";
         let expected =
 "#![allow(unused)]
-fn main() {
 //Ceci n'est pas une `fn main`
+fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
         let output = make_test(input, None, false, &opts);
@@ -1083,8 +1125,8 @@ fn make_test_issues_21299_33731() {
 
         let expected =
 "#![allow(unused)]
-fn main() {
 // fn main
+fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
 
index f46c4f2938b998eda0f7479185c2aebf2e5e95a9..7e155396b8d5e6ec56d4d2a396ba090447bbe9be 100644 (file)
 //!
 //! * **From Rust to C:** [`CString`] represents an owned, C-friendly
 //! string: it is nul-terminated, and has no internal nul characters.
-//! Rust code can create a `CString` out of a normal string (provided
+//! Rust code can create a [`CString`] out of a normal string (provided
 //! that the string doesn't have nul characters in the middle), and
-//! then use a variety of methods to obtain a raw `*mut u8` that can
+//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can
 //! then be passed as an argument to functions which use the C
 //! conventions for strings.
 //!
 //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
-//! is what you would use to wrap a raw `*const u8` that you got from
-//! a C function. A `CStr` is guaranteed to be a nul-terminated array
-//! of bytes. Once you have a `CStr`, you can convert it to a Rust
-//! `&str` if it's valid UTF-8, or lossily convert it by adding
+//! is what you would use to wrap a raw `*const `[`u8`] that you got from
+//! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a [`CStr`], you can convert it to a Rust
+//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding
 //! replacement characters.
 //!
 //! [`OsString`] and [`OsStr`] are useful when you need to transfer
 //! strings to and from the operating system itself, or when capturing
-//! the output of external commands. Conversions between `OsString`,
-//! `OsStr` and Rust strings work similarly to those for [`CString`]
+//! the output of external commands. Conversions between [`OsString`],
+//! [`OsStr`] and Rust strings work similarly to those for [`CString`]
 //! and [`CStr`].
 //!
 //! * [`OsString`] represents an owned string in whatever
 //! representation the operating system prefers. In the Rust standard
 //! library, various APIs that transfer strings to/from the operating
-//! system use `OsString` instead of plain strings. For example,
+//! system use [`OsString`] instead of plain strings. For example,
 //! [`env::var_os()`] is used to query environment variables; it
-//! returns an `Option<OsString>`. If the environment variable exists
-//! you will get a `Some(os_string)`, which you can *then* try to
+//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable
+//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to
 //! convert to a Rust string. This yields a [`Result<>`], so that
 //! your code can detect errors in case the environment variable did
 //! not in fact contain valid Unicode data.
 //! * [`OsStr`] represents a borrowed reference to a string in a
 //! format that can be passed to the operating system. It can be
 //! converted into an UTF-8 Rust string slice in a similar way to
-//! `OsString`.
+//! [`OsString`].
 //!
 //! # Conversions
 //!
 //! Additionally, on Windows [`OsString`] implements the
 //! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
 //! trait, which provides a [`from_wide`] method. The result of this
-//! method is an `OsString` which can be round-tripped to a Windows
+//! method is an [`OsString`] which can be round-tripped to a Windows
 //! string losslessly.
 //!
 //! [`String`]: ../string/struct.String.html
 //! [`collect`]: ../iter/trait.Iterator.html#method.collect
 //! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
 //! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
+//! [`Option`]: ../option/enum.Option.html
+//! [`Some`]: ../option/enum.Option.html#variant.Some
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index d581ba1de23f29627284f6f1d71f2de11ebfa5f6..edcfdd9e5348336c2764ab4fb7607c465542e656 100644 (file)
@@ -195,9 +195,10 @@ pub struct File {
 /// This module only currently provides one bit of information, [`readonly`],
 /// which is exposed on all currently supported platforms. Unix-specific
 /// functionality, such as mode bits, is available through the
-/// `os::unix::PermissionsExt` trait.
+/// [`PermissionsExt`] trait.
 ///
 /// [`readonly`]: struct.Permissions.html#method.readonly
+/// [`PermissionsExt`]: ../os/unix/fs/trait.PermissionsExt.html
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Permissions(fs_imp::FilePermissions);
index 95faf3a5dd63d351460c7f70fa2a770e7d711690..05f30f2881a00e7d0ab35dcab1a71bdf65540739 100644 (file)
           all(target_os = "android", any(target_arch = "aarch64",
                                          target_arch = "arm")),
           all(target_os = "l4re", target_arch = "x86_64"),
+          all(target_os = "freebsd", any(target_arch = "aarch64",
+                                         target_arch = "arm",
+                                         target_arch = "powerpc",
+                                         target_arch = "powerpc64")),
           all(target_os = "netbsd", any(target_arch = "aarch64",
                                         target_arch = "arm",
                                         target_arch = "powerpc")),
               all(target_os = "android", any(target_arch = "aarch64",
                                              target_arch = "arm")),
               all(target_os = "l4re", target_arch = "x86_64"),
+              all(target_os = "freebsd", any(target_arch = "aarch64",
+                                             target_arch = "arm",
+                                             target_arch = "powerpc",
+                                             target_arch = "powerpc64")),
               all(target_os = "netbsd", any(target_arch = "aarch64",
                                             target_arch = "arm",
                                             target_arch = "powerpc")),
index f4e9a7e409359aa5000886970332defd81c71f02..03c7aa9682477701d5fc0efa52ba72b720088418 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{self, Block, Ident, NodeId, PatKind, Path};
+use ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use attr::{self, HasAttrs};
 use source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan};
@@ -1535,21 +1535,65 @@ fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> {
                             let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info);
                             items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem(item)));
                         }
-                        Err(ref e) if e.kind() == ErrorKind::InvalidData => {
-                            self.cx.span_err(
-                                at.span,
-                                &format!("{} wasn't a utf-8 file", filename.display()),
-                            );
-                        }
                         Err(e) => {
-                            self.cx.span_err(
-                                at.span,
-                                &format!("couldn't read {}: {}", filename.display(), e),
-                            );
+                            let lit = it
+                                .meta_item()
+                                .and_then(|item| item.name_value_literal())
+                                .unwrap();
+
+                            if e.kind() == ErrorKind::InvalidData {
+                                self.cx
+                                    .struct_span_err(
+                                        lit.span,
+                                        &format!("{} wasn't a utf-8 file", filename.display()),
+                                    )
+                                    .span_label(lit.span, "contains invalid utf-8")
+                                    .emit();
+                            } else {
+                                let mut err = self.cx.struct_span_err(
+                                    lit.span,
+                                    &format!("couldn't read {}: {}", filename.display(), e),
+                                );
+                                err.span_label(lit.span, "couldn't read file");
+
+                                if e.kind() == ErrorKind::NotFound {
+                                    err.help("external doc paths are relative to the crate root");
+                                }
+
+                                err.emit();
+                            }
                         }
                     }
                 } else {
-                    items.push(noop_fold_meta_list_item(it, self));
+                    let mut err = self.cx.struct_span_err(
+                        it.span,
+                        &format!("expected path to external documentation"),
+                    );
+
+                    // Check if the user erroneously used `doc(include(...))` syntax.
+                    let literal = it.meta_item_list().and_then(|list| {
+                        if list.len() == 1 {
+                            list[0].literal().map(|literal| &literal.node)
+                        } else {
+                            None
+                        }
+                    });
+
+                    let (path, applicability) = match &literal {
+                        Some(LitKind::Str(path, ..)) => {
+                            (path.to_string(), Applicability::MachineApplicable)
+                        }
+                        _ => (String::from("<path>"), Applicability::HasPlaceholders),
+                    };
+
+                    err.span_suggestion_with_applicability(
+                        it.span,
+                        "provide a file path with `=`",
+                        format!("include = \"{}\"", path),
+                        applicability,
+                    );
+
+                    err.emit();
                 }
             }
 
index ded6da9f3adb8845e00a132e043b1731c613aba7..a4326d9ba47be03f8a4bf099cbeb4196602f0d40 100644 (file)
@@ -1407,7 +1407,7 @@ fn parse_trait_item_(&mut self,
                 // definition...
 
                 // We don't allow argument names to be left off in edition 2018.
-                p.parse_arg_general(p.span.rust_2018())
+                p.parse_arg_general(p.span.rust_2018(), true)
             })?;
             generics.where_clause = self.parse_where_clause()?;
 
@@ -1820,7 +1820,7 @@ fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
 
     /// This version of parse arg doesn't necessarily require
     /// identifier names.
-    fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
+    fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool) -> PResult<'a, Arg> {
         maybe_whole!(self, NtArg, |x| x);
 
         if let Ok(Some(_)) = self.parse_self_arg() {
@@ -1852,6 +1852,17 @@ fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
                         String::from("<identifier>: <type>"),
                         Applicability::HasPlaceholders,
                     );
+                } else if require_name && is_trait_item {
+                    if let PatKind::Ident(_, ident, _) = pat.node {
+                        err.span_suggestion_with_applicability(
+                            pat.span,
+                            "explicitly ignore parameter",
+                            format!("_: {}", ident),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+
+                    err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
                 }
 
                 return Err(err);
@@ -1917,7 +1928,7 @@ fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
 
     /// Parse a single function argument
     crate fn parse_arg(&mut self) -> PResult<'a, Arg> {
-        self.parse_arg_general(true)
+        self.parse_arg_general(true, false)
     }
 
     /// Parse an argument in a lambda header e.g., |arg, arg|
@@ -5473,7 +5484,7 @@ fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
                             }
                         }
                     } else {
-                        match p.parse_arg_general(named_args) {
+                        match p.parse_arg_general(named_args, false) {
                             Ok(arg) => Ok(Some(arg)),
                             Err(mut e) => {
                                 e.emit();
index a784eca10d2c1f09e65d67e16eca266485e1eac3..95185c8c801c765ac1072392d081d265af9fb310 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit a784eca10d2c1f09e65d67e16eca266485e1eac3
+Subproject commit 95185c8c801c765ac1072392d081d265af9fb310
index 9cf17c45e87a27af99f031d844aab242ca63f853..a268838de451550fe5518de5be28fbc00563be9c 100644 (file)
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2018-11-28
+2018-12-13
index 5e628c5120c619a22799187371f057ec41e06f87..3c0503db8439928e42c1175f0009c506fc874ae9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5e628c5120c619a22799187371f057ec41e06f87
+Subproject commit 3c0503db8439928e42c1175f0009c506fc874ae9
diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs
new file mode 100644 (file)
index 0000000..4bb5c59
--- /dev/null
@@ -0,0 +1,47 @@
+#![deny(unused_must_use)]
+#![feature(futures_api, pin, arbitrary_self_types)]
+
+use std::iter::Iterator;
+use std::future::Future;
+
+use std::task::{Poll, LocalWaker};
+use std::pin::Pin;
+use std::unimplemented;
+
+struct MyFuture;
+
+impl Future for MyFuture {
+   type Output = u32;
+
+   fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<u32> {
+      Poll::Pending
+   }
+}
+
+fn iterator() -> impl Iterator {
+   std::iter::empty::<u32>()
+}
+
+fn future() -> impl Future {
+   MyFuture
+}
+
+fn square_fn_once() -> impl FnOnce(u32) -> u32 {
+   |x| x * x
+}
+
+fn square_fn_mut() -> impl FnMut(u32) -> u32 {
+   |x| x * x
+}
+
+fn square_fn() -> impl Fn(u32) -> u32 {
+   |x| x * x
+}
+
+fn main() {
+   iterator(); //~ ERROR unused implementer of `std::iter::Iterator` that must be used
+   future(); //~ ERROR unused implementer of `std::future::Future` that must be used
+   square_fn_once(); //~ ERROR unused implementer of `std::ops::FnOnce` that must be used
+   square_fn_mut(); //~ ERROR unused implementer of `std::ops::FnMut` that must be used
+   square_fn(); //~ ERROR unused implementer of `std::ops::Fn` that must be used
+}
index 946ed246bb05e652b115bd5e1690773817a46ae1..421f35438302b6d1d927405a9fd1c1242b14d8ae 100644 (file)
@@ -28,6 +28,7 @@ fn main() {
         _ => panic!("c"),
     }
 
+    #[allow(unreachable_patterns)]
     match &43 {
         &42 => panic!(),
         BOO => panic!(),
diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs
new file mode 100644 (file)
index 0000000..3468bb7
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--test
+
+// comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into
+// thinking that everything after it was part of the regular program. combined with the libsyntax
+// parser loop failing to detect the manual main function, it would wrap everything in `fn main`,
+// which would cause the doctest to fail as the "extern crate" declaration was no longer valid.
+// oddly enough, it would pass in 2018 if a crate was in the extern prelude. see
+// https://github.com/rust-lang/rust/issues/56727
+
+//! ```
+//! // crate: proc-macro-test
+//! //! this is a test
+//!
+//! // used to pull in proc-macro specific items
+//! extern crate proc_macro;
+//!
+//! use proc_macro::TokenStream;
+//!
+//! # fn main() {}
+//! ```
index 24a1e6ecd932c75dbb940187a96f45b04a5487de..dd9e933542fa79f9252e01ed1dd07378ccf0f51b 100644 (file)
@@ -2,13 +2,21 @@ error: expected one of `:` or `@`, found `)`
   --> $DIR/anon-params-denied-2018.rs:6:15
    |
 LL |     fn foo(i32); //~ expected one of `:` or `@`, found `)`
-   |               ^ expected one of `:` or `@` here
+   |            ---^ expected one of `:` or `@` here
+   |            |
+   |            help: explicitly ignore parameter: `_: i32`
+   |
+   = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
 
 error: expected one of `:` or `@`, found `,`
   --> $DIR/anon-params-denied-2018.rs:8:36
    |
 LL |     fn bar_with_default_impl(String, String) {}
-   |                                    ^ expected one of `:` or `@` here
+   |                              ------^ expected one of `:` or `@` here
+   |                              |
+   |                              help: explicitly ignore parameter: `_: String`
+   |
+   = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
 
 error: aborting due to 2 previous errors
 
index 17722bf226d82992f403f2493ca45280f0f52743..6f72de0edee327be283d5389f05ea746f85fd5e7 100644 (file)
@@ -1,3 +1,31 @@
+warning[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:27:7
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |       Foo::Y(_, ref mut b) => b,
+   |       ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+   |
+   = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+           It represents potential unsoundness in your code.
+           This warning will become a hard error in the future.
+
+error[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:44:7
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |       Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow
+   |       ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+
 error[E0499]: cannot borrow `y.0` as mutable more than once at a time
   --> $DIR/borrowck-anon-fields-variant.rs:44:14
    |
@@ -10,6 +38,7 @@ LL |       Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow
 LL |     *a += 1;
    |     ------- first borrow later used here
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0499`.
+Some errors occurred: E0499, E0503.
+For more information about an error, try `rustc --explain E0499`.
index f11b43dcd865ce54e407a2c7a5f537acebcdc818..92e99c6228a9b853e471dc5d3257146e3808e758 100644 (file)
@@ -28,13 +28,13 @@ const fn call_unsafe_generic_cell_const_fn() -> *const Vec<std::cell::Cell<u32>>
     unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() }
     //~^ ERROR calls to `const unsafe fn` in const fns
 }
-const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x }
 //~^ dereferencing raw pointers in constant functions
 
 fn main() {}
 
 const unsafe fn no_union() {
     union Foo { x: (), y: () }
-    Foo { x: () }.y //~ ERROR not allowed in const fn
+    Foo { x: () }.y
     //~^ unions in const fn
 }
index 922a7883b9f2d3b4e933c2a8ae9efdedbd910d7b..fafc89d1493685e1619b21729acec88de921ad7f 100644 (file)
@@ -1,7 +1,7 @@
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
   --> $DIR/min_const_fn_unsafe.rs:31:59
    |
-LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x }
    |                                                           ^^
    |
    = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
@@ -9,7 +9,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no
 error[E0658]: unions in const fn are unstable (see issue #51909)
   --> $DIR/min_const_fn_unsafe.rs:38:5
    |
-LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+LL |     Foo { x: () }.y
    |     ^^^^^^^^^^^^^^^
    |
    = help: add #![feature(const_fn_union)] to the crate attributes to enable
@@ -38,24 +38,6 @@ LL |     unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() }
    |
    = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
-error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:31:59
-   |
-LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
-   |                                                           ^^ dereference of raw pointer
-   |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: access to union field is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:38:5
-   |
-LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
-   |     ^^^^^^^^^^^^^^^ access to union field
-   |
-   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 8a6884bc6b93c3207e5c09b4ff2cc942834c5cdb..67a48206126421f973e497d0c1ad2eae03dda04b 100644 (file)
@@ -34,29 +34,28 @@ const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
 const unsafe fn foo10_3() -> *const Vec<std::cell::Cell<u32>> {
     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() }
 }
-// not ok
 const unsafe fn foo8_2() -> i32 {
-    foo4() //~ ERROR not allowed in const fn
+    foo4()
 }
 const unsafe fn foo9_2() -> *const String {
-    foo5::<String>() //~ ERROR not allowed in const fn
+    foo5::<String>()
 }
 const unsafe fn foo10_2() -> *const Vec<std::cell::Cell<u32>> {
-    foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn
+    foo6::<Vec<std::cell::Cell<u32>>>()
 }
-const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+const unsafe fn foo30_3(x: *mut usize) -> usize { *x }
 //~^ dereferencing raw pointers in constant functions
 
-const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
+const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x }
 //~^ dereferencing raw pointers in constant functions
 
-const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe
 //~^ dereferencing raw pointers in constant functions
 
 fn main() {}
 
 const unsafe fn no_union() {
     union Foo { x: (), y: () }
-    Foo { x: () }.y //~ ERROR not allowed in const fn
+    Foo { x: () }.y
     //~^ unions in const fn
 }
index 20c75afbe638b81478c0cb9dfb3ab6b00e9fd363..63bf9a53e509cc7a908b2813d23c5d92b00bbdd8 100644 (file)
@@ -1,97 +1,44 @@
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:46:51
    |
-LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x }
    |                                                   ^^
    |
    = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
 
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:49:60
    |
-LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
+LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x }
    |                                                            ^^^
    |
    = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
 
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62
    |
-LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe
    |                                                              ^^^
    |
    = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
 
 error[E0658]: unions in const fn are unstable (see issue #51909)
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:59:5
    |
-LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+LL |     Foo { x: () }.y
    |     ^^^^^^^^^^^^^^^
    |
    = help: add #![feature(const_fn_union)] to the crate attributes to enable
 
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:39:5
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62
    |
-LL |     foo4() //~ ERROR not allowed in const fn
-   |     ^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5
-   |
-LL |     foo5::<String>() //~ ERROR not allowed in const fn
-   |     ^^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5
-   |
-LL |     foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51
-   |
-LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
-   |                                                   ^^ dereference of raw pointer
-   |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60
-   |
-LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
-   |                                                            ^^^ dereference of raw pointer
-   |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62
-   |
-LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe
    |                                                              ^^^ dereference of raw pointer
    |
    = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
-error: access to union field is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5
-   |
-LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
-   |     ^^^^^^^^^^^^^^^ access to union field
-   |
-   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
-
-error: aborting due to 11 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors occurred: E0133, E0658.
+For more information about an error, try `rustc --explain E0133`.
diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs
new file mode 100644 (file)
index 0000000..c6c6017
--- /dev/null
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+
+#![deny(deprecated_in_future)]
+
+#[deprecated(since = "99.99.99", note = "text")]
+pub fn deprecated_future() {}
+
+fn test() {
+    deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+}
+
+fn main() {}
diff --git a/src/test/ui/deprecation/deprecation-in-future.stderr b/src/test/ui/deprecation/deprecation-in-future.stderr
new file mode 100644 (file)
index 0000000..38392cf
--- /dev/null
@@ -0,0 +1,14 @@
+error: use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+  --> $DIR/deprecation-in-future.rs:9:5
+   |
+LL |     deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+   |     ^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/deprecation-in-future.rs:3:9
+   |
+LL | #![deny(deprecated_in_future)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 445d0c5f3edc0db383c7925cdc243d22b23eab57..20d42da1c0c40f5a96026c40777b2046d1f55f2c 100644 (file)
@@ -19,4 +19,5 @@ fn foo() {
 }
 
 fn main () {
+    let self = "self"; //~ ERROR E0424
 }
index a1b7a5f65336fa7cdad173a69cd9dcafffd29275..5eccd7d2283fedfb32226e272f1676937256a89b 100644 (file)
@@ -4,6 +4,12 @@ error[E0424]: expected value, found module `self`
 LL |         self.bar(); //~ ERROR E0424
    |         ^^^^ `self` value is a keyword only available in methods with `self` parameter
 
-error: aborting due to previous error
+error[E0424]: expected unit struct/variant or constant, found module `self`
+  --> $DIR/E0424.rs:22:9
+   |
+LL |     let self = "self"; //~ ERROR E0424
+   |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0424`.
diff --git a/src/test/ui/extern/auxiliary/invalid-utf8.txt b/src/test/ui/extern/auxiliary/invalid-utf8.txt
new file mode 100644 (file)
index 0000000..dc1115b
--- /dev/null
@@ -0,0 +1 @@
+Ã(
\ No newline at end of file
index 5c6f6e49b3d77f9bcec8d825ca8206ea434e8bff..e17dda65568e9139d6cdcdf190f990f3a103f25b 100644 (file)
@@ -2,7 +2,31 @@
 
 #![feature(external_doc)]
 
-#[doc(include = "not-a-file.md")] //~ ERROR: couldn't read
-pub struct SomeStruct;
+#[doc(include = "not-a-file.md")]
+pub struct SomeStruct; //~^ ERROR couldn't read
+                       //~| HELP external doc paths are relative to the crate root
+
+#[doc(include = "auxiliary/invalid-utf8.txt")]
+pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
+
+#[doc(include)]
+pub struct MissingPath; //~^ ERROR expected path
+                        //~| HELP provide a file path with `=`
+                        //~| SUGGESTION include = "<path>"
+
+#[doc(include("../README.md"))]
+pub struct InvalidPathSyntax; //~^ ERROR expected path
+                              //~| HELP provide a file path with `=`
+                              //~| SUGGESTION include = "../README.md"
+
+#[doc(include = 123)]
+pub struct InvalidPathType; //~^ ERROR expected path
+                            //~| HELP provide a file path with `=`
+                            //~| SUGGESTION include = "<path>"
+
+#[doc(include(123))]
+pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path
+                                     //~| HELP provide a file path with `=`
+                                     //~| SUGGESTION include = "<path>"
 
 fn main() {}
index 5cc7551ee03aa253732711a91bae481c4f956c99..a3be3277de5455691be7259c318e267e9262a3c2 100644 (file)
@@ -1,8 +1,40 @@
 error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/external-doc-error.rs:5:1
+  --> $DIR/external-doc-error.rs:5:17
    |
-LL | #[doc(include = "not-a-file.md")] //~ ERROR: couldn't read
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[doc(include = "not-a-file.md")]
+   |                 ^^^^^^^^^^^^^^^ couldn't read file
+   |
+   = help: external doc paths are relative to the crate root
+
+error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
+  --> $DIR/external-doc-error.rs:9:17
+   |
+LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
+
+error: expected path to external documentation
+  --> $DIR/external-doc-error.rs:12:7
+   |
+LL | #[doc(include)]
+   |       ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
+
+error: expected path to external documentation
+  --> $DIR/external-doc-error.rs:17:7
+   |
+LL | #[doc(include("../README.md"))]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
+
+error: expected path to external documentation
+  --> $DIR/external-doc-error.rs:22:7
+   |
+LL | #[doc(include = 123)]
+   |       ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
+
+error: expected path to external documentation
+  --> $DIR/external-doc-error.rs:27:7
+   |
+LL | #[doc(include(123))]
+   |       ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
 
-error: aborting due to previous error
+error: aborting due to 6 previous errors
 
index e2630b5b8ce473066fc9da822a5911ec22f6fd76..ed6b325a01d4d9872006924120008a38dc0b6962 100644 (file)
@@ -14,8 +14,8 @@ LL |         .collect(); //~ ERROR no method named `collect`
    |          ^^^^^^^
    |
    = note: the method `collect` exists but the following trait bounds were not satisfied:
-           `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:16:39: 19:6 found_e:_]>> : std::iter::Iterator`
            `&mut std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:16:39: 19:6 found_e:_]>> : std::iter::Iterator`
+           `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:16:39: 19:6 found_e:_]>> : std::iter::Iterator`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-35677.rs b/src/test/ui/issues/issue-35677.rs
new file mode 100644 (file)
index 0000000..46d3f7e
--- /dev/null
@@ -0,0 +1,5 @@
+use std::collections::HashMap;
+fn intersect_map<K, V>(this: &mut HashMap<K, V>, other: HashMap<K, V>) -> bool {
+    this.drain()
+    //~^ ERROR no method named
+}
diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr
new file mode 100644 (file)
index 0000000..dca096b
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0601]: `main` function not found in crate `issue_35677`
+   |
+   = note: consider adding a `main` function to `$DIR/issue-35677.rs`
+
+error[E0599]: no method named `drain` found for type `&mut std::collections::HashMap<K, V>` in the current scope
+  --> $DIR/issue-35677.rs:3:10
+   |
+LL |     this.drain()
+   |          ^^^^^
+   |
+   = note: the method `drain` exists but the following trait bounds were not satisfied:
+           `K : std::cmp::Eq`
+           `K : std::hash::Hash`
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0599, E0601.
+For more information about an error, try `rustc --explain E0599`.
index a8b0e3e4250ea751410c6b07e0425e4ed682cf35..6b9e1dc70573ee58ffe0887bbaa6e0db04602ee8 100644 (file)
@@ -55,6 +55,7 @@ note: lint level defined here
 LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    |         ^^^^^^
    = note: #[warn(unused_assignments)] implied by #[warn(unused)]
+   = help: maybe it is overwritten before being read?
 
 warning: unused variable: `fire`
   --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:32
index 063915d5b5f9a6c368169b92612311f2a26402e1..1df2d7babe91b11735f293040587e3a91d023817 100644 (file)
@@ -1,8 +1,8 @@
-warning: lint `private_no_mangle_fns` has been removed: `no longer an warning, #[no_mangle] functions always exported`
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, #[no_mangle] functions always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
 
-warning: lint `private_no_mangle_statics` has been removed: `no longer an warning, #[no_mangle] statics always exported`
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, #[no_mangle] statics always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
index 6709fee0abb72fd015b012d14e4fe410f3bc7933..6e43cccdccff230b5b9916021bb0958e0e607d41 100644 (file)
@@ -9,24 +9,31 @@ note: lint level defined here
    |
 LL | #![deny(unused_assignments)]
    |         ^^^^^^^^^^^^^^^^^^
+   = help: maybe it is overwritten before being read?
 
 error: value assigned to `x` is never read
   --> $DIR/liveness-dead.rs:27:5
    |
 LL |     x = 4; //~ ERROR: value assigned to `x` is never read
    |     ^
+   |
+   = help: maybe it is overwritten before being read?
 
 error: value passed to `x` is never read
   --> $DIR/liveness-dead.rs:30:11
    |
 LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read
    |           ^
+   |
+   = help: maybe it is overwritten before being read?
 
 error: value assigned to `x` is never read
   --> $DIR/liveness-dead.rs:37:5
    |
 LL |     x = 4; //~ ERROR: value assigned to `x` is never read
    |     ^
+   |
+   = help: maybe it is overwritten before being read?
 
 error: aborting due to 4 previous errors
 
index 2846f242fbe4c47077bcce3b4a80e0043abaab58..35ccc79a19ac094f3210762d67dcc006daa2e8a6 100644 (file)
@@ -60,6 +60,7 @@ note: lint level defined here
    |
 LL | #![deny(unused_assignments)]
    |         ^^^^^^^^^^^^^^^^^^
+   = help: maybe it is overwritten before being read?
 
 error: variable `z` is assigned to, but never used
   --> $DIR/liveness-unused.rs:47:13
@@ -106,6 +107,8 @@ error: value assigned to `x` is never read
    |
 LL |         x = 0;  //~ ERROR value assigned to `x` is never read
    |         ^
+   |
+   = help: maybe it is overwritten before being read?
 
 error: aborting due to 13 previous errors
 
index 86a92a70287e96c615764b12db5929eb9e7af787..1fbac9d688140aff535cce2402488793b39691b3 100644 (file)
@@ -5,8 +5,8 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                                       ^^^^^
    |
    = note: the method `count` exists but the following trait bounds were not satisfied:
-           `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
            `&mut std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
+           `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-36053-2.rs:17:32
index 6a8ce03e8fd255cba0ec950ed7fc8e1924f7e944..edce2b185df34bdcd3372e1845953e7d49ddaf96 100644 (file)
@@ -46,9 +46,9 @@ fn enum_example(mut e: E) {
         E::V(ref mut x, _) => x,
         E::W => panic!(),
     };
-    match e { // OK, no access of borrowed data
+    match e { // Don't know that E uses a tag for its discriminant
         _ if false => (),
-        E::V(_, r) => (),
+        E::V(_, r) => (), //~ ERROR
         E::W => (),
     }
     x;
@@ -59,9 +59,9 @@ fn indirect_enum_example(mut f: &mut E) {
         E::V(ref mut x, _) => x,
         E::W => panic!(),
     };
-    match f { // OK, no access of borrowed data
+    match f { // Don't know that E uses a tag for its discriminant
         _ if false => (),
-        E::V(_, r) => (),
+        E::V(_, r) => (), //~ ERROR
         E::W => (),
     }
     x;
index cdff29d44b85bf904ca22917546ea6f07c2b4965..2d34dd7805dbf5337f08b3d3a5d00937d117363a 100644 (file)
@@ -1,3 +1,27 @@
+error[E0503]: cannot use `e` because it was mutably borrowed
+  --> $DIR/match-on-borrowed.rs:51:9
+   |
+LL |         E::V(ref mut x, _) => x,
+   |              --------- borrow of `e.0` occurs here
+...
+LL |         E::V(_, r) => (), //~ ERROR
+   |         ^^^^^^^^^^ use of borrowed `e.0`
+...
+LL |     x;
+   |     - borrow later used here
+
+error[E0503]: cannot use `*f` because it was mutably borrowed
+  --> $DIR/match-on-borrowed.rs:64:9
+   |
+LL |         E::V(ref mut x, _) => x,
+   |              --------- borrow of `f.0` occurs here
+...
+LL |         E::V(_, r) => (), //~ ERROR
+   |         ^^^^^^^^^^ use of borrowed `f.0`
+...
+LL |     x;
+   |     - borrow later used here
+
 error[E0503]: cannot use `t` because it was mutably borrowed
   --> $DIR/match-on-borrowed.rs:82:9
    |
@@ -16,7 +40,7 @@ error[E0381]: use of possibly uninitialized variable: `n`
 LL |     match n {} //~ ERROR
    |           ^ use of possibly uninitialized `n`
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 Some errors occurred: E0381, E0503.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs
new file mode 100644 (file)
index 0000000..6496a2a
--- /dev/null
@@ -0,0 +1,13 @@
+// failure-status: 101
+
+// This is a repro test for an ICE in our pattern handling of constants.
+
+const FOO: &&&u32 = &&&42;
+
+fn main() {
+    match unimplemented!() {
+        &&&42 => {},
+        FOO => {},
+        _ => {},
+    }
+}
index 6f9501d025c26c53cde04b87e1b1fd18f2692c6e..6cfef115d08dc0fc0697211e4d56d45e3b92c253 100644 (file)
@@ -1,4 +1,4 @@
-// compile-pass
+#![deny(unreachable_patterns)]
 
 fn main() {
     let s = &[0x00; 4][..]; //Slice of any value
@@ -6,19 +6,26 @@ fn main() {
     match s {
         MAGIC_TEST => (),
         [0x00, 0x00, 0x00, 0x00] => (),
-        [4, 5, 6, 7] => (), // this should warn
+        [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
         _ => (),
     }
     match s {
         [0x00, 0x00, 0x00, 0x00] => (),
         MAGIC_TEST => (),
-        [4, 5, 6, 7] => (), // this should warn
+        [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
         _ => (),
     }
     match s {
         [0x00, 0x00, 0x00, 0x00] => (),
         [4, 5, 6, 7] => (),
-        MAGIC_TEST => (), // this should warn
+        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    const FOO: [u32; 1] = [4];
+    match [99] {
+        [0x00] => (),
+        [4] => (),
+        FOO => (), //~ ERROR unreachable pattern
         _ => (),
     }
 }
diff --git a/src/test/ui/pattern/slice-pattern-const-2.stderr b/src/test/ui/pattern/slice-pattern-const-2.stderr
new file mode 100644 (file)
index 0000000..95651cc
--- /dev/null
@@ -0,0 +1,26 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-2.rs:9:9
+   |
+LL |         [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+   |         ^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const-2.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-2.rs:15:9
+   |
+LL |         [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+   |         ^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-2.rs:28:9
+   |
+LL |         FOO => (), //~ ERROR unreachable pattern
+   |         ^^^
+
+error: aborting due to 3 previous errors
+
index e7a30cef57a8ee3af0a8650f739616459eade95e..8805c43ba0283bdabe7f46093ee46b6be341470b 100644 (file)
@@ -1,4 +1,4 @@
-// compile-pass
+#![deny(unreachable_patterns)]
 
 fn main() {
     let s = &["0x00"; 4][..]; //Slice of any value
@@ -6,19 +6,26 @@ fn main() {
     match s {
         MAGIC_TEST => (),
         ["0x00", "0x00", "0x00", "0x00"] => (),
-        ["4", "5", "6", "7"] => (), // this should warn
+        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
         _ => (),
     }
     match s {
         ["0x00", "0x00", "0x00", "0x00"] => (),
         MAGIC_TEST => (),
-        ["4", "5", "6", "7"] => (), // this should warn
+        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
         _ => (),
     }
     match s {
         ["0x00", "0x00", "0x00", "0x00"] => (),
         ["4", "5", "6", "7"] => (),
-        MAGIC_TEST => (), // this should warn
+        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    const FOO: [&str; 1] = ["boo"];
+    match ["baa"] {
+        ["0x00"] => (),
+        ["boo"] => (),
+        FOO => (), //~ ERROR unreachable pattern
         _ => (),
     }
 }
diff --git a/src/test/ui/pattern/slice-pattern-const-3.stderr b/src/test/ui/pattern/slice-pattern-const-3.stderr
new file mode 100644 (file)
index 0000000..531bbbc
--- /dev/null
@@ -0,0 +1,14 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-3.rs:28:9
+   |
+LL |         FOO => (), //~ ERROR unreachable pattern
+   |         ^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const-3.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index d353f6cddbd0d05e8d27eda568c0daaf18b7a164..f0a04513f91fb71d11cc68154225df0c0ed10176 100644 (file)
@@ -1,4 +1,4 @@
-//compile-pass
+#![deny(unreachable_patterns)]
 
 fn main() {
     let s = &[0x00; 4][..]; //Slice of any value
@@ -6,19 +6,42 @@ fn main() {
     match s {
         MAGIC_TEST => (),
         [0x00, 0x00, 0x00, 0x00] => (),
-        [84, 69, 83, 84] => (), // this should warn
+        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
         _ => (),
     }
     match s {
         [0x00, 0x00, 0x00, 0x00] => (),
         MAGIC_TEST => (),
-        [84, 69, 83, 84] => (), // this should warn
+        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
         _ => (),
     }
     match s {
         [0x00, 0x00, 0x00, 0x00] => (),
         [84, 69, 83, 84] => (),
-        MAGIC_TEST => (), // this should warn
+        MAGIC_TEST => (), //~ ERROR unreachable pattern
         _ => (),
     }
+    const FOO: [u8; 1] = [4];
+    match [99] {
+        [0x00] => (),
+        [4] => (),
+        FOO => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+    const BAR: &[u8; 1] = &[4];
+    match &[99] {
+        [0x00] => (),
+        [4] => (),
+        BAR => (), //~ ERROR unreachable pattern
+        b"a" => (),
+        _ => (),
+    }
+
+    const BOO: &[u8; 0] = &[];
+    match &[] {
+        [] => (),
+        BOO => (), //~ ERROR unreachable pattern
+        b"" => (), //~ ERROR unreachable pattern
+        _ => (), //~ ERROR unreachable pattern
+    }
 }
diff --git a/src/test/ui/pattern/slice-pattern-const.stderr b/src/test/ui/pattern/slice-pattern-const.stderr
new file mode 100644 (file)
index 0000000..412e015
--- /dev/null
@@ -0,0 +1,56 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:9:9
+   |
+LL |         [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+   |         ^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:15:9
+   |
+LL |         [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+   |         ^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:21:9
+   |
+LL |         MAGIC_TEST => (), //~ ERROR unreachable pattern
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:28:9
+   |
+LL |         FOO => (), //~ ERROR unreachable pattern
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:35:9
+   |
+LL |         BAR => (), //~ ERROR unreachable pattern
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:43:9
+   |
+LL |         BOO => (), //~ ERROR unreachable pattern
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:44:9
+   |
+LL |         b"" => (), //~ ERROR unreachable pattern
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:45:9
+   |
+LL |         _ => (), //~ ERROR unreachable pattern
+   |         ^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs
new file mode 100644 (file)
index 0000000..24676fe
--- /dev/null
@@ -0,0 +1,74 @@
+// This is a collection of examples where a function's formal
+// parameter has an explicit lifetime and a closure within that
+// function returns that formal parameter. The closure's return type,
+// to be correctly inferred, needs to include the lifetime introduced
+// by the function.
+//
+// This works today, which precludes changing things so that closures
+// follow the same lifetime-elision rules used elsehwere. See
+// rust-lang/rust#56537
+
+// compile-pass
+// We are already testing NLL explicitly via the revision system below.
+// ignore-compare-mode-nll
+
+// revisions: ll nll migrate
+//[ll] compile-flags:-Zborrowck=ast
+//[nll] compile-flags:-Zborrowck=mir -Z two-phase-borrows
+//[migrate] compile-flags:-Zborrowck=migrate -Z two-phase-borrows
+
+fn willy_no_annot<'w>(p: &'w str, q: &str) -> &'w str {
+    let free_dumb = |_x| { p }; // no type annotation at all
+    let hello = format!("Hello");
+    free_dumb(&hello)
+}
+
+fn willy_ret_type_annot<'w>(p: &'w str, q: &str) -> &'w str {
+    let free_dumb = |_x| -> &str { p }; // type annotation on the return type
+    let hello = format!("Hello");
+    free_dumb(&hello)
+}
+
+fn willy_ret_region_annot<'w>(p: &'w str, q: &str) -> &'w str {
+    let free_dumb = |_x| -> &'w str { p }; // type+region annotation on return type
+    let hello = format!("Hello");
+    free_dumb(&hello)
+}
+
+fn willy_arg_type_ret_type_annot<'w>(p: &'w str, q: &str) -> &'w str {
+    let free_dumb = |_x: &str| -> &str { p }; // type annotation on arg and return types
+    let hello = format!("Hello");
+    free_dumb(&hello)
+}
+
+fn willy_arg_type_ret_region_annot<'w>(p: &'w str, q: &str) -> &'w str {
+    let free_dumb = |_x: &str| -> &'w str { p }; // fully annotated
+    let hello = format!("Hello");
+    free_dumb(&hello)
+}
+
+fn main() {
+    let world = format!("World");
+    let w1: &str = {
+        let hello = format!("He11o");
+        willy_no_annot(&world, &hello)
+    };
+    let w2: &str = {
+        let hello = format!("He22o");
+        willy_ret_type_annot(&world, &hello)
+    };
+    let w3: &str = {
+        let hello = format!("He33o");
+        willy_ret_region_annot(&world, &hello)
+    };
+    let w4: &str = {
+        let hello = format!("He44o");
+        willy_arg_type_ret_type_annot(&world, &hello)
+    };
+    let w5: &str = {
+        let hello = format!("He55o");
+        willy_arg_type_ret_region_annot(&world, &hello)
+    };
+    assert_eq!((w1, w2, w3, w4, w5),
+               ("World","World","World","World","World"));
+}
index 2a2d35e7bd9228a11d251881520e44d530c4a566..31ec8a7dc1c83a8a227f7cfa69f7993ebe101510 100644 (file)
@@ -54,8 +54,14 @@ fn main() {
         simd_select(z, z, z);
         //~^ ERROR mask element type is `f32`, expected `i_`
 
+        simd_select(m4, 0u32, 1u32);
+        //~^ ERROR found non-SIMD `u32`
+
         simd_select_bitmask(0u8, x, x);
         //~^ ERROR mask length `8` != other vector length `4`
+        //
+        simd_select_bitmask(0u8, 1u32, 2u32);
+        //~^ ERROR found non-SIMD `u32`
 
         simd_select_bitmask(0.0f32, x, x);
         //~^ ERROR `f32` is not an integral type
index 584f3d539213b8a99ea8cd0fc368ad99df1e2954..05317da2475f1298f488d6828c5632538222de39 100644 (file)
@@ -16,24 +16,36 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element
 LL |         simd_select(z, z, z);
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
+error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32`
   --> $DIR/simd-intrinsic-generic-select.rs:57:9
    |
+LL |         simd_select(m4, 0u32, 1u32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
+  --> $DIR/simd-intrinsic-generic-select.rs:60:9
+   |
 LL |         simd_select_bitmask(0u8, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
+  --> $DIR/simd-intrinsic-generic-select.rs:63:9
+   |
+LL |         simd_select_bitmask(0u8, 1u32, 2u32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type
-  --> $DIR/simd-intrinsic-generic-select.rs:60:9
+  --> $DIR/simd-intrinsic-generic-select.rs:66:9
    |
 LL |         simd_select_bitmask(0.0f32, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type
-  --> $DIR/simd-intrinsic-generic-select.rs:63:9
+  --> $DIR/simd-intrinsic-generic-select.rs:69:9
    |
 LL |         simd_select_bitmask("x", x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/suggestions/path-display.rs b/src/test/ui/suggestions/path-display.rs
new file mode 100644 (file)
index 0000000..62fc9e7
--- /dev/null
@@ -0,0 +1,7 @@
+use std::path::Path;
+
+fn main() {
+    let path = Path::new("/tmp/foo/bar.txt");
+    println!("{}", path);
+    //~^ ERROR E0277
+}
diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr
new file mode 100644 (file)
index 0000000..39d236a
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display`
+  --> $DIR/path-display.rs:5:20
+   |
+LL |     println!("{}", path);
+   |                    ^^^^ `std::path::Path` cannot be formatted with the default formatter; call `.display()` on it
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `std::path::Path`
+   = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
+   = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path`
+   = note: required by `std::fmt::Display::fmt`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed b/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed
new file mode 100644 (file)
index 0000000..8592af1
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+
+use std::fmt::Debug;
+
+fn foo(d: impl Debug + 'static) {
+//~^ HELP consider adding an explicit lifetime bound  `'static` to `impl Debug`
+    bar(d);
+//~^ ERROR the parameter type `impl Debug` may not live long enough
+//~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
+}
+
+fn bar(d: impl Debug + 'static) {
+    println!("{:?}", d)
+}
+
+fn main() {
+  foo("hi");
+}
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs b/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs
new file mode 100644 (file)
index 0000000..c67d78e
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+
+use std::fmt::Debug;
+
+fn foo(d: impl Debug) {
+//~^ HELP consider adding an explicit lifetime bound  `'static` to `impl Debug`
+    bar(d);
+//~^ ERROR the parameter type `impl Debug` may not live long enough
+//~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
+}
+
+fn bar(d: impl Debug + 'static) {
+    println!("{:?}", d)
+}
+
+fn main() {
+  foo("hi");
+}
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
new file mode 100644 (file)
index 0000000..cba231d
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0310]: the parameter type `impl Debug` may not live long enough
+  --> $DIR/suggest-impl-trait-lifetime.rs:7:5
+   |
+LL |     bar(d);
+   |     ^^^
+   |
+note: ...so that the type `impl Debug` will meet its required lifetime bounds
+  --> $DIR/suggest-impl-trait-lifetime.rs:7:5
+   |
+LL |     bar(d);
+   |     ^^^
+help: consider adding an explicit lifetime bound  `'static` to `impl Debug`...
+   |
+LL | fn foo(d: impl Debug + 'static) {
+   |           ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
index 003839982429ff467bdfc3331731149096cb94b9..8b3023e63dfb49c732a5f2668629a416c2684e09 100644 (file)
@@ -873,3 +873,29 @@ fn parse_normalization_string(line: &mut &str) -> Option<String> {
     *line = &line[end + 1..];
     Some(result)
 }
+
+#[test]
+fn test_parse_normalization_string() {
+    let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\".";
+    let first = parse_normalization_string(&mut s);
+    assert_eq!(first, Some("something (32 bits)".to_owned()));
+    assert_eq!(s, " -> \"something ($WORD bits)\".");
+
+    // Nothing to normalize (No quotes)
+    let mut s = "normalize-stderr-32bit: something (32 bits) -> something ($WORD bits).";
+    let first = parse_normalization_string(&mut s);
+    assert_eq!(first, None);
+    assert_eq!(s, r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."#);
+
+    // Nothing to normalize (Only a single quote)
+    let mut s = "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits).";
+    let first = parse_normalization_string(&mut s);
+    assert_eq!(first, None);
+    assert_eq!(s, "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits).");
+
+    // Nothing to normalize (Three quotes)
+    let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits).";
+    let first = parse_normalization_string(&mut s);
+    assert_eq!(first, Some("something (32 bits)".to_owned()));
+    assert_eq!(s, " -> \"something ($WORD bits).");
+}
index 2a716970ca7b9a03edead9992cc41fa2dc203e0b..381d808e8028f9f5760b976d4042e94865d7e445 100644 (file)
@@ -86,6 +86,8 @@ pub fn matches_os(triple: &str, name: &str) -> bool {
     }
     panic!("Cannot determine OS from triple");
 }
+
+/// Determine the architecture from `triple`
 pub fn get_arch(triple: &str) -> &'static str {
     let triple: Vec<_> = triple.split('-').collect();
     for &(triple_arch, arch) in ARCH_TABLE {
@@ -151,3 +153,29 @@ fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
         }
     }
 }
+
+#[test]
+#[should_panic(expected = "Cannot determine Architecture from triple")]
+fn test_get_arch_failure() {
+    get_arch("abc");
+}
+
+#[test]
+fn test_get_arch() {
+    assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu"));
+    assert_eq!("x86_64", get_arch("amd64"));
+}
+
+#[test]
+#[should_panic(expected = "Cannot determine OS from triple")]
+fn test_matches_os_failure() {
+    matches_os("abc", "abc");
+}
+
+#[test]
+fn test_matches_os() {
+    assert!(matches_os("x86_64-unknown-linux-gnu", "linux"));
+    assert!(matches_os("wasm32-unknown-unknown", "emscripten"));
+    assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare"));
+    assert!(!matches_os("wasm32-unknown-unknown", "windows"));
+}