diff --git a/README.md b/README.md index 95d543b8bb3..4fc003036e9 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Read ["Installation"] from [The Book]. ## Building from Source [building-from-source]: #building-from-source +### Building on *nix 1. Make sure you have installed the dependencies: * `g++` 4.7 or later or `clang++` 3.x or later @@ -193,7 +194,7 @@ Snapshot binaries are currently built and tested on several platforms: You may find that other platforms work, but these are our officially supported build environments that are most likely to work. -Rust currently needs between 600MiB and 1.5GiB to build, depending on platform. +Rust currently needs between 600MiB and 1.5GiB of RAM to build, depending on platform. If it hits swap, it will take a very long time to build. There is more advice about hacking on Rust in [CONTRIBUTING.md]. diff --git a/RELEASES.md b/RELEASES.md index e65934a89e6..194745d9caa 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3,12 +3,6 @@ Version 1.21.0 (2017-10-12) Language -------- -- [Relaxed path syntax. You can now add type parameters to values][43540] - Example: - ```rust - my_macro!(Vec::new); // Always worked - my_macro!(Vec::::new); // Now works - ``` - [You can now use static references for literals.][43838] Example: ```rust @@ -16,6 +10,12 @@ Language let x: &'static u32 = &0; } ``` +- [Relaxed path syntax. Optional `::` before `<` is now allowed in all contexts.][43540] + Example: + ```rust + my_macro!(Vec::new); // Always worked + my_macro!(Vec::::new); // Now works + ``` Compiler -------- diff --git a/config.toml.example b/config.toml.example index a3790c8d202..f50543e18a7 100644 --- a/config.toml.example +++ b/config.toml.example @@ -250,14 +250,11 @@ # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true -# The default linker that will be used by the generated compiler. Note that this -# is not the linker used to link said compiler. +# The default linker that will be hard-coded into the generated compiler for +# targets that don't specify linker explicitly in their target specifications. +# Note that this is not the linker used to link said compiler. #default-linker = "cc" -# The default ar utility that will be used by the generated compiler if LLVM -# cannot be used. Note that this is not used to assemble said compiler. -#default-ar = "ar" - # The "channel" for the Rust build to produce. The stable/beta channels only # allow using stable features, whereas the nightly and dev channels allow using # nightly features @@ -303,7 +300,7 @@ # ============================================================================= [target.x86_64-unknown-linux-gnu] -# C compiler to be used to compiler C code and link Rust code. Note that the +# C compiler to be used to compiler C code. Note that the # default value is platform specific, and if not specified it may also depend on # what platform is crossing to what platform. #cc = "cc" @@ -312,6 +309,15 @@ # This is only used for host targets. #cxx = "c++" +# Archiver to be used to assemble static libraries compiled from C/C++ code. +# Note: an absolute path should be used, otherwise LLVM build will break. +#ar = "ar" + +# Linker to be used to link Rust code. Note that the +# default value is platform specific, and if not specified it may also depend on +# what platform is crossing to what platform. +#linker = "cc" + # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specifed we don't compile LLVM at all for this # target. diff --git a/src/Cargo.lock b/src/Cargo.lock index 77e33855f23..328ce353e2a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -42,7 +42,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.0.0", ] @@ -99,7 +99,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -136,7 +136,7 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -199,7 +199,7 @@ dependencies = [ "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -246,7 +246,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -275,7 +275,7 @@ name = "cmake" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -290,7 +290,7 @@ dependencies = [ name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -407,7 +407,7 @@ name = "curl-sys" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -759,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jobserver" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -833,7 +833,7 @@ name = "libgit2-sys" version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -860,7 +860,7 @@ name = "libz-sys" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,7 +880,7 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -968,7 +968,7 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1104,7 +1104,7 @@ name = "openssl-sys" version = "0.9.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1208,7 +1208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1429,7 +1429,7 @@ dependencies = [ "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", - "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", @@ -1504,6 +1504,7 @@ dependencies = [ "graphviz 0.0.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc_back 0.0.0", "rustc_errors 0.0.0", "rustc_mir 0.0.0", "syntax 0.0.0", @@ -1611,7 +1612,6 @@ version = "0.0.0" dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_back 0.0.0", "rustc_const_eval 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -1623,7 +1623,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1755,9 +1755,9 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1824,7 +1824,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1994,7 +1994,6 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", @@ -2485,7 +2484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cde24d1b2e2216a726368b2363a273739c91f4e3eb4e0dd12d672d396ad989" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" -"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" +"checksum cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c674f0870e3dbd4105184ea035acb1c32c8ae69939c9e228d2b11bbfe29efad" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2" "checksum cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "357c07e7a1fc95732793c1edb5901e1a1f305cfcf63a90eb12dbd22bdb6b789d" @@ -2530,7 +2529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" -"checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133" +"checksum jobserver 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "094f87ed101b6832def8632f43db43dc204d27897eb95aca69b26ce2e4011e84" "checksum jsonrpc-core 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1acd0f9934da94466d2370f36832b9b19271b4abdfdb5e69f0bcd991ebcd515" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kuchiki 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ef2ea4f2f7883cd7c6772b06c14abca01a2cc1f75c426cebffcf6b3b925ef9fc" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 3f1d03b1872..bbbbf0e1915 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -34,7 +34,7 @@ cmake = "0.1.23" filetime = "0.1" num_cpus = "1.0" getopts = "0.2" -cc = "1.0" +cc = "1.0.1" libc = "0.2" serde = "1.0.8" serde_derive = "1.0.8" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index e543b8c070b..6eb074605fc 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -39,7 +39,7 @@ The script accepts commands, flags, and arguments to determine what to do: ``` If files are dirty that would normally be rebuilt from stage 0, that can be - overidden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps + overridden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps that belong to stage n or earlier: ``` @@ -126,7 +126,7 @@ install a nightly, presumably using `rustup`. You will then want to configure your directory to use this build, like so: ``` -# configure to use local rust instead of downloding a beta. +# configure to use local rust instead of downloading a beta. # `--local-rust-root` is optional here. If elided, we will # use whatever rustc we find on your PATH. > configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 848b10d312c..aeeda85e924 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -31,8 +31,6 @@ extern crate bootstrap; use std::env; use std::ffi::OsString; -use std::io; -use std::io::prelude::*; use std::str::FromStr; use std::path::PathBuf; use std::process::{Command, ExitStatus}; @@ -122,19 +120,14 @@ fn main() { cmd.arg("-L").arg(&root); } - // Pass down extra flags, commonly used to configure `-Clinker` when - // cross compiling. - if let Ok(s) = env::var("RUSTC_FLAGS") { - cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::>()); + // Override linker if necessary. + if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") { + cmd.arg(format!("-Clinker={}", target_linker)); } // Pass down incremental directory, if any. if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { cmd.arg(format!("-Zincremental={}", dir)); - - if verbose > 0 { - cmd.arg("-Zincremental-info"); - } } let crate_name = args.windows(2) @@ -258,6 +251,11 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } + } else { + // Override linker if necessary. + if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { + cmd.arg(format!("-Clinker={}", host_linker)); + } } let color = match env::var("RUSTC_COLOR") { @@ -270,7 +268,7 @@ fn main() { } if verbose > 1 { - writeln!(&mut io::stderr(), "rustc command: {:?}", cmd).unwrap(); + eprintln!("rustc command: {:?}", cmd); } // Actually run the compiler! diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index d7d72d5dd56..4e975adc972 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -47,6 +47,17 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } + if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } + + // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick + // it up so we can make rustdoc print this into the docs + if let Some(version) = env::var_os("RUSTDOC_CRATE_VERSION") { + // This "unstable-options" can be removed when `--crate-version` is stabilized + cmd.arg("-Z").arg("unstable-options") + .arg("--crate-version").arg(version); + } std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index fecb8e6a05e..842144ff1ea 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -302,6 +302,7 @@ def default_build_triple(): return "{}-{}".format(cputype, ostype) + class RustBuild(object): """Provide all the methods required to build Rust""" def __init__(self): @@ -498,7 +499,7 @@ class RustBuild(object): If the key does not exists, the result is None: - >>> rb.get_toml("key3") == None + >>> rb.get_toml("key3") is None True """ for line in self.config_toml.splitlines(): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index e7a5196178c..6480b5a619c 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -413,12 +413,15 @@ impl<'a> Builder<'a> { pub fn rustdoc_cmd(&self, host: Interned) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let compiler = self.compiler(self.top_stage, host); - cmd - .env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) - .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)); + cmd.env("RUSTC_STAGE", compiler.stage.to_string()) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) + .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) + .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + if let Some(linker) = self.build.linker(host) { + cmd.env("RUSTC_TARGET_LINKER", linker); + } cmd } @@ -481,8 +484,14 @@ impl<'a> Builder<'a> { } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }) - .env("TEST_MIRI", self.config.test_miri.to_string()) - .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + .env("TEST_MIRI", self.config.test_miri.to_string()); + + if let Some(host_linker) = self.build.linker(compiler.host) { + cargo.env("RUSTC_HOST_LINKER", host_linker); + } + if let Some(target_linker) = self.build.linker(target) { + cargo.env("RUSTC_TARGET_LINKER", target_linker); + } if mode != Mode::Tool { // Tools don't get debuginfo right now, e.g. cargo and rls don't @@ -556,17 +565,35 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); - // Specify some various options for build scripts used throughout - // the build. + // Throughout the build Cargo can execute a number of build scripts + // compiling C/C++ code and we need to pass compilers, archivers, flags, etc + // obtained previously to those build scripts. + // Build scripts use either the `cc` crate or `configure/make` so we pass + // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here if !target.contains("msvc") { - cargo.env(format!("CC_{}", target), self.cc(target)) - .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None - .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); + let cc = self.cc(target); + cargo.env(format!("CC_{}", target), cc) + .env("CC", cc); + + let cflags = self.cflags(target).join(" "); + cargo.env(format!("CFLAGS_{}", target), cflags.clone()) + .env("CFLAGS", cflags.clone()); + + if let Some(ar) = self.ar(target) { + let ranlib = format!("{} s", ar.display()); + cargo.env(format!("AR_{}", target), ar) + .env("AR", ar) + .env(format!("RANLIB_{}", target), ranlib.clone()) + .env("RANLIB", ranlib); + } if let Ok(cxx) = self.cxx(target) { - cargo.env(format!("CXX_{}", target), cxx); + cargo.env(format!("CXX_{}", target), cxx) + .env("CXX", cxx) + .env(format!("CXXFLAGS_{}", target), cflags.clone()) + .env("CXXFLAGS", cflags); } } @@ -574,6 +601,9 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } + // For `cargo doc` invocations, make rustdoc print the Rust version into the docs + cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + // Environment variables *required* throughout the build // // FIXME: should update code to not require this env var diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 08df65c7611..6e3e3c92029 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -31,20 +31,51 @@ //! ever be probed for. Instead the compilers found here will be used for //! everything. +use std::collections::HashSet; +use std::{env, iter}; +use std::path::{Path, PathBuf}; use std::process::Command; -use std::iter; -use build_helper::{cc2ar, output}; +use build_helper::output; use cc; use Build; use config::Target; use 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 +// try to infer the archiver path from the C compiler path. +// In the future this logic should be replaced by calling into the `cc` crate. +fn cc2ar(cc: &Path, target: &str) -> Option { + if let Some(ar) = env::var_os("AR") { + Some(PathBuf::from(ar)) + } else if target.contains("msvc") { + None + } else if target.contains("musl") { + Some(PathBuf::from("ar")) + } else if target.contains("openbsd") { + Some(PathBuf::from("ar")) + } else { + let parent = cc.parent().unwrap(); + let file = cc.file_name().unwrap().to_str().unwrap(); + for suffix in &["gcc", "cc", "clang"] { + if let Some(idx) = file.rfind(suffix) { + let mut file = file[..idx].to_owned(); + file.push_str("ar"); + return Some(parent.join(&file)); + } + } + Some(parent.join(file)) + } +} + pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) { + let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) + .collect::>(); + for target in targets.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) .target(&target).host(&build.build); @@ -57,16 +88,23 @@ pub fn find(build: &mut Build) { } let compiler = cfg.get_compiler(); - let ar = cc2ar(compiler.path(), &target); + let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { + ar + } else { + cc2ar(compiler.path(), &target) + }; + build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); - if let Some(ref ar) = ar { + build.cc.insert(target, compiler); + if let Some(ar) = ar { build.verbose(&format!("AR_{} = {:?}", &target, ar)); + build.ar.insert(target, ar); } - build.cc.insert(target, (compiler, ar)); } // For all host triples we need to find a C++ compiler as well - for host in build.hosts.iter().cloned().chain(iter::once(build.build)) { + let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); + for host in hosts.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true) .target(&host).host(&build.build); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 6e276f44668..d9ee63eef8c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -246,8 +246,11 @@ impl Step for Rls { let compiler = builder.compiler(stage, host); builder.ensure(tool::Rls { compiler, target: self.host }); - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.src.join("src/tools/rls/Cargo.toml")); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + host, + "test", + "src/tools/rls"); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -291,8 +294,11 @@ impl Step for Rustfmt { let compiler = builder.compiler(stage, host); builder.ensure(tool::Rustfmt { compiler, target: self.host }); - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.src.join("src/tools/rustfmt/Cargo.toml")); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + host, + "test", + "src/tools/rustfmt"); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -358,6 +364,7 @@ impl Step for Miri { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Clippy { + stage: u32, host: Interned, } @@ -372,6 +379,7 @@ impl Step for Clippy { fn make_run(run: RunConfig) { run.builder.ensure(Clippy { + stage: run.builder.top_stage, host: run.target, }); } @@ -379,10 +387,11 @@ impl Step for Clippy { /// Runs `cargo test` for clippy. fn run(self, builder: &Builder) { let build = builder.build; + let stage = self.stage; let host = self.host; - let compiler = builder.compiler(1, host); + let compiler = builder.compiler(stage, host); - let _clippy = builder.ensure(tool::Clippy { compiler, target: self.host }); + let clippy = builder.ensure(tool::Clippy { compiler, target: self.host }); let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml")); @@ -390,6 +399,8 @@ impl Step for Clippy { cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); // clippy tests need to know about the stage sysroot cargo.env("SYSROOT", builder.sysroot(compiler)); + // clippy tests need to find the driver + cargo.env("CLIPPY_DRIVER_PATH", clippy); builder.add_rustc_lib_path(compiler, &mut cargo); @@ -736,12 +747,14 @@ impl Step for Compiletest { flags.push("-g".to_string()); } - let mut hostflags = build.rustc_flags(compiler.host); - hostflags.extend(flags.clone()); + if let Some(linker) = build.linker(target) { + cmd.arg("--linker").arg(linker); + } + + let hostflags = flags.clone(); cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); - let mut targetflags = build.rustc_flags(target); - targetflags.extend(flags); + let mut targetflags = flags.clone(); targetflags.push(format!("-Lnative={}", build.test_helpers_out(target).display())); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); @@ -795,6 +808,9 @@ impl Step for Compiletest { .arg("--cflags").arg(build.cflags(target).join(" ")) .arg("--llvm-components").arg(llvm_components.trim()) .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + if let Some(ar) = build.ar(target) { + cmd.arg("--ar").arg(ar); + } } } if suite == "run-make" && !build.config.llvm_enabled { @@ -820,7 +836,7 @@ impl Step for Compiletest { // Note that if we encounter `PATH` we make sure to append to our own `PATH` // rather than stomp over it. if target.contains("msvc") { - for &(ref k, ref v) in build.cc[&target].0.env() { + for &(ref k, ref v) in build.cc[&target].env() { if k != "PATH" { cmd.env(k, v); } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 335e1690a2e..b1c630a8de9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -560,9 +560,6 @@ pub fn rustc_cargo(build: &Build, if let Some(ref s) = build.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } - if let Some(ref s) = build.config.rustc_default_ar { - cargo.env("CFG_DEFAULT_AR", s); - } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c8b2ed042c1..69e0f58f1cd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -88,7 +88,6 @@ pub struct Config { pub rust_debuginfo_only_std: bool, pub rust_rpath: bool, pub rustc_default_linker: Option, - pub rustc_default_ar: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, pub rust_dist_src: bool, @@ -144,6 +143,8 @@ pub struct Target { pub jemalloc: Option, pub cc: Option, pub cxx: Option, + pub ar: Option, + pub linker: Option, pub ndk: Option, pub crt_static: Option, pub musl_root: Option, @@ -262,7 +263,6 @@ struct Rust { use_jemalloc: Option, backtrace: Option, default_linker: Option, - default_ar: Option, channel: Option, musl_root: Option, rpath: Option, @@ -284,6 +284,8 @@ struct TomlTarget { jemalloc: Option, cc: Option, cxx: Option, + ar: Option, + linker: Option, android_ndk: Option, crt_static: Option, musl_root: Option, @@ -464,7 +466,6 @@ impl Config { set(&mut config.quiet_tests, rust.quiet_tests); set(&mut config.test_miri, rust.test_miri); config.rustc_default_linker = rust.default_linker.clone(); - config.rustc_default_ar = rust.default_ar.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); match rust.codegen_units { @@ -487,8 +488,10 @@ impl Config { if let Some(ref s) = cfg.android_ndk { target.ndk = Some(env::current_dir().unwrap().join(s)); } - target.cxx = cfg.cxx.clone().map(PathBuf::from); target.cc = cfg.cc.clone().map(PathBuf::from); + target.cxx = cfg.cxx.clone().map(PathBuf::from); + target.ar = cfg.ar.clone().map(PathBuf::from); + target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static.clone(); target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 3c161b7bb14..42425a164a2 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -20,6 +20,7 @@ rust_dir = os.path.dirname(rust_dir) sys.path.append(os.path.join(rust_dir, "src", "bootstrap")) import bootstrap + class Option(object): def __init__(self, name, rustbuild, desc, value): self.name = name @@ -27,14 +28,18 @@ class Option(object): self.desc = desc self.value = value + options = [] + def o(*args): options.append(Option(*args, value=False)) + def v(*args): options.append(Option(*args, value=True)) + o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-optimize` given") o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") @@ -120,9 +125,8 @@ v("experimental-targets", "llvm.experimental-targets", "experimental LLVM targets to build") v("release-channel", "rust.channel", "the name of the release channel to build") -# Used on systems where "cc" and "ar" are unavailable +# Used on systems where "cc" is unavailable v("default-linker", "rust.default-linker", "the default linker") -v("default-ar", "rust.default-ar", "the default ar") # Many of these are saved below during the "writing configuration" step # (others are conditionally saved). @@ -137,13 +141,16 @@ v("target", None, "GNUs ./configure syntax LLVM target triples") v("set", None, "set arbitrary key/value pairs in TOML configuration") + def p(msg): print("configure: " + msg) + def err(msg): print("configure: error: " + msg) sys.exit(1) + if '--help' in sys.argv or '-h' in sys.argv: print('Usage: ./configure [options]') print('') @@ -209,7 +216,7 @@ while i < len(sys.argv): continue found = True - if not option.name in known_args: + if option.name not in known_args: known_args[option.name] = [] known_args[option.name].append((option, value)) break @@ -228,27 +235,30 @@ if 'option-checking' not in known_args or known_args['option-checking'][1]: # TOML we're going to write out config = {} + def build(): if 'build' in known_args: return known_args['build'][0][1] return bootstrap.default_build_triple() -def set(key, value): - s = "{:20} := {}".format(key, value) - if len(s) < 70: - p(s) - else: - p(s[:70] + " ...") - arr = config - parts = key.split('.') - for i, part in enumerate(parts): - if i == len(parts) - 1: - arr[part] = value - else: - if not part in arr: - arr[part] = {} - arr = arr[part] +def set(key, value): + s = "{:20} := {}".format(key, value) + if len(s) < 70: + p(s) + else: + p(s[:70] + " ...") + + arr = config + parts = key.split('.') + for i, part in enumerate(parts): + if i == len(parts) - 1: + arr[part] = value + else: + if part not in arr: + arr[part] = {} + arr = arr[part] + for key in known_args: # The `set` option is special and can be passed a bunch of times @@ -346,8 +356,9 @@ for target in configured_targets: targets[target] = sections['target'][:] targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", target) + # Here we walk through the constructed configuration we have from the parsed -# command line arguemnts. We then apply each piece of configuration by +# command line arguments. We then apply each piece of configuration by # basically just doing a `sed` to change the various configuration line to what # we've got configure. def to_toml(value): @@ -361,7 +372,8 @@ def to_toml(value): elif isinstance(value, str): return "'" + value + "'" else: - raise 'no toml' + raise RuntimeError('no toml') + def configure_section(lines, config): for key in config: @@ -376,10 +388,11 @@ def configure_section(lines, config): if not found: raise RuntimeError("failed to find config line for {}".format(key)) + for section_key in config: section_config = config[section_key] - if not section_key in sections: - raise RuntimeError("config key {} not in sections".format(key)) + if section_key not in sections: + raise RuntimeError("config key {} not in sections".format(section_key)) if section_key == 'target': for target in section_config: @@ -408,11 +421,6 @@ with open('Makefile', 'w') as f: contents = contents.replace("$(CFG_PYTHON)", sys.executable) f.write(contents) -# Finally, clean up with a bit of a help message -relpath = os.path.dirname(__file__) -if relpath == '': - relpath = '.' - p("") -p("run `python {}/x.py --help`".format(relpath)) +p("run `python {}/x.py --help`".format(rust_dir)) p("") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 3d4aa0413db..02dfa04d920 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -176,7 +176,7 @@ fn make_win_dist( } } - let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"]; + let target_tools = ["gcc.exe", "ld.exe", "dlltool.exe", "libwinpthread-1.dll"]; let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"]; if target_triple.starts_with("i686-") { rustc_dlls.push("libgcc_s_dw2-1.dll"); @@ -1035,7 +1035,7 @@ pub struct Rls { } impl Step for Rls { - type Output = PathBuf; + type Output = Option; const ONLY_BUILD_TARGETS: bool = true; const ONLY_HOSTS: bool = true; @@ -1050,12 +1050,17 @@ impl Step for Rls { }); } - fn run(self, builder: &Builder) -> PathBuf { + fn run(self, builder: &Builder) -> Option { let build = builder.build; let stage = self.stage; let target = self.target; assert!(build.config.extended); + if !builder.config.toolstate.rls.testing() { + println!("skipping Dist RLS stage{} ({})", stage, target); + return None + } + println!("Dist RLS stage{} ({})", stage, target); let src = build.src.join("src/tools/rls"); let release_num = build.release_num("rls"); @@ -1102,7 +1107,7 @@ impl Step for Rls { .arg("--component-name=rls-preview"); build.run(&mut cmd); - distdir(build).join(format!("{}-{}.tar.gz", name, target)) + Some(distdir(build).join(format!("{}-{}.tar.gz", name, target))) } } @@ -1202,8 +1207,12 @@ impl Step for Extended { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer, - analysis_installer, std_installer]; + let mut tarballs = Vec::new(); + tarballs.push(rustc_installer); + tarballs.push(cargo_installer); + tarballs.extend(rls_installer.clone()); + tarballs.push(analysis_installer); + tarballs.push(std_installer); if build.config.docs { tarballs.push(docs_installer); } @@ -1245,35 +1254,38 @@ impl Step for Extended { } rtf.push_str("}"); + fn filter(contents: &str, marker: &str) -> String { + let start = format!("tool-{}-start", marker); + let end = format!("tool-{}-end", marker); + let mut lines = Vec::new(); + let mut omitted = false; + for line in contents.lines() { + if line.contains(&start) { + omitted = true; + } else if line.contains(&end) { + omitted = false; + } else if !omitted { + lines.push(line); + } + } + + lines.join("\n") + } + + let xform = |p: &Path| { + let mut contents = String::new(); + t!(t!(File::open(p)).read_to_string(&mut contents)); + if rls_installer.is_none() { + contents = filter(&contents, "rls"); + } + let ret = tmp.join(p.file_name().unwrap()); + t!(t!(File::create(&ret)).write_all(contents.as_bytes())); + return ret + }; + if target.contains("apple-darwin") { let pkg = tmp.join("pkg"); let _ = fs::remove_dir_all(&pkg); - t!(fs::create_dir_all(pkg.join("rustc"))); - t!(fs::create_dir_all(pkg.join("cargo"))); - t!(fs::create_dir_all(pkg.join("rust-docs"))); - t!(fs::create_dir_all(pkg.join("rust-std"))); - t!(fs::create_dir_all(pkg.join("rls"))); - t!(fs::create_dir_all(pkg.join("rust-analysis"))); - - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)), - &pkg.join("rustc")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), - &pkg.join("cargo")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), - &pkg.join("rust-docs")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)), - &pkg.join("rust-std")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)), - &pkg.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)), - &pkg.join("rust-analysis")); - - install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755); let pkgbuild = |component: &str| { let mut cmd = Command::new("pkgbuild"); @@ -1283,12 +1295,23 @@ impl Step for Extended { .arg(pkg.join(component).with_extension("pkg")); build.run(&mut cmd); }; - pkgbuild("rustc"); - pkgbuild("cargo"); - pkgbuild("rust-docs"); - pkgbuild("rust-std"); - pkgbuild("rls"); - pkgbuild("rust-analysis"); + + let prepare = |name: &str| { + t!(fs::create_dir_all(pkg.join(name))); + cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)), + &pkg.join(name)); + install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755); + pkgbuild(name); + }; + prepare("rustc"); + prepare("cargo"); + prepare("rust-docs"); + prepare("rust-std"); + prepare("rust-analysis"); + + if rls_installer.is_some() { + prepare("rls"); + } // create an 'uninstall' package install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); @@ -1298,7 +1321,7 @@ impl Step for Extended { t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes())); install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); let mut cmd = Command::new("productbuild"); - cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml")) + cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml"))) .arg("--resources").arg(pkg.join("res")) .arg(distdir(build).join(format!("{}-{}.pkg", pkgname(build, "rust"), @@ -1310,46 +1333,34 @@ impl Step for Extended { if target.contains("windows") { let exe = tmp.join("exe"); let _ = fs::remove_dir_all(&exe); - t!(fs::create_dir_all(exe.join("rustc"))); - t!(fs::create_dir_all(exe.join("cargo"))); - t!(fs::create_dir_all(exe.join("rls"))); - t!(fs::create_dir_all(exe.join("rust-analysis"))); - t!(fs::create_dir_all(exe.join("rust-docs"))); - t!(fs::create_dir_all(exe.join("rust-std"))); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) - .join("rustc"), - &exe.join("rustc")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) - .join("cargo"), - &exe.join("cargo")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) - .join("rust-docs"), - &exe.join("rust-docs")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)) - .join(format!("rust-std-{}", target)), - &exe.join("rust-std")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview"), - &exe.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)) - .join(format!("rust-analysis-{}", target)), - &exe.join("rust-analysis")); - - t!(fs::remove_file(exe.join("rustc/manifest.in"))); - t!(fs::remove_file(exe.join("cargo/manifest.in"))); - t!(fs::remove_file(exe.join("rust-docs/manifest.in"))); - t!(fs::remove_file(exe.join("rust-std/manifest.in"))); - t!(fs::remove_file(exe.join("rls/manifest.in"))); - t!(fs::remove_file(exe.join("rust-analysis/manifest.in"))); + let prepare = |name: &str| { + t!(fs::create_dir_all(exe.join(name))); + let dir = if name == "rust-std" || name == "rust-analysis" { + format!("{}-{}", name, target) + } else if name == "rls" { + "rls-preview".to_string() + } else { + name.to_string() + }; + cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)) + .join(dir), + &exe.join(name)); + t!(fs::remove_file(exe.join(name).join("manifest.in"))); + }; + prepare("rustc"); + prepare("cargo"); + prepare("rust-analysis"); + prepare("rust-docs"); + prepare("rust-std"); + if rls_installer.is_some() { + prepare("rls"); + } if target.contains("windows-gnu") { - t!(fs::create_dir_all(exe.join("rust-mingw"))); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target)) - .join("rust-mingw"), - &exe.join("rust-mingw")); - t!(fs::remove_file(exe.join("rust-mingw/manifest.in"))); + prepare("rust-mingw"); } - install(&etc.join("exe/rust.iss"), &exe, 0o644); + install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644); install(&etc.join("exe/modpath.iss"), &exe, 0o644); install(&etc.join("exe/upgrade.iss"), &exe, 0o644); install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); @@ -1413,16 +1424,18 @@ impl Step for Extended { .arg("-dr").arg("Std") .arg("-var").arg("var.StdDir") .arg("-out").arg(exe.join("StdGroup.wxs"))); - build.run(Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rls") - .args(&heat_flags) - .arg("-cg").arg("RlsGroup") - .arg("-dr").arg("Rls") - .arg("-var").arg("var.RlsDir") - .arg("-out").arg(exe.join("RlsGroup.wxs")) - .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); + if rls_installer.is_some() { + build.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rls") + .args(&heat_flags) + .arg("-cg").arg("RlsGroup") + .arg("-dr").arg("Rls") + .arg("-var").arg("var.RlsDir") + .arg("-out").arg(exe.join("RlsGroup.wxs")) + .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); + } build.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -1456,26 +1469,30 @@ impl Step for Extended { .arg("-dDocsDir=rust-docs") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") - .arg("-dRlsDir=rls") .arg("-dAnalysisDir=rust-analysis") .arg("-arch").arg(&arch) .arg("-out").arg(&output) .arg(&input); add_env(build, &mut cmd, target); + if rls_installer.is_some() { + cmd.arg("-dRlsDir=rls"); + } if target.contains("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } build.run(&mut cmd); }; - candle(&etc.join("msi/rust.wxs")); + candle(&xform(&etc.join("msi/rust.wxs"))); candle(&etc.join("msi/ui.wxs")); candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); candle("DocsGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); - candle("RlsGroup.wxs".as_ref()); + if rls_installer.is_some() { + candle("RlsGroup.wxs".as_ref()); + } candle("AnalysisGroup.wxs".as_ref()); if target.contains("windows-gnu") { @@ -1499,10 +1516,13 @@ impl Step for Extended { .arg("DocsGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") - .arg("RlsGroup.wixobj") .arg("AnalysisGroup.wixobj") .current_dir(&exe); + if rls_installer.is_some() { + cmd.arg("RlsGroup.wixobj"); + } + if target.contains("windows-gnu") { cmd.arg("GccGroup.wixobj"); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2d721f45578..6ac919d3fbd 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -240,10 +240,11 @@ pub struct Build { lldb_python_dir: Option, // Runtime state filled in later on - // target -> (cc, ar) - cc: HashMap, (cc::Tool, Option)>, - // host -> (cc, ar) + // C/C++ compilers and archiver for all targets + cc: HashMap, cc::Tool>, cxx: HashMap, cc::Tool>, + ar: HashMap, PathBuf>, + // Misc crates: HashMap, Crate>, is_sudo: bool, ci_env: CiEnv, @@ -324,6 +325,7 @@ impl Build { rls_info, cc: HashMap::new(), cxx: HashMap::new(), + ar: HashMap::new(), crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, @@ -612,7 +614,7 @@ impl Build { /// Returns the path to the C compiler for the target specified. fn cc(&self, target: Interned) -> &Path { - self.cc[&target].0.path() + self.cc[&target].path() } /// Returns a list of flags to pass to the C compiler for the target @@ -620,7 +622,7 @@ impl Build { fn cflags(&self, target: Interned) -> Vec { // Filter out -O and /O (the optimization flags) that we picked up from // cc-rs because the build scripts will determine that for themselves. - let mut base = self.cc[&target].0.args().iter() + let mut base = self.cc[&target].args().iter() .map(|s| s.to_string_lossy().into_owned()) .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::>(); @@ -644,7 +646,7 @@ impl Build { /// Returns the path to the `ar` archive utility for the target specified. fn ar(&self, target: Interned) -> Option<&Path> { - self.cc[&target].1.as_ref().map(|p| &**p) + self.ar.get(&target).map(|p| &**p) } /// Returns the path to the C++ compiler for the target specified. @@ -657,21 +659,17 @@ impl Build { } } - /// Returns flags to pass to the compiler to generate code for `target`. - fn rustc_flags(&self, target: Interned) -> Vec { - // New flags should be added here with great caution! - // - // It's quite unfortunate to **require** flags to generate code for a - // target, so it should only be passed here if absolutely necessary! - // Most default configuration should be done through target specs rather - // than an entry here. - - let mut base = Vec::new(); - if target != self.config.build && !target.contains("msvc") && - !target.contains("emscripten") { - base.push(format!("-Clinker={}", self.cc(target).display())); + /// Returns the path to the linker for the given target if it needs to be overriden. + fn linker(&self, target: Interned) -> Option<&Path> { + if let Some(linker) = self.config.target_config.get(&target) + .and_then(|c| c.linker.as_ref()) { + Some(linker) + } else if target != self.config.build && + !target.contains("msvc") && !target.contains("emscripten") { + Some(self.cc(target)) + } else { + None } - base } /// Returns if this target should statically link the C runtime, if specified diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index c4e80630315..941ea96bbec 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -227,6 +227,13 @@ impl Step for Llvm { cfg.build_arg("-j").build_arg(build.jobs().to_string()); cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); + if let Some(ar) = build.ar(target) { + if ar.is_absolute() { + // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it + // tries to resolve this path in the LLVM build directory. + cfg.define("CMAKE_AR", sanitize_cc(ar)); + } + } }; configure_compilers(&mut cfg); @@ -352,34 +359,51 @@ impl Step for Openssl { // originally from https://www.openssl.org/source/... let url = format!("https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/{}", name); - let mut ok = false; + let mut last_error = None; for _ in 0..3 { let status = Command::new("curl") .arg("-o").arg(&tmp) + .arg("-f") // make curl fail if the URL does not return HTTP 200 .arg(&url) .status() .expect("failed to spawn curl"); - if status.success() { - ok = true; - break + + // Retry if download failed. + if !status.success() { + last_error = Some(status.to_string()); + continue; } + + // Ensure the hash is correct. + let mut shasum = if target.contains("apple") || build.build.contains("netbsd") { + let mut cmd = Command::new("shasum"); + cmd.arg("-a").arg("256"); + cmd + } else { + Command::new("sha256sum") + }; + let output = output(&mut shasum.arg(&tmp)); + let found = output.split_whitespace().next().unwrap(); + + // If the hash is wrong, probably the download is incomplete or S3 served an error + // page. In any case, retry. + if found != OPENSSL_SHA256 { + last_error = Some(format!( + "downloaded openssl sha256 different\n\ + expected: {}\n\ + found: {}\n", + OPENSSL_SHA256, + found + )); + continue; + } + + // Everything is fine, so exit the retry loop. + last_error = None; + break; } - if !ok { - panic!("failed to download openssl source") - } - let mut shasum = if target.contains("apple") || build.build.contains("netbsd") { - let mut cmd = Command::new("shasum"); - cmd.arg("-a").arg("256"); - cmd - } else { - Command::new("sha256sum") - }; - let output = output(&mut shasum.arg(&tmp)); - let found = output.split_whitespace().next().unwrap(); - if found != OPENSSL_SHA256 { - panic!("downloaded openssl sha256 different\n\ - expected: {}\n\ - found: {}\n", OPENSSL_SHA256, found); + if let Some(error) = last_error { + panic!("failed to download openssl source: {}", error); } t!(fs::rename(&tmp, &tarball)); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index a05e58e6a22..662c56d728d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -387,7 +387,7 @@ pub struct Clippy { impl Step for Clippy { type Output = PathBuf; - const DEFAULT: bool = false; + const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { @@ -411,7 +411,7 @@ impl Step for Clippy { builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, - tool: "clippy", + tool: "clippy-driver", mode: Mode::Librustc, path: "src/tools/clippy", expectation: builder.build.config.toolstate.clippy.passes(ToolState::Compiling), @@ -561,7 +561,7 @@ impl<'a> Builder<'a> { if compiler.host.contains("msvc") { let curpaths = env::var_os("PATH").unwrap_or_default(); let curpaths = env::split_paths(&curpaths).collect::>(); - for &(ref k, ref v) in self.cc[&compiler.host].0.env() { + for &(ref k, ref v) in self.cc[&compiler.host].env() { if k != "PATH" { continue } diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 8a113f6b4d2..328cbf0e5d7 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -31,6 +31,13 @@ impl ToolState { BuildExpectation::Failing } } + + pub fn testing(&self) -> bool { + match *self { + ToolState::Testing => true, + _ => false, + } + } } impl Default for ToolState { diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index e81dab70b43..97723e260f6 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -138,27 +138,6 @@ pub fn gnu_target(target: &str) -> String { } } -pub fn cc2ar(cc: &Path, target: &str) -> Option { - if target.contains("msvc") { - None - } else if target.contains("musl") { - Some(PathBuf::from("ar")) - } else if target.contains("openbsd") { - Some(PathBuf::from("ar")) - } else { - let parent = cc.parent().unwrap(); - let file = cc.file_name().unwrap().to_str().unwrap(); - for suffix in &["gcc", "cc", "clang"] { - if let Some(idx) = file.rfind(suffix) { - let mut file = file[..idx].to_owned(); - file.push_str("ar"); - return Some(parent.join(&file)); - } - } - Some(parent.join(file)) - } -} - pub fn make(host: &str) -> PathBuf { if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || diff --git a/src/ci/docker/cross2/Dockerfile b/src/ci/docker/cross2/Dockerfile index f5fc06767ce..cc260382f49 100644 --- a/src/ci/docker/cross2/Dockerfile +++ b/src/ci/docker/cross2/Dockerfile @@ -5,6 +5,7 @@ RUN sh /scripts/cross-apt-packages.sh RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \ build-essential \ + gcc-multilib \ libedit-dev \ libgmp-dev \ libisl-dev \ @@ -36,17 +37,18 @@ ENV \ AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \ CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \ CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \ - AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-ar \ - CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-gcc \ - CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-g++ \ - AR_x86_64_sun_solaris=x86_64-sun-solaris2.11-ar \ - CC_x86_64_sun_solaris=x86_64-sun-solaris2.11-gcc \ - CXX_x86_64_sun_solaris=x86_64-sun-solaris2.11-g++ + AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ + CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ + CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ + AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \ + CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ + CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-sun-solaris +ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/cross2/build-solaris-toolchain.sh b/src/ci/docker/cross2/build-solaris-toolchain.sh index ae84cc62b60..935cbe5d61b 100755 --- a/src/ci/docker/cross2/build-solaris-toolchain.sh +++ b/src/ci/docker/cross2/build-solaris-toolchain.sh @@ -25,7 +25,7 @@ cd binutils curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf - mkdir binutils-build cd binutils-build -hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.11 +hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.10 hide_output make -j10 hide_output make install @@ -58,13 +58,17 @@ for deb in *$APT_ARCH.deb; do dpkg -x $deb . done -mkdir /usr/local/$ARCH-sun-solaris2.11/usr -mv usr/include /usr/local/$ARCH-sun-solaris2.11/usr/include -mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib -mv lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib +# Strip Solaris 11 functions that are optionally used by libbacktrace. +# This is for Solaris 10 compatibility. +$ARCH-sun-solaris2.10-strip -N dl_iterate_phdr -N strnlen lib/$LIB_ARCH/libc.so -ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/sys-include -ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/include +mkdir /usr/local/$ARCH-sun-solaris2.10/usr +mv usr/include /usr/local/$ARCH-sun-solaris2.10/usr/include +mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib +mv lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib + +ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include +ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/include cd .. rm -rf solaris @@ -80,7 +84,7 @@ mkdir ../gcc-build cd ../gcc-build hide_output ../gcc-$GCC/configure \ --enable-languages=c,c++ \ - --target=$ARCH-sun-solaris2.11 \ + --target=$ARCH-sun-solaris2.10 \ --with-gnu-as \ --with-gnu-ld \ --disable-multilib \ @@ -94,7 +98,7 @@ hide_output ../gcc-$GCC/configure \ --disable-libsanitizer \ --disable-libquadmath-support \ --disable-lto \ - --with-sysroot=/usr/local/$ARCH-sun-solaris2.11 + --with-sysroot=/usr/local/$ARCH-sun-solaris2.10 hide_output make -j10 hide_output make install diff --git a/src/ci/docker/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh index d343aae9dfb..3aa2b9d58d5 100644 --- a/src/ci/docker/scripts/android-sdk.sh +++ b/src/ci/docker/scripts/android-sdk.sh @@ -31,7 +31,7 @@ download_sysimage() { # Keep printing yes to accept the licenses while true; do echo yes; sleep 10; done | \ /android/sdk/tools/android update sdk -a --no-ui \ - --filter "$filter" + --filter "$filter" --no-https } create_avd() { diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 6c80f11fa72..0bb41cee2c5 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -152,9 +152,6 @@ never colorize output. .SH CODEGEN OPTIONS -.TP -\fBar\fR=\fI/path/to/ar\fR -Path to the archive utility to use when assembling archives. .TP \fBlinker\fR=\fI/path/to/cc\fR Path to the linker utility to use when linking libraries, executables, and diff --git a/src/doc/unstable-book/src/language-features/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md index d5600c58fd9..efb5495fe26 100644 --- a/src/doc/unstable-book/src/language-features/non-ascii-idents.md +++ b/src/doc/unstable-book/src/language-features/non-ascii-idents.md @@ -15,4 +15,34 @@ The `non_ascii_idents` feature adds support for non-ASCII identifiers. const ε: f64 = 0.00001f64; const Π: f64 = 3.14f64; -``` \ No newline at end of file +``` + +## Changes to the language reference + +> **Lexer:** +> IDENTIFIER : +>       XID_start XID_continue\* +>    | `_` XID_continue+ + +An identifier is any nonempty Unicode string of the following form: + +Either + + * The first character has property [`XID_start`] + * The remaining characters have property [`XID_continue`] + +Or + + * The first character is `_` + * The identifier is more than one character, `_` alone is not an identifier + * The remaining characters have property [`XID_continue`] + +that does _not_ occur in the set of [strict keywords]. + +> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the +> character ranges used to form the more familiar C and Java language-family +> identifiers. + +[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i= +[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i= +[strict keywords]: ../reference/keywords.html#strict-keywords diff --git a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md new file mode 100644 index 00000000000..ee24dd87d90 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md @@ -0,0 +1,47 @@ +# `optin_builtin_traits` + +The tracking issue for this feature is [#13231] + +[#13231]: https://github.com/rust-lang/rust/issues/13231 + +---- + +The `optin_builtin_traits` feature gate allows you to define auto traits. + +Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits +that are automatically implemented for every type, unless the type, or a type it contains, +has explictly opted out via a negative impl. + +[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html +[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html + +```rust,ignore +impl !Type for Trait +``` + +Example: + +```rust +#![feature(optin_builtin_traits)] + +trait Valid {} + +impl Valid for .. {} + +struct True; +struct False; + +impl !Valid for False {} + +struct MaybeValid(T); + +fn must_be_valid(_t: T) { } + +fn main() { + // works + must_be_valid( MaybeValid(True) ); + + // compiler error - trait bound not satisfied + // must_be_valid( MaybeValid(False) ); +} +``` diff --git a/src/doc/unstable-book/src/language-features/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md new file mode 100644 index 00000000000..0eaed7a1989 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/unboxed-closures.md @@ -0,0 +1,25 @@ +# `unboxed_closures` + +The tracking issue for this feature is [#29625] + +See Also: [`fn_traits`](library-features/fn-traits.html) + +[#29625]: https://github.com/rust-lang/rust/issues/29625 + +---- + +The `unboxed_closures` feature allows you to write functions using the `"rust-call"` ABI, +required for implmenting the [`Fn*`] family of traits. `"rust-call"` functions must have +exactly one (non self) argument, a tuple representing the argument list. + +[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html + +```rust +#![feature(unboxed_closures)] + +extern "rust-call" fn add_args(args: (u32, u32)) -> u32 { + args.0 + args.1 +} + +fn main() {} +``` diff --git a/src/doc/unstable-book/src/library-features/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md new file mode 100644 index 00000000000..72a3f36c10b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fn-traits.md @@ -0,0 +1,35 @@ +# `fn_traits` + +The tracking issue for this feature is [#29625] + +See Also: [`unboxed_closures`](language-features/unboxed-closures.html) + +[#29625]: https://github.com/rust-lang/rust/issues/29625 + +---- + +The `fn_traits` feature allows for implementation of the [`Fn*`] traits +for creating custom closure-like types. + +[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html + +```rust +#![feature(unboxed_closures)] +#![feature(fn_traits)] + +struct Adder { + a: u32 +} + +impl FnOnce<(u32, )> for Adder { + type Output = u32; + extern "rust-call" fn call_once(self, b: (u32, )) -> Self::Output { + self.a + b.0 + } +} + +fn main() { + let adder = Adder { a: 3 }; + assert_eq!(adder(2), 5); +} +``` diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 822dc581404..0612873e281 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -248,7 +248,10 @@ class RustStringSlicePrinter(object): def to_string(self): (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) raw_ptr = data_ptr.get_wrapped_value() - return '"%s"' % raw_ptr.string(encoding="utf-8", length=length) + return raw_ptr.lazy_string(encoding="utf-8", length=length) + + def display_hint(self): + return "string" class RustStdVecPrinter(object): @@ -278,9 +281,11 @@ class RustStdStringPrinter(object): def to_string(self): vec = self.__val.get_child_at_index(0) (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec) - return '"%s"' % data_ptr.get_wrapped_value().string(encoding="utf-8", - length=length) + return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8", + length=length) + def display_hint(self): + return "string" class RustOsStringPrinter(object): def __init__(self, val): @@ -294,8 +299,10 @@ class RustOsStringPrinter(object): (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec( vec) - return '"%s"' % data_ptr.get_wrapped_value().string(length=length) + return data_ptr.get_wrapped_value().lazy_string(length=length) + def display_hint(self): + return "string" class RustCStyleVariantPrinter(object): def __init__(self, val): diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss index e7d4ec61946..c22d60b6c5d 100644 --- a/src/etc/installer/exe/rust.iss +++ b/src/etc/installer/exe/rust.iss @@ -46,7 +46,9 @@ Name: gcc; Description: "Linker and platform libraries"; Types: full Name: docs; Description: "HTML documentation"; Types: full Name: cargo; Description: "Cargo, the Rust package manager"; Types: full Name: std; Description: "The Rust Standard Library"; Types: full +// tool-rls-start Name: rls; Description: "RLS, the Rust Language Server" +// tool-rls-end [Files] Source: "rustc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust @@ -56,8 +58,10 @@ Source: "rust-mingw/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Source: "rust-docs/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: docs Source: "cargo/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: cargo Source: "rust-std/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: std +// tool-rls-start Source: "rls/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls Source: "rust-analysis/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls +// tool-rls-end [Code] const diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 258291cbb72..d95b096d732 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -170,8 +170,10 @@ + + @@ -275,6 +277,7 @@ + + diff --git a/src/etc/installer/pkg/Distribution.xml b/src/etc/installer/pkg/Distribution.xml index f138a1a3154..077ee175116 100644 --- a/src/etc/installer/pkg/Distribution.xml +++ b/src/etc/installer/pkg/Distribution.xml @@ -16,7 +16,9 @@ + + @@ -62,6 +64,7 @@ > + + rustc.pkg cargo.pkg rust-docs.pkg rust-std.pkg + rls.pkg + rust-analysis.pkg uninstall.pkg (.|\n) { } _ { return UNDERSCORE; } +abstract { return ABSTRACT; } +alignof { return ALIGNOF; } as { return AS; } +become { return BECOME; } box { return BOX; } break { return BREAK; } +catch { return CATCH; } const { return CONST; } continue { return CONTINUE; } crate { return CRATE; } +default { return DEFAULT; } +do { return DO; } else { return ELSE; } enum { return ENUM; } extern { return EXTERN; } false { return FALSE; } +final { return FINAL; } fn { return FN; } for { return FOR; } if { return IF; } @@ -102,26 +109,36 @@ impl { return IMPL; } in { return IN; } let { return LET; } loop { return LOOP; } +macro { return MACRO; } match { return MATCH; } mod { return MOD; } move { return MOVE; } mut { return MUT; } +offsetof { return OFFSETOF; } +override { return OVERRIDE; } priv { return PRIV; } proc { return PROC; } +pure { return PURE; } pub { return PUB; } ref { return REF; } return { return RETURN; } self { return SELF; } +sizeof { return SIZEOF; } static { return STATIC; } struct { return STRUCT; } +super { return SUPER; } trait { return TRAIT; } true { return TRUE; } type { return TYPE; } typeof { return TYPEOF; } +union { return UNION; } unsafe { return UNSAFE; } +unsized { return UNSIZED; } use { return USE; } +virtual { return VIRTUAL; } where { return WHERE; } while { return WHILE; } +yield { return YIELD; } {ident} { return IDENT; } @@ -189,25 +206,25 @@ while { return WHILE; } \>\>= { return SHREQ; } \> { return '>'; } -\x27 { BEGIN(ltorchar); yymore(); } -static { BEGIN(INITIAL); return STATIC_LIFETIME; } -{ident} { BEGIN(INITIAL); return LIFETIME; } -\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } -\\u\{[0-9a-fA-F]?{6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } -.\x27 { BEGIN(suffix); return LIT_CHAR; } -[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } -<> { BEGIN(INITIAL); return -1; } +\x27 { BEGIN(ltorchar); yymore(); } +static { BEGIN(INITIAL); return STATIC_LIFETIME; } +{ident} { BEGIN(INITIAL); return LIFETIME; } +\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } +\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } +\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } +.\x27 { BEGIN(suffix); return LIT_CHAR; } +[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } +<> { BEGIN(INITIAL); return -1; } b\x22 { BEGIN(bytestr); yymore(); } \x22 { BEGIN(suffix); return LIT_BYTE_STR; } -<> { return -1; } -\\[n\nrt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } +<> { return -1; } +\\[n\nrt\\\x27\x220] { yymore(); } +\\x[0-9a-fA-F]{2} { yymore(); } +\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } +\\[^n\nrt\\\x27\x220] { return -1; } +(.|\n) { yymore(); } br\x22 { BEGIN(rawbytestr_nohash); yymore(); } \x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } @@ -252,13 +269,13 @@ br/# { } <> { return -1; } -b\x27 { BEGIN(byte); yymore(); } -\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\u[0-9a-fA-F]{4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\U[0-9a-fA-F]{8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -.\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<> { BEGIN(INITIAL); return -1; } +b\x27 { BEGIN(byte); yymore(); } +\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } +\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +.\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<> { BEGIN(INITIAL); return -1; } r\x22 { BEGIN(rawstr); yymore(); } \x22 { BEGIN(suffix); return LIT_STR_RAW; } @@ -310,12 +327,12 @@ r/# { \x22 { BEGIN(str); yymore(); } \x22 { BEGIN(suffix); return LIT_STR; } -<> { return -1; } -\\[n\nr\rt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } +<> { return -1; } +\\[n\nr\rt\\\x27\x220] { yymore(); } +\\x[0-9a-fA-F]{2} { yymore(); } +\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } +\\[^n\nrt\\\x27\x220] { return -1; } +(.|\n) { yymore(); } \<- { return LARROW; } -\> { return RARROW; } diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index c9fcdf7647b..de1f96aac50 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -62,13 +62,19 @@ extern char *yytext; // keywords %token SELF %token STATIC +%token ABSTRACT +%token ALIGNOF %token AS +%token BECOME %token BREAK +%token CATCH %token CRATE +%token DO %token ELSE %token ENUM %token EXTERN %token FALSE +%token FINAL %token FN %token FOR %token IF @@ -76,19 +82,29 @@ extern char *yytext; %token IN %token LET %token LOOP +%token MACRO %token MATCH %token MOD %token MOVE %token MUT +%token OFFSETOF +%token OVERRIDE %token PRIV %token PUB +%token PURE %token REF %token RETURN +%token SIZEOF %token STRUCT +%token SUPER +%token UNION +%token UNSIZED %token TRUE %token TRAIT %token TYPE %token UNSAFE +%token VIRTUAL +%token YIELD %token DEFAULT %token USE %token WHILE @@ -141,6 +157,10 @@ extern char *yytext; // 'foo:bar . <' is shifted (in a trait reference occurring in a // bounds list), parsing as foo:(bar) rather than (foo:bar). %precedence IDENT + // Put the weak keywords that can be used as idents here as well +%precedence CATCH +%precedence DEFAULT +%precedence UNION // A couple fake-precedence symbols to use in rules associated with + // and < in trailing type contexts. These come up when you have a type @@ -161,13 +181,13 @@ extern char *yytext; %precedence FOR // Binops & unops, and their precedences +%precedence '?' %precedence BOX -%precedence BOXPLACE %nonassoc DOTDOT // RETURN needs to be lower-precedence than tokens that start // prefix_exprs -%precedence RETURN +%precedence RETURN YIELD %right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ %right LARROW @@ -321,6 +341,8 @@ view_path | path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } | MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); } | path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); } +| MOD_SEP '*' { $$ = mk_atom("ViewPathGlob"); } +| '*' { $$ = mk_atom("ViewPathGlob"); } | '{' '}' { $$ = mk_atom("ViewPathListEmpty"); } | '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); } | '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); } @@ -334,6 +356,7 @@ block_item | item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); } | item_struct | item_enum +| item_union | item_trait | item_impl ; @@ -387,6 +410,7 @@ struct_decl_field struct_tuple_fields : struct_tuple_field { $$ = mk_node("StructFields", 1, $1); } | struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } +| %empty { $$ = mk_none(); } ; struct_tuple_field @@ -417,6 +441,11 @@ enum_args | %empty { $$ = mk_none(); } ; +// unions +item_union +: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}' { $$ = mk_node("ItemUnion", 0); } +| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node("ItemUnion", 0); } + item_mod : MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); } | MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); } @@ -475,7 +504,7 @@ visibility idents_or_self : ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } -| ident_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } +| idents_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } | idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } ; @@ -515,6 +544,7 @@ trait_item : trait_const | trait_type | trait_method +| maybe_outer_attrs item_macro { $$ = mk_node("TraitMacroItem", 2, $1, $2); } ; trait_const @@ -547,36 +577,48 @@ trait_method ; type_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' { $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7); } -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +{ + $$ = mk_node("TypeMethod", 6, $1, $3, $5, $6, $7, $8); +} +| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' { $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9); } ; method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block { $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); } -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node("Method", 7, $1, $3, $5, $6, $7, $8, $9); +} +| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block { $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); } ; impl_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block { - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); + $$ = mk_node("Method", 8, $1, $2, $3, $5, $6, $7, $8, $9); } -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block { $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); } +| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node("Method", 9, $1, $2, $3, $5, $7, $8, $9, $10, $11); +} ; // There are two forms of impl: @@ -638,12 +680,17 @@ impl_item | impl_type ; +maybe_default +: DEFAULT { $$ = mk_atom("Default"); } +| %empty { $$ = mk_none(); } +; + impl_const -: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); } +: attrs_and_vis maybe_default item_const { $$ = mk_node("ImplConst", 3, $1, $2, $3); } ; impl_type -: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); } +: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 5, $1, $2, $4, $5, $7); } ; item_fn @@ -651,6 +698,10 @@ item_fn { $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6); } +| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node("ItemFn", 5, $3, $4, $5, $6, $7); +} ; item_unsafe_fn @@ -658,6 +709,10 @@ item_unsafe_fn { $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7); } +| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node("ItemUnsafeFn", 5, $4, $5, $6, $7, $8); +} | UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block { $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9); @@ -723,12 +778,6 @@ inferrable_param : pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); } ; -maybe_unboxed_closure_kind -: %empty -| ':' -| '&' maybe_mut ':' -; - maybe_comma_params : ',' { $$ = mk_none(); } | ',' params { $$ = $2; } @@ -784,7 +833,8 @@ ret_ty ; generic_params -: '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } +: '<' '>' { $$ = mk_node("Generics", 2, mk_none(), mk_none()); } +| '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } | '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } | '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } | '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } @@ -837,6 +887,8 @@ path_no_types_allowed | MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); } | SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } | MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } +| SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } +| MOD_SEP SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } | path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } ; @@ -882,7 +934,7 @@ generic_args ; generic_values -: maybe_lifetimes maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 2, $1, $2); } +: maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 1, $1); } ; maybe_ty_sums_and_or_bindings @@ -910,12 +962,11 @@ pat | ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); } | '(' ')' { $$ = mk_atom("PatUnit"); } | '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); } -| '(' pat_tup ',' ')' { $$ = mk_node("PatTup", 1, $2); } | '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); } | lit_or_path | lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); } | path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); } -| path_expr '(' DOTDOT ')' { $$ = mk_node("PatEnum", 1, $1); } +| path_expr '(' ')' { $$ = mk_node("PatEnum", 2, $1, mk_none()); } | path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); } | path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); } | binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); } @@ -953,6 +1004,7 @@ pat_field | BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); } | ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); } | binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); } +| LIT_INTEGER ':' pat { $$ = mk_node("PatField", 2, mk_atom(yytext), $3); } ; pat_fields @@ -965,11 +1017,26 @@ pat_struct | pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } | pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); } | DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); } +| %empty { $$ = mk_node("PatStruct", 1, mk_none()); } ; pat_tup -: pat { $$ = mk_node("pat_tup", 1, $1); } -| pat_tup ',' pat { $$ = ext_node($1, 1, $3); } +: pat_tup_elts { $$ = mk_node("PatTup", 2, $1, mk_none()); } +| pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, mk_none()); } +| pat_tup_elts DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } +| pat_tup_elts ',' DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } +| pat_tup_elts DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $4); } +| pat_tup_elts DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $4); } +| pat_tup_elts ',' DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $5); } +| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $5); } +| DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, mk_none(), $3); } +| DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, mk_none(), $3); } +| DOTDOT { $$ = mk_node("PatTup", 2, mk_none(), mk_none()); } +; + +pat_tup_elts +: pat { $$ = mk_node("PatTupElts", 1, $1); } +| pat_tup_elts ',' pat { $$ = ext_node($1, 1, $3); } ; pat_vec @@ -1007,24 +1074,25 @@ ty ; ty_prim -: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } -| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } -| BOX ty { $$ = mk_node("TyBox", 1, $2); } -| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } -| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } -| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } -| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } -| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } -| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } -| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } -| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } -| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } -| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } -| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } -| UNDERSCORE { $$ = mk_atom("TyInfer"); } +: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } +| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } +| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } +| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $1, $3, $4); } +| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $2, $4, $5); } +| BOX ty { $$ = mk_node("TyBox", 1, $2); } +| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } +| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } +| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } +| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } +| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } +| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } +| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } +| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } +| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } +| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } +| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } +| UNDERSCORE { $$ = mk_atom("TyInfer"); } | ty_bare_fn -| ty_proc | for_in_type ; @@ -1046,17 +1114,12 @@ ty_closure | OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); } ; -ty_proc -: PROC generic_params fn_params maybe_bounds ret_ty { $$ = mk_node("TyProc", 4, $2, $3, $4, $5); } -; - for_in_type : FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); } ; for_in_type_suffix -: ty_proc -| ty_bare_fn +: ty_bare_fn | trait_ref | ty_closure ; @@ -1100,13 +1163,23 @@ ty_sums ; ty_sum -: ty { $$ = mk_node("TySum", 1, $1); } -| ty '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } +: ty_sum_elt { $$ = mk_node("TySum", 1, $1); } +| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); } +; + +ty_sum_elt +: ty +| lifetime ; ty_prim_sum -: ty_prim { $$ = mk_node("TySum", 1, $1); } -| ty_prim '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } +: ty_prim_sum_elt { $$ = mk_node("TySum", 1, $1); } +| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); } +; + +ty_prim_sum_elt +: ty_prim +| lifetime ; maybe_ty_param_bounds @@ -1127,6 +1200,7 @@ boundseq polybound : FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); } | bound +| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $4, $6); } | '?' bound { $$ = $2; } ; @@ -1244,11 +1318,6 @@ maybe_stmts // block, nonblock-prefix, and nonblock-nonprefix. // // In non-stmts contexts, expr can relax this trichotomy. -// -// There is also one other expr subtype: nonparen_expr disallows exprs -// surrounded by parens (including tuple expressions), this is -// necessary for BOX (place) expressions, so a parens expr following -// the BOX is always parsed as the place. stmts : stmt { $$ = mk_node("stmts", 1, $1); } @@ -1256,14 +1325,15 @@ stmts ; stmt -: let +: maybe_outer_attrs let { $$ = $2; } | stmt_item | PUB stmt_item { $$ = $2; } | outer_attrs stmt_item { $$ = $2; } | outer_attrs PUB stmt_item { $$ = $3; } | full_block_expr -| block -| nonblock_expr ';' +| maybe_outer_attrs block { $$ = $2; } +| nonblock_expr ';' +| outer_attrs nonblock_expr ';' { $$ = $2; } | ';' { $$ = mk_none(); } ; @@ -1296,7 +1366,9 @@ path_expr // expressions. path_generic_args_with_colons : ident { $$ = mk_node("components", 1, $1); } +| SUPER { $$ = mk_atom("Super"); } | path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } +| path_generic_args_with_colons MOD_SEP SUPER { $$ = ext_node($1, 1, mk_atom("Super")); } | path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } ; @@ -1313,6 +1385,7 @@ nonblock_expr | SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } | macro_expr { $$ = mk_node("ExprMac", 1, $1); } | path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } +| nonblock_expr '?' { $$ = mk_node("ExprTry", 1, $1); } | nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } | nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } | nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } @@ -1325,6 +1398,8 @@ nonblock_expr | RETURN expr { $$ = mk_node("ExprRet", 1, $2); } | BREAK { $$ = mk_node("ExprBreak", 0); } | BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } +| YIELD { $$ = mk_node("ExprYield", 0); } +| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } | nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } @@ -1360,8 +1435,8 @@ nonblock_expr | DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } | DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } | nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' nonblock_expr { $$ = mk_node("ExprBox", 2, $3, $5); } +| nonblock_expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } +| BOX expr { $$ = mk_node("ExprBox", 1, $2); } | expr_qualified_path | nonblock_prefix_expr ; @@ -1373,6 +1448,7 @@ expr | SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } | macro_expr { $$ = mk_node("ExprMac", 1, $1); } | path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } +| expr '?' { $$ = mk_node("ExprTry", 1, $1); } | expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } | expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } | expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } @@ -1385,6 +1461,8 @@ expr | RETURN expr { $$ = mk_node("ExprRet", 1, $2); } | BREAK { $$ = mk_node("ExprBreak", 0); } | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } +| YIELD { $$ = mk_node("ExprYield", 0); } +| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } | expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } @@ -1420,69 +1498,8 @@ expr | DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } | DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } | expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 2, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -nonparen_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonparen_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonparen_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonparen_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonparen_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| nonparen_expr LARROW nonparen_expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| nonparen_expr '=' nonparen_expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonparen_expr SHLEQ nonparen_expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonparen_expr SHREQ nonparen_expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonparen_expr MINUSEQ nonparen_expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonparen_expr ANDEQ nonparen_expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonparen_expr OREQ nonparen_expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonparen_expr PLUSEQ nonparen_expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonparen_expr STAREQ nonparen_expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonparen_expr SLASHEQ nonparen_expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonparen_expr CARETEQ nonparen_expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonparen_expr PERCENTEQ nonparen_expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonparen_expr OROR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonparen_expr ANDAND nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonparen_expr EQEQ nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonparen_expr NE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonparen_expr '<' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonparen_expr '>' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonparen_expr LE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonparen_expr GE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonparen_expr '|' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonparen_expr '^' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonparen_expr '&' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonparen_expr SHL nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonparen_expr SHR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonparen_expr '+' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonparen_expr '-' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonparen_expr '*' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonparen_expr '/' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonparen_expr '%' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonparen_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonparen_expr DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonparen_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 1, $3, $5); } +| expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } +| BOX expr { $$ = mk_node("ExprBox", 1, $2); } | expr_qualified_path | block_expr | block @@ -1495,6 +1512,7 @@ expr_nostruct path_expr { $$ = mk_node("ExprPath", 1, $1); } | SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } | macro_expr { $$ = mk_node("ExprMac", 1, $1); } +| expr_nostruct '?' { $$ = mk_node("ExprTry", 1, $1); } | expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } | expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } | expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } @@ -1507,6 +1525,8 @@ expr_nostruct | RETURN expr { $$ = mk_node("ExprRet", 1, $2); } | BREAK { $$ = mk_node("ExprBreak", 0); } | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } +| YIELD { $$ = mk_node("ExprYield", 0); } +| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } | expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } @@ -1542,8 +1562,8 @@ expr_nostruct | DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); } | DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } | expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr_nostruct { $$ = mk_node("ExprBox", 1, $3, $5); } +| expr_nostruct ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } +| BOX expr { $$ = mk_node("ExprBox", 1, $2); } | expr_qualified_path | block_expr | block @@ -1558,7 +1578,6 @@ nonblock_prefix_expr_nostruct | ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } | lambda_expr_nostruct | MOVE lambda_expr_nostruct { $$ = $2; } -| proc_expr_nostruct ; nonblock_prefix_expr @@ -1569,7 +1588,6 @@ nonblock_prefix_expr | ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } | lambda_expr | MOVE lambda_expr { $$ = $2; } -| proc_expr ; expr_qualified_path @@ -1606,43 +1624,42 @@ maybe_as_trait_ref lambda_expr : %prec LAMBDA - OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } + OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } | %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $4, $5); } + '|' '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } | %prec LAMBDA - '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } + '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } | %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $5, $7, $8); } + '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } +; + +lambda_expr_no_first_bar +: %prec LAMBDA + '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } | %prec LAMBDA - '|' ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $3, $5, $6); } + inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } +| %prec LAMBDA + inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } ; lambda_expr_nostruct : %prec LAMBDA - OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } + OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } | %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $4); } + '|' '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } | %prec LAMBDA - '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } + '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } | %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $5, $7); } -| %prec LAMBDA - '|' ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $3, $5); } - + '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } ; -proc_expr +lambda_expr_nostruct_no_first_bar : %prec LAMBDA - PROC '(' ')' expr { $$ = mk_node("ExprProc", 2, mk_none(), $4); } + '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } | %prec LAMBDA - PROC '(' inferrable_params ')' expr { $$ = mk_node("ExprProc", 2, $3, $5); } -; - -proc_expr_nostruct -: %prec LAMBDA - PROC '(' ')' expr_nostruct { $$ = mk_node("ExprProc", 2, mk_none(), $4); } + inferrable_params '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } | %prec LAMBDA - PROC '(' inferrable_params ')' expr_nostruct { $$ = mk_node("ExprProc", 2, $3, $5); } + inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } ; vec_expr @@ -1654,6 +1671,7 @@ struct_expr_fields : field_inits | field_inits ',' | maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } +| %empty { $$ = mk_none(); } ; maybe_field_inits @@ -1668,7 +1686,9 @@ field_inits ; field_init -: ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } +: ident { $$ = mk_node("FieldInit", 1, $1); } +| ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } +| LIT_INTEGER ':' expr { $$ = mk_node("FieldInit", 2, mk_atom(yytext), $3); } ; default_field_init @@ -1689,10 +1709,18 @@ block_expr full_block_expr : block_expr -| full_block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| full_block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| full_block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| full_block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } +| block_expr_dot +; + +block_expr_dot +: block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } +| block_expr_dot '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } +| block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } +| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } +| block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } +| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } +| block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } +| block_expr_dot '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } ; expr_match @@ -1714,12 +1742,13 @@ match_clause ; nonblock_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW full_block_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } +: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } +| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } ; block_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } +: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } +| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } ; maybe_guard @@ -1796,6 +1825,10 @@ maybe_ident ident : IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); } +// Weak keywords that can be used as identifiers +| CATCH { $$ = mk_node("ident", 1, mk_atom(yytext)); } +| DEFAULT { $$ = mk_node("ident", 1, mk_atom(yytext)); } +| UNION { $$ = mk_node("ident", 1, mk_atom(yytext)); } ; unpaired_token @@ -1836,13 +1869,20 @@ unpaired_token | LIFETIME { $$ = mk_atom(yytext); } | SELF { $$ = mk_atom(yytext); } | STATIC { $$ = mk_atom(yytext); } +| ABSTRACT { $$ = mk_atom(yytext); } +| ALIGNOF { $$ = mk_atom(yytext); } | AS { $$ = mk_atom(yytext); } +| BECOME { $$ = mk_atom(yytext); } | BREAK { $$ = mk_atom(yytext); } +| CATCH { $$ = mk_atom(yytext); } | CRATE { $$ = mk_atom(yytext); } +| DEFAULT { $$ = mk_atom(yytext); } +| DO { $$ = mk_atom(yytext); } | ELSE { $$ = mk_atom(yytext); } | ENUM { $$ = mk_atom(yytext); } | EXTERN { $$ = mk_atom(yytext); } | FALSE { $$ = mk_atom(yytext); } +| FINAL { $$ = mk_atom(yytext); } | FN { $$ = mk_atom(yytext); } | FOR { $$ = mk_atom(yytext); } | IF { $$ = mk_atom(yytext); } @@ -1850,21 +1890,31 @@ unpaired_token | IN { $$ = mk_atom(yytext); } | LET { $$ = mk_atom(yytext); } | LOOP { $$ = mk_atom(yytext); } +| MACRO { $$ = mk_atom(yytext); } | MATCH { $$ = mk_atom(yytext); } | MOD { $$ = mk_atom(yytext); } | MOVE { $$ = mk_atom(yytext); } | MUT { $$ = mk_atom(yytext); } +| OFFSETOF { $$ = mk_atom(yytext); } +| OVERRIDE { $$ = mk_atom(yytext); } | PRIV { $$ = mk_atom(yytext); } | PUB { $$ = mk_atom(yytext); } +| PURE { $$ = mk_atom(yytext); } | REF { $$ = mk_atom(yytext); } | RETURN { $$ = mk_atom(yytext); } | STRUCT { $$ = mk_atom(yytext); } +| SIZEOF { $$ = mk_atom(yytext); } +| SUPER { $$ = mk_atom(yytext); } | TRUE { $$ = mk_atom(yytext); } | TRAIT { $$ = mk_atom(yytext); } | TYPE { $$ = mk_atom(yytext); } +| UNION { $$ = mk_atom(yytext); } | UNSAFE { $$ = mk_atom(yytext); } +| UNSIZED { $$ = mk_atom(yytext); } | USE { $$ = mk_atom(yytext); } +| VIRTUAL { $$ = mk_atom(yytext); } | WHILE { $$ = mk_atom(yytext); } +| YIELD { $$ = mk_atom(yytext); } | CONTINUE { $$ = mk_atom(yytext); } | PROC { $$ = mk_atom(yytext); } | BOX { $$ = mk_atom(yytext); } @@ -1942,4 +1992,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; \ No newline at end of file +; diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h index 081bd050259..15ea738ed00 100644 --- a/src/grammar/tokens.h +++ b/src/grammar/tokens.h @@ -30,6 +30,7 @@ enum Token { DOTDOT, DOTDOTDOT, MOD_SEP, + LARROW, RARROW, FAT_ARROW, LIT_BYTE, @@ -47,13 +48,20 @@ enum Token { // keywords SELF, STATIC, + ABSTRACT, + ALIGNOF, AS, + BECOME, BREAK, + CATCH, CRATE, + DEFAULT, + DO, ELSE, ENUM, EXTERN, FALSE, + FINAL, FN, FOR, IF, @@ -61,21 +69,31 @@ enum Token { IN, LET, LOOP, + MACRO, MATCH, MOD, MOVE, MUT, + OFFSETOF, + OVERRIDE, PRIV, PUB, + PURE, REF, RETURN, + SIZEOF, STRUCT, + SUPER, + UNION, TRUE, TRAIT, TYPE, UNSAFE, + UNSIZED, USE, + VIRTUAL, WHILE, + YIELD, CONTINUE, PROC, BOX, diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 35c8530b4dd..79292d390e5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -269,7 +269,38 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { - mem::transmute(raw) + Box::from_unique(Unique::new_unchecked(raw)) + } + + /// Constructs a `Box` from a `Unique` pointer. + /// + /// After calling this function, the memory is owned by a `Box` and `T` can + /// then be destroyed and released upon drop. + /// + /// # Safety + /// + /// A `Unique` can be safely created via [`Unique::new`] and thus doesn't + /// necessarily own the data pointed to nor is the data guaranteed to live + /// as long as the pointer. + /// + /// [`Unique::new`]: ../../core/ptr/struct.Unique.html#method.new + /// + /// # Examples + /// + /// ``` + /// #![feature(unique)] + /// + /// fn main() { + /// let x = Box::new(5); + /// let ptr = Box::into_unique(x); + /// let x = unsafe { Box::from_unique(ptr) }; + /// } + /// ``` + #[unstable(feature = "unique", reason = "needs an RFC to flesh out design", + issue = "27730")] + #[inline] + pub unsafe fn from_unique(u: Unique) -> Self { + mem::transmute(u) } /// Consumes the `Box`, returning the wrapped raw pointer. @@ -295,7 +326,7 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Box) -> *mut T { - unsafe { mem::transmute(b) } + Box::into_unique(b).as_ptr() } /// Consumes the `Box`, returning the wrapped pointer as `Unique`. @@ -303,13 +334,18 @@ impl Box { /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The - /// proper way to do so is to convert the raw pointer back into a - /// `Box` with the [`Box::from_raw`] function. + /// proper way to do so is to either convert the `Unique` pointer: + /// + /// - Into a `Box` with the [`Box::from_unique`] function. + /// + /// - Into a raw pointer and back into a `Box` with the [`Box::from_raw`] + /// function. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::into_unique(b)` instead of `b.into_unique()`. This /// is so that there is no conflict with a method on the inner type. /// + /// [`Box::from_unique`]: struct.Box.html#method.from_unique /// [`Box::from_raw`]: struct.Box.html#method.from_raw /// /// # Examples diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d51aaa23c6a..0cbfc9e9dac 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -121,6 +121,7 @@ #![feature(unique)] #![feature(unsize)] #![feature(allocator_internals)] +#![feature(on_unimplemented)] #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 861291194f3..cf34e195dea 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1543,6 +1543,7 @@ impl Hash for Vec { } #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl Index for Vec { type Output = T; @@ -1554,6 +1555,7 @@ impl Index for Vec { } #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl IndexMut for Vec { #[inline] fn index_mut(&mut self, index: usize) -> &mut T { @@ -1562,8 +1564,8 @@ impl IndexMut for Vec { } } - #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index> for Vec { type Output = [T]; @@ -1572,7 +1574,9 @@ impl ops::Index> for Vec { Index::index(&**self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index> for Vec { type Output = [T]; @@ -1581,7 +1585,9 @@ impl ops::Index> for Vec { Index::index(&**self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index> for Vec { type Output = [T]; @@ -1590,7 +1596,9 @@ impl ops::Index> for Vec { Index::index(&**self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index for Vec { type Output = [T]; @@ -1599,7 +1607,9 @@ impl ops::Index for Vec { self } } + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index> for Vec { type Output = [T]; @@ -1608,7 +1618,9 @@ impl ops::Index> for Vec { Index::index(&**self, index) } } + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::Index> for Vec { type Output = [T]; @@ -1619,41 +1631,52 @@ impl ops::Index> for Vec { } #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut> for Vec { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut> for Vec { #[inline] fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut> for Vec { #[inline] fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } } + #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut for Vec { #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] { self } } + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut> for Vec { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } } + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut> for Vec { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut [T] { diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 4042c4d2d4e..6d7d83dd993 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -19,7 +19,7 @@ libc = { path = "../rustc/libc_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" [features] debug = [] diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 7dd85ddcc79..65e035d4ffd 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -63,15 +63,6 @@ fn main() { _ => return, }; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); - let cflags = compiler.args() - .iter() - .map(|s| s.to_str().unwrap()) - .collect::>() - .join(" "); - let mut cmd = Command::new("sh"); cmd.arg(native.src_dir.join("configure") .to_str() @@ -79,8 +70,6 @@ fn main() { .replace("C:\\", "/c/") .replace("\\", "/")) .current_dir(&native.out_dir) - .env("CC", compiler.path()) - .env("EXTRA_CFLAGS", cflags.clone()) // jemalloc generates Makefile deps using GCC's "-MM" flag. This means // that GCC will run the preprocessor, and only the preprocessor, over // jemalloc's source files. If we don't specify CPPFLAGS, then at least @@ -89,9 +78,7 @@ fn main() { // passed to GCC, and then GCC won't define the // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to // select an atomic operation implementation. - .env("CPPFLAGS", cflags.clone()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())); + .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default()); if target.contains("ios") { cmd.arg("--disable-tls"); diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index e9e31065cf8..79767b37601 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -2059,14 +2059,23 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return Ordering::Equal, - (None, _ ) => return Ordering::Less, - (_ , None) => return Ordering::Greater, - (Some(x), Some(y)) => match x.cmp(&y) { - Ordering::Equal => (), - non_eq => return non_eq, + let x = match self.next() { + None => if other.next().is_none() { + return Ordering::Equal + } else { + return Ordering::Less }, + Some(val) => val, + }; + + let y = match other.next() { + None => return Ordering::Greater, + Some(val) => val, + }; + + match x.cmp(&y) { + Ordering::Equal => (), + non_eq => return non_eq, } } } @@ -2082,14 +2091,23 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return Some(Ordering::Equal), - (None, _ ) => return Some(Ordering::Less), - (_ , None) => return Some(Ordering::Greater), - (Some(x), Some(y)) => match x.partial_cmp(&y) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, + let x = match self.next() { + None => if other.next().is_none() { + return Some(Ordering::Equal) + } else { + return Some(Ordering::Less) }, + Some(val) => val, + }; + + let y = match other.next() { + None => return Some(Ordering::Greater), + Some(val) => val, + }; + + match x.partial_cmp(&y) { + Some(Ordering::Equal) => (), + non_eq => return non_eq, } } } @@ -2105,11 +2123,17 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return true, - (None, _) | (_, None) => return false, - (Some(x), Some(y)) => if x != y { return false }, - } + let x = match self.next() { + None => return other.next().is_none(), + Some(val) => val, + }; + + let y = match other.next() { + None => return false, + Some(val) => val, + }; + + if x != y { return false } } } @@ -2124,11 +2148,17 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return false, - (None, _) | (_, None) => return true, - (Some(x), Some(y)) => if x.ne(&y) { return true }, - } + let x = match self.next() { + None => return other.next().is_some(), + Some(val) => val, + }; + + let y = match other.next() { + None => return true, + Some(val) => val, + }; + + if x != y { return true } } } @@ -2143,18 +2173,21 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return false, - (None, _ ) => return true, - (_ , None) => return false, - (Some(x), Some(y)) => { - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => return false, - None => return false, - } - }, + let x = match self.next() { + None => return other.next().is_some(), + Some(val) => val, + }; + + let y = match other.next() { + None => return false, + Some(val) => val, + }; + + match x.partial_cmp(&y) { + Some(Ordering::Less) => return true, + Some(Ordering::Equal) => (), + Some(Ordering::Greater) => return false, + None => return false, } } } @@ -2170,18 +2203,21 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return true, - (None, _ ) => return true, - (_ , None) => return false, - (Some(x), Some(y)) => { - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => return false, - None => return false, - } - }, + let x = match self.next() { + None => { other.next(); return true; }, + Some(val) => val, + }; + + let y = match other.next() { + None => return false, + Some(val) => val, + }; + + match x.partial_cmp(&y) { + Some(Ordering::Less) => return true, + Some(Ordering::Equal) => (), + Some(Ordering::Greater) => return false, + None => return false, } } } @@ -2197,18 +2233,21 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return false, - (None, _ ) => return false, - (_ , None) => return true, - (Some(x), Some(y)) => { - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => return true, - None => return false, - } - } + let x = match self.next() { + None => { other.next(); return false; }, + Some(val) => val, + }; + + let y = match other.next() { + None => return true, + Some(val) => val, + }; + + match x.partial_cmp(&y) { + Some(Ordering::Less) => return false, + Some(Ordering::Equal) => (), + Some(Ordering::Greater) => return true, + None => return false, } } } @@ -2224,18 +2263,21 @@ pub trait Iterator { let mut other = other.into_iter(); loop { - match (self.next(), other.next()) { - (None, None) => return true, - (None, _ ) => return false, - (_ , None) => return true, - (Some(x), Some(y)) => { - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => return true, - None => return false, - } - }, + let x = match self.next() { + None => return other.next().is_none(), + Some(val) => val, + }; + + let y = match other.next() { + None => return true, + Some(val) => val, + }; + + match x.partial_cmp(&y) { + Some(Ordering::Less) => return false, + Some(Ordering::Equal) => (), + Some(Ordering::Greater) => return true, + None => return false, } } } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e085d427b8c..16d5fadc536 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -429,9 +429,11 @@ pub fn align_of_val(val: &T) -> usize { /// Returns whether dropping values of type `T` matters. /// -/// This is purely an optimization hint, and may be implemented conservatively. -/// For instance, always returning `true` would be a valid implementation of -/// this function. +/// This is purely an optimization hint, and may be implemented conservatively: +/// it may return `true` for types that don't actually need to be dropped. +/// As such always returning `true` would be a valid implementation of +/// this function. However if this function actually returns `false`, then you +/// can be certain dropping `T` has no side effect. /// /// Low level implementations of things like collections, which need to manually /// drop their data, should use this function to avoid unnecessarily @@ -836,7 +838,7 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// /// See the `discriminant` function in this module for more information. #[stable(feature = "discriminant_value", since = "1.21.0")] -pub struct Discriminant(u64, PhantomData<*const T>); +pub struct Discriminant(u64, PhantomData T>); // N.B. These trait implementations cannot be derived because we don't want any bounds on T. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 0af9fcf0a3d..670c2afa66f 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1405,16 +1405,6 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} -/* -Section: Comparing strings -*/ - -/// Bytewise slice equality -#[inline] -fn eq_slice(a: &str, b: &str) -> bool { - a.as_bytes() == b.as_bytes() -} - /* Section: UTF-8 validation */ @@ -1590,7 +1580,6 @@ mod traits { use cmp::Ordering; use ops; use slice::{self, SliceIndex}; - use str::eq_slice; /// Implements ordering of strings. /// @@ -1611,7 +1600,7 @@ mod traits { impl PartialEq for str { #[inline] fn eq(&self, other: &str) -> bool { - eq_slice(self, other) + self.as_bytes() == other.as_bytes() } #[inline] fn ne(&self, other: &str) -> bool { !(*self).eq(other) } diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index 86e59c736ba..f55a1c81463 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -121,3 +121,19 @@ fn test_transmute() { } } +#[test] +#[allow(dead_code)] +fn test_discriminant_send_sync() { + enum Regular { + A, + B(i32) + } + enum NotSendSync { + A(*const i32) + } + + fn is_send_sync() { } + + is_send_sync::>(); + is_send_sync::>(); +} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index e6307f10c13..cf30966fa89 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -488,7 +488,7 @@ impl Literal { pub fn string(string: &str) -> Literal { let mut escaped = String::new(); for ch in string.chars() { - escaped.extend(ch.escape_unicode()); + escaped.extend(ch.escape_debug()); } Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)) } diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml index eb31f5730d1..04f456917b9 100644 --- a/src/libprofiler_builtins/Cargo.toml +++ b/src/libprofiler_builtins/Cargo.toml @@ -15,4 +15,4 @@ doc = false core = { path = "../libcore" } [build-dependencies] -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1ecbc62225e..4600cdbc692 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -65,7 +65,7 @@ use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; use ich::Fingerprint; -use ty::{TyCtxt, Instance, InstanceDef, ParamEnvAnd, Ty}; +use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; use ty::subst::Substs; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use ich::StableHashingContext; @@ -505,6 +505,8 @@ define_dep_nodes!( <'tcx> [] InstanceSymbolName { instance: Instance<'tcx> }, [] SpecializationGraph(DefId), [] ObjectSafety(DefId), + [] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> }, + [] VtableMethods { trait_ref: PolyTraitRef<'tcx> }, [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 8d2cf676849..690db8a5522 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -19,7 +19,7 @@ mod safe; mod serialized; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; -pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId}; +pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs}; pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor}; pub use self::prev::PreviousDepGraph; pub use self::query::DepGraphQuery; diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index ce1a34faf5e..2221ecf07b4 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -41,7 +41,7 @@ use super::intravisit::Visitor; /// - Example: Lifetime resolution, which wants to bring lifetimes declared on the /// impl into scope while visiting the impl-items, and then back out again. /// - How: Implement `intravisit::Visitor` and override the -/// `visit_nested_map()` methods to return +/// `nested_visit_map()` methods to return /// `NestedVisitorMap::All`. Walk your crate with /// `intravisit::walk_crate()` invoked on `tcx.hir.krate()`. /// - Pro: Visitor methods for any kind of HIR node, not just item-like things. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 64a2ba1fa6f..54aecb4b00f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -705,7 +705,7 @@ impl<'a> LoweringContext<'a> { let expr = self.lower_body(None, |this| this.lower_expr(expr)); hir::TyTypeof(expr) } - TyKind::TraitObject(ref bounds) => { + TyKind::TraitObject(ref bounds, ..) => { let mut lifetime_bound = None; let bounds = bounds.iter().filter_map(|bound| { match *bound { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index fe060aaf426..f719ce15092 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -61,6 +61,9 @@ for ty::RegionKind { def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } + ty::ReLateBound(db, ty::BrEnv) => { + db.depth.hash_stable(hcx, hasher); + } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { def_id.hash_stable(hcx, hasher); index.hash_stable(hcx, hasher); @@ -841,3 +844,129 @@ impl_stable_hash_for!(struct ::util::common::ErrorReported {}); impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet { reachable_set }); + +impl<'gcx, N> HashStable> +for traits::Vtable<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + use traits::Vtable::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match self { + &VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher), + &VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher), + &VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher), + &VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher), + &VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher), + &VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher), + &VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher), + &VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher), + } + } +} + +impl<'gcx, N> HashStable> +for traits::VtableImplData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableImplData { + impl_def_id, + substs, + ref nested, + } = *self; + impl_def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableDefaultImplData where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableDefaultImplData { + trait_def_id, + ref nested, + } = *self; + trait_def_id.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableObjectData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableObjectData { + upcast_trait_ref, + vtable_base, + ref nested, + } = *self; + upcast_trait_ref.hash_stable(hcx, hasher); + vtable_base.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableBuiltinData where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableBuiltinData { + ref nested, + } = *self; + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableClosureData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableClosureData { + closure_def_id, + substs, + ref nested, + } = *self; + closure_def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableFnPointerData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableFnPointerData { + fn_ty, + ref nested, + } = *self; + fn_ty.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + +impl<'gcx, N> HashStable> +for traits::VtableGeneratorData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let traits::VtableGeneratorData { + closure_def_id, + substs, + ref nested, + } = *self; + closure_def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 015dbbb7aff..ed440849b48 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -106,6 +106,7 @@ pub mod lint; pub mod middle { pub mod allocator; + pub mod borrowck; pub mod expr_use_visitor; pub mod const_val; pub mod cstore; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 5fe75d8ca71..d28963fc726 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -222,6 +222,12 @@ declare_lint! { "unnecessary use of an `unsafe` block" } +declare_lint! { + pub UNUSED_MUT, + Warn, + "detect mut variables which don't need to be mutable" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -263,7 +269,8 @@ impl LintPass for HardwiredLints { PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, LATE_BOUND_LIFETIME_ARGUMENTS, DEPRECATED, - UNUSED_UNSAFE + UNUSED_UNSAFE, + UNUSED_MUT ) } } diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs new file mode 100644 index 00000000000..c8690422b18 --- /dev/null +++ b/src/librustc/middle/borrowck.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ich::StableHashingContext; +use hir::HirId; +use util::nodemap::FxHashSet; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +pub struct BorrowCheckResult { + pub used_mut_nodes: FxHashSet, +} + +impl<'gcx> HashStable> for BorrowCheckResult { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let BorrowCheckResult { + ref used_mut_nodes, + } = *self; + used_mut_nodes.hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 55d0c6b4c66..bb6213cb5fa 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -336,6 +336,12 @@ struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { + // Anything which has custom linkage gets thrown on the worklist no + // matter where it is in the crate. + if attr::contains_name(&item.attrs, "linkage") { + self.worklist.push(item.id); + } + // We need only trait impls here, not inherent impls, and only non-exported ones if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node { if !self.access_levels.is_reachable(item.id) { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 075a629de04..0159a198bc6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -415,9 +415,11 @@ pub enum BorrowKind { /////////////////////////////////////////////////////////////////////////// // Variables and temps -newtype_index!(Local, "_"); - -pub const RETURN_POINTER: Local = Local(0); +newtype_index!(Local + { + DEBUG_NAME = "_", + const RETURN_POINTER = 0, + }); /// Classifies locals into categories. See `Mir::local_kind`. #[derive(PartialEq, Eq, Debug)] @@ -551,7 +553,7 @@ pub struct UpvarDecl { /////////////////////////////////////////////////////////////////////////// // BasicBlock -newtype_index!(BasicBlock, "bb"); +newtype_index!(BasicBlock { DEBUG_NAME = "bb" }); /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator @@ -1131,7 +1133,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx> /// and the index is a local. pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; -newtype_index!(Field, "field"); +newtype_index!(Field { DEBUG_NAME = "field" }); impl<'tcx> Lvalue<'tcx> { pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> { @@ -1196,8 +1198,11 @@ impl<'tcx> Debug for Lvalue<'tcx> { /////////////////////////////////////////////////////////////////////////// // Scopes -newtype_index!(VisibilityScope, "scope"); -pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0); +newtype_index!(VisibilityScope + { + DEBUG_NAME = "scope", + const ARGUMENT_VISIBILITY_SCOPE = 0, + }); #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct VisibilityScopeData { @@ -1522,7 +1527,7 @@ pub struct Constant<'tcx> { pub literal: Literal<'tcx>, } -newtype_index!(Promoted, "promoted"); +newtype_index!(Promoted { DEBUG_NAME = "promoted" }); #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8b35b064eb3..f9a4b5bb9a5 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -352,7 +352,7 @@ top_level_options!( actually_rustdoc: bool [TRACKED], // Number of object files/codegen units to produce on the backend - codegen_units: usize [UNTRACKED], + cli_forced_codegen_units: Option [UNTRACKED], } ); @@ -505,7 +505,7 @@ pub fn basic_options() -> Options { unstable_features: UnstableFeatures::Disallow, debug_assertions: true, actually_rustdoc: false, - codegen_units: 1, + cli_forced_codegen_units: None, } } @@ -864,8 +864,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, build_codegen_options, "C", "codegen", CG_OPTIONS, cg_type_desc, cgsetters, ar: Option = (None, parse_opt_string, [UNTRACKED], - "tool to assemble archives with (has no effect currently, \ - rustc doesn't use an external archiver)"), + "this option is deprecated and does nothing"), linker: Option = (None, parse_opt_string, [UNTRACKED], "system linker to link outputs with"), link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], @@ -1100,6 +1099,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "generate a graphical HTML report of time spent in trans and LLVM"), thinlto: bool = (false, parse_bool, [TRACKED], "enable ThinLTO when possible"), + inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], + "control whether #[inline] functions are in all cgus"), } pub fn default_lib_output() -> CrateType { @@ -1709,48 +1710,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m)); - let codegen_units = codegen_units.unwrap_or_else(|| { - match opt_level { - // If we're compiling at `-O0` then default to 16 codegen units. - // The number here shouldn't matter too too much as debug mode - // builds don't rely on performance at all, meaning that lost - // opportunities for inlining through multiple codegen units is - // a non-issue. - // - // Note that the high number here doesn't mean that we'll be - // spawning a large number of threads in parallel. The backend - // of rustc contains global rate limiting through the - // `jobserver` crate so we'll never overload the system with too - // much work, but rather we'll only be optimizing when we're - // otherwise cooperating with other instances of rustc. - // - // Rather the high number here means that we should be able to - // keep a lot of idle cpus busy. By ensuring that no codegen - // unit takes *too* long to build we'll be guaranteed that all - // cpus will finish pretty closely to one another and we should - // make relatively optimal use of system resources - // - // Another note worth mentioning here, however, is that this number - // isn't *too* high. When codegen units are increased that means we - // currently have to codegen `#[inline]` functions into each codegen - // unit, which means the more codegen units we're using the more we - // may be generating. In other words, increasing codegen units may - // increase the overall work the compiler does. If we don't have - // enough cores to make up for this loss then increasing the number - // of codegen units could become an overall loss! - // - // As a result we choose a hopefully conservative value 16, which - // should be more than the number of cpus of most hardware compiling - // Rust but also not too much for 2-4 core machines to have too much - // loss of compile time. - OptLevel::No => 16, - - // All other optimization levels default use one codegen unit, - // the historical default in Rust for a Long Time. - _ => 1, - } - }); - (Options { crate_types, optimize: opt_level, @@ -1775,7 +1734,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, - codegen_units, + cli_forced_codegen_units: codegen_units, }, cfg) } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bd6e5eb67c8..2634ab10007 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -54,24 +54,24 @@ pub mod config; pub mod filesearch; pub mod search_paths; -// Represents the data associated with a compilation -// session for a single crate. +/// Represents the data associated with a compilation +/// session for a single crate. pub struct Session { pub target: config::Config, pub host: Target, pub opts: config::Options, pub parse_sess: ParseSess, - // For a library crate, this is always none + /// For a library crate, this is always none pub entry_fn: RefCell>, pub entry_type: Cell>, pub plugin_registrar_fn: Cell>, pub derive_registrar_fn: Cell>, pub default_sysroot: Option, - // The name of the root source file of the crate, in the local file system. - // `None` means that there is no source file. + /// The name of the root source file of the crate, in the local file system. + /// `None` means that there is no source file. pub local_crate_source_file: Option, - // The directory the compiler has been executed in plus a flag indicating - // if the value stored here has been affected by path remapping. + /// The directory the compiler has been executed in plus a flag indicating + /// if the value stored here has been affected by path remapping. pub working_dir: (String, bool), pub lint_store: RefCell, pub buffered_lints: RefCell>, @@ -83,11 +83,11 @@ pub struct Session { pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, - // The crate_disambiguator is constructed out of all the `-C metadata` - // arguments passed to the compiler. Its value together with the crate-name - // forms a unique global identifier for the crate. It is used to allow - // multiple crates with the same name to coexist. See the - // trans::back::symbol_names module for more information. + /// The crate_disambiguator is constructed out of all the `-C metadata` + /// arguments passed to the compiler. Its value together with the crate-name + /// forms a unique global identifier for the crate. It is used to allow + /// multiple crates with the same name to coexist. See the + /// trans::back::symbol_names module for more information. pub crate_disambiguator: RefCell>, pub features: RefCell, @@ -143,17 +143,17 @@ pub struct Session { } pub struct PerfStats { - // The accumulated time needed for computing the SVH of the crate + /// The accumulated time needed for computing the SVH of the crate pub svh_time: Cell, - // The accumulated time spent on computing incr. comp. hashes + /// The accumulated time spent on computing incr. comp. hashes pub incr_comp_hashes_time: Cell, - // The number of incr. comp. hash computations performed + /// The number of incr. comp. hash computations performed pub incr_comp_hashes_count: Cell, - // The number of bytes hashed when computing ICH values + /// The number of bytes hashed when computing ICH values pub incr_comp_bytes_hashed: Cell, - // The accumulated time spent on computing symbol hashes + /// The accumulated time spent on computing symbol hashes pub symbol_hash_time: Cell, - // The accumulated time spent decoding def path tables from metadata + /// The accumulated time spent decoding def path tables from metadata pub decode_def_path_tables_time: Cell, } @@ -636,6 +636,43 @@ impl Session { } ret } + + /// Returns the number of codegen units that should be used for this + /// compilation + pub fn codegen_units(&self) -> usize { + if let Some(n) = self.opts.cli_forced_codegen_units { + return n + } + if let Some(n) = self.target.target.options.default_codegen_units { + return n as usize + } + + match self.opts.optimize { + // If we're compiling at `-O0` then default to 16 codegen units. + // The number here shouldn't matter too too much as debug mode + // builds don't rely on performance at all, meaning that lost + // opportunities for inlining through multiple codegen units is + // a non-issue. + // + // Note that the high number here doesn't mean that we'll be + // spawning a large number of threads in parallel. The backend + // of rustc contains global rate limiting through the + // `jobserver` crate so we'll never overload the system with too + // much work, but rather we'll only be optimizing when we're + // otherwise cooperating with other instances of rustc. + // + // Rather the high number here means that we should be able to + // keep a lot of idle cpus busy. By ensuring that no codegen + // unit takes *too* long to build we'll be guaranteed that all + // cpus will finish pretty closely to one another and we should + // make relatively optimal use of system resources + config::OptLevel::No => 16, + + // All other optimization levels default use one codegen unit, + // the historical default in Rust for a Long Time. + _ => 1, + } + } } pub fn build_session(sopts: config::Options, @@ -804,24 +841,24 @@ pub fn build_session_(sopts: config::Options, /// Holds data on the current incremental compilation session, if there is one. #[derive(Debug)] pub enum IncrCompSession { - // This is the state the session will be in until the incr. comp. dir is - // needed. + /// This is the state the session will be in until the incr. comp. dir is + /// needed. NotInitialized, - // This is the state during which the session directory is private and can - // be modified. + /// This is the state during which the session directory is private and can + /// be modified. Active { session_directory: PathBuf, lock_file: flock::Lock, load_dep_graph: bool, }, - // This is the state after the session directory has been finalized. In this - // state, the contents of the directory must not be modified any more. + /// This is the state after the session directory has been finalized. In this + /// state, the contents of the directory must not be modified any more. Finalized { session_directory: PathBuf, }, - // This is an error state that is reached when some compilation error has - // occurred. It indicates that the contents of the session directory must - // not be used, since they might be invalid. + /// This is an error state that is reached when some compilation error has + /// occurred. It indicates that the contents of the session directory must + /// not be used, since they might be invalid. InvalidBecauseOfErrors { session_directory: PathBuf, } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c7c8141f4f7..030b7e4f646 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -711,41 +711,105 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, _) => { + OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { + let found_trait_ref = self.resolve_type_vars_if_possible(&*found_trait_ref); let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref); - let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref); - if actual_trait_ref.self_ty().references_error() { + if expected_trait_ref.self_ty().references_error() { return; } - let expected_trait_ty = expected_trait_ref.self_ty(); - let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| { + let found_trait_ty = found_trait_ref.self_ty(); + + let found_did = found_trait_ty.ty_to_def_id(); + let found_span = found_did.and_then(|did| { self.tcx.hir.span_if_local(did) }); - let self_ty_count = + let found_ty_count = + match found_trait_ref.skip_binder().substs.type_at(1).sty { + ty::TyTuple(ref tys, _) => tys.len(), + _ => 1, + }; + let (expected_tys, expected_ty_count) = match expected_trait_ref.skip_binder().substs.type_at(1).sty { - ty::TyTuple(ref tys, _) => tys.len(), - _ => 1, + ty::TyTuple(ref tys, _) => + (tys.iter().map(|t| &t.sty).collect(), tys.len()), + ref sty => (vec![sty], 1), }; - let arg_ty_count = - match actual_trait_ref.skip_binder().substs.type_at(1).sty { - ty::TyTuple(ref tys, _) => tys.len(), - _ => 1, - }; - if self_ty_count == arg_ty_count { + if found_ty_count == expected_ty_count { self.report_closure_arg_mismatch(span, found_span, - expected_trait_ref, - actual_trait_ref) + found_trait_ref, + expected_trait_ref) } else { - // Expected `|| { }`, found `|x, y| { }` - // Expected `fn(x) -> ()`, found `|| { }` + let expected_tuple = if expected_ty_count == 1 { + expected_tys.first().and_then(|t| { + if let &&ty::TyTuple(ref tuptys, _) = t { + Some(tuptys.len()) + } else { + None + } + }) + } else { + None + }; + + // FIXME(#44150): Expand this to "N args expected but a N-tuple found." + // Type of the 1st expected argument is somehow provided as type of a + // found one in that case. + // + // ``` + // [1i32, 2, 3].sort_by(|(a, b)| ..) + // // ^^^^^^^^ + // // expected_trait_ref: std::ops::FnMut<(&i32, &i32)> + // // found_trait_ref: std::ops::FnMut<(&i32,)> + // ``` + + let (closure_span, closure_args) = found_did + .and_then(|did| self.tcx.hir.get_if_local(did)) + .and_then(|node| { + if let hir::map::NodeExpr( + &hir::Expr { + node: hir::ExprClosure(_, ref decl, id, span, _), + .. + }) = node + { + let ty_snips = decl.inputs.iter() + .map(|ty| { + self.tcx.sess.codemap().span_to_snippet(ty.span).ok() + .and_then(|snip| { + // filter out dummy spans + if snip == "," || snip == "|" { + None + } else { + Some(snip) + } + }) + }) + .collect::>>(); + + let body = self.tcx.hir.body(id); + let pat_snips = body.arguments.iter() + .map(|arg| + self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok()) + .collect::>>(); + + Some((span, pat_snips, ty_snips)) + } else { + None + } + }) + .map(|(span, pat, ty)| (Some(span), Some((pat, ty)))) + .unwrap_or((None, None)); + let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty))); + self.report_arg_count_mismatch( span, - found_span, - arg_ty_count, - self_ty_count, - expected_trait_ty.is_closure() + closure_span.or(found_span), + expected_ty_count, + expected_tuple, + found_ty_count, + closure_args, + found_trait_ty.is_closure() ) } } @@ -767,32 +831,97 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.emit(); } - fn report_arg_count_mismatch(&self, - span: Span, - found_span: Option, - expected: usize, - found: usize, - is_closure: bool) - -> DiagnosticBuilder<'tcx> - { - let mut err = struct_span_err!(self.tcx.sess, span, E0593, - "{} takes {} argument{} but {} argument{} {} required", - if is_closure { "closure" } else { "function" }, - found, - if found == 1 { "" } else { "s" }, - expected, - if expected == 1 { "" } else { "s" }, - if expected == 1 { "is" } else { "are" }); + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected: usize, + expected_tuple: Option, + found: usize, + closure_args: Option<(Vec, Vec>)>, + is_closure: bool + ) -> DiagnosticBuilder<'tcx> { + use std::borrow::Cow; + + let kind = if is_closure { "closure" } else { "function" }; + + let args_str = |n, distinct| format!( + "{} {}argument{}", + n, + if distinct && n >= 2 { "distinct " } else { "" }, + if n == 1 { "" } else { "s" }, + ); + + let expected_str = if let Some(n) = expected_tuple { + assert!(expected == 1); + if closure_args.as_ref().map(|&(ref pats, _)| pats.len()) == Some(n) { + Cow::from("a single tuple as argument") + } else { + // be verbose when numbers differ + Cow::from(format!("a single {}-tuple as argument", n)) + } + } else { + Cow::from(args_str(expected, false)) + }; + + let found_str = if expected_tuple.is_some() { + args_str(found, true) + } else { + args_str(found, false) + }; + + + let mut err = struct_span_err!(self.tcx.sess, span, E0593, + "{} is expected to take {}, but it takes {}", + kind, + expected_str, + found_str, + ); + + err.span_label( + span, + format!( + "expected {} that takes {}", + kind, + expected_str, + ) + ); - err.span_label(span, format!("expected {} that takes {} argument{}", - if is_closure { "closure" } else { "function" }, - expected, - if expected == 1 { "" } else { "s" })); if let Some(span) = found_span { - err.span_label(span, format!("takes {} argument{}", - found, - if found == 1 { "" } else { "s" })); + if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) { + if expected_tuple != found || pats.len() != found { + err.span_label(span, format!("takes {}", found_str)); + } else { + let sugg = format!( + "|({}){}|", + pats.join(", "), + + // add type annotations if available + if tys.iter().any(|ty| ty.is_some()) { + Cow::from(format!( + ": ({})", + tys.into_iter().map(|ty| if let Some(ty) = ty { + ty + } else { + "_".to_string() + }).collect::>().join(", ") + )) + } else { + Cow::from("") + }, + ); + + err.span_suggestion( + span, + "consider changing the closure to accept a tuple", + sugg + ); + } + } else { + err.span_label(span, format!("takes {}", found_str)); + } } + err } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a1817f18106..1fddb186417 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -650,53 +650,55 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Given a trait `trait_ref`, iterates the vtable entries /// that come from `trait_ref`, including its supertraits. #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. -pub fn get_vtable_methods<'a, 'tcx>( +fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) - -> impl Iterator)>> + 'a + -> Rc)>>> { - debug!("get_vtable_methods({:?})", trait_ref); + debug!("vtable_methods({:?})", trait_ref); - supertraits(tcx, trait_ref).flat_map(move |trait_ref| { - let trait_methods = tcx.associated_items(trait_ref.def_id()) - .filter(|item| item.kind == ty::AssociatedKind::Method); + Rc::new( + supertraits(tcx, trait_ref).flat_map(move |trait_ref| { + let trait_methods = tcx.associated_items(trait_ref.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Method); - // Now list each method's DefId and Substs (for within its trait). - // If the method can never be called from this object, produce None. - trait_methods.map(move |trait_method| { - debug!("get_vtable_methods: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; + // Now list each method's DefId and Substs (for within its trait). + // If the method can never be called from this object, produce None. + trait_methods.map(move |trait_method| { + debug!("vtable_methods: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; - // Some methods cannot be called on an object; skip those. - if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { - debug!("get_vtable_methods: not vtable safe"); - return None; - } + // Some methods cannot be called on an object; skip those. + if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { + debug!("vtable_methods: not vtable safe"); + return None; + } - // the method may have some early-bound lifetimes, add - // regions for those - let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.types.re_erased, - |def, _| trait_ref.substs().type_for_def(def)); + // the method may have some early-bound lifetimes, add + // regions for those + let substs = Substs::for_item(tcx, def_id, + |_, _| tcx.types.re_erased, + |def, _| trait_ref.substs().type_for_def(def)); - // the trait type may have higher-ranked lifetimes in it; - // so erase them if they appear, so that we get the type - // at some particular call site - let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs)); + // the trait type may have higher-ranked lifetimes in it; + // so erase them if they appear, so that we get the type + // at some particular call site + let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs)); - // It's possible that the method relies on where clauses that - // do not hold for this particular set of type parameters. - // Note that this method could then never be called, so we - // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("get_vtable_methods: predicates do not hold"); - return None; - } + // It's possible that the method relies on where clauses that + // do not hold for this particular set of type parameters. + // Note that this method could then never be called, so we + // do not want to try and trans it, in that case (see #23435). + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + if !normalize_and_test_predicates(tcx, predicates.predicates) { + debug!("vtable_methods: predicates do not hold"); + return None; + } - Some((def_id, substs)) - }) - }) + Some((def_id, substs)) + }) + }).collect() + ) } impl<'tcx,O> Obligation<'tcx,O> { @@ -835,6 +837,8 @@ pub fn provide(providers: &mut ty::maps::Providers) { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, + trans_fulfill_obligation: trans::trans_fulfill_obligation, + vtable_methods, ..*providers }; } @@ -844,6 +848,8 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, + trans_fulfill_obligation: trans::trans_fulfill_obligation, + vtable_methods, ..*providers }; } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 947e7117c4e..aa3179dd01f 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -17,85 +17,77 @@ use dep_graph::{DepGraph, DepKind, DepTrackingMap, DepTrackingMapConfig}; use infer::TransNormalize; use std::cell::RefCell; use std::marker::PhantomData; -use syntax::ast; -use syntax_pos::Span; +use syntax_pos::DUMMY_SP; use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable}; use ty::{self, Ty, TyCtxt}; use ty::subst::{Subst, Substs}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::MemoizationMap; +/// Attempts to resolve an obligation to a vtable.. The result is +/// a shallow vtable resolution -- meaning that we do not +/// (necessarily) resolve all nested obligations on the impl. Note +/// that type check should guarantee to us that all nested +/// obligations *could be* resolved if we wanted to. +/// Assumes that this is run after the entire crate has been successfully type-checked. +pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, + (param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) + -> Vtable<'tcx, ()> +{ + // Remove any references to regions; this helps improve caching. + let trait_ref = ty.erase_regions(&trait_ref); + + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + (param_env, trait_ref), trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + ty.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(obligation_cause, + param_env, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + bug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref) + } + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) +} + impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { - /// Attempts to resolve an obligation to a vtable.. The result is - /// a shallow vtable resolution -- meaning that we do not - /// (necessarily) resolve all nested obligations on the impl. Note - /// that type check should guarantee to us that all nested - /// obligations *could be* resolved if we wanted to. - /// Assumes that this is run after the entire crate has been successfully type-checked. - pub fn trans_fulfill_obligation(self, - span: Span, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) - -> Vtable<'tcx, ()> - { - // Remove any references to regions; this helps improve caching. - let trait_ref = self.erase_regions(&trait_ref); - - self.trans_trait_caches.trait_cache.memoize((param_env, trait_ref), || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - self.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = Obligation::new(obligation_cause, - param_env, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - self.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) - } - /// Monomorphizes a type from the AST by first applying the in-scope /// substitutions and then normalizing any associated types. pub fn trans_apply_param_substs(self, @@ -149,14 +141,12 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { /// Specializes caches used in trans -- in particular, they assume all /// types are fully monomorphized and that free regions can be erased. pub struct TransTraitCaches<'tcx> { - trait_cache: RefCell>>, project_cache: RefCell>>, } impl<'tcx> TransTraitCaches<'tcx> { pub fn new(graph: DepGraph) -> Self { TransTraitCaches { - trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), project_cache: RefCell::new(DepTrackingMap::new(graph)), } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 740299b91f1..24ba38cf147 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -898,11 +898,6 @@ pub struct GlobalCtxt<'tcx> { pub inhabitedness_cache: RefCell, DefIdForest>>, - /// Set of nodes which mark locals as mutable which end up getting used at - /// some point. Local variable definitions not in this set can be warned - /// about. - pub used_mut_nodes: RefCell, - /// Caches the results of trait selection. This cache is used /// for things that do not have to do with the parameters in scope. pub selection_cache: traits::SelectionCache<'tcx>, @@ -1185,7 +1180,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { rcache: RefCell::new(FxHashMap()), normalized_cache: RefCell::new(FxHashMap()), inhabitedness_cache: RefCell::new(FxHashMap()), - used_mut_nodes: RefCell::new(NodeSet()), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), rvalue_promotable_to_static: RefCell::new(NodeMap()), diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 35ab1cec4cf..600b2572f92 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -13,7 +13,6 @@ use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; use ty::subst::{Kind, Subst}; use traits; use syntax::abi::Abi; -use syntax::codemap::DUMMY_SP; use util::ppaux; use std::fmt; @@ -212,7 +211,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder(trait_ref))); // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index c8520c5be2d..137039598a5 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -221,6 +221,12 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> { } } +impl<'tcx> QueryDescription for queries::trans_fulfill_obligation<'tcx> { + fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String { + format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id())) + } +} + impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("trait impls of `{}`", tcx.item_path_str(def_id)) @@ -497,6 +503,12 @@ impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> { } } +impl<'tcx> QueryDescription for queries::vtable_methods<'tcx> { + fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String { + format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())) + } +} + impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("seeing if the crate has enabled `Copy` closures") diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index e37cf669797..ee4523d6f3e 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -134,6 +134,24 @@ impl Key for (MirSuite, MirPassIndex, DefId) { } } +impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { + fn map_crate(&self) -> CrateNum { + self.1.def_id().krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.1.def_id()) + } +} + +impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ + fn map_crate(&self) -> CrateNum { + self.def_id().krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + impl<'tcx> Key for Ty<'tcx> { fn map_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 3dcbeda94bc..58405c261ad 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -15,6 +15,7 @@ use hir::def::{Def, Export}; use hir::{self, TraitCandidate, ItemLocalId}; use hir::svh::Svh; use lint; +use middle::borrowck::BorrowCheckResult; use middle::const_val; use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ExternBodyNestedBodies}; @@ -30,6 +31,7 @@ use middle::trans::{CodegenUnit, Stats}; use mir; use session::CompileResult; use session::config::OutputFilenames; +use traits::Vtable; use traits::specialization_graph; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::layout::{Layout, LayoutError}; @@ -182,7 +184,7 @@ define_maps! { <'tcx> [] fn coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), - [] fn borrowck: BorrowCheck(DefId) -> (), + [] fn borrowck: BorrowCheck(DefId) -> Rc, // FIXME: shouldn't this return a `Result<(), BorrowckErrors>` instead? [] fn mir_borrowck: MirBorrowCheck(DefId) -> (), @@ -227,7 +229,11 @@ define_maps! { <'tcx> [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies, [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn is_mir_available: IsMirAvailable(DefId) -> bool, + [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) + -> Rc)>>>, + [] fn trans_fulfill_obligation: fulfill_obligation_dep_node( + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, [] fn trait_impls_of: TraitImpls(DefId) -> Rc, [] fn specialization_graph_of: SpecializationGraph(DefId) -> Rc, [] fn is_object_safe: ObjectSafety(DefId) -> bool, @@ -347,6 +353,14 @@ fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstr } } +fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { + DepConstructor::FulfillObligation { + param_env, + trait_ref + } +} + fn coherent_trait_dep_node<'tcx>((_, def_id): (CrateNum, DefId)) -> DepConstructor<'tcx> { DepConstructor::CoherenceCheckTrait(def_id) } @@ -459,3 +473,7 @@ fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstru fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::OutputFilenames } + +fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::VtableMethods{ trait_ref } +} diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 88b619558d9..d6eaf6d1bc4 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -344,6 +344,52 @@ macro_rules! define_maps { } } + /// Ensure that either this query has all green inputs or been executed. + /// Executing query::ensure(D) is considered a read of the dep-node D. + /// + /// This function is particularly useful when executing passes for their + /// side-effects -- e.g., in order to report errors for erroneous programs. + /// + /// Note: The optimization is only available during incr. comp. + pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { + let dep_node = Self::to_dep_node(tcx, &key); + + // Ensuring an "input" or anonymous query makes no sense + assert!(!dep_node.kind.is_anon()); + assert!(!dep_node.kind.is_input()); + use dep_graph::DepNodeColor; + match tcx.dep_graph.node_color(&dep_node) { + Some(DepNodeColor::Green(dep_node_index)) => { + tcx.dep_graph.read_index(dep_node_index); + } + Some(DepNodeColor::Red) => { + // A DepNodeColor::Red DepNode means that this query was executed + // before. We can not call `dep_graph.read()` here as we don't have + // the DepNodeIndex. Instead, We call the query again to issue the + // appropriate `dep_graph.read()` call. The performance cost this + // introduces should be negligible as we'll immediately hit the + // in-memory cache. + let _ = tcx.$name(key); + } + None => { + // Huh + if !tcx.dep_graph.is_fully_enabled() { + let _ = tcx.$name(key); + return; + } + match tcx.dep_graph.try_mark_green(tcx, &dep_node) { + Some(dep_node_index) => { + debug_assert!(tcx.dep_graph.is_green(dep_node_index)); + tcx.dep_graph.read_index(dep_node_index); + } + None => { + let _ = tcx.$name(key); + } + } + } + } + } + fn compute_result(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V { let provider = tcx.maps.providers[key.map_crate()].$name; provider(tcx.global_tcx(), key) @@ -468,8 +514,7 @@ macro_rules! define_maps { define_provider_struct! { tcx: $tcx, - input: ($(([$($modifiers)*] [$name] [$K] [$V]))*), - output: () + input: ($(([$($modifiers)*] [$name] [$K] [$V]))*) } impl<$tcx> Copy for Providers<$tcx> {} @@ -480,78 +525,19 @@ macro_rules! define_maps { } macro_rules! define_map_struct { - // Initial state (tcx: $tcx:tt, - input: $input:tt) => { - define_map_struct! { - tcx: $tcx, - input: $input, - output: () - } - }; - - // Final output - (tcx: $tcx:tt, - input: (), - output: ($($output:tt)*)) => { + input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Maps<$tcx> { providers: IndexVec>, query_stack: RefCell)>>, - $($output)* - } - }; - - // Field recognized and ready to shift into the output - (tcx: $tcx:tt, - ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]), - input: $input:tt, - output: ($($output:tt)*)) => { - define_map_struct! { - tcx: $tcx, - input: $input, - output: ($($output)* - $(#[$attr])* $($pub)* $name: RefCell>>,) - } - }; - - // No modifiers left? This is a private item. - (tcx: $tcx:tt, - input: (([] $attrs:tt $name:tt) $($input:tt)*), - output: $output:tt) => { - define_map_struct! { - tcx: $tcx, - ready: ([] $attrs $name), - input: ($($input)*), - output: $output - } - }; - - // Skip other modifiers - (tcx: $tcx:tt, - input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), - output: $output:tt) => { - define_map_struct! { - tcx: $tcx, - input: (([$($modifiers)*] $($fields)*) $($input)*), - output: $output + $($(#[$attr])* $name: RefCell>>,)* } }; } macro_rules! define_provider_struct { - // Initial state: - (tcx: $tcx:tt, input: $input:tt) => { - define_provider_struct! { - tcx: $tcx, - input: $input, - output: () - } - }; - - // Final state: (tcx: $tcx:tt, - input: (), - output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => { + input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => { pub struct Providers<$tcx> { $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)* } @@ -566,43 +552,51 @@ macro_rules! define_provider_struct { } } }; - - // Something ready to shift: - (tcx: $tcx:tt, - ready: ($name:tt $K:tt $V:tt), - input: $input:tt, - output: ($($output:tt)*)) => { - define_provider_struct! { - tcx: $tcx, - input: $input, - output: ($($output)* ($name $K $V)) - } - }; - - // Regular queries produce a `V` only. - (tcx: $tcx:tt, - input: (([] $name:tt $K:tt $V:tt) $($input:tt)*), - output: $output:tt) => { - define_provider_struct! { - tcx: $tcx, - ready: ($name $K $V), - input: ($($input)*), - output: $output - } - }; - - // Skip modifiers. - (tcx: $tcx:tt, - input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), - output: $output:tt) => { - define_provider_struct! { - tcx: $tcx, - input: (([$($modifiers)*] $($fields)*) $($input)*), - output: $output - } - }; } + +/// The red/green evaluation system will try to mark a specific DepNode in the +/// dependency graph as green by recursively trying to mark the dependencies of +/// that DepNode as green. While doing so, it will sometimes encounter a DepNode +/// where we don't know if it is red or green and we therefore actually have +/// to recompute its value in order to find out. Since the only piece of +/// information that we have at that point is the DepNode we are trying to +/// re-evaluate, we need some way to re-run a query from just that. This is what +/// `force_from_dep_node()` implements. +/// +/// In the general case, a DepNode consists of a DepKind and an opaque +/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint +/// is usually constructed by computing a stable hash of the query-key that the +/// DepNode corresponds to. Consequently, it is not in general possible to go +/// back from hash to query-key (since hash functions are not reversible). For +/// this reason `force_from_dep_node()` is expected to fail from time to time +/// because we just cannot find out, from the DepNode alone, what the +/// corresponding query-key is and therefore cannot re-run the query. +/// +/// The system deals with this case letting `try_mark_green` fail which forces +/// the root query to be re-evaluated. +/// +/// Now, if force_from_dep_node() would always fail, it would be pretty useless. +/// Fortunately, we can use some contextual information that will allow us to +/// reconstruct query-keys for certain kinds of DepNodes. In particular, we +/// enforce by construction that the GUID/fingerprint of certain DepNodes is a +/// valid DefPathHash. Since we also always build a huge table that maps every +/// DefPathHash in the current codebase to the corresponding DefId, we have +/// everything we need to re-run the query. +/// +/// Take the `mir_validated` query as an example. Like many other queries, it +/// just has a single parameter: the DefId of the item it will compute the +/// validated MIR for. Now, when we call `force_from_dep_node()` on a dep-node +/// with kind `MirValidated`, we know that the GUID/fingerprint of the dep-node +/// is actually a DefPathHash, and can therefore just look up the corresponding +/// DefId in `tcx.def_path_hash_to_def_id`. +/// +/// When you implement a new query, it will likely have a corresponding new +/// DepKind, and you'll have to support it here in `force_from_dep_node()`. As +/// a rule of thumb, if your query takes a DefId or DefIndex as sole parameter, +/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just +/// add it to the "We don't have enough information to reconstruct..." group in +/// the match below. pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, dep_node: &DepNode) -> bool { @@ -687,16 +681,16 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::Hir | // This are anonymous nodes + DepKind::TraitSelect | + + // We don't have enough information to reconstruct the query key of + // these DepKind::IsCopy | DepKind::IsSized | DepKind::IsFreeze | DepKind::NeedsDrop | DepKind::Layout | - DepKind::TraitSelect | DepKind::ConstEval | - - // We don't have enough information to reconstruct the query key of - // these DepKind::InstanceSymbolName | DepKind::MirShim | DepKind::BorrowCheckKrate | @@ -705,6 +699,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TypeParamPredicates | DepKind::CodegenUnit | DepKind::CompileCodegenUnit | + DepKind::FulfillObligation | + DepKind::VtableMethods | // These are just odd DepKind::Null | diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 214973e3085..0eb2c19fe44 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -20,6 +20,7 @@ use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyGenerator, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; +use util::nodemap::FxHashSet; use std::cell::Cell; use std::fmt; @@ -32,6 +33,491 @@ use syntax::ast::CRATE_NODE_ID; use syntax::symbol::Symbol; use hir; +macro_rules! gen_display_debug_body { + ( $with:path ) => { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut cx = PrintContext::new(); + $with(self, f, &mut cx) + } + }; +} +macro_rules! gen_display_debug { + ( ($($x:tt)+) $target:ty, display yes ) => { + impl<$($x)+> fmt::Display for $target { + gen_display_debug_body! { Print::print_display } + } + }; + ( () $target:ty, display yes ) => { + impl fmt::Display for $target { + gen_display_debug_body! { Print::print_display } + } + }; + ( ($($x:tt)+) $target:ty, debug yes ) => { + impl<$($x)+> fmt::Debug for $target { + gen_display_debug_body! { Print::print_debug } + } + }; + ( () $target:ty, debug yes ) => { + impl fmt::Debug for $target { + gen_display_debug_body! { Print::print_debug } + } + }; + ( $generic:tt $target:ty, $t:ident no ) => {}; +} +macro_rules! gen_print_impl { + ( ($($x:tt)+) $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => { + impl<$($x)+> Print for $target { + fn print(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result { + if $cx.is_debug $dbg + else $disp + } + } + }; + ( () $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => { + impl Print for $target { + fn print(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result { + if $cx.is_debug $dbg + else $disp + } + } + }; + ( $generic:tt $target:ty, + $vars:tt $gendisp:ident $disp:block $gendbg:ident $dbg:block ) => { + gen_print_impl! { $generic $target, $vars $disp $dbg } + gen_display_debug! { $generic $target, display $gendisp } + gen_display_debug! { $generic $target, debug $gendbg } + } +} +macro_rules! define_print { + ( $generic:tt $target:ty, + $vars:tt { display $disp:block debug $dbg:block } ) => { + gen_print_impl! { $generic $target, $vars yes $disp yes $dbg } + }; + ( $generic:tt $target:ty, + $vars:tt { debug $dbg:block display $disp:block } ) => { + gen_print_impl! { $generic $target, $vars yes $disp yes $dbg } + }; + ( $generic:tt $target:ty, + $vars:tt { debug $dbg:block } ) => { + gen_print_impl! { $generic $target, $vars no { + bug!(concat!("display not implemented for ", stringify!($target))); + } yes $dbg } + }; + ( $generic:tt $target:ty, + ($self:ident, $f:ident, $cx:ident) { display $disp:block } ) => { + gen_print_impl! { $generic $target, ($self, $f, $cx) yes $disp no { + write!($f, "{:?}", $self) + } } + }; +} +macro_rules! define_print_multi { + ( [ $($generic:tt $target:ty),* ] $vars:tt $def:tt ) => { + $(define_print! { $generic $target, $vars $def })* + }; +} +macro_rules! print_inner { + ( $f:expr, $cx:expr, write ($($data:expr),+) ) => { + write!($f, $($data),+) + }; + ( $f:expr, $cx:expr, $kind:ident ($data:expr) ) => { + $data.$kind($f, $cx) + }; +} +macro_rules! print { + ( $f:expr, $cx:expr $(, $kind:ident $data:tt)+ ) => { + Ok(())$(.and_then(|_| print_inner!($f, $cx, $kind $data)))+ + }; +} + + +struct LateBoundRegionNameCollector(FxHashSet); +impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match *r { + ty::ReLateBound(_, ty::BrNamed(_, name)) => { + self.0.insert(name); + }, + _ => {}, + } + r.super_visit_with(self) + } +} + +#[derive(Debug)] +pub struct PrintContext { + is_debug: bool, + is_verbose: bool, + identify_regions: bool, + used_region_names: Option>, + region_index: usize, + binder_depth: usize, +} +impl PrintContext { + fn new() -> Self { + ty::tls::with_opt(|tcx| { + let (is_verbose, identify_regions) = tcx.map( + |tcx| (tcx.sess.verbose(), tcx.sess.opts.debugging_opts.identify_regions) + ).unwrap_or((false, false)); + PrintContext { + is_debug: false, + is_verbose: is_verbose, + identify_regions: identify_regions, + used_region_names: None, + region_index: 0, + binder_depth: 0, + } + }) + } + fn prepare_late_bound_region_info<'tcx, T>(&mut self, value: &ty::Binder) + where T: TypeFoldable<'tcx> + { + let mut collector = LateBoundRegionNameCollector(FxHashSet()); + value.visit_with(&mut collector); + self.used_region_names = Some(collector.0); + self.region_index = 0; + } +} + +pub trait Print { + fn print(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result; + fn print_to_string(&self, cx: &mut PrintContext) -> String { + let mut result = String::new(); + let _ = self.print(&mut result, cx); + result + } + fn print_display(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { + let old_debug = cx.is_debug; + cx.is_debug = false; + let result = self.print(f, cx); + cx.is_debug = old_debug; + result + } + fn print_display_to_string(&self, cx: &mut PrintContext) -> String { + let mut result = String::new(); + let _ = self.print_display(&mut result, cx); + result + } + fn print_debug(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { + let old_debug = cx.is_debug; + cx.is_debug = true; + let result = self.print(f, cx); + cx.is_debug = old_debug; + result + } + fn print_debug_to_string(&self, cx: &mut PrintContext) -> String { + let mut result = String::new(); + let _ = self.print_debug(&mut result, cx); + result + } +} + +impl PrintContext { + fn fn_sig(&mut self, + f: &mut F, + inputs: &[Ty], + variadic: bool, + output: Ty) + -> fmt::Result { + write!(f, "(")?; + let mut inputs = inputs.iter(); + if let Some(&ty) = inputs.next() { + print!(f, self, print_display(ty))?; + for &ty in inputs { + print!(f, self, write(", "), print_display(ty))?; + } + if variadic { + write!(f, ", ...")?; + } + } + write!(f, ")")?; + if !output.is_nil() { + print!(f, self, write(" -> "), print_display(output))?; + } + + Ok(()) + } + + fn parameterized(&mut self, + f: &mut F, + substs: &subst::Substs, + mut did: DefId, + projections: &[ty::ProjectionPredicate]) + -> fmt::Result { + let key = ty::tls::with(|tcx| tcx.def_key(did)); + let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() { + Some(name) + } else { + did.index = key.parent.unwrap_or_else( + || bug!("finding type for {:?}, encountered def-id {:?} with no parent", + did, did)); + self.parameterized(f, substs, did, projections)?; + return write!(f, "::{}", key.disambiguated_data.data.as_interned_str()); + }; + + let verbose = self.is_verbose; + let mut num_supplied_defaults = 0; + let mut has_self = false; + let mut num_regions = 0; + let mut num_types = 0; + let mut is_value_path = false; + let fn_trait_kind = ty::tls::with(|tcx| { + // Unfortunately, some kinds of items (e.g., closures) don't have + // generics. So walk back up the find the closest parent that DOES + // have them. + let mut item_def_id = did; + loop { + let key = tcx.def_key(item_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) => { + break; + } + DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => { + is_value_path = true; + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + item_def_id.index = key.parent.unwrap_or_else(|| { + bug!("finding type for {:?}, encountered def-id {:?} with no \ + parent", did, item_def_id); + }); + } + } + } + let mut generics = tcx.generics_of(item_def_id); + let mut path_def_id = did; + has_self = generics.has_self; + + let mut child_types = 0; + if let Some(def_id) = generics.parent { + // Methods. + assert!(is_value_path); + child_types = generics.types.len(); + generics = tcx.generics_of(def_id); + num_regions = generics.regions.len(); + num_types = generics.types.len(); + + if has_self { + print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?; + } + + path_def_id = def_id; + } else { + item_name = None; + + if is_value_path { + // Functions. + assert_eq!(has_self, false); + } else { + // Types and traits. + num_regions = generics.regions.len(); + num_types = generics.types.len(); + } + } + + if !verbose { + if generics.types.last().map_or(false, |def| def.has_default) { + if let Some(substs) = tcx.lift(&substs) { + let tps = substs.types().rev().skip(child_types); + for (def, actual) in generics.types.iter().rev().zip(tps) { + if !def.has_default { + break; + } + if tcx.type_of(def.def_id).subst(tcx, substs) != actual { + break; + } + num_supplied_defaults += 1; + } + } + } + } + + print!(f, self, write("{}", tcx.item_path_str(path_def_id)))?; + Ok(tcx.lang_items().fn_trait_kind(path_def_id)) + })?; + + if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { + let projection_ty = projections[0].ty; + if let TyTuple(ref args, _) = substs.type_at(1).sty { + return self.fn_sig(f, args, false, projection_ty); + } + } + + let empty = Cell::new(true); + let start_or_continue = |f: &mut F, start: &str, cont: &str| { + if empty.get() { + empty.set(false); + write!(f, "{}", start) + } else { + write!(f, "{}", cont) + } + }; + + let print_regions = |f: &mut F, start: &str, skip, count| { + // Don't print any regions if they're all erased. + let regions = || substs.regions().skip(skip).take(count); + if regions().all(|r: ty::Region| *r == ty::ReErased) { + return Ok(()); + } + + for region in regions() { + let region: ty::Region = region; + start_or_continue(f, start, ", ")?; + if verbose { + write!(f, "{:?}", region)?; + } else { + let s = region.to_string(); + if s.is_empty() { + // This happens when the value of the region + // parameter is not easily serialized. This may be + // because the user omitted it in the first place, + // or because it refers to some block in the code, + // etc. I'm not sure how best to serialize this. + write!(f, "'_")?; + } else { + write!(f, "{}", s)?; + } + } + } + + Ok(()) + }; + + print_regions(f, "<", 0, num_regions)?; + + let tps = substs.types().take(num_types - num_supplied_defaults) + .skip(has_self as usize); + + for ty in tps { + start_or_continue(f, "<", ", ")?; + ty.print_display(f, self)?; + } + + for projection in projections { + start_or_continue(f, "<", ", ")?; + ty::tls::with(|tcx| + print!(f, self, + write("{}=", + tcx.associated_item(projection.projection_ty.item_def_id).name), + print_display(projection.ty)) + )?; + } + + start_or_continue(f, "", ">")?; + + // For values, also print their name and type parameters. + if is_value_path { + empty.set(true); + + if has_self { + write!(f, ">")?; + } + + if let Some(item_name) = item_name { + write!(f, "::{}", item_name)?; + } + + print_regions(f, "::<", num_regions, usize::MAX)?; + + // FIXME: consider being smart with defaults here too + for ty in substs.types().skip(num_types) { + start_or_continue(f, "::<", ", ")?; + ty.print_display(f, self)?; + } + + start_or_continue(f, "", ">")?; + } + + Ok(()) + } + + fn in_binder<'a, 'gcx, 'tcx, T, U, F>(&mut self, + f: &mut F, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + original: &ty::Binder, + lifted: Option>) -> fmt::Result + where T: Print, U: Print + TypeFoldable<'tcx>, F: fmt::Write + { + fn name_by_region_index(index: usize) -> Symbol { + match index { + 0 => Symbol::intern("'r"), + 1 => Symbol::intern("'s"), + i => Symbol::intern(&format!("'t{}", i-2)), + } + } + + // Replace any anonymous late-bound regions with named + // variants, using gensym'd identifiers, so that we can + // clearly differentiate between named and unnamed regions in + // the output. We'll probably want to tweak this over time to + // decide just how much information to give. + let value = if let Some(v) = lifted { + v + } else { + return original.0.print_display(f, self); + }; + + if self.binder_depth == 0 { + self.prepare_late_bound_region_info(&value); + } + + let mut empty = true; + let mut start_or_continue = |f: &mut F, start: &str, cont: &str| { + if empty { + empty = false; + write!(f, "{}", start) + } else { + write!(f, "{}", cont) + } + }; + + let old_region_index = self.region_index; + let mut region_index = old_region_index; + let new_value = tcx.replace_late_bound_regions(&value, |br| { + let _ = start_or_continue(f, "for<", ", "); + let br = match br { + ty::BrNamed(_, name) => { + let _ = write!(f, "{}", name); + br + } + ty::BrAnon(_) | + ty::BrFresh(_) | + ty::BrEnv => { + let name = loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !self.is_name_used(&name) { + break name; + } + }; + let _ = write!(f, "{}", name); + ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), + name) + } + }; + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) + }).0; + start_or_continue(f, "", "> ")?; + + // Push current state to gcx, and restore after writing new_value. + self.binder_depth += 1; + self.region_index = region_index; + let result = new_value.print_display(f, self); + self.region_index = old_region_index; + self.binder_depth -= 1; + result + } + + fn is_name_used(&self, name: &Symbol) -> bool { + match self.used_region_names { + Some(ref names) => names.contains(name), + None => false, + } + } +} + pub fn verbose() -> bool { ty::tls::with(|tcx| tcx.sess.verbose()) } @@ -40,302 +526,50 @@ pub fn identify_regions() -> bool { ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions) } -fn fn_sig(f: &mut fmt::Formatter, - inputs: &[Ty], - variadic: bool, - output: Ty) - -> fmt::Result { - write!(f, "(")?; - let mut inputs = inputs.iter(); - if let Some(&ty) = inputs.next() { - write!(f, "{}", ty)?; - for &ty in inputs { - write!(f, ", {}", ty)?; - } - if variadic { - write!(f, ", ...")?; - } - } - write!(f, ")")?; - if !output.is_nil() { - write!(f, " -> {}", output)?; - } - - Ok(()) +pub fn parameterized(f: &mut F, + substs: &subst::Substs, + did: DefId, + projections: &[ty::ProjectionPredicate]) + -> fmt::Result { + PrintContext::new().parameterized(f, substs, did, projections) } -pub fn parameterized(f: &mut fmt::Formatter, - substs: &subst::Substs, - mut did: DefId, - projections: &[ty::ProjectionPredicate]) - -> fmt::Result { - let key = ty::tls::with(|tcx| tcx.def_key(did)); - let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() { - Some(name) - } else { - did.index = key.parent.unwrap_or_else( - || bug!("finding type for {:?}, encountered def-id {:?} with no parent", - did, did)); - parameterized(f, substs, did, projections)?; - return write!(f, "::{}", key.disambiguated_data.data.as_interned_str()); - }; - let mut verbose = false; - let mut num_supplied_defaults = 0; - let mut has_self = false; - let mut num_regions = 0; - let mut num_types = 0; - let mut is_value_path = false; - let fn_trait_kind = ty::tls::with(|tcx| { - // Unfortunately, some kinds of items (e.g., closures) don't have - // generics. So walk back up the find the closest parent that DOES - // have them. - let mut item_def_id = did; - loop { - let key = tcx.def_key(item_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) => { - break; - } - DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => { - is_value_path = true; - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - item_def_id.index = key.parent.unwrap_or_else(|| { - bug!("finding type for {:?}, encountered def-id {:?} with no \ - parent", did, item_def_id); - }); - } - } - } - let mut generics = tcx.generics_of(item_def_id); - let mut path_def_id = did; - verbose = tcx.sess.verbose(); - has_self = generics.has_self; - - let mut child_types = 0; - if let Some(def_id) = generics.parent { - // Methods. - assert!(is_value_path); - child_types = generics.types.len(); - generics = tcx.generics_of(def_id); - num_regions = generics.regions.len(); - num_types = generics.types.len(); - - if has_self { - write!(f, "<{} as ", substs.type_at(0))?; - } - - path_def_id = def_id; - } else { - item_name = None; - - if is_value_path { - // Functions. - assert_eq!(has_self, false); - } else { - // Types and traits. - num_regions = generics.regions.len(); - num_types = generics.types.len(); - } - } - - if !verbose { - if generics.types.last().map_or(false, |def| def.has_default) { - if let Some(substs) = tcx.lift(&substs) { - let tps = substs.types().rev().skip(child_types); - for (def, actual) in generics.types.iter().rev().zip(tps) { - if !def.has_default { - break; - } - if tcx.type_of(def.def_id).subst(tcx, substs) != actual { - break; - } - num_supplied_defaults += 1; - } - } - } - } - - write!(f, "{}", tcx.item_path_str(path_def_id))?; - Ok(tcx.lang_items().fn_trait_kind(path_def_id)) - })?; - - if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { - let projection_ty = projections[0].ty; - if let TyTuple(ref args, _) = substs.type_at(1).sty { - return fn_sig(f, args, false, projection_ty); - } +impl<'a, T: Print> Print for &'a T { + fn print(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { + (*self).print(f, cx) } - - let empty = Cell::new(true); - let start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| { - if empty.get() { - empty.set(false); - write!(f, "{}", start) - } else { - write!(f, "{}", cont) - } - }; - - let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| { - // Don't print any regions if they're all erased. - let regions = || substs.regions().skip(skip).take(count); - if regions().all(|r: ty::Region| *r == ty::ReErased) { - return Ok(()); - } - - for region in regions() { - let region: ty::Region = region; - start_or_continue(f, start, ", ")?; - if verbose { - write!(f, "{:?}", region)?; - } else { - let s = region.to_string(); - if s.is_empty() { - // This happens when the value of the region - // parameter is not easily serialized. This may be - // because the user omitted it in the first place, - // or because it refers to some block in the code, - // etc. I'm not sure how best to serialize this. - write!(f, "'_")?; - } else { - write!(f, "{}", s)?; - } - } - } - - Ok(()) - }; - - print_regions(f, "<", 0, num_regions)?; - - let tps = substs.types().take(num_types - num_supplied_defaults) - .skip(has_self as usize); - - for ty in tps { - start_or_continue(f, "<", ", ")?; - write!(f, "{}", ty)?; - } - - for projection in projections { - start_or_continue(f, "<", ", ")?; - ty::tls::with(|tcx| - write!(f, "{}={}", - tcx.associated_item(projection.projection_ty.item_def_id).name, - projection.ty) - )?; - } - - start_or_continue(f, "", ">")?; - - // For values, also print their name and type parameters. - if is_value_path { - empty.set(true); - - if has_self { - write!(f, ">")?; - } - - if let Some(item_name) = item_name { - write!(f, "::{}", item_name)?; - } - - print_regions(f, "::<", num_regions, usize::MAX)?; - - // FIXME: consider being smart with defaults here too - for ty in substs.types().skip(num_types) { - start_or_continue(f, "::<", ", ")?; - write!(f, "{}", ty)?; - } - - start_or_continue(f, "", ">")?; - } - - Ok(()) } -fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - original: &ty::Binder, - lifted: Option>) -> fmt::Result - where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx> -{ - // Replace any anonymous late-bound regions with named - // variants, using gensym'd identifiers, so that we can - // clearly differentiate between named and unnamed regions in - // the output. We'll probably want to tweak this over time to - // decide just how much information to give. - let value = if let Some(v) = lifted { - v - } else { - return write!(f, "{}", original.0); - }; +define_print! { + ('tcx) &'tcx ty::Slice>, (self, f, cx) { + display { + // Generate the main trait ref, including associated types. + ty::tls::with(|tcx| { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = tcx.mk_infer(ty::FreshTy(0)); - let mut empty = true; - let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| { - if empty { - empty = false; - write!(f, "{}", start) - } else { - write!(f, "{}", cont) - } - }; + if let Some(p) = self.principal() { + let principal = tcx.lift(&p).expect("could not lift TraitRef for printing") + .with_self_ty(tcx, dummy_self); + let projections = self.projection_bounds().map(|p| { + tcx.lift(&p) + .expect("could not lift projection for printing") + .with_self_ty(tcx, dummy_self) + }).collect::>(); + cx.parameterized(f, principal.substs, principal.def_id, &projections)?; + } - let new_value = tcx.replace_late_bound_regions(&value, |br| { - let _ = start_or_continue(f, "for<", ", "); - let br = match br { - ty::BrNamed(_, name) => { - let _ = write!(f, "{}", name); - br - } - ty::BrAnon(_) | - ty::BrFresh(_) | - ty::BrEnv => { - let name = Symbol::intern("'r"); - let _ = write!(f, "{}", name); - ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), - name) - } - }; - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) - }).0; + // Builtin bounds. + for did in self.auto_traits() { + write!(f, " + {}", tcx.item_path_str(did))?; + } - start_or_continue(f, "", "> ")?; - write!(f, "{}", new_value) -} - -impl<'tcx> fmt::Display for &'tcx ty::Slice> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Generate the main trait ref, including associated types. - ty::tls::with(|tcx| { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = tcx.mk_infer(ty::FreshTy(0)); - - if let Some(p) = self.principal() { - let principal = tcx.lift(&p).expect("could not lift TraitRef for printing") - .with_self_ty(tcx, dummy_self); - let projections = self.projection_bounds().map(|p| { - tcx.lift(&p) - .expect("could not lift projection for printing") - .with_self_ty(tcx, dummy_self) - }).collect::>(); - parameterized(f, principal.substs, principal.def_id, &projections)?; - } - - // Builtin bounds. - for did in self.auto_traits() { - write!(f, " + {}", tcx.item_path_str(did))?; - } + Ok(()) + })?; Ok(()) - })?; - - Ok(()) + } } } @@ -357,42 +591,6 @@ impl fmt::Debug for ty::RegionParameterDef { } } -impl<'tcx> fmt::Debug for ty::TyS<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", *self) - } -} - -impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{}", - if self.mutbl == hir::MutMutable { "mut " } else { "" }, - self.ty) - } -} - -impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // when printing out the debug representation, we don't need - // to enumerate the `for<...>` etc because the debruijn index - // tells you everything you need to know. - write!(f, "<{:?} as {}>", self.self_ty(), *self) - } -} - -impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| { - let dummy_self = tcx.mk_infer(ty::FreshTy(0)); - - let trait_ref = tcx.lift(&ty::Binder(*self)) - .expect("could not lift TraitRef for printing") - .with_self_ty(tcx, dummy_self).0; - parameterized(f, trait_ref.substs, trait_ref.def_id, &[]) - }) - } -} - impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| { @@ -409,100 +607,6 @@ impl fmt::Debug for ty::AdtDef { } } -impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} -> {}", self.kind, self.target) - } -} - -impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), - ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), - ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair), - ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), - ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), - ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair), - ty::Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty), - ty::Predicate::ObjectSafe(trait_def_id) => { - write!(f, "ObjectSafe({:?})", trait_def_id) - } - ty::Predicate::ClosureKind(closure_def_id, kind) => { - write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) - } - } - } -} - -impl fmt::Display for ty::BoundRegion { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if verbose() { - return write!(f, "{:?}", *self); - } - - match *self { - BrNamed(_, name) => write!(f, "{}", name), - BrAnon(_) | BrFresh(_) | BrEnv => Ok(()) - } - } -} - -impl fmt::Debug for ty::BoundRegion { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - BrAnon(n) => write!(f, "BrAnon({:?})", n), - BrFresh(n) => write!(f, "BrFresh({:?})", n), - BrNamed(did, name) => { - write!(f, "BrNamed({:?}:{:?}, {:?})", - did.krate, did.index, name) - } - BrEnv => "BrEnv".fmt(f), - } - } -} - -impl fmt::Debug for ty::RegionKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::ReEarlyBound(ref data) => { - write!(f, "ReEarlyBound({}, {})", - data.index, - data.name) - } - - ty::ReLateBound(binder_id, ref bound_region) => { - write!(f, "ReLateBound({:?}, {:?})", - binder_id, - bound_region) - } - - ty::ReFree(ref fr) => write!(f, "{:?}", fr), - - ty::ReScope(id) => { - write!(f, "ReScope({:?})", id) - } - - ty::ReStatic => write!(f, "ReStatic"), - - ty::ReVar(ref vid) => { - write!(f, "{:?}", vid) - } - - ty::ReSkolemized(id, ref bound_region) => { - write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) - } - - ty::ReEmpty => write!(f, "ReEmpty"), - - ty::ReErased => write!(f, "ReErased") - } - } -} - impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ClosureUpvar({:?},{:?})", @@ -511,94 +615,218 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { } } -impl fmt::Display for ty::RegionKind { +impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if verbose() { - return write!(f, "{:?}", *self); - } + write!(f, "UpvarId({:?};`{}`;{:?})", + self.var_id, + ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), + self.closure_expr_id) + } +} - // These printouts are concise. They do not contain all the information - // the user might want to diagnose an error, but there is basically no way - // to fit that into a short string. Hence the recommendation to use - // `explain_region()` or `note_and_explain_region()`. - match *self { - ty::ReEarlyBound(ref data) => { - write!(f, "{}", data.name) +impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UpvarBorrow({:?}, {:?})", + self.kind, self.region) + } +} + +define_print! { + ('tcx) ty::TypeAndMut<'tcx>, (self, f, cx) { + display { + print!(f, cx, + write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }), + print(self.ty)) + } + } +} + +define_print! { + ('tcx) ty::ExistentialTraitRef<'tcx>, (self, f, cx) { + debug { + ty::tls::with(|tcx| { + let dummy_self = tcx.mk_infer(ty::FreshTy(0)); + + let trait_ref = tcx.lift(&ty::Binder(*self)) + .expect("could not lift TraitRef for printing") + .with_self_ty(tcx, dummy_self).0; + cx.parameterized(f, trait_ref.substs, trait_ref.def_id, &[]) + }) + } + } +} + +define_print! { + ('tcx) ty::adjustment::Adjustment<'tcx>, (self, f, cx) { + debug { + print!(f, cx, write("{:?} -> ", self.kind), print(self.target)) + } + } +} + +define_print! { + () ty::BoundRegion, (self, f, cx) { + display { + if cx.is_verbose { + return self.print_debug(f, cx); } - ty::ReLateBound(_, br) | - ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::ReSkolemized(_, br) => { - write!(f, "{}", br) + + match *self { + BrNamed(_, name) => write!(f, "{}", name), + BrAnon(_) | BrFresh(_) | BrEnv => Ok(()) } - ty::ReScope(scope) if identify_regions() => { - match scope.data() { - region::ScopeData::Node(id) => - write!(f, "'{}s", id.as_usize()), - region::ScopeData::CallSite(id) => - write!(f, "'{}cs", id.as_usize()), - region::ScopeData::Arguments(id) => - write!(f, "'{}as", id.as_usize()), - region::ScopeData::Destruction(id) => - write!(f, "'{}ds", id.as_usize()), - region::ScopeData::Remainder(BlockRemainder { block, first_statement_index }) => - write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()), + } + debug { + return match *self { + BrAnon(n) => write!(f, "BrAnon({:?})", n), + BrFresh(n) => write!(f, "BrFresh({:?})", n), + BrNamed(did, name) => { + write!(f, "BrNamed({:?}:{:?}, {:?})", + did.krate, did.index, name) } + BrEnv => write!(f, "BrEnv"), + }; + } + } +} + +define_print! { + () ty::RegionKind, (self, f, cx) { + display { + if cx.is_verbose { + return self.print_debug(f, cx); } - ty::ReVar(region_vid) if identify_regions() => { - write!(f, "'{}rv", region_vid.index) + + // These printouts are concise. They do not contain all the information + // the user might want to diagnose an error, but there is basically no way + // to fit that into a short string. Hence the recommendation to use + // `explain_region()` or `note_and_explain_region()`. + match *self { + ty::ReEarlyBound(ref data) => { + write!(f, "{}", data.name) + } + ty::ReLateBound(_, br) | + ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | + ty::ReSkolemized(_, br) => { + write!(f, "{}", br) + } + ty::ReScope(scope) if cx.identify_regions => { + match scope.data() { + region::ScopeData::Node(id) => + write!(f, "'{}s", id.as_usize()), + region::ScopeData::CallSite(id) => + write!(f, "'{}cs", id.as_usize()), + region::ScopeData::Arguments(id) => + write!(f, "'{}as", id.as_usize()), + region::ScopeData::Destruction(id) => + write!(f, "'{}ds", id.as_usize()), + region::ScopeData::Remainder(BlockRemainder + { block, first_statement_index }) => + write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()), + } + } + ty::ReVar(region_vid) if cx.identify_regions => { + write!(f, "'{}rv", region_vid.index) + } + ty::ReScope(_) | + ty::ReVar(_) | + ty::ReErased => Ok(()), + ty::ReStatic => write!(f, "'static"), + ty::ReEmpty => write!(f, "'"), + } + } + debug { + match *self { + ty::ReEarlyBound(ref data) => { + write!(f, "ReEarlyBound({}, {})", + data.index, + data.name) + } + + ty::ReLateBound(binder_id, ref bound_region) => { + write!(f, "ReLateBound({:?}, {:?})", + binder_id, + bound_region) + } + + ty::ReFree(ref fr) => write!(f, "{:?}", fr), + + ty::ReScope(id) => { + write!(f, "ReScope({:?})", id) + } + + ty::ReStatic => write!(f, "ReStatic"), + + ty::ReVar(ref vid) => { + write!(f, "{:?}", vid) + } + + ty::ReSkolemized(id, ref bound_region) => { + write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) + } + + ty::ReEmpty => write!(f, "ReEmpty"), + + ty::ReErased => write!(f, "ReErased") } - ty::ReScope(_) | - ty::ReVar(_) | - ty::ReErased => Ok(()), - ty::ReStatic => write!(f, "'static"), - ty::ReEmpty => write!(f, "'"), } } } -impl fmt::Debug for ty::FreeRegion { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ReFree({:?}, {:?})", - self.scope, self.bound_region) - } -} - -impl fmt::Debug for ty::Variance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - ty::Covariant => "+", - ty::Contravariant => "-", - ty::Invariant => "o", - ty::Bivariant => "*", - }) - } -} - -impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "GenericPredicates({:?})", self.predicates) - } -} - -impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "InstantiatedPredicates({:?})", - self.predicates) - } -} - -impl<'tcx> fmt::Display for ty::FnSig<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.unsafety == hir::Unsafety::Unsafe { - write!(f, "unsafe ")?; +define_print! { + () ty::FreeRegion, (self, f, cx) { + debug { + write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) } + } +} - if self.abi != Abi::Rust { - write!(f, "extern {} ", self.abi)?; +define_print! { + () ty::Variance, (self, f, cx) { + debug { + f.write_str(match *self { + ty::Covariant => "+", + ty::Contravariant => "-", + ty::Invariant => "o", + ty::Bivariant => "*", + }) } + } +} - write!(f, "fn")?; - fn_sig(f, self.inputs(), self.variadic, self.output()) +define_print! { + ('tcx) ty::GenericPredicates<'tcx>, (self, f, cx) { + debug { + write!(f, "GenericPredicates({:?})", self.predicates) + } + } +} + +define_print! { + ('tcx) ty::InstantiatedPredicates<'tcx>, (self, f, cx) { + debug { + write!(f, "InstantiatedPredicates({:?})", self.predicates) + } + } +} + +define_print! { + ('tcx) ty::FnSig<'tcx>, (self, f, cx) { + display { + if self.unsafety == hir::Unsafety::Unsafe { + write!(f, "unsafe ")?; + } + + if self.abi != Abi::Rust { + write!(f, "extern {} ", self.abi)?; + } + + write!(f, "fn")?; + cx.fn_sig(f, self.inputs(), self.variadic, self.output()) + } + debug { + write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output()) + } } } @@ -626,21 +854,27 @@ impl fmt::Debug for ty::RegionVid { } } -impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output()) - } -} - -impl fmt::Debug for ty::InferTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::TyVar(ref v) => v.fmt(f), - ty::IntVar(ref v) => v.fmt(f), - ty::FloatVar(ref v) => v.fmt(f), - ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), - ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), - ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) +define_print! { + () ty::InferTy, (self, f, cx) { + display { + match *self { + ty::TyVar(_) => write!(f, "_"), + ty::IntVar(_) => write!(f, "{}", "{integer}"), + ty::FloatVar(_) => write!(f, "{}", "{float}"), + ty::FreshTy(v) => write!(f, "FreshTy({})", v), + ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), + ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) + } + } + debug { + match *self { + ty::TyVar(ref v) => write!(f, "{:?}", v), + ty::IntVar(ref v) => write!(f, "{:?}", v), + ty::FloatVar(ref v) => write!(f, "{:?}", v), + ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), + ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), + ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) + } } } } @@ -665,406 +899,393 @@ impl fmt::Debug for ty::IntVarValue { } }*/ -impl<'tcx> fmt::Display for ty::Binder<&'tcx ty::Slice>> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) +define_print_multi! { + [ + ('tcx) ty::Binder<&'tcx ty::Slice>>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder>, + ('tcx) ty::Binder, ty::Region<'tcx>>>, + ('tcx) ty::Binder, ty::Region<'tcx>>> + ] + (self, f, cx) { + display { + ty::tls::with(|tcx| cx.in_binder(f, tcx, self, tcx.lift(self))) + } } } -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) +define_print! { + ('tcx) ty::TraitRef<'tcx>, (self, f, cx) { + display { + cx.parameterized(f, self.substs, self.def_id, &[]) + } + debug { + // when printing out the debug representation, we don't need + // to enumerate the `for<...>` etc because the debruijn index + // tells you everything you need to know. + print!(f, cx, + write("<"), + print(self.self_ty()), + write(" as "))?; + cx.parameterized(f, self.substs, self.def_id, &[])?; + write!(f, ">") + } } } -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) +define_print! { + ('tcx) ty::GeneratorInterior<'tcx>, (self, f, cx) { + display { + self.witness.print(f, cx) + } } } -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::Binder> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::Binder, ty::Region<'tcx>>> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::Binder, - ty::Region<'tcx>>> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) - } -} - -impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - parameterized(f, self.substs, self.def_id, &[]) - } -} - -impl<'tcx> fmt::Display for ty::GeneratorInterior<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.witness.fmt(f) - } -} - -impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TyBool => write!(f, "bool"), - TyChar => write!(f, "char"), - TyInt(t) => write!(f, "{}", t.ty_to_string()), - TyUint(t) => write!(f, "{}", t.ty_to_string()), - TyFloat(t) => write!(f, "{}", t.ty_to_string()), - TyRawPtr(ref tm) => { - write!(f, "*{} {}", match tm.mutbl { - hir::MutMutable => "mut", - hir::MutImmutable => "const", - }, tm.ty) - } - TyRef(r, ref tm) => { - write!(f, "&")?; - let s = r.to_string(); - write!(f, "{}", s)?; - if !s.is_empty() { - write!(f, " ")?; +define_print! { + ('tcx) ty::TypeVariants<'tcx>, (self, f, cx) { + display { + match *self { + TyBool => write!(f, "bool"), + TyChar => write!(f, "char"), + TyInt(t) => write!(f, "{}", t.ty_to_string()), + TyUint(t) => write!(f, "{}", t.ty_to_string()), + TyFloat(t) => write!(f, "{}", t.ty_to_string()), + TyRawPtr(ref tm) => { + write!(f, "*{} ", match tm.mutbl { + hir::MutMutable => "mut", + hir::MutImmutable => "const", + })?; + tm.ty.print(f, cx) } - write!(f, "{}", tm) - } - TyNever => write!(f, "!"), - TyTuple(ref tys, _) => { - write!(f, "(")?; - let mut tys = tys.iter(); - if let Some(&ty) = tys.next() { - write!(f, "{},", ty)?; + TyRef(r, ref tm) => { + write!(f, "&")?; + let s = r.print_to_string(cx); + write!(f, "{}", s)?; + if !s.is_empty() { + write!(f, " ")?; + } + tm.print(f, cx) + } + TyNever => write!(f, "!"), + TyTuple(ref tys, _) => { + write!(f, "(")?; + let mut tys = tys.iter(); if let Some(&ty) = tys.next() { - write!(f, " {}", ty)?; - for &ty in tys { - write!(f, ", {}", ty)?; - } - } - } - write!(f, ")") - } - TyFnDef(def_id, substs) => { - ty::tls::with(|tcx| { - let mut sig = tcx.fn_sig(def_id); - if let Some(substs) = tcx.lift(&substs) { - sig = sig.subst(tcx, substs); - } - write!(f, "{} {{", sig.0) - })?; - parameterized(f, substs, def_id, &[])?; - write!(f, "}}") - } - TyFnPtr(ref bare_fn) => { - write!(f, "{}", bare_fn.0) - } - TyInfer(infer_ty) => write!(f, "{}", infer_ty), - TyError => write!(f, "[type error]"), - TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyAdt(def, substs) => parameterized(f, substs, def.did, &[]), - TyDynamic(data, r) => { - write!(f, "{}", data)?; - let r = r.to_string(); - if !r.is_empty() { - write!(f, " + {}", r) - } else { - Ok(()) - } - } - TyProjection(ref data) => write!(f, "{}", data), - TyAnon(def_id, substs) => { - ty::tls::with(|tcx| { - // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, - // by looking up the projections associated with the def_id. - let predicates_of = tcx.predicates_of(def_id); - let substs = tcx.lift(&substs).unwrap_or_else(|| { - tcx.intern_substs(&[]) - }); - let bounds = predicates_of.instantiate(tcx, substs); - - let mut first = true; - let mut is_sized = false; - write!(f, "impl")?; - for predicate in bounds.predicates { - if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { - // Don't print +Sized, but rather +?Sized if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { - is_sized = true; - continue; + print!(f, cx, print(ty), write(","))?; + if let Some(&ty) = tys.next() { + print!(f, cx, write(" "), print(ty))?; + for &ty in tys { + print!(f, cx, write(", "), print(ty))?; } - - write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?; - first = false; } } - if !is_sized { - write!(f, "{}?Sized", if first { " " } else { "+" })?; - } - Ok(()) - }) - } - TyStr => write!(f, "str"), - TyGenerator(did, substs, interior) => ty::tls::with(|tcx| { - let upvar_tys = substs.upvar_tys(did, tcx); - write!(f, "[generator")?; - - if let Some(node_id) = tcx.hir.as_local_node_id(did) { - write!(f, "@{:?}", tcx.hir.span(node_id))?; - let mut sep = " "; - tcx.with_freevars(node_id, |freevars| { - for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { - write!(f, - "{}{}:{}", - sep, - tcx.hir.name(freevar.var_id()), - upvar_ty)?; - sep = ", "; - } - Ok(()) - })? - } else { - // cross-crate closure types should only be - // visible in trans bug reports, I imagine. - write!(f, "@{:?}", did)?; - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - write!(f, "{}{}:{}", sep, index, upvar_ty)?; - sep = ", "; - } + write!(f, ")") } - - write!(f, " {}", interior)?; - - write!(f, "]") - }), - TyClosure(did, substs) => ty::tls::with(|tcx| { - let upvar_tys = substs.upvar_tys(did, tcx); - write!(f, "[closure")?; - - if let Some(node_id) = tcx.hir.as_local_node_id(did) { - if tcx.sess.opts.debugging_opts.span_free_formats { - write!(f, "@{:?}", node_id)?; + TyFnDef(def_id, substs) => { + ty::tls::with(|tcx| { + let mut sig = tcx.fn_sig(def_id); + if let Some(substs) = tcx.lift(&substs) { + sig = sig.subst(tcx, substs); + } + print!(f, cx, print(sig), write(" {{")) + })?; + cx.parameterized(f, substs, def_id, &[])?; + write!(f, "}}") + } + TyFnPtr(ref bare_fn) => { + bare_fn.print(f, cx) + } + TyInfer(infer_ty) => write!(f, "{}", infer_ty), + TyError => write!(f, "[type error]"), + TyParam(ref param_ty) => write!(f, "{}", param_ty), + TyAdt(def, substs) => cx.parameterized(f, substs, def.did, &[]), + TyDynamic(data, r) => { + data.print(f, cx)?; + let r = r.print_to_string(cx); + if !r.is_empty() { + write!(f, " + {}", r) } else { - write!(f, "@{:?}", tcx.hir.span(node_id))?; + Ok(()) } - let mut sep = " "; - tcx.with_freevars(node_id, |freevars| { - for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { - write!(f, - "{}{}:{}", - sep, - tcx.hir.name(freevar.var_id()), - upvar_ty)?; - sep = ", "; + } + TyProjection(ref data) => data.print(f, cx), + TyAnon(def_id, substs) => { + ty::tls::with(|tcx| { + // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, + // by looking up the projections associated with the def_id. + let predicates_of = tcx.predicates_of(def_id); + let substs = tcx.lift(&substs).unwrap_or_else(|| { + tcx.intern_substs(&[]) + }); + let bounds = predicates_of.instantiate(tcx, substs); + + let mut first = true; + let mut is_sized = false; + write!(f, "impl")?; + for predicate in bounds.predicates { + if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { + // Don't print +Sized, but rather +?Sized if absent. + if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { + is_sized = true; + continue; + } + + print!(f, cx, + write("{}", if first { " " } else { "+" }), + print(trait_ref))?; + first = false; + } + } + if !is_sized { + write!(f, "{}?Sized", if first { " " } else { "+" })?; } Ok(()) - })? - } else { - // cross-crate closure types should only be - // visible in trans bug reports, I imagine. - write!(f, "@{:?}", did)?; - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - write!(f, "{}{}:{}", sep, index, upvar_ty)?; - sep = ", "; - } + }) } + TyStr => write!(f, "str"), + TyGenerator(did, substs, interior) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); + write!(f, "[generator")?; - write!(f, "]") - }), - TyArray(ty, sz) => { - write!(f, "[{}; ", ty)?; - match sz.val { - ConstVal::Integral(ConstInt::Usize(sz)) => { - write!(f, "{}", sz)?; + if let Some(node_id) = tcx.hir.as_local_node_id(did) { + write!(f, "@{:?}", tcx.hir.span(node_id))?; + let mut sep = " "; + tcx.with_freevars(node_id, |freevars| { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { + print!(f, cx, + write("{}{}:", + sep, + tcx.hir.name(freevar.var_id())), + print(upvar_ty))?; + sep = ", "; + } + Ok(()) + })? + } else { + // cross-crate closure types should only be + // visible in trans bug reports, I imagine. + write!(f, "@{:?}", did)?; + let mut sep = " "; + for (index, upvar_ty) in upvar_tys.enumerate() { + print!(f, cx, + write("{}{}:", sep, index), + print(upvar_ty))?; + sep = ", "; + } } - ConstVal::Unevaluated(_def_id, substs) => { - write!(f, "", &substs[..])?; + + print!(f, cx, write(" "), print(interior), write("]")) + }), + TyClosure(did, substs) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); + write!(f, "[closure")?; + + if let Some(node_id) = tcx.hir.as_local_node_id(did) { + if tcx.sess.opts.debugging_opts.span_free_formats { + write!(f, "@{:?}", node_id)?; + } else { + write!(f, "@{:?}", tcx.hir.span(node_id))?; + } + let mut sep = " "; + tcx.with_freevars(node_id, |freevars| { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { + print!(f, cx, + write("{}{}:", + sep, + tcx.hir.name(freevar.var_id())), + print(upvar_ty))?; + sep = ", "; + } + Ok(()) + })? + } else { + // cross-crate closure types should only be + // visible in trans bug reports, I imagine. + write!(f, "@{:?}", did)?; + let mut sep = " "; + for (index, upvar_ty) in upvar_tys.enumerate() { + print!(f, cx, + write("{}{}:", sep, index), + print(upvar_ty))?; + sep = ", "; + } } - _ => { - write!(f, "{:?}", sz)?; + + write!(f, "]") + }), + TyArray(ty, sz) => { + print!(f, cx, write("["), print(ty), write("; "))?; + match sz.val { + ConstVal::Integral(ConstInt::Usize(sz)) => { + write!(f, "{}", sz)?; + } + ConstVal::Unevaluated(_def_id, substs) => { + write!(f, "", &substs[..])?; + } + _ => { + write!(f, "{:?}", sz)?; + } } + write!(f, "]") + } + TySlice(ty) => { + print!(f, cx, write("["), print(ty), write("]")) + } + } + } + } +} + +define_print! { + ('tcx) ty::TyS<'tcx>, (self, f, cx) { + display { + self.sty.print(f, cx) + } + debug { + self.sty.print_display(f, cx) + } + } +} + +define_print! { + () ty::ParamTy, (self, f, cx) { + display { + write!(f, "{}", self.name) + } + debug { + write!(f, "{}/#{}", self.name, self.idx) + } + } +} + +define_print! { + ('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate, + (self, f, cx) { + display { + print!(f, cx, print(self.0), write(" : "), print(self.1)) + } + } +} + +define_print! { + ('tcx) ty::EquatePredicate<'tcx>, (self, f, cx) { + display { + print!(f, cx, print(self.0), write(" == "), print(self.1)) + } + } +} + +define_print! { + ('tcx) ty::SubtypePredicate<'tcx>, (self, f, cx) { + display { + print!(f, cx, print(self.a), write(" <: "), print(self.b)) + } + } +} + +define_print! { + ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { + debug { + write!(f, "TraitPredicate({:?})", + self.trait_ref) + } + display { + print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) + } + } +} + +define_print! { + ('tcx) ty::ProjectionPredicate<'tcx>, (self, f, cx) { + debug { + print!(f, cx, + write("ProjectionPredicate("), + print(self.projection_ty), + write(", "), + print(self.ty), + write(")")) + } + display { + print!(f, cx, print(self.projection_ty), write(" == "), print(self.ty)) + } + } +} + +define_print! { + ('tcx) ty::ProjectionTy<'tcx>, (self, f, cx) { + display { + // FIXME(tschottdorf): use something like + // parameterized(f, self.substs, self.item_def_id, &[]) + // (which currently ICEs). + let (trait_ref, item_name) = ty::tls::with(|tcx| + (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) + ); + print!(f, cx, print_debug(trait_ref), write("::{}", item_name)) + } + } +} + +define_print! { + () ty::ClosureKind, (self, f, cx) { + display { + match *self { + ty::ClosureKind::Fn => write!(f, "Fn"), + ty::ClosureKind::FnMut => write!(f, "FnMut"), + ty::ClosureKind::FnOnce => write!(f, "FnOnce"), + } + } + } +} + +define_print! { + ('tcx) ty::Predicate<'tcx>, (self, f, cx) { + display { + match *self { + ty::Predicate::Trait(ref data) => data.print(f, cx), + ty::Predicate::Equate(ref predicate) => predicate.print(f, cx), + ty::Predicate::Subtype(ref predicate) => predicate.print(f, cx), + ty::Predicate::RegionOutlives(ref predicate) => predicate.print(f, cx), + ty::Predicate::TypeOutlives(ref predicate) => predicate.print(f, cx), + ty::Predicate::Projection(ref predicate) => predicate.print(f, cx), + ty::Predicate::WellFormed(ty) => print!(f, cx, print(ty), write(" well-formed")), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::tls::with(|tcx| { + write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) + }), + ty::Predicate::ClosureKind(closure_def_id, kind) => + ty::tls::with(|tcx| { + write!(f, "the closure `{}` implements the trait `{}`", + tcx.item_path_str(closure_def_id), kind) + }), + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "the constant `")?; + cx.parameterized(f, substs, def_id, &[])?; + write!(f, "` can be evaluated") + } + } + } + debug { + match *self { + ty::Predicate::Trait(ref a) => a.print(f, cx), + ty::Predicate::Equate(ref pair) => pair.print(f, cx), + ty::Predicate::Subtype(ref pair) => pair.print(f, cx), + ty::Predicate::RegionOutlives(ref pair) => pair.print(f, cx), + ty::Predicate::TypeOutlives(ref pair) => pair.print(f, cx), + ty::Predicate::Projection(ref pair) => pair.print(f, cx), + ty::Predicate::WellFormed(ty) => ty.print(f, cx), + ty::Predicate::ObjectSafe(trait_def_id) => { + write!(f, "ObjectSafe({:?})", trait_def_id) + } + ty::Predicate::ClosureKind(closure_def_id, kind) => { + write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) + } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } - write!(f, "]") - } - TySlice(ty) => write!(f, "[{}]", ty) - } - } -} - -impl<'tcx> fmt::Display for ty::TyS<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.sty) - } -} - -impl fmt::Debug for ty::UpvarId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UpvarId({:?};`{}`;{:?})", - self.var_id, - ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), - self.closure_expr_id) - } -} - -impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UpvarBorrow({:?}, {:?})", - self.kind, self.region) - } -} - -impl fmt::Display for ty::InferTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let print_var_ids = verbose(); - match *self { - ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), - ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), - ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), - ty::TyVar(_) => write!(f, "_"), - ty::IntVar(_) => write!(f, "{}", "{integer}"), - ty::FloatVar(_) => write!(f, "{}", "{float}"), - ty::FreshTy(v) => write!(f, "FreshTy({})", v), - ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), - ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) - } - } -} - -impl fmt::Display for ty::ParamTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -impl fmt::Debug for ty::ParamTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}/#{}", self, self.idx) - } -} - -impl<'tcx, T, U> fmt::Display for ty::OutlivesPredicate - where T: fmt::Display, U: fmt::Display -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} : {}", self.0, self.1) - } -} - -impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} == {}", self.0, self.1) - } -} - -impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} <: {}", self.a, self.b) - } -} - -impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TraitPredicate({:?})", - self.trait_ref) - } -} - -impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {}", self.trait_ref.self_ty(), self.trait_ref) - } -} - -impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ProjectionPredicate({:?}, {:?})", - self.projection_ty, - self.ty) - } -} - -impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} == {}", - self.projection_ty, - self.ty) - } -} - -impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(tschottdorf): use something like - // parameterized(f, self.substs, self.item_def_id, &[]) - // (which currently ICEs). - let (trait_ref, item_name) = ty::tls::with(|tcx| - (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) - ); - write!(f, "{:?}::{}", - trait_ref, - item_name) - } -} - -impl fmt::Display for ty::ClosureKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::ClosureKind::Fn => write!(f, "Fn"), - ty::ClosureKind::FnMut => write!(f, "FnMut"), - ty::ClosureKind::FnOnce => write!(f, "FnOnce"), - } - } -} - -impl<'tcx> fmt::Display for ty::Predicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::Predicate::Trait(ref data) => write!(f, "{}", data), - ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), - ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate), - ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), - ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), - ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), - ty::Predicate::WellFormed(ty) => write!(f, "{} well-formed", ty), - ty::Predicate::ObjectSafe(trait_def_id) => - ty::tls::with(|tcx| { - write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) - }), - ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::tls::with(|tcx| { - write!(f, "the closure `{}` implements the trait `{}`", - tcx.item_path_str(closure_def_id), kind) - }), - ty::Predicate::ConstEvaluatable(def_id, substs) => { - write!(f, "the constant `")?; - parameterized(f, substs, def_id, &[])?; - write!(f, "` can be evaluated") } } } diff --git a/src/librustc_back/build.rs b/src/librustc_back/build.rs index 16f0872b25a..6f6fde1e9e7 100644 --- a/src/librustc_back/build.rs +++ b/src/librustc_back/build.rs @@ -11,5 +11,4 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=CFG_DEFAULT_LINKER"); - println!("cargo:rerun-if-env-changed=CFG_DEFAULT_AR"); } diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 033e840f202..a54627279b0 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -20,7 +20,6 @@ pub fn target() -> Result { let opts = TargetOptions { linker: cmd("emcc"), - ar: cmd("emar"), dynamic_linking: false, executables: true, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 039e0153656..a56d0678158 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -135,6 +135,7 @@ macro_rules! supported_targets { supported_targets! { ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu), + ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), @@ -268,8 +269,6 @@ pub struct TargetOptions { /// Linker to invoke. Defaults to "cc". pub linker: String, - /// Archive utility to use when managing archives. Defaults to "ar". - pub ar: String, /// Linker arguments that are unconditionally passed *before* any /// user-defined libraries. @@ -430,6 +429,9 @@ pub struct TargetOptions { /// The minimum alignment for global symbols. pub min_global_align: Option, + + /// Default number of codegen units to use in debug mode + pub default_codegen_units: Option, } impl Default for TargetOptions { @@ -439,7 +441,6 @@ impl Default for TargetOptions { TargetOptions { is_builtin: false, linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), - ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), pre_link_args: LinkArgs::new(), post_link_args: LinkArgs::new(), asm_args: Vec::new(), @@ -492,6 +493,7 @@ impl Default for TargetOptions { crt_static_respected: false, stack_probes: false, min_global_align: None, + default_codegen_units: None, } } } @@ -680,7 +682,6 @@ impl Target { key!(is_builtin, bool); key!(linker); - key!(ar); key!(pre_link_args, link_args); key!(pre_link_objects_exe, list); key!(pre_link_objects_dll, list); @@ -732,6 +733,7 @@ impl Target { key!(crt_static_respected, bool); key!(stack_probes, bool); key!(min_global_align, Option); + key!(default_codegen_units, Option); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -872,7 +874,6 @@ impl ToJson for Target { target_option_val!(is_builtin); target_option_val!(linker); - target_option_val!(ar); target_option_val!(link_args - pre_link_args); target_option_val!(pre_link_objects_exe); target_option_val!(pre_link_objects_dll); @@ -924,6 +925,7 @@ impl ToJson for Target { target_option_val!(crt_static_respected); target_option_val!(stack_probes); target_option_val!(min_global_align); + target_option_val!(default_codegen_units); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs index 9227a96e750..509a7cf5e03 100644 --- a/src/librustc_back/target/msp430_none_elf.rs +++ b/src/librustc_back/target/msp430_none_elf.rs @@ -48,6 +48,11 @@ pub fn target() -> TargetResult { // code because of the extra costs it involves. relocation_model: "static".to_string(), + // Right now we invoke an external assembler and this isn't + // compatible with multiple codegen units, and plus we probably + // don't want to invoke that many gcc instances. + default_codegen_units: Some(1), + .. Default::default( ) } }) diff --git a/src/librustc_back/target/wasm32_experimental_emscripten.rs b/src/librustc_back/target/wasm32_experimental_emscripten.rs index 71668444d9a..a261c982b3f 100644 --- a/src/librustc_back/target/wasm32_experimental_emscripten.rs +++ b/src/librustc_back/target/wasm32_experimental_emscripten.rs @@ -25,7 +25,6 @@ pub fn target() -> Result { let opts = TargetOptions { linker: cmd("emcc"), - ar: cmd("emar"), dynamic_linking: false, executables: true, diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index e6584addf4a..197c1f7a4da 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -22,7 +22,6 @@ pub fn target() -> Result { let opts = TargetOptions { linker: cmd("emcc"), - ar: cmd("emar"), dynamic_linking: false, executables: true, diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index 42a4e6f5f11..64df6624dd1 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -21,37 +21,6 @@ pub fn opts() -> TargetOptions { TargetOptions { function_sections: true, linker: "link.exe".to_string(), - // When taking a look at the value of this `ar` field, one might expect - // `lib.exe` to be the value here! The `lib.exe` program is the default - // tool for managing `.lib` archives on Windows, but unfortunately the - // compiler cannot use it. - // - // To recap, we use `ar` here to manage rlibs (which are just archives). - // LLVM does not expose bindings for modifying archives so we have to - // invoke this utility for write operations (e.g. deleting files, adding - // files, etc). Normally archives only have object files within them, - // but the compiler also uses archives for storing metadata and - // compressed bytecode, so we don't exactly fall within "normal use - // cases". - // - // MSVC's `lib.exe` tool by default will choke when adding a non-object - // file to an archive, which we do on a regular basis, making it - // inoperable for us. Luckily, however, LLVM has already rewritten `ar` - // in the form of `llvm-ar` which is built by default when we build - // LLVM. This tool, unlike `lib.exe`, works just fine with non-object - // files, so we use it instead. - // - // Note that there's a few caveats associated with this: - // - // * This still requires that the *linker* (the consumer of rlibs) will - // ignore non-object files. Thankfully `link.exe` on Windows does - // indeed ignore non-object files in archives. - // * This requires `llvm-ar.exe` to be distributed with the compiler - // itself, but we already make sure of this elsewhere. - // - // Perhaps one day we won't even need this tool at all and we'll just be - // able to make library calls into LLVM! - ar: "llvm-ar.exe".to_string(), dynamic_linking: true, executables: true, dll_prefix: "".to_string(), diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index ab5a6f71ebc..18f6380b6ee 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -16,7 +16,6 @@ pub fn target() -> TargetResult { base.cpu = "x86-64".to_string(); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); - base.ar = "x86_64-rumprun-netbsd-ar".to_string(); base.max_atomic_width = Some(64); base.dynamic_linking = false; diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs b/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs new file mode 100644 index 00000000000..70382032836 --- /dev/null +++ b/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs @@ -0,0 +1,35 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use LinkerFlavor; +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_base::opts(); + base.cpu = "x86-64".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string()); + base.stack_probes = true; + base.has_elf_tls = false; + + Ok(Target { + llvm_target: "x86_64-unknown-linux-gnux32".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index 25f02537490..4c09a9e003d 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -15,5 +15,6 @@ syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } rustc_mir = { path = "../librustc_mir" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index fea662e21fa..6ce5afd4bf1 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -770,7 +770,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let lp = opt_loan_path(&assignee_cmt).unwrap(); self.move_data.each_assignment_of(assignment_id, &lp, |assign| { if assignee_cmt.mutbl.is_mutable() { - self.tcx().used_mut_nodes.borrow_mut().insert(local_id); + let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id); + self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); } else { self.bccx.report_reassigned_immutable_variable( assignment_span, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index a58b62ba2a7..1827ddabe4e 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -442,13 +442,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { wrapped_path = match current_path.kind { LpVar(local_id) => { if !through_borrow { - self.tcx().used_mut_nodes.borrow_mut().insert(local_id); + let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id); + self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); } None } LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { - let local_id = self.tcx().hir.hir_to_node_id(var_id); - self.tcx().used_mut_nodes.borrow_mut().insert(local_id); + self.bccx.used_mut_nodes.borrow_mut().insert(var_id); None } LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) | diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index a3f1340d429..d29250ac57c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -20,6 +20,7 @@ pub use self::MovedValueUseKind::*; use self::InteriorKind::*; +use rustc::hir::HirId; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::cfg; @@ -27,6 +28,7 @@ use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; +use rustc::middle::borrowck::BorrowCheckResult; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; @@ -37,7 +39,9 @@ use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; +use rustc::util::nodemap::FxHashSet; +use std::cell::RefCell; use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; @@ -54,6 +58,8 @@ pub mod gather_loans; pub mod move_data; +mod unused; + #[derive(Clone, Copy)] pub struct LoanDataFlowOperator; @@ -79,7 +85,9 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { +fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) + -> Rc +{ debug!("borrowck(body_owner_def_id={:?})", owner_def_id); let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); @@ -91,7 +99,9 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { // those things (notably the synthesized constructors from // tuple structs/variants) do not have an associated body // and do not need borrowchecking. - return; + return Rc::new(BorrowCheckResult { + used_mut_nodes: FxHashSet(), + }) } _ => { } } @@ -100,7 +110,14 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { let tables = tcx.typeck_tables_of(owner_def_id); let region_scope_tree = tcx.region_scope_tree(owner_def_id); let body = tcx.hir.body(body_id); - let bccx = &mut BorrowckCtxt { tcx, tables, region_scope_tree, owner_def_id, body }; + let mut bccx = BorrowckCtxt { + tcx, + tables, + region_scope_tree, + owner_def_id, + body, + used_mut_nodes: RefCell::new(FxHashSet()), + }; // Eventually, borrowck will always read the MIR, but at the // moment we do not. So, for now, we always force MIR to be @@ -118,14 +135,19 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { if let Some(AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves }) = - build_borrowck_dataflow_data(bccx, false, body_id, + build_borrowck_dataflow_data(&mut bccx, false, body_id, |bccx| { cfg = Some(cfg::CFG::new(bccx.tcx, &body)); cfg.as_mut().unwrap() }) { - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); + check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } + unused::check(&mut bccx, body); + + Rc::new(BorrowCheckResult { + used_mut_nodes: bccx.used_mut_nodes.into_inner(), + }) } fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>, @@ -198,7 +220,14 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let tables = tcx.typeck_tables_of(owner_def_id); let region_scope_tree = tcx.region_scope_tree(owner_def_id); let body = tcx.hir.body(body_id); - let mut bccx = BorrowckCtxt { tcx, tables, region_scope_tree, owner_def_id, body }; + let mut bccx = BorrowckCtxt { + tcx, + tables, + region_scope_tree, + owner_def_id, + body, + used_mut_nodes: RefCell::new(FxHashSet()), + }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg); (bccx, dataflow_data.unwrap()) @@ -219,6 +248,8 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { owner_def_id: DefId, body: &'tcx hir::Body, + + used_mut_nodes: RefCell>, } impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { @@ -614,11 +645,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let partial = moved_lp.depth() > lp.depth(); let msg = if !has_fork && partial { "partially " } else if has_fork && !has_common { "collaterally "} - else { "" }; - let mut err = struct_span_err!( - self.tcx.sess, use_span, E0382, - "{} of {}moved value: `{}`", - verb, msg, nl); + else { "" }; + let mut err = self.cannot_act_on_moved_value(use_span, + verb, + msg, + &format!("{}", nl), + Origin::Ast); let need_note = match lp.ty.sty { ty::TypeVariants::TyClosure(id, _) => { let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); @@ -698,10 +730,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { &self, span: Span, lp: &LoanPath<'tcx>) { - span_err!( - self.tcx.sess, span, E0383, - "partial reinitialization of uninitialized structure `{}`", - self.loan_path_to_string(lp)); + self.cannot_partially_reinit_an_uninit_struct(span, + &self.loan_path_to_string(lp), + Origin::Ast) + .emit(); } pub fn report_reassigned_immutable_variable(&self, @@ -759,11 +791,24 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let mut db = match err.cause { MutabilityViolation => { - self.cannot_assign(error_span, &descr, Origin::Ast) + let mut db = self.cannot_assign(error_span, &descr, Origin::Ast); + if let mc::NoteClosureEnv(upvar_id) = err.cmt.note { + let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let sp = self.tcx.hir.span(node_id); + match self.tcx.sess.codemap().span_to_snippet(sp) { + Ok(snippet) => { + let msg = &format!("consider making `{}` mutable", snippet); + db.span_suggestion(sp, msg, format!("mut {}", snippet)); + } + _ => { + db.span_help(sp, "consider making this binding mutable"); + } + } + } + db } BorrowViolation(euv::ClosureCapture(_)) => { - struct_span_err!(self.tcx.sess, error_span, E0595, - "closure cannot assign to {}", descr) + self.closure_cannot_assign_to_borrowed(error_span, &descr, Origin::Ast) } BorrowViolation(euv::OverloadedOperator) | BorrowViolation(euv::AddrOf) | @@ -772,8 +817,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - struct_span_err!(self.tcx.sess, error_span, E0596, - "cannot borrow {} as mutable", descr) + self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast) } BorrowViolation(euv::ClosureInvocation) => { span_bug!(err.span, @@ -855,21 +899,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some((yield_span, _)) = maybe_borrow_across_yield { debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span); - struct_span_err!(self.tcx.sess, - error_span, - E0626, - "borrow may still be in use when generator yields") - .span_label(yield_span, "possible yield occurs here") + self.cannot_borrow_across_generator_yield(error_span, yield_span, Origin::Ast) .emit(); return; } - let mut db = struct_span_err!(self.tcx.sess, - error_span, - E0597, - "{} does not live long enough", - msg); - + let mut db = self.path_does_not_live_long_enough(error_span, &msg, Origin::Ast); let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => ("temporary value", "temporary value created here"), @@ -978,11 +1013,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { let descr = self.cmt_to_path_or_string(&err.cmt); - let mut db = struct_span_err!(self.tcx.sess, error_span, E0598, - "lifetime of {} is too short to guarantee \ - its contents can be safely reborrowed", - descr); - + let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast); let descr = match opt_loan_path(&err.cmt) { Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) @@ -1054,12 +1085,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let blame = cmt.immutability_blame(); let mut err = match blame { Some(ImmutabilityBlame::ClosureEnv(id)) => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0387, - "{} in a captured outer variable in an `Fn` closure", prefix); - // FIXME: the distinction between these 2 messages looks wrong. - let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind { + let help_msg = if let BorrowViolation(euv::ClosureCapture(_)) = kind { // The aliasability violation with closure captures can // happen for nested closures, so we know the enclosing // closure incorrectly accepts an `Fn` while it needs to @@ -1070,15 +1097,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { "consider changing this closure to take self by mutable reference" }; let node_id = self.tcx.hir.def_index_to_node_id(id); - err.span_help(self.tcx.hir.span(node_id), help); - err + let help_span = self.tcx.hir.span(node_id); + self.cannot_act_on_capture_in_sharable_fn(span, + prefix, + (help_span, help_msg), + Origin::Ast) } _ => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0389, - "{} in a `&` reference", prefix); - err.span_label(span, "assignment into an immutable reference"); - err + self.cannot_assign_into_immutable_reference(span, prefix, + Origin::Ast) } }; self.note_immutability_blame(&mut err, blame); @@ -1230,17 +1257,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Err(_) => format!("move || ") }; - struct_span_err!(self.tcx.sess, err.span, E0373, - "closure may outlive the current function, \ - but it borrows {}, \ - which is owned by the current function", - cmt_path_or_string) - .span_label(capture_span, - format!("{} is borrowed here", - cmt_path_or_string)) - .span_label(err.span, - format!("may outlive borrowed value {}", - cmt_path_or_string)) + self.cannot_capture_in_long_lived_closure(err.span, + &cmt_path_or_string, + capture_span, + Origin::Ast) .span_suggestion(err.span, &format!("to force the closure to take ownership of {} \ (and any other referenced variables), \ diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs new file mode 100644 index 00000000000..228824b663d --- /dev/null +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -0,0 +1,118 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; +use rustc::hir::{self, HirId}; +use rustc::lint::builtin::UNUSED_MUT; +use rustc::ty; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc_back::slice; +use syntax::ptr::P; + +use borrowck::BorrowckCtxt; + +pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) { + let mut used_mut = bccx.used_mut_nodes.borrow().clone(); + UsedMutFinder { + bccx, + set: &mut used_mut, + }.visit_expr(&body.value); + let mut cx = UnusedMutCx { bccx, used_mut }; + for arg in body.arguments.iter() { + cx.check_unused_mut_pat(slice::ref_slice(&arg.pat)); + } + cx.visit_expr(&body.value); +} + +struct UsedMutFinder<'a, 'tcx: 'a> { + bccx: &'a BorrowckCtxt<'a, 'tcx>, + set: &'a mut FxHashSet, +} + +struct UnusedMutCx<'a, 'tcx: 'a> { + bccx: &'a BorrowckCtxt<'a, 'tcx>, + used_mut: FxHashSet, +} + +impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { + fn check_unused_mut_pat(&self, pats: &[P]) { + let tcx = self.bccx.tcx; + let mut mutables = FxHashMap(); + for p in pats { + p.each_binding(|_, id, span, path1| { + let name = path1.node; + + // Skip anything that looks like `_foo` + if name.as_str().starts_with("_") { + return + } + + // Skip anything that looks like `&foo` or `&mut foo`, only look + // for by-value bindings + let hir_id = tcx.hir.node_to_hir_id(id); + let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) { + Some(&bm) => bm, + None => span_bug!(span, "missing binding mode"), + }; + match bm { + ty::BindByValue(hir::MutMutable) => {} + _ => return, + } + + mutables.entry(name).or_insert(Vec::new()).push((id, hir_id, span)); + }); + } + + for (_name, ids) in mutables { + // If any id for this name was used mutably then consider them all + // ok, so move on to the next + if ids.iter().any(|&(_, ref id, _)| self.used_mut.contains(id)) { + continue + } + + let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' '); + + // Ok, every name wasn't used mutably, so issue a warning that this + // didn't need to be mutable. + tcx.struct_span_lint_node(UNUSED_MUT, + ids[0].0, + ids[0].2, + "variable does not need to be mutable") + .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) + .emit(); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir) + } + + fn visit_arm(&mut self, arm: &hir::Arm) { + self.check_unused_mut_pat(&arm.pats) + } + + fn visit_local(&mut self, local: &hir::Local) { + self.check_unused_mut_pat(slice::ref_slice(&local.pat)); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir) + } + + fn visit_nested_body(&mut self, id: hir::BodyId) { + let def_id = self.bccx.tcx.hir.body_owner_def_id(id); + self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned()); + self.visit_body(self.bccx.tcx.hir.body(id)); + } +} diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 031dbcb1ebb..3fea01443be 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -9,472 +9,3 @@ // except according to those terms. #![allow(non_snake_case)] - -register_long_diagnostics! { - -E0373: r##" -This error occurs when an attempt is made to use data captured by a closure, -when that data may no longer exist. It's most commonly seen when attempting to -return a closure: - -```compile_fail,E0373 -fn foo() -> Box u32> { - let x = 0u32; - Box::new(|y| x + y) -} -``` - -Notice that `x` is stack-allocated by `foo()`. By default, Rust captures -closed-over data by reference. This means that once `foo()` returns, `x` no -longer exists. An attempt to access `x` within the closure would thus be -unsafe. - -Another situation where this might be encountered is when spawning threads: - -```compile_fail,E0373 -fn foo() { - let x = 0u32; - let y = 1u32; - - let thr = std::thread::spawn(|| { - x + y - }); -} -``` - -Since our new thread runs in parallel, the stack frame containing `x` and `y` -may well have disappeared by the time we try to use them. Even if we call -`thr.join()` within foo (which blocks until `thr` has completed, ensuring the -stack frame won't disappear), we will not succeed: the compiler cannot prove -that this behaviour is safe, and so won't let us do it. - -The solution to this problem is usually to switch to using a `move` closure. -This approach moves (or copies, where possible) data into the closure, rather -than taking references to it. For example: - -``` -fn foo() -> Box u32> { - let x = 0u32; - Box::new(move |y| x + y) -} -``` - -Now that the closure has its own copy of the data, there's no need to worry -about safety. -"##, - -E0382: r##" -This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. For example: - -```compile_fail,E0382 -struct MyStruct { s: u32 } - -fn main() { - let mut x = MyStruct{ s: 5u32 }; - let y = x; - x.s = 6; - println!("{}", x.s); -} -``` - -Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out -of `x` when we set `y`. This is fundamental to Rust's ownership system: outside -of workarounds like `Rc`, a value cannot be owned by more than one variable. - -If we own the type, the easiest way to address this problem is to implement -`Copy` and `Clone` on it, as shown below. This allows `y` to copy the -information in `x`, while leaving the original version owned by `x`. Subsequent -changes to `x` will not be reflected when accessing `y`. - -``` -#[derive(Copy, Clone)] -struct MyStruct { s: u32 } - -fn main() { - let mut x = MyStruct{ s: 5u32 }; - let y = x; - x.s = 6; - println!("{}", x.s); -} -``` - -Alternatively, if we don't control the struct's definition, or mutable shared -ownership is truly required, we can use `Rc` and `RefCell`: - -``` -use std::cell::RefCell; -use std::rc::Rc; - -struct MyStruct { s: u32 } - -fn main() { - let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); - let y = x.clone(); - x.borrow_mut().s = 6; - println!("{}", x.borrow().s); -} -``` - -With this approach, x and y share ownership of the data via the `Rc` (reference -count type). `RefCell` essentially performs runtime borrow checking: ensuring -that at most one writer or multiple readers can access the data at any one time. - -If you wish to learn more about ownership in Rust, start with the chapter in the -Book: - -https://doc.rust-lang.org/book/first-edition/ownership.html -"##, - -E0383: r##" -This error occurs when an attempt is made to partially reinitialize a -structure that is currently uninitialized. - -For example, this can happen when a drop has taken place: - -```compile_fail,E0383 -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); // `x` is now uninitialized -x.a = 2; // error, partial reinitialization of uninitialized structure `t` -``` - -This error can be fixed by fully reinitializing the structure in question: - -``` -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); -x = Foo { a: 2 }; -``` -"##, - -/*E0386: r##" -This error occurs when an attempt is made to mutate the target of a mutable -reference stored inside an immutable container. - -For example, this can happen when storing a `&mut` inside an immutable `Box`: - -```compile_fail,E0386 -let mut x: i64 = 1; -let y: Box<_> = Box::new(&mut x); -**y = 2; // error, cannot assign to data in an immutable container -``` - -This error can be fixed by making the container mutable: - -``` -let mut x: i64 = 1; -let mut y: Box<_> = Box::new(&mut x); -**y = 2; -``` - -It can also be fixed by using a type with interior mutability, such as `Cell` -or `RefCell`: - -``` -use std::cell::Cell; - -let x: i64 = 1; -let y: Box> = Box::new(Cell::new(x)); -y.set(2); -``` -"##,*/ - -E0387: r##" -This error occurs when an attempt is made to mutate or mutably reference data -that a closure has captured immutably. Examples of this error are shown below: - -```compile_fail,E0387 -// Accepts a function or a closure that captures its environment immutably. -// Closures passed to foo will not be able to mutate their closed-over state. -fn foo(f: F) { } - -// Attempts to mutate closed-over data. Error message reads: -// `cannot assign to data in a captured outer variable...` -fn mutable() { - let mut x = 0u32; - foo(|| x = 2); -} - -// Attempts to take a mutable reference to closed-over data. Error message -// reads: `cannot borrow data mutably in a captured outer variable...` -fn mut_addr() { - let mut x = 0u32; - foo(|| { let y = &mut x; }); -} -``` - -The problem here is that foo is defined as accepting a parameter of type `Fn`. -Closures passed into foo will thus be inferred to be of type `Fn`, meaning that -they capture their context immutably. - -If the definition of `foo` is under your control, the simplest solution is to -capture the data mutably. This can be done by defining `foo` to take FnMut -rather than Fn: - -``` -fn foo(f: F) { } -``` - -Alternatively, we can consider using the `Cell` and `RefCell` types to achieve -interior mutability through a shared reference. Our example's `mutable` -function could be redefined as below: - -``` -use std::cell::Cell; - -fn foo(f: F) { } - -fn mutable() { - let x = Cell::new(0u32); - foo(|| x.set(2)); -} -``` - -You can read more about cell types in the API documentation: - -https://doc.rust-lang.org/std/cell/ -"##, - -E0388: r##" -E0388 was removed and is no longer issued. -"##, - -E0389: r##" -An attempt was made to mutate data using a non-mutable reference. This -commonly occurs when attempting to assign to a non-mutable reference of a -mutable reference (`&(&mut T)`). - -Example of erroneous code: - -```compile_fail,E0389 -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - let fancy_ref = &(&mut fancy); - fancy_ref.num = 6; // error: cannot assign to data in a `&` reference - println!("{}", fancy_ref.num); -} -``` - -Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an -immutable reference to a value borrows it immutably. There can be multiple -references of type `&(&mut T)` that point to the same value, so they must be -immutable to prevent multiple mutable references to the same value. - -To fix this, either remove the outer reference: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut fancy; - // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` - -Or make the outer reference mutable: - -``` -struct FancyNum { - num: u8 -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut (&mut fancy); - // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` -"##, - -E0595: r##" -Closures cannot mutate immutable captured variables. - -Erroneous code example: - -```compile_fail,E0595 -let x = 3; // error: closure cannot assign to immutable local variable `x` -let mut c = || { x += 1 }; -``` - -Make the variable binding mutable: - -``` -let mut x = 3; // ok! -let mut c = || { x += 1 }; -``` -"##, - -E0596: r##" -This error occurs because you tried to mutably borrow a non-mutable variable. - -Example of erroneous code: - -```compile_fail,E0596 -let x = 1; -let y = &mut x; // error: cannot borrow mutably -``` - -In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it -fails. To fix this error, you need to make `x` mutable: - -``` -let mut x = 1; -let y = &mut x; // ok! -``` -"##, - -E0597: r##" -This error occurs because a borrow was made inside a variable which has a -greater lifetime than the borrowed one. - -Example of erroneous code: - -```compile_fail,E0597 -struct Foo<'a> { - x: Option<&'a u32>, -} - -let mut x = Foo { x: None }; -let y = 0; -x.x = Some(&y); // error: `y` does not live long enough -``` - -In here, `x` is created before `y` and therefore has a greater lifetime. Always -keep in mind that values in a scope are dropped in the opposite order they are -created. So to fix the previous example, just make the `y` lifetime greater than -the `x`'s one: - -``` -struct Foo<'a> { - x: Option<&'a u32>, -} - -let y = 0; -let mut x = Foo { x: None }; -x.x = Some(&y); -``` -"##, - -E0626: r##" -This error occurs because a borrow in a generator persists across a -yield point. - -```compile_fail,E0626 -# #![feature(generators, generator_trait)] -# use std::ops::Generator; -let mut b = || { - let a = &String::new(); // <-- This borrow... - yield (); // ...is still in scope here, when the yield occurs. - println!("{}", a); -}; -b.resume(); -``` - -At present, it is not permitted to have a yield that occurs while a -borrow is still in scope. To resolve this error, the borrow must -either be "contained" to a smaller scope that does not overlap the -yield or else eliminated in another way. So, for example, we might -resolve the previous example by removing the borrow and just storing -the integer by value: - -``` -# #![feature(generators, generator_trait)] -# use std::ops::Generator; -let mut b = || { - let a = 3; - yield (); - println!("{}", a); -}; -b.resume(); -``` - -This is a very simple case, of course. In more complex cases, we may -wish to have more than one reference to the value that was borrowed -- -in those cases, something like the `Rc` or `Arc` types may be useful. - -This error also frequently arises with iteration: - -```compile_fail,E0626 -# #![feature(generators, generator_trait)] -# use std::ops::Generator; -let mut b = || { - let v = vec![1,2,3]; - for &x in &v { // <-- borrow of `v` is still in scope... - yield x; // ...when this yield occurs. - } -}; -b.resume(); -``` - -Such cases can sometimes be resolved by iterating "by value" (or using -`into_iter()`) to avoid borrowing: - -``` -# #![feature(generators, generator_trait)] -# use std::ops::Generator; -let mut b = || { - let v = vec![1,2,3]; - for x in v { // <-- Take ownership of the values instead! - yield x; // <-- Now yield is OK. - } -}; -b.resume(); -``` - -If taking ownership is not an option, using indices can work too: - -``` -# #![feature(generators, generator_trait)] -# use std::ops::Generator; -let mut b = || { - let v = vec![1,2,3]; - let len = v.len(); // (*) - for i in 0..len { - let x = v[i]; // (*) - yield x; // <-- Now yield is OK. - } -}; -b.resume(); - -// (*) -- Unfortunately, these temporaries are currently required. -// See . -``` -"##, - -} - -register_diagnostics! { -// E0385, // {} in an aliasable location - E0598, // lifetime of {} is too short to guarantee its contents can be... -} diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 9bedbfed5db..78aacd49f80 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,12 +16,12 @@ #![allow(non_camel_case_types)] #![feature(quote)] -#![feature(rustc_diagnostic_macros)] #[macro_use] extern crate log; -#[macro_use] extern crate syntax; +extern crate syntax; extern crate syntax_pos; extern crate rustc_errors as errors; +extern crate rustc_back; // for "clarity", rename the graphviz crate to dot; graphviz within `borrowck` // refers to the borrowck-specific graphviz adapter traits. @@ -33,14 +33,8 @@ extern crate rustc_mir; pub use borrowck::check_crate; pub use borrowck::build_borrowck_dataflow_data_for_fn; -// NB: This module needs to be declared first so diagnostics are -// registered before they are used. -mod diagnostics; - mod borrowck; pub mod graphviz; pub use borrowck::provide; - -__build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS } diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 474622f3669..56d5f5ffa3f 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -31,7 +31,7 @@ //! be indexed by the direction (see the type `Direction`). use bitvec::BitVector; -use std::fmt::{Formatter, Error, Debug}; +use std::fmt::Debug; use std::usize; use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; @@ -48,6 +48,7 @@ pub struct Node { pub data: N, } +#[derive(Debug)] pub struct Edge { next_edge: [EdgeIndex; 2], // see module comment source: NodeIndex, @@ -69,18 +70,6 @@ impl SnapshotVecDelegate for Edge { fn reverse(_: &mut Vec>, _: ()) {} } -impl Debug for Edge { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, - "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", - self.next_edge[0], - self.next_edge[1], - self.source, - self.target, - self.data) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct NodeIndex(pub usize); diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 4b7f55eba06..6c5a37aa1e5 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -40,39 +40,80 @@ impl Idx for u32 { #[macro_export] macro_rules! newtype_index { + // ---- public rules ---- + + // Use default constants ($name:ident) => ( - newtype_index!($name, unsafe { ::std::intrinsics::type_name::<$name>() }); + newtype_index!( + @type[$name] + @max[::std::u32::MAX] + @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]); ); - ($name:ident, $debug_name:expr) => ( + // Define any constants + ($name:ident { $($tokens:tt)+ }) => ( + newtype_index!( + @type[$name] + @max[::std::u32::MAX] + @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }] + $($tokens)+); + ); + + // ---- private rules ---- + + // Base case, user-defined constants (if any) have already been defined + (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => ( #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, - RustcEncodable, RustcDecodable)] - pub struct $name(u32); + RustcEncodable, RustcDecodable)] + pub struct $type(u32); - impl $name { - // HACK use for constants - #[allow(unused)] - const fn const_new(x: u32) -> Self { - $name(x) - } - } - - impl Idx for $name { + impl Idx for $type { fn new(value: usize) -> Self { - assert!(value < (::std::u32::MAX) as usize); - $name(value as u32) + assert!(value < ($max) as usize); + $type(value as u32) } fn index(self) -> usize { self.0 as usize } } - impl ::std::fmt::Debug for $name { + impl ::std::fmt::Debug for $type { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(fmt, "{}{}", $debug_name, self.0) } } - ) + ); + + // Rewrite final without comma to one that includes comma + (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr] + $name:ident = $constant:expr) => ( + newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $name = $constant,); + ); + + // Rewrite final const without comma to one that includes comma + (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr] + const $name:ident = $constant:expr) => ( + newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] const $name = $constant,); + ); + + // Replace existing default for max + (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr] + MAX = $max:expr, $($tokens:tt)*) => ( + newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $(tokens)*); + ); + + // Replace existing default for debug_name + (@type[$type:ident] @max[$max:expr] @debug_name[$_debug_name:expr] + DEBUG_NAME = $debug_name:expr, $($tokens:tt)*) => ( + newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*); + ); + + // Assign a user-defined constant (as final param) + (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr] + const $name:ident = $constant:expr, $($tokens:tt)*) => ( + pub const $name: $type = $type($constant); + newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*); + ); } #[derive(Clone, PartialEq, Eq)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6bdad0b212c..3514302c6c8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1238,7 +1238,7 @@ pub fn monitor(f: F) { errors::Level::Note); } - writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap(); + eprintln!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); } exit_on_err(); @@ -1259,7 +1259,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry { let mut all_errors = Vec::new(); all_errors.extend_from_slice(&rustc::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); #[cfg(feature="llvm")] diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 0270e3618e2..0cb920a111d 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -13,12 +13,12 @@ //! we will compare the fingerprint from the current and from the previous //! compilation session as appropriate: //! -//! - `#[rustc_dirty(label="TypeckTables", cfg="rev2")]` if we are +//! - `#[rustc_clean(cfg="rev2", except="TypeckTables")]` if we are //! in `#[cfg(rev2)]`, then the fingerprints associated with //! `DepNode::TypeckTables(X)` must be DIFFERENT (`X` is the def-id of the //! current node). -//! - `#[rustc_clean(label="TypeckTables", cfg="rev2")]` same as above, -//! except that the fingerprints must be the SAME. +//! - `#[rustc_clean(cfg="rev2")]` same as above, except that the +//! fingerprints must be the SAME (along with all other fingerprints). //! //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. @@ -40,9 +40,12 @@ //! use std::collections::HashSet; +use std::iter::FromIterator; use std::vec::Vec; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, label_strs}; use rustc::hir; +use rustc::hir::{Item_ as HirItem, ImplItemKind, TraitItemKind}; +use rustc::hir::map::Node as HirNode; use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; @@ -53,11 +56,183 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax_pos::Span; use rustc::ty::TyCtxt; -const LABEL: &'static str = "label"; -const CFG: &'static str = "cfg"; +const EXCEPT: &str = "except"; +const LABEL: &str = "label"; +const CFG: &str = "cfg"; + +// Base and Extra labels to build up the labels + +/// For typedef, constants, and statics +const BASE_CONST: &[&str] = &[ + label_strs::TypeOfItem, +]; + +/// DepNodes for functions + methods +const BASE_FN: &[&str] = &[ + // Callers will depend on the signature of these items, so we better test + label_strs::FnSignature, + label_strs::GenericsOfItem, + label_strs::PredicatesOfItem, + label_strs::TypeOfItem, + + // And a big part of compilation (that we eventually want to cache) is type inference + // information: + label_strs::TypeckTables, +]; + +/// DepNodes for Hir, which is pretty much everything +const BASE_HIR: &[&str] = &[ + // Hir and HirBody should be computed for all nodes + label_strs::Hir, + label_strs::HirBody, +]; + +/// `impl` implementation of struct/trait +const BASE_IMPL: &[&str] = &[ + label_strs::AssociatedItemDefIds, + label_strs::GenericsOfItem, + label_strs::ImplTraitRef, +]; + +/// DepNodes for MirValidated/Optimized, which is relevant in "executable" +/// code, i.e. functions+methods +const BASE_MIR: &[&str] = &[ + label_strs::MirOptimized, + label_strs::MirValidated, +]; + +/// Struct, Enum and Union DepNodes +/// +/// Note that changing the type of a field does not change the type of the struct or enum, but +/// adding/removing fields or changing a fields name or visibility does. +const BASE_STRUCT: &[&str] = &[ + label_strs::GenericsOfItem, + label_strs::PredicatesOfItem, + label_strs::TypeOfItem, +]; + +/// Trait Definition DepNodes +const BASE_TRAIT_DEF: &[&str] = &[ + label_strs::AssociatedItemDefIds, + label_strs::GenericsOfItem, + label_strs::ObjectSafety, + label_strs::PredicatesOfItem, + label_strs::SpecializationGraph, + label_strs::TraitDefOfItem, + label_strs::TraitImpls, +]; + +/// extra DepNodes for methods (+fn) +const EXTRA_ASSOCIATED: &[&str] = &[ + label_strs::AssociatedItems, +]; + +const EXTRA_TRAIT: &[&str] = &[ + label_strs::TraitOfItem, +]; + +// Fully Built Labels + +const LABELS_CONST: &[&[&str]] = &[ + BASE_HIR, + BASE_CONST, +]; + +/// Constant/Typedef in an impl +const LABELS_CONST_IN_IMPL: &[&[&str]] = &[ + BASE_HIR, + BASE_CONST, + EXTRA_ASSOCIATED, +]; + +/// Trait-Const/Typedef DepNodes +const LABELS_CONST_IN_TRAIT: &[&[&str]] = &[ + BASE_HIR, + BASE_CONST, + EXTRA_ASSOCIATED, + EXTRA_TRAIT, +]; + +/// Function DepNode +const LABELS_FN: &[&[&str]] = &[ + BASE_HIR, + BASE_MIR, + BASE_FN, +]; + +/// Method DepNodes +const LABELS_FN_IN_IMPL: &[&[&str]] = &[ + BASE_HIR, + BASE_MIR, + BASE_FN, + EXTRA_ASSOCIATED, +]; + +/// Trait-Method DepNodes +const LABELS_FN_IN_TRAIT: &[&[&str]] = &[ + BASE_HIR, + BASE_MIR, + BASE_FN, + EXTRA_ASSOCIATED, + EXTRA_TRAIT, +]; + +/// For generic cases like inline-assemply/mod/etc +const LABELS_HIR_ONLY: &[&[&str]] = &[ + BASE_HIR, +]; + +/// Impl DepNodes +const LABELS_IMPL: &[&[&str]] = &[ + BASE_HIR, + BASE_IMPL, +]; + +/// Abstract Data Type (Struct, Enum, Unions) DepNodes +const LABELS_ADT: &[&[&str]] = &[ + BASE_HIR, + BASE_STRUCT, +]; + +/// Trait Definition DepNodes +#[allow(dead_code)] +const LABELS_TRAIT: &[&[&str]] = &[ + BASE_HIR, + BASE_TRAIT_DEF, +]; + + +// FIXME: Struct/Enum/Unions Fields (there is currently no way to attach these) +// +// Fields are kind of separate from their containers, as they can change independently from +// them. We should at least check +// +// TypeOfItem for these. type Labels = HashSet; +/// Represents the requested configuration by rustc_clean/dirty +struct Assertion { + clean: Labels, + dirty: Labels, +} + +impl Assertion { + fn from_clean_labels(labels: Labels) -> Assertion { + Assertion { + clean: labels, + dirty: Labels::new(), + } + } + + fn from_dirty_labels(labels: Labels) -> Assertion { + Assertion { + clean: Labels::new(), + dirty: labels, + } + } +} + pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature if !tcx.sess.features.borrow().rustc_attrs { @@ -91,14 +266,189 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn labels(&self, attr: &Attribute) -> Labels { + + /// Possibly "deserialize" the attribute into a clean/dirty assertion + fn assertion_maybe(&mut self, item_id: ast::NodeId, attr: &Attribute) + -> Option + { + let is_clean = if attr.check_name(ATTR_DIRTY) { + false + } else if attr.check_name(ATTR_CLEAN) { + true + } else { + // skip: not rustc_clean/dirty + return None + }; + if !check_config(self.tcx, attr) { + // skip: not the correct `cfg=` + return None; + } + let assertion = if let Some(labels) = self.labels(attr) { + if is_clean { + Assertion::from_clean_labels(labels) + } else { + Assertion::from_dirty_labels(labels) + } + } else { + self.assertion_auto(item_id, attr, is_clean) + }; + Some(assertion) + } + + /// Get the "auto" assertion on pre-validated attr, along with the `except` labels + fn assertion_auto(&mut self, item_id: ast::NodeId, attr: &Attribute, is_clean: bool) + -> Assertion + { + let (name, mut auto) = self.auto_labels(item_id, attr); + let except = self.except(attr); + for e in except.iter() { + if !auto.remove(e) { + let msg = format!( + "`except` specified DepNodes that can not be affected for \"{}\": \"{}\"", + name, + e + ); + self.tcx.sess.span_fatal(attr.span, &msg); + } + } + if is_clean { + Assertion { + clean: auto, + dirty: except, + } + } else { + Assertion { + clean: except, + dirty: auto, + } + } + } + + fn labels(&self, attr: &Attribute) -> Option { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { + let value = expect_associated_value(self.tcx, &item); + return Some(self.resolve_labels(&item, value.as_str().as_ref())); + } + } + None + } + + /// `except=` attribute value + fn except(&self, attr: &Attribute) -> Labels { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.check_name(EXCEPT) { let value = expect_associated_value(self.tcx, &item); return self.resolve_labels(&item, value.as_str().as_ref()); } } - self.tcx.sess.span_fatal(attr.span, "no `label` found"); + // if no `label` or `except` is given, only the node's group are asserted + Labels::new() + } + + /// Return all DepNode labels that should be asserted for this item. + /// index=0 is the "name" used for error messages + fn auto_labels(&mut self, item_id: ast::NodeId, attr: &Attribute) -> (&'static str, Labels) { + let node = self.tcx.hir.get(item_id); + let (name, labels) = match node { + HirNode::NodeItem(item) => { + match item.node { + // note: these are in the same order as hir::Item_; + // FIXME(michaelwoerister): do commented out ones + + // // An `extern crate` item, with optional original crate name, + // HirItem::ItemExternCrate(..), // intentionally no assertions + + // // `use foo::bar::*;` or `use foo::bar::baz as quux;` + // HirItem::ItemUse(..), // intentionally no assertions + + // A `static` item + HirItem::ItemStatic(..) => ("ItemStatic", LABELS_CONST), + + // A `const` item + HirItem::ItemConst(..) => ("ItemConst", LABELS_CONST), + + // A function declaration + HirItem::ItemFn(..) => ("ItemFn", LABELS_FN), + + // // A module + HirItem::ItemMod(..) =>("ItemMod", LABELS_HIR_ONLY), + + // // An external module + HirItem::ItemForeignMod(..) => ("ItemForeignMod", LABELS_HIR_ONLY), + + // Module-level inline assembly (from global_asm!) + HirItem::ItemGlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY), + + // A type alias, e.g. `type Foo = Bar` + HirItem::ItemTy(..) => ("ItemTy", LABELS_HIR_ONLY), + + // An enum definition, e.g. `enum Foo {C, D}` + HirItem::ItemEnum(..) => ("ItemEnum", LABELS_ADT), + + // A struct definition, e.g. `struct Foo {x: A}` + HirItem::ItemStruct(..) => ("ItemStruct", LABELS_ADT), + + // A union definition, e.g. `union Foo {x: A, y: B}` + HirItem::ItemUnion(..) => ("ItemUnion", LABELS_ADT), + + // Represents a Trait Declaration + // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of + // the depnodes don't exist (because they legitametely didn't need to be + // calculated) + // + // michaelwoerister and vitiral came up with a possible solution, + // to just do this before every query + // ``` + // ::rustc::ty::maps::plumbing::force_from_dep_node(tcx, dep_node) + // ``` + // + // However, this did not seem to work effectively and more bugs were hit. + // Nebie @vitiral gave up :) + // + //HirItem::ItemTrait(..) => ("ItemTrait", LABELS_TRAIT), + + // `impl Trait for .. {}` + HirItem::ItemDefaultImpl(..) => ("ItemDefaultImpl", LABELS_IMPL), + + // An implementation, eg `impl Trait for Foo { .. }` + HirItem::ItemImpl(..) => ("ItemImpl", LABELS_IMPL), + + _ => self.tcx.sess.span_fatal( + attr.span, + &format!( + "clean/dirty auto-assertions not yet defined for NodeItem.node={:?}", + item.node + ) + ), + } + }, + HirNode::NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(..) => ("NodeTraitItem", LABELS_FN_IN_TRAIT), + TraitItemKind::Const(..) => ("NodeTraitConst", LABELS_CONST_IN_TRAIT), + TraitItemKind::Type(..) => ("NodeTraitType", LABELS_CONST_IN_TRAIT), + } + }, + HirNode::NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL), + ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL), + ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), + } + }, + _ => self.tcx.sess.span_fatal( + attr.span, + &format!( + "clean/dirty auto-assertions not yet defined for {:?}", + node + ) + ), + }; + let labels = Labels::from_iter( + labels.iter().flat_map(|s| s.iter().map(|l| l.to_string())) + ); + (name, labels) } fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels { @@ -174,22 +524,16 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { fn check_item(&mut self, item_id: ast::NodeId, item_span: Span) { let def_id = self.tcx.hir.local_def_id(item_id); for attr in self.tcx.get_attrs(def_id).iter() { - if attr.check_name(ATTR_DIRTY) { - if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - let labels = self.labels(attr); - for dep_node in self.dep_nodes(&labels, def_id) { - self.assert_dirty(item_span, dep_node); - } - } - } else if attr.check_name(ATTR_CLEAN) { - if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - let labels = self.labels(attr); - for dep_node in self.dep_nodes(&labels, def_id) { - self.assert_clean(item_span, dep_node); - } - } + let assertion = match self.assertion_maybe(item_id, attr) { + Some(a) => a, + None => continue, + }; + self.checked_attrs.insert(attr.id); + for dep_node in self.dep_nodes(&assertion.clean, def_id) { + self.assert_clean(item_span, dep_node); + } + for dep_node in self.dep_nodes(&assertion.dirty, def_id) { + self.assert_dirty(item_span, dep_node); } } } @@ -363,21 +707,42 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { /// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan /// for a `cfg="foo"` attribute and check whether we have a cfg /// flag called `foo`. +/// +/// Also make sure that the `label` and `except` fields do not +/// both exist. fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); + let (mut cfg, mut except, mut label) = (None, false, false); for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(CFG) { let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); - return config.contains(&(value, None)); + cfg = Some(config.contains(&(value, None))); + } + if item.check_name(LABEL) { + label = true; + } + if item.check_name(EXCEPT) { + except = true; } } - tcx.sess.span_fatal( - attr.span, - "no cfg attribute"); + if label && except { + tcx.sess.span_fatal( + attr.span, + "must specify only one of: `label`, `except`" + ); + } + + match cfg { + None => tcx.sess.span_fatal( + attr.span, + "no cfg attribute" + ), + Some(c) => c, + } } fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index 13b019af2ea..7d1400b6b95 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -117,7 +117,7 @@ fn report_format_mismatch(sess: &Session, file: &Path, message: &str) { debug!("read_file: {}", message); if sess.opts.debugging_opts.incremental_info { - eprintln!("incremental: ignoring cache artifact `{}`: {}", + println!("[incremental] ignoring cache artifact `{}`: {}", file.file_name().unwrap().to_string_lossy(), message); } diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 9b12b755581..d53ee5c804f 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -256,11 +256,12 @@ pub fn prepare_session_directory(sess: &Session, debug!("attempting to copy data from source: {}", source_directory.display()); - let print_file_copy_stats = sess.opts.debugging_opts.incremental_info; + // Try copying over all files from the source directory - if let Ok(allows_links) = copy_files(&session_dir, &source_directory, - print_file_copy_stats) { + if let Ok(allows_links) = copy_files(sess, + &session_dir, + &source_directory) { debug!("successfully copied data from: {}", source_directory.display()); @@ -390,9 +391,9 @@ pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> { Ok(()) } -fn copy_files(target_dir: &Path, - source_dir: &Path, - print_stats_on_success: bool) +fn copy_files(sess: &Session, + target_dir: &Path, + source_dir: &Path) -> Result { // We acquire a shared lock on the lock file of the directory, so that // nobody deletes it out from under us while we are reading from it. @@ -440,9 +441,11 @@ fn copy_files(target_dir: &Path, } } - if print_stats_on_success { - eprintln!("incremental: session directory: {} files hard-linked", files_linked); - eprintln!("incremental: session directory: {} files copied", files_copied); + if sess.opts.debugging_opts.incremental_info { + println!("[incremental] session directory: \ + {} files hard-linked", files_linked); + println!("[incremental] session directory: \ + {} files copied", files_copied); } Ok(files_linked > 0 || files_copied == 0) diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index cdfc9f2edc3..63cfbcac145 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -177,8 +177,8 @@ pub fn load_dep_graph(sess: &Session) -> PreviousDepGraph { if prev_commandline_args_hash != sess.opts.dep_tracking_hash() { if sess.opts.debugging_opts.incremental_info { - eprintln!("incremental: completely ignoring cache because of \ - differing commandline arguments"); + println!("[incremental] completely ignoring cache because of \ + differing commandline arguments"); } // We can't reuse the cache, purge it. debug!("load_dep_graph_new: differing commandline arg hashes"); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 4919870fcd5..b9f73500e27 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepGraph; +use rustc::dep_graph::{DepGraph, DepKind}; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; @@ -170,6 +170,77 @@ fn encode_dep_graph(tcx: TyCtxt, // Encode the graph data. let serialized_graph = tcx.dep_graph.serialize(); + + if tcx.sess.opts.debugging_opts.incremental_info { + #[derive(Clone)] + struct Stat { + kind: DepKind, + node_counter: u64, + edge_counter: u64, + } + + let total_node_count = serialized_graph.nodes.len(); + let total_edge_count = serialized_graph.edge_list_data.len(); + + let mut counts: FxHashMap<_, Stat> = FxHashMap(); + + for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() { + let stat = counts.entry(node.kind).or_insert(Stat { + kind: node.kind, + node_counter: 0, + edge_counter: 0, + }); + + stat.node_counter += 1; + let (edge_start, edge_end) = serialized_graph.edge_list_indices[i]; + stat.edge_counter += (edge_end - edge_start) as u64; + } + + let mut counts: Vec<_> = counts.values().cloned().collect(); + counts.sort_by_key(|s| -(s.node_counter as i64)); + + let percentage_of_all_nodes: Vec = counts.iter().map(|s| { + (100.0 * (s.node_counter as f64)) / (total_node_count as f64) + }).collect(); + + let average_edges_per_kind: Vec = counts.iter().map(|s| { + (s.edge_counter as f64) / (s.node_counter as f64) + }).collect(); + + println!("[incremental]"); + println!("[incremental] DepGraph Statistics"); + + const SEPARATOR: &str = "[incremental] --------------------------------\ + ----------------------------------------------\ + ------------"; + + println!("{}", SEPARATOR); + println!("[incremental]"); + println!("[incremental] Total Node Count: {}", total_node_count); + println!("[incremental] Total Edge Count: {}", total_edge_count); + println!("[incremental]"); + println!("[incremental] {:<36}| {:<17}| {:<12}| {:<17}|", + "Node Kind", + "Node Frequency", + "Node Count", + "Avg. Edge Count"); + println!("[incremental] -------------------------------------\ + |------------------\ + |-------------\ + |------------------|"); + + for (i, stat) in counts.iter().enumerate() { + println!("[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |", + format!("{:?}", stat.kind), + percentage_of_all_nodes[i], + stat.node_counter, + average_edges_per_kind[i]); + } + + println!("{}", SEPARATOR); + println!("[incremental]"); + } + serialized_graph.encode(encoder)?; Ok(()) diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index c3c5461ff7c..cebf52d5af7 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -12,7 +12,6 @@ test = false [dependencies] log = "0.3" rustc = { path = "../librustc" } -rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index fbf993f4557..4ba7f7aa951 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,7 +38,6 @@ extern crate syntax; extern crate rustc; #[macro_use] extern crate log; -extern crate rustc_back; extern crate rustc_const_eval; extern crate syntax_pos; @@ -129,7 +128,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NonUpperCaseGlobals, NonShorthandFieldPatterns, UnsafeCode, - UnusedMut, UnusedAllocation, MissingCopyImplementations, UnstableFeatures, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index e2ade19b6e2..a058f84e588 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -11,105 +11,18 @@ use rustc::hir::def_id::DefId; use rustc::ty; use rustc::ty::adjustment; -use util::nodemap::FxHashMap; use lint::{LateContext, EarlyContext, LintContext, LintArray}; use lint::{LintPass, EarlyLintPass, LateLintPass}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; - use syntax::ast; use syntax::attr; use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType}; -use syntax::symbol::keywords; -use syntax::ptr::P; use syntax::print::pprust; +use syntax::symbol::keywords; use syntax::util::parser; use syntax_pos::Span; -use rustc_back::slice; use rustc::hir; -use rustc::hir::intravisit::FnKind; - -declare_lint! { - pub UNUSED_MUT, - Warn, - "detect mut variables which don't need to be mutable" -} - -#[derive(Copy, Clone)] -pub struct UnusedMut; - -impl UnusedMut { - fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P]) { - // collect all mutable pattern and group their NodeIDs by their Identifier to - // avoid false warnings in match arms with multiple patterns - - let mut mutables = FxHashMap(); - for p in pats { - p.each_binding(|_, id, span, path1| { - let hir_id = cx.tcx.hir.node_to_hir_id(id); - let bm = match cx.tables.pat_binding_modes().get(hir_id) { - Some(&bm) => bm, - None => span_bug!(span, "missing binding mode"), - }; - let name = path1.node; - if let ty::BindByValue(hir::MutMutable) = bm { - if !name.as_str().starts_with("_") { - match mutables.entry(name) { - Vacant(entry) => { - entry.insert(vec![id]); - } - Occupied(mut entry) => { - entry.get_mut().push(id); - } - } - } - } - }); - } - - let used_mutables = cx.tcx.used_mut_nodes.borrow(); - for (_, v) in &mutables { - if !v.iter().any(|e| used_mutables.contains(e)) { - let binding_span = cx.tcx.hir.span(v[0]); - let mut_span = cx.tcx.sess.codemap().span_until_char(binding_span, ' '); - let mut err = cx.struct_span_lint(UNUSED_MUT, - binding_span, - "variable does not need to be mutable"); - err.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()); - err.emit(); - } - } - } -} - -impl LintPass for UnusedMut { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_MUT) - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut { - fn check_arm(&mut self, cx: &LateContext, a: &hir::Arm) { - self.check_unused_mut_pat(cx, &a.pats) - } - - fn check_local(&mut self, cx: &LateContext, l: &hir::Local) { - self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); - } - - fn check_fn(&mut self, - cx: &LateContext, - _: FnKind, - _: &hir::FnDecl, - body: &hir::Body, - _: Span, - _: ast::NodeId) { - for a in &body.arguments { - self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); - } - } -} declare_lint! { pub UNUSED_MUST_USE, diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index de5add56b76..a9566c4bcac 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -18,4 +18,4 @@ rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index db6a0ee4ba5..ff923ce259f 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, TyCtxt, ParamEnv}; use rustc::ty::maps::Providers; -use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue}; +use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local}; use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind}; use rustc::mir::transform::{MirSource}; @@ -586,7 +586,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> context: Context, (lvalue, span): (&Lvalue<'gcx>, Span), flow_state: &InProgress<'b, 'gcx>) { - let move_data = flow_state.inits.base_results.operator().move_data(); + let move_data = self.move_data; // determine if this path has a non-mut owner (and thus needs checking). let mut l = lvalue; @@ -611,7 +611,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } - if let Some(mpi) = self.move_path_for_lvalue(context, move_data, lvalue) { + if let Some(mpi) = self.move_path_for_lvalue(lvalue) { if flow_state.inits.curr_state.contains(&mpi) { // may already be assigned before reaching this statement; // report error. @@ -642,21 +642,107 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> let lvalue = self.base_path(lvalue_span.0); let maybe_uninits = &flow_state.uninits; - let move_data = maybe_uninits.base_results.operator().move_data(); - if let Some(mpi) = self.move_path_for_lvalue(context, move_data, lvalue) { - if maybe_uninits.curr_state.contains(&mpi) { - // find and report move(s) that could cause this to be uninitialized + + // Bad scenarios: + // + // 1. Move of `a.b.c`, use of `a.b.c` + // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`) + // 3. Move of `a.b.c`, use of `a` or `a.b` + // 4. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with + // partial initialization support, one might have `a.x` + // initialized but not `a.b`. + // + // OK scenarios: + // + // 5. Move of `a.b.c`, use of `a.b.d` + // 6. Uninitialized `a.x`, initialized `a.b`, use of `a.b` + // 7. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` + // must have been initialized for the use to be sound. + // 8. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` + + // The dataflow tracks shallow prefixes distinctly (that is, + // field-accesses on P distinctly from P itself), in order to + // track substructure initialization separately from the whole + // structure. + // + // E.g., when looking at (*a.b.c).d, if the closest prefix for + // which we have a MovePath is `a.b`, then that means that the + // initialization state of `a.b` is all we need to inspect to + // know if `a.b.c` is valid (and from that we infer that the + // dereference and `.d` access is also valid, since we assume + // `a.b.c` is assigned a reference to a initialized and + // well-formed record structure.) + + // Therefore, if we seek out the *closest* prefix for which we + // have a MovePath, that should capture the initialization + // state for the lvalue scenario. + // + // This code covers scenarios 1, 2, and 4. + + debug!("check_if_path_is_moved part1 lvalue: {:?}", lvalue); + match self.move_path_closest_to(lvalue) { + Ok(mpi) => { + if maybe_uninits.curr_state.contains(&mpi) { + self.report_use_of_moved(context, desired_action, lvalue_span); + return; // don't bother finding other problems. + } + } + Err(NoMovePathFound::ReachedStatic) => { + // Okay: we do not build MoveData for static variables + } + + // Only query longest prefix with a MovePath, not further + // ancestors; dataflow recurs on children when parents + // move (to support partial (re)inits). + // + // (I.e. querying parents breaks scenario 8; but may want + // to do such a query based on partial-init feature-gate.) + } + + // A move of any shallow suffix of `lvalue` also interferes + // with an attempt to use `lvalue`. This is scenario 3 above. + // + // (Distinct from handling of scenarios 1+2+4 above because + // `lvalue` does not interfere with suffixes of its prefixes, + // e.g. `a.b.c` does not interfere with `a.b.d`) + + debug!("check_if_path_is_moved part2 lvalue: {:?}", lvalue); + if let Some(mpi) = self.move_path_for_lvalue(lvalue) { + if let Some(_) = maybe_uninits.has_any_child_of(mpi) { self.report_use_of_moved(context, desired_action, lvalue_span); - } else { - // sanity check: initialized on *some* path, right? - assert!(flow_state.inits.curr_state.contains(&mpi)); + return; // don't bother finding other problems. } } } + /// Currently MoveData does not store entries for all lvalues in + /// the input MIR. For example it will currently filter out + /// lvalues that are Copy; thus we do not track lvalues of shared + /// reference type. This routine will walk up an lvalue along its + /// prefixes, searching for a foundational lvalue that *is* + /// tracked in the MoveData. + /// + /// An Err result includes a tag indicated why the search failed. + /// Currenly this can only occur if the lvalue is built off of a + /// static variable, as we do not track those in the MoveData. + fn move_path_closest_to(&mut self, lvalue: &Lvalue<'gcx>) + -> Result + { + let mut last_prefix = lvalue; + for prefix in self.prefixes(lvalue, PrefixSet::All) { + if let Some(mpi) = self.move_path_for_lvalue(prefix) { + return Ok(mpi); + } + last_prefix = prefix; + } + match *last_prefix { + Lvalue::Local(_) => panic!("should have move path for every Local"), + Lvalue::Projection(_) => panic!("PrefixSet::All meant dont stop for Projection"), + Lvalue::Static(_) => return Err(NoMovePathFound::ReachedStatic), + } + } + fn move_path_for_lvalue(&mut self, - _context: Context, - move_data: &MoveData<'gcx>, lvalue: &Lvalue<'gcx>) -> Option { @@ -664,7 +750,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> // to a direct owner of `lvalue` (which means there is nothing // that borrowck tracks for its analysis). - match move_data.rev_lookup.find(lvalue) { + match self.move_data.rev_lookup.find(lvalue) { LookupResult::Parent(_) => None, LookupResult::Exact(mpi) => Some(mpi), } @@ -733,6 +819,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum NoMovePathFound { + ReachedStatic, +} + impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { fn each_borrow_involving_path(&mut self, _context: Context, @@ -846,12 +937,19 @@ mod prefixes { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) enum PrefixSet { + /// Doesn't stop until it returns the base case (a Local or + /// Static prefix). All, + /// Stops at any dereference. Shallow, + /// Stops at the deref of a shared reference. Supporting, } impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { + /// Returns an iterator over the prefixes of `lvalue` + /// (inclusive) from longest to smallest, potentially + /// terminating the iteration early based on `kind`. pub(super) fn prefixes<'d>(&self, lvalue: &'d Lvalue<'gcx>, kind: PrefixSet) @@ -1080,49 +1178,52 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> // End-user visible description of `lvalue` fn describe_lvalue(&self, lvalue: &Lvalue) -> String { let mut buf = String::new(); - self.append_lvalue_to_string(lvalue, &mut buf); + self.append_lvalue_to_string(lvalue, &mut buf, None); buf } // Appends end-user visible description of `lvalue` to `buf`. - fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String) { + fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option) { match *lvalue { Lvalue::Local(local) => { - let local = &self.mir.local_decls[local]; - match local.name { - Some(name) => buf.push_str(&format!("{}", name)), - None => buf.push_str("_"), - } + self.append_local_to_string(local, buf, "_"); } Lvalue::Static(ref static_) => { buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id))); } Lvalue::Projection(ref proj) => { + let mut autoderef = autoderef.unwrap_or(false); let (prefix, suffix, index_operand) = match proj.elem { - ProjectionElem::Deref => - ("(*", format!(")"), None), + ProjectionElem::Deref => { + if autoderef { + ("", format!(""), None) + } else { + ("(*", format!(")"), None) + } + }, ProjectionElem::Downcast(..) => ("", format!(""), None), // (dont emit downcast info) - ProjectionElem::Field(field, _ty) => - ("", format!(".{}", field.index()), None), // FIXME: report name of field - ProjectionElem::Index(index) => - ("", format!(""), Some(index)), - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => - ("", format!("[{} of {}]", offset, min_length), None), - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => - ("", format!("[-{} of {}]", offset, min_length), None), - ProjectionElem::Subslice { from, to: 0 } => - ("", format!("[{}:]", from), None), - ProjectionElem::Subslice { from: 0, to } => - ("", format!("[:-{}]", to), None), - ProjectionElem::Subslice { from, to } => - ("", format!("[{}:-{}]", from, to), None), + ProjectionElem::Field(field, _ty) => { + autoderef = true; + ("", format!(".{}", self.describe_field(&proj.base, field.index())), None) + }, + ProjectionElem::Index(index) => { + autoderef = true; + ("", format!(""), Some(index)) + }, + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { + autoderef = true; + // Since it isn't possible to borrow an element on a particular index and + // then use another while the borrow is held, don't output indices details + // to avoid confusing the end-user + ("", format!("[..]"), None) + }, }; buf.push_str(prefix); - self.append_lvalue_to_string(&proj.base, buf); + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); if let Some(index) = index_operand { buf.push_str("["); - self.append_lvalue_to_string(&Lvalue::Local(index), buf); + self.append_local_to_string(index, buf, ".."); buf.push_str("]"); } else { buf.push_str(&suffix); @@ -1131,6 +1232,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } + // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have + // a name, then `none_string` is appended instead + fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) { + let local = &self.mir.local_decls[local_index]; + match local.name { + Some(name) => buf.push_str(&format!("{}", name)), + None => buf.push_str(none_string) + } + } + + // End-user visible description of the `field_index`nth field of `base` + fn describe_field(&self, base: &Lvalue, field_index: usize) -> String { + match *base { + Lvalue::Local(local) => { + let local = &self.mir.local_decls[local]; + self.describe_field_from_ty(&local.ty, field_index) + }, + Lvalue::Static(ref static_) => { + self.describe_field_from_ty(&static_.ty, field_index) + }, + Lvalue::Projection(ref proj) => { + match proj.elem { + ProjectionElem::Deref => + self.describe_field(&proj.base, field_index), + ProjectionElem::Downcast(def, variant_index) => + format!("{}", def.variants[variant_index].fields[field_index].name), + ProjectionElem::Field(_, field_type) => + self.describe_field_from_ty(&field_type, field_index), + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => + format!("{}", self.describe_field(&proj.base, field_index)), + } + } + } + } + + // End-user visible description of the `field_index`nth field of `ty` + fn describe_field_from_ty(&self, ty: &ty::Ty, field_index: usize) -> String { + if ty.is_box() { + // If the type is a box, the field is described from the boxed type + self.describe_field_from_ty(&ty.boxed_ty(), field_index) + } + else { + match ty.sty { + ty::TyAdt(def, _) => { + if def.is_enum() { + format!("{}", field_index) + } + else { + format!("{}", def.struct_variant().fields[field_index].name) + } + }, + ty::TyTuple(_, _) => { + format!("{}", field_index) + }, + ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => { + self.describe_field_from_ty(&tnm.ty, field_index) + }, + ty::TyArray(ty, _) | ty::TySlice(ty) => { + self.describe_field_from_ty(&ty, field_index) + } + _ => { + // Might need a revision when the fields in trait RFC is implemented + // (https://github.com/rust-lang/rfcs/pull/1546) + bug!("End-user description not implemented for field access on `{:?}`", ty.sty); + } + } + } + } + // Retrieve span of given borrow from the current MIR representation fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span { self.mir.source_info(borrow.location).span @@ -1266,6 +1438,35 @@ impl<'b, 'tcx: 'b> InProgress<'b, 'tcx> { } } +impl<'b, 'tcx> FlowInProgress> { + fn has_any_child_of(&self, mpi: MovePathIndex) -> Option { + let move_data = self.base_results.operator().move_data(); + + let mut todo = vec![mpi]; + let mut push_siblings = false; // don't look at siblings of original `mpi`. + while let Some(mpi) = todo.pop() { + if self.curr_state.contains(&mpi) { + return Some(mpi); + } + let move_path = &move_data.move_paths[mpi]; + if let Some(child) = move_path.first_child { + todo.push(child); + } + if push_siblings { + if let Some(sibling) = move_path.next_sibling { + todo.push(sibling); + } + } else { + // after we've processed the original `mpi`, we should + // always traverse the siblings of any of its + // children. + push_siblings = true; + } + } + return None; + } +} + impl FlowInProgress where BD: BitDenotation { fn each_state_bit(&self, f: F) where F: FnMut(BD::Idx) { self.curr_state.each_bit(self.base_results.operator().bits_per_block(), f) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index f04dede6e40..56c926eaa61 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -21,7 +21,7 @@ use rustc::mir::*; use rustc::hir; use hair::*; use syntax::ast::{Name, NodeId}; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; // helper functions, broken out by category: mod simplify; @@ -398,10 +398,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidates.iter().take_while(|c| c.match_pairs.is_empty()).count(); debug!("match_candidates: {:?} candidates fully matched", fully_matched); let mut unmatched_candidates = candidates.split_off(fully_matched); - for candidate in candidates { + for (index, candidate) in candidates.into_iter().enumerate() { // If so, apply any bindings, test the guard (if any), and // branch to the arm. - if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { + let is_last = index == fully_matched - 1; + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, + candidate, is_last) { block = b; } else { // if None is returned, then any remaining candidates @@ -664,7 +666,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn bind_and_guard_matched_candidate<'pat>(&mut self, mut block: BasicBlock, arm_blocks: &mut ArmBlocks, - candidate: Candidate<'pat, 'tcx>) + candidate: Candidate<'pat, 'tcx>, + is_last_arm: bool) -> Option { debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", block, candidate); @@ -685,10 +688,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); Some(otherwise) + } else if !is_last_arm { + // Add always true guard in case of more than one arm + // it creates false edges and allow MIR borrowck detects errors + // FIXME(#45184) -- permit "false edges" + let source_info = self.source_info(candidate.span); + let true_expr = Expr { + temp_lifetime: None, + ty: self.hir.tcx().types.bool, + span: DUMMY_SP, + kind: ExprKind::Literal{literal: self.hir.true_literal()}, + }; + let cond = unpack!(block = self.as_local_operand(block, true_expr)); + let otherwise = self.cfg.start_new_block(); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); + Some(otherwise) } else { let source_info = self.source_info(candidate.span); self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: arm_block }); + TerminatorKind::Goto { target: arm_block }); None } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 46a5e5abbdd..b8bb2a40462 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -149,7 +149,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) ); mir }) @@ -227,7 +227,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) ); mir }) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 645af0bff64..98c5345c69d 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -229,6 +229,57 @@ fn main() { See also https://doc.rust-lang.org/book/first-edition/unsafe.html "##, +E0373: r##" +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure: + +```compile_fail,E0373 +fn foo() -> Box u32> { + let x = 0u32; + Box::new(|y| x + y) +} +``` + +Notice that `x` is stack-allocated by `foo()`. By default, Rust captures +closed-over data by reference. This means that once `foo()` returns, `x` no +longer exists. An attempt to access `x` within the closure would thus be +unsafe. + +Another situation where this might be encountered is when spawning threads: + +```compile_fail,E0373 +fn foo() { + let x = 0u32; + let y = 1u32; + + let thr = std::thread::spawn(|| { + x + y + }); +} +``` + +Since our new thread runs in parallel, the stack frame containing `x` and `y` +may well have disappeared by the time we try to use them. Even if we call +`thr.join()` within foo (which blocks until `thr` has completed, ensuring the +stack frame won't disappear), we will not succeed: the compiler cannot prove +that this behaviour is safe, and so won't let us do it. + +The solution to this problem is usually to switch to using a `move` closure. +This approach moves (or copies, where possible) data into the closure, rather +than taking references to it. For example: + +``` +fn foo() -> Box u32> { + let x = 0u32; + Box::new(move |y| x + y) +} +``` + +Now that the closure has its own copy of the data, there's no need to worry +about safety. +"##, + E0381: r##" It is not allowed to use or capture an uninitialized variable. For example: @@ -250,6 +301,104 @@ fn main() { ``` "##, +E0382: r##" +This error occurs when an attempt is made to use a variable after its contents +have been moved elsewhere. For example: + +```compile_fail,E0382 +struct MyStruct { s: u32 } + +fn main() { + let mut x = MyStruct{ s: 5u32 }; + let y = x; + x.s = 6; + println!("{}", x.s); +} +``` + +Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out +of `x` when we set `y`. This is fundamental to Rust's ownership system: outside +of workarounds like `Rc`, a value cannot be owned by more than one variable. + +If we own the type, the easiest way to address this problem is to implement +`Copy` and `Clone` on it, as shown below. This allows `y` to copy the +information in `x`, while leaving the original version owned by `x`. Subsequent +changes to `x` will not be reflected when accessing `y`. + +``` +#[derive(Copy, Clone)] +struct MyStruct { s: u32 } + +fn main() { + let mut x = MyStruct{ s: 5u32 }; + let y = x; + x.s = 6; + println!("{}", x.s); +} +``` + +Alternatively, if we don't control the struct's definition, or mutable shared +ownership is truly required, we can use `Rc` and `RefCell`: + +``` +use std::cell::RefCell; +use std::rc::Rc; + +struct MyStruct { s: u32 } + +fn main() { + let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); + let y = x.clone(); + x.borrow_mut().s = 6; + println!("{}", x.borrow().s); +} +``` + +With this approach, x and y share ownership of the data via the `Rc` (reference +count type). `RefCell` essentially performs runtime borrow checking: ensuring +that at most one writer or multiple readers can access the data at any one time. + +If you wish to learn more about ownership in Rust, start with the chapter in the +Book: + +https://doc.rust-lang.org/book/first-edition/ownership.html +"##, + +E0383: r##" +This error occurs when an attempt is made to partially reinitialize a +structure that is currently uninitialized. + +For example, this can happen when a drop has taken place: + +```compile_fail,E0383 +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); // `x` is now uninitialized +x.a = 2; // error, partial reinitialization of uninitialized structure `t` +``` + +This error can be fixed by fully reinitializing the structure in question: + +``` +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); +x = Foo { a: 2 }; +``` +"##, + E0384: r##" This error occurs when an attempt is made to reassign an immutable variable. For example: @@ -272,6 +421,161 @@ fn main() { ``` "##, +/*E0386: r##" +This error occurs when an attempt is made to mutate the target of a mutable +reference stored inside an immutable container. + +For example, this can happen when storing a `&mut` inside an immutable `Box`: + +```compile_fail,E0386 +let mut x: i64 = 1; +let y: Box<_> = Box::new(&mut x); +**y = 2; // error, cannot assign to data in an immutable container +``` + +This error can be fixed by making the container mutable: + +``` +let mut x: i64 = 1; +let mut y: Box<_> = Box::new(&mut x); +**y = 2; +``` + +It can also be fixed by using a type with interior mutability, such as `Cell` +or `RefCell`: + +``` +use std::cell::Cell; + +let x: i64 = 1; +let y: Box> = Box::new(Cell::new(x)); +y.set(2); +``` +"##,*/ + +E0387: r##" +This error occurs when an attempt is made to mutate or mutably reference data +that a closure has captured immutably. Examples of this error are shown below: + +```compile_fail,E0387 +// Accepts a function or a closure that captures its environment immutably. +// Closures passed to foo will not be able to mutate their closed-over state. +fn foo(f: F) { } + +// Attempts to mutate closed-over data. Error message reads: +// `cannot assign to data in a captured outer variable...` +fn mutable() { + let mut x = 0u32; + foo(|| x = 2); +} + +// Attempts to take a mutable reference to closed-over data. Error message +// reads: `cannot borrow data mutably in a captured outer variable...` +fn mut_addr() { + let mut x = 0u32; + foo(|| { let y = &mut x; }); +} +``` + +The problem here is that foo is defined as accepting a parameter of type `Fn`. +Closures passed into foo will thus be inferred to be of type `Fn`, meaning that +they capture their context immutably. + +If the definition of `foo` is under your control, the simplest solution is to +capture the data mutably. This can be done by defining `foo` to take FnMut +rather than Fn: + +``` +fn foo(f: F) { } +``` + +Alternatively, we can consider using the `Cell` and `RefCell` types to achieve +interior mutability through a shared reference. Our example's `mutable` +function could be redefined as below: + +``` +use std::cell::Cell; + +fn foo(f: F) { } + +fn mutable() { + let x = Cell::new(0u32); + foo(|| x.set(2)); +} +``` + +You can read more about cell types in the API documentation: + +https://doc.rust-lang.org/std/cell/ +"##, + +E0388: r##" +E0388 was removed and is no longer issued. +"##, + +E0389: r##" +An attempt was made to mutate data using a non-mutable reference. This +commonly occurs when attempting to assign to a non-mutable reference of a +mutable reference (`&(&mut T)`). + +Example of erroneous code: + +```compile_fail,E0389 +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + let fancy_ref = &(&mut fancy); + fancy_ref.num = 6; // error: cannot assign to data in a `&` reference + println!("{}", fancy_ref.num); +} +``` + +Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an +immutable reference to a value borrows it immutably. There can be multiple +references of type `&(&mut T)` that point to the same value, so they must be +immutable to prevent multiple mutable references to the same value. + +To fix this, either remove the outer reference: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut fancy; + // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` + +Or make the outer reference mutable: + +``` +struct FancyNum { + num: u8 +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut (&mut fancy); + // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` +"##, E0394: r##" A static was referred to by value by another static. @@ -1265,12 +1569,169 @@ fn main() { ``` "##, +E0595: r##" +Closures cannot mutate immutable captured variables. + +Erroneous code example: + +```compile_fail,E0595 +let x = 3; // error: closure cannot assign to immutable local variable `x` +let mut c = || { x += 1 }; +``` + +Make the variable binding mutable: + +``` +let mut x = 3; // ok! +let mut c = || { x += 1 }; +``` +"##, + +E0596: r##" +This error occurs because you tried to mutably borrow a non-mutable variable. + +Example of erroneous code: + +```compile_fail,E0596 +let x = 1; +let y = &mut x; // error: cannot borrow mutably +``` + +In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it +fails. To fix this error, you need to make `x` mutable: + +``` +let mut x = 1; +let y = &mut x; // ok! +``` +"##, + +E0597: r##" +This error occurs because a borrow was made inside a variable which has a +greater lifetime than the borrowed one. + +Example of erroneous code: + +```compile_fail,E0597 +struct Foo<'a> { + x: Option<&'a u32>, +} + +let mut x = Foo { x: None }; +let y = 0; +x.x = Some(&y); // error: `y` does not live long enough +``` + +In here, `x` is created before `y` and therefore has a greater lifetime. Always +keep in mind that values in a scope are dropped in the opposite order they are +created. So to fix the previous example, just make the `y` lifetime greater than +the `x`'s one: + +``` +struct Foo<'a> { + x: Option<&'a u32>, +} + +let y = 0; +let mut x = Foo { x: None }; +x.x = Some(&y); +``` +"##, + +E0626: r##" +This error occurs because a borrow in a generator persists across a +yield point. + +```compile_fail,E0626 +# #![feature(generators, generator_trait)] +# use std::ops::Generator; +let mut b = || { + let a = &String::new(); // <-- This borrow... + yield (); // ...is still in scope here, when the yield occurs. + println!("{}", a); +}; +b.resume(); +``` + +At present, it is not permitted to have a yield that occurs while a +borrow is still in scope. To resolve this error, the borrow must +either be "contained" to a smaller scope that does not overlap the +yield or else eliminated in another way. So, for example, we might +resolve the previous example by removing the borrow and just storing +the integer by value: + +``` +# #![feature(generators, generator_trait)] +# use std::ops::Generator; +let mut b = || { + let a = 3; + yield (); + println!("{}", a); +}; +b.resume(); +``` + +This is a very simple case, of course. In more complex cases, we may +wish to have more than one reference to the value that was borrowed -- +in those cases, something like the `Rc` or `Arc` types may be useful. + +This error also frequently arises with iteration: + +```compile_fail,E0626 +# #![feature(generators, generator_trait)] +# use std::ops::Generator; +let mut b = || { + let v = vec![1,2,3]; + for &x in &v { // <-- borrow of `v` is still in scope... + yield x; // ...when this yield occurs. + } +}; +b.resume(); +``` + +Such cases can sometimes be resolved by iterating "by value" (or using +`into_iter()`) to avoid borrowing: + +``` +# #![feature(generators, generator_trait)] +# use std::ops::Generator; +let mut b = || { + let v = vec![1,2,3]; + for x in v { // <-- Take ownership of the values instead! + yield x; // <-- Now yield is OK. + } +}; +b.resume(); +``` + +If taking ownership is not an option, using indices can work too: + +``` +# #![feature(generators, generator_trait)] +# use std::ops::Generator; +let mut b = || { + let v = vec![1,2,3]; + let len = v.len(); // (*) + for i in 0..len { + let x = v[i]; // (*) + yield x; // <-- Now yield is OK. + } +}; +b.resume(); + +// (*) -- Unfortunately, these temporaries are currently required. +// See . +``` +"##, + } register_diagnostics! { +// E0385, // {} in an aliasable location E0493, // destructors cannot be evaluated at compile-time E0524, // two closures require unique access to `..` at the same time E0526, // shuffle indices are not constant E0594, // cannot assign to {} + E0598, // lifetime of {} is too short to guarantee its contents can be... E0625, // thread-local statics cannot be accessed at compile-time } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 67a3281dba4..cea66837d9a 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -65,7 +65,18 @@ impl PassHook for DumpMir { pass_name, &Disambiguator { is_after }, source, - mir); + mir, + |_, _| Ok(()) ); + for (index, promoted_mir) in mir.promoted.iter_enumerated() { + let promoted_source = MirSource::Promoted(source.item_id(), index); + mir_util::dump_mir(tcx, + Some((suite, pass_num)), + pass_name, + &Disambiguator { is_after }, + promoted_source, + promoted_mir, + |_, _| Ok(()) ); + } } } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 729fe46ef37..7d0814b67fb 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -587,7 +587,7 @@ fn create_generator_drop_shim<'a, 'tcx>( // unrelated code from the resume part of the function simplify::remove_dead_blocks(&mut mir); - dump_mir(tcx, None, "generator_drop", &0, source, &mut mir); + dump_mir(tcx, None, "generator_drop", &0, source, &mut mir, |_, _| Ok(()) ); mir } @@ -673,7 +673,7 @@ fn create_generator_resume_function<'a, 'tcx>( // unrelated code from the drop part of the function simplify::remove_dead_blocks(mir); - dump_mir(tcx, None, "generator_resume", &0, source, mir); + dump_mir(tcx, None, "generator_resume", &0, source, mir, |_, _| Ok(()) ); } fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo { @@ -816,14 +816,14 @@ impl MirPass for StateTransform { // This is expanded to a drop ladder in `elaborate_generator_drops`. let drop_clean = insert_clean_drop(mir); - dump_mir(tcx, None, "generator_pre-elab", &0, source, mir); + dump_mir(tcx, None, "generator_pre-elab", &0, source, mir, |_, _| Ok(()) ); // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_generator_drops(tcx, def_id, mir); - dump_mir(tcx, None, "generator_post-transform", &0, source, mir); + dump_mir(tcx, None, "generator_post-transform", &0, source, mir, |_, _| Ok(()) ); // Create a copy of our MIR and use it to create the drop shim for the generator let drop_shim = create_generator_drop_shim(tcx, diff --git a/src/librustc_mir/transform/nll/infer.rs b/src/librustc_mir/transform/nll/infer.rs new file mode 100644 index 00000000000..e6e00f295ca --- /dev/null +++ b/src/librustc_mir/transform/nll/infer.rs @@ -0,0 +1,222 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{Region, RegionIndex}; +use std::mem; +use rustc::infer::InferCtxt; +use rustc::mir::{Location, Mir}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::fx::FxHashSet; + +pub struct InferenceContext { + definitions: IndexVec, + constraints: IndexVec, + errors: IndexVec, +} + +pub struct InferenceError { + pub constraint_point: Location, + pub name: (), // FIXME(nashenas88) RegionName +} + +newtype_index!(InferenceErrorIndex); + +struct VarDefinition { + name: (), // FIXME(nashenas88) RegionName + value: Region, + capped: bool, +} + +impl VarDefinition { + pub fn new(value: Region) -> Self { + Self { + name: (), + value, + capped: false, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Constraint { + sub: RegionIndex, + sup: RegionIndex, + point: Location, +} + +newtype_index!(ConstraintIndex); + +impl InferenceContext { + pub fn new(values: IndexVec) -> Self { + Self { + definitions: values.into_iter().map(VarDefinition::new).collect(), + constraints: IndexVec::new(), + errors: IndexVec::new(), + } + } + + #[allow(dead_code)] + pub fn cap_var(&mut self, v: RegionIndex) { + self.definitions[v].capped = true; + } + + #[allow(dead_code)] + pub fn add_live_point(&mut self, v: RegionIndex, point: Location) { + debug!("add_live_point({:?}, {:?})", v, point); + let definition = &mut self.definitions[v]; + if definition.value.add_point(point) { + if definition.capped { + self.errors.push(InferenceError { + constraint_point: point, + name: definition.name, + }); + } + } + } + + #[allow(dead_code)] + pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) { + debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point); + self.constraints.push(Constraint { sup, sub, point }); + } + + #[allow(dead_code)] + pub fn region(&self, v: RegionIndex) -> &Region { + &self.definitions[v].value + } + + pub fn solve<'a, 'gcx, 'tcx>( + &mut self, + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + mir: &'a Mir<'tcx>, + ) -> IndexVec + where + 'gcx: 'tcx + 'a, + 'tcx: 'a, + { + let mut changed = true; + let mut dfs = Dfs::new(infcx, mir); + while changed { + changed = false; + for constraint in &self.constraints { + let sub = &self.definitions[constraint.sub].value.clone(); + let sup_def = &mut self.definitions[constraint.sup]; + debug!("constraint: {:?}", constraint); + debug!(" sub (before): {:?}", sub); + debug!(" sup (before): {:?}", sup_def.value); + + if dfs.copy(sub, &mut sup_def.value, constraint.point) { + changed = true; + if sup_def.capped { + // This is kind of a hack, but when we add a + // constraint, the "point" is always the point + // AFTER the action that induced the + // constraint. So report the error on the + // action BEFORE that. + assert!(constraint.point.statement_index > 0); + let p = Location { + block: constraint.point.block, + statement_index: constraint.point.statement_index - 1, + }; + + self.errors.push(InferenceError { + constraint_point: p, + name: sup_def.name, + }); + } + } + + debug!(" sup (after) : {:?}", sup_def.value); + debug!(" changed : {:?}", changed); + } + debug!("\n"); + } + + mem::replace(&mut self.errors, IndexVec::new()) + } +} + +struct Dfs<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> { + #[allow(dead_code)] + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> { + fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { + Self { infcx, mir } + } + + fn copy( + &mut self, + from_region: &Region, + to_region: &mut Region, + start_point: Location, + ) -> bool { + let mut changed = false; + + let mut stack = vec![]; + let mut visited = FxHashSet(); + + stack.push(start_point); + while let Some(p) = stack.pop() { + debug!(" dfs: p={:?}", p); + + if !from_region.may_contain(p) { + debug!(" not in from-region"); + continue; + } + + if !visited.insert(p) { + debug!(" already visited"); + continue; + } + + changed |= to_region.add_point(p); + + let block_data = &self.mir[p.block]; + let successor_points = if p.statement_index < block_data.statements.len() { + vec![Location { + statement_index: p.statement_index + 1, + ..p + }] + } else { + block_data.terminator() + .successors() + .iter() + .map(|&basic_block| Location { + statement_index: 0, + block: basic_block, + }) + .collect::>() + }; + + if successor_points.is_empty() { + // FIXME handle free regions + // If we reach the END point in the graph, then copy + // over any skolemized end points in the `from_region` + // and make sure they are included in the `to_region`. + // for region_decl in self.infcx.tcx.tables.borrow().free_region_map() { + // // FIXME(nashenas88) figure out skolemized_end points + // let block = self.env.graph.skolemized_end(region_decl.name); + // let skolemized_end_point = Location { + // block, + // statement_index: 0, + // }; + // changed |= to_region.add_point(skolemized_end_point); + // } + } else { + stack.extend(successor_points); + } + } + + changed + } +} diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index d4a5354c78f..805e9c976e4 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -8,27 +8,35 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use self::infer::InferenceContext; use rustc::ty::TypeFoldable; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind}; use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Lookup}; use rustc::mir::transform::{MirPass, MirSource}; -use rustc::infer::{self, InferCtxt}; +use rustc::infer::{self as rustc_infer, InferCtxt}; use rustc::util::nodemap::FxHashSet; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use syntax_pos::DUMMY_SP; use std::collections::HashMap; +use std::fmt; + +use util as mir_util; +use self::mir_util::PassWhere; + +mod infer; #[allow(dead_code)] struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { lookup_map: HashMap, regions: IndexVec, - infcx: InferCtxt<'a, 'gcx, 'tcx>, + #[allow(dead_code)] + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, } impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { + pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { NLLVisitor { infcx, lookup_map: HashMap::new(), @@ -36,14 +44,14 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { } } - pub fn into_results(self) -> HashMap { - self.lookup_map + pub fn into_results(self) -> (HashMap, IndexVec) { + (self.lookup_map, self.regions) } fn renumber_regions(&mut self, value: &T) -> T where T: TypeFoldable<'tcx> { self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { self.regions.push(Region::default()); - self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP)) + self.infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) }) } @@ -134,7 +142,7 @@ pub struct NLL; impl MirPass for NLL { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, + source: MirSource, mir: &mut Mir<'tcx>) { if !tcx.sess.opts.debugging_opts.nll { return; @@ -143,16 +151,42 @@ impl MirPass for NLL { tcx.infer_ctxt().enter(|infcx| { // Clone mir so we can mutate it without disturbing the rest of the compiler let mut renumbered_mir = mir.clone(); - let mut visitor = NLLVisitor::new(infcx); + let mut visitor = NLLVisitor::new(&infcx); visitor.visit_mir(&mut renumbered_mir); - let _results = visitor.into_results(); + mir_util::dump_mir(tcx, None, "nll", &0, source, mir, |pass_where, out| { + if let PassWhere::BeforeCFG = pass_where { + for (index, value) in visitor.regions.iter_enumerated() { + writeln!(out, "// R{:03}: {:?}", index.0, value)?; + } + } + Ok(()) + }); + let (_lookup_map, regions) = visitor.into_results(); + let mut inference_context = InferenceContext::new(regions); + inference_context.solve(&infcx, &renumbered_mir); }) } } -#[derive(Clone, Debug, Default, PartialEq, Eq)] -struct Region { +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Region { points: FxHashSet, } +impl fmt::Debug for Region { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{:?}", self.points) + } +} + +impl Region { + pub fn add_point(&mut self, point: Location) -> bool { + self.points.insert(point) + } + + pub fn may_contain(&self, point: Location) -> bool { + self.points.contains(&point) + } +} + newtype_index!(RegionIndex); diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 37d53ca829e..216f6e44570 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -294,6 +294,139 @@ pub trait BorrowckErrors { err.span_label(move_from_span, "cannot move out of here"); err } + + fn cannot_act_on_moved_value(&self, + use_span: Span, + verb: &str, + optional_adverb_for_moved: &str, + moved_path: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, use_span, E0382, + "{} of {}moved value: `{}`{OGN}", + verb, optional_adverb_for_moved, moved_path, OGN=o); + err + } + + fn cannot_partially_reinit_an_uninit_struct(&self, + span: Span, + uninit_path: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, + span, + E0383, + "partial reinitialization of uninitialized structure `{}`{OGN}", + uninit_path, OGN=o); + err + } + + fn closure_cannot_assign_to_borrowed(&self, + span: Span, + descr: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, span, E0595, "closure cannot assign to {}{OGN}", + descr, OGN=o); + err + } + + fn cannot_borrow_path_as_mutable(&self, + span: Span, + path: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{OGN}", + path, OGN=o); + err + } + + fn cannot_borrow_across_generator_yield(&self, + span: Span, + yield_span: Span, + o: Origin) + -> DiagnosticBuilder + { + let mut err = struct_span_err!(self, + span, + E0626, + "borrow may still be in use when generator yields{OGN}", + OGN=o); + err.span_label(yield_span, "possible yield occurs here"); + err + } + + fn path_does_not_live_long_enough(&self, + span: Span, + path: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, span, E0597, "{} does not live long enough{OGN}", + path, OGN=o); + err + } + + fn lifetime_too_short_for_reborrow(&self, + span: Span, + path: &str, + o: Origin) + -> DiagnosticBuilder + { + let err = struct_span_err!(self, span, E0598, + "lifetime of {} is too short to guarantee \ + its contents can be safely reborrowed{OGN}", + path, OGN=o); + err + } + + fn cannot_act_on_capture_in_sharable_fn(&self, + span: Span, + bad_thing: &str, + help: (Span, &str), + o: Origin) + -> DiagnosticBuilder + { + let (help_span, help_msg) = help; + let mut err = struct_span_err!(self, span, E0387, + "{} in a captured outer variable in an `Fn` closure{OGN}", + bad_thing, OGN=o); + err.span_help(help_span, help_msg); + err + } + + fn cannot_assign_into_immutable_reference(&self, + span: Span, + bad_thing: &str, + o: Origin) + -> DiagnosticBuilder + { + let mut err = struct_span_err!(self, span, E0389, "{} in a `&` reference{OGN}", + bad_thing, OGN=o); + err.span_label(span, "assignment into an immutable reference"); + err + } + + fn cannot_capture_in_long_lived_closure(&self, + closure_span: Span, + borrowed_path: &str, + capture_span: Span, + o: Origin) + -> DiagnosticBuilder + { + let mut err = struct_span_err!(self, closure_span, E0373, + "closure may outlive the current function, \ + but it borrows {}, \ + which is owned by the current function{OGN}", + borrowed_path, OGN=o); + err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) + .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path)); + err + } } impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> { diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index e6d3a82ff9b..1424c063d73 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -232,7 +232,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(w, "{} {{{}}}", prefix, live.join(", ")) }; print(w, " ", &result.ins)?; - write_basic_block(tcx, block, mir, w)?; + write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?; print(w, " ", &result.outs)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 4b6da96824d..13c14f8920f 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -17,6 +17,6 @@ mod graphviz; mod pretty; pub mod liveness; -pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty}; +pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; pub use self::graphviz::{write_mir_graphviz}; pub use self::graphviz::write_node_label as write_graphviz_node_label; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9e1f05f6d2f..8a9047fb491 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -25,6 +25,22 @@ const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements const ALIGN: usize = 40; +/// An indication of where we are in the control flow graph. Used for printing +/// extra information in `dump_mir` +pub enum PassWhere { + /// We have not started dumping the control flow graph, but we are about to. + BeforeCFG, + + /// We just finished dumping the control flow graph. This is right before EOF + AfterCFG, + + /// We are about to start dumping the given basic block. + BeforeBlock(BasicBlock), + + /// We are just about to dumpt the given statement or terminator. + InCFG(Location), +} + /// If the session is properly configured, dumps a human-readable /// representation of the mir into: /// @@ -39,12 +55,16 @@ const ALIGN: usize = 40; /// - `substring1&substring2,...` -- `&`-separated list of substrings /// that can appear in the pass-name or the `item_path_str` for the given /// node-id. If any one of the substrings match, the data is dumped out. -pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>) { +pub fn dump_mir<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + extra_data: F) +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ if !dump_enabled(tcx, pass_name, source) { return; } @@ -53,12 +73,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(tcx.hir.local_def_id(source.item_id())) }); dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, - disambiguator, source, mir); - for (index, promoted_mir) in mir.promoted.iter_enumerated() { - let promoted_source = MirSource::Promoted(source.item_id(), index); - dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, - promoted_source, promoted_mir); - } + disambiguator, source, mir, extra_data); } pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -85,13 +100,17 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `item_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. -fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - node_path: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>) { +fn dump_matched_mir_node<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + node_path: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + mut extra_data: F) +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ let promotion_id = match source { MirSource::Promoted(_, id) => format!("-{:?}", id), MirSource::GeneratorDrop(_) => format!("-drop"), @@ -125,7 +144,9 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(file, "// generator_layout = {:?}", layout)?; } writeln!(file, "")?; - write_mir_fn(tcx, source, mir, &mut file)?; + extra_data(PassWhere::BeforeCFG, &mut file)?; + write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; + extra_data(PassWhere::AfterCFG, &mut file)?; Ok(()) }); } @@ -152,24 +173,29 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let id = tcx.hir.as_local_node_id(def_id).unwrap(); let src = MirSource::from_node(tcx, id); - write_mir_fn(tcx, src, mir, w)?; + write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?; for (i, mir) in mir.promoted.iter_enumerated() { writeln!(w, "")?; - write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?; + write_mir_fn(tcx, MirSource::Promoted(id, i), mir, &mut |_, _| Ok(()), w)?; } } Ok(()) } -pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - w: &mut Write) - -> io::Result<()> { +pub fn write_mir_fn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + extra_data: &mut F, + w: &mut Write) + -> io::Result<()> +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { - write_basic_block(tcx, block, mir, w)?; + extra_data(PassWhere::BeforeBlock(block), w)?; + write_basic_block(tcx, block, mir, extra_data, w)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; } @@ -180,11 +206,15 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block(tcx: TyCtxt, - block: BasicBlock, - mir: &Mir, - w: &mut Write) - -> io::Result<()> { +pub fn write_basic_block(tcx: TyCtxt, + block: BasicBlock, + mir: &Mir, + extra_data: &mut F, + w: &mut Write) + -> io::Result<()> +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ let data = &mir[block]; // Basic block label at the top. @@ -195,6 +225,7 @@ pub fn write_basic_block(tcx: TyCtxt, // List of statements in the middle. let mut current_location = Location { block: block, statement_index: 0 }; for statement in &data.statements { + extra_data(PassWhere::InCFG(current_location), w)?; let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); writeln!(w, "{0:1$} // {2}", indented_mir, @@ -205,6 +236,7 @@ pub fn write_basic_block(tcx: TyCtxt, } // Terminator at the bottom. + extra_data(PassWhere::InCFG(current_location), w)?; let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); writeln!(w, "{0:1$} // {2}", indented_terminator, diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index efb5b031809..14e33378969 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -152,7 +152,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { err.emit(); }); } - TyKind::TraitObject(ref bounds) => { + TyKind::TraitObject(ref bounds, ..) => { let mut any_lifetime_bounds = false; for bound in bounds { if let RegionTyParamBound(ref lifetime) = *bound { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 9193ac0fcd6..564626ac398 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -43,7 +43,7 @@ parameter if so. "##, E0154: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. Imports (`use` statements) are not allowed after non-item statements, such as variable declarations and expression statements. @@ -79,7 +79,7 @@ https://doc.rust-lang.org/reference.html#statements "##, E0251: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. Two items of the same name cannot be imported without rebinding one of the items under a new local name. @@ -268,7 +268,7 @@ fn main() { "##, E0256: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. You can't import a type or module when the name of the item being imported is the same as another type or submodule defined in the module. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 36cd69f91b9..4aab43cbec7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -137,7 +137,7 @@ enum ResolutionError<'a> { /// error E0416: identifier is bound more than once in the same pattern IdentifierBoundMoreThanOnceInSamePattern(&'a str), /// error E0426: use of undeclared label - UndeclaredLabel(&'a str), + UndeclaredLabel(&'a str, Option), /// error E0429: `self` imports are only allowed within a { } list SelfImportsOnlyAllowedWithin, /// error E0430: `self` import can only appear once in the list @@ -263,13 +263,17 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(span, "used in a pattern more than once"); err } - ResolutionError::UndeclaredLabel(name) => { + ResolutionError::UndeclaredLabel(name, lev_candidate) => { let mut err = struct_span_err!(resolver.session, span, E0426, "use of undeclared label `{}`", name); - err.span_label(span, format!("undeclared label `{}`", name)); + if let Some(lev_candidate) = lev_candidate { + err.span_label(span, format!("did you mean `{}`?", lev_candidate)); + } else { + err.span_label(span, format!("undeclared label `{}`", name)); + } err } ResolutionError::SelfImportsOnlyAllowedWithin => { @@ -1790,9 +1794,13 @@ impl<'a> Resolver<'a> { } } - /// Searches the current set of local scopes for labels. + /// Searches the current set of local scopes for labels. Returns the first non-None label that + /// is returned by the given predicate function + /// /// Stops after meeting a closure. - fn search_label(&self, mut ident: Ident) -> Option { + fn search_label(&self, mut ident: Ident, pred: P) -> Option + where P: Fn(&Rib, Ident) -> Option + { for rib in self.label_ribs.iter().rev() { match rib.kind { NormalRibKind => {} @@ -1808,9 +1816,9 @@ impl<'a> Resolver<'a> { return None; } } - let result = rib.bindings.get(&ident).cloned(); - if result.is_some() { - return result; + let r = pred(rib, ident); + if r.is_some() { + return r; } } None @@ -3202,12 +3210,20 @@ impl<'a> Resolver<'a> { } ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { - match self.search_label(label.node) { + match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) { None => { + // Search again for close matches... + // Picks the first label that is "close enough", which is not necessarily + // the closest match + let close_match = self.search_label(label.node, |rib, ident| { + let names = rib.bindings.iter().map(|(id, _)| &id.name); + find_best_match_for_name(names, &*ident.name.as_str(), None) + }); self.record_def(expr.id, err_path_resolution()); resolve_error(self, label.span, - ResolutionError::UndeclaredLabel(&label.node.name.as_str())); + ResolutionError::UndeclaredLabel(&label.node.name.as_str(), + close_match)); } Some(def @ Def::Label(_)) => { // Since this def is a label, it is never read. diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index c7e00245d63..47e5ad6c010 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -288,7 +288,7 @@ impl Sig for ast::Ty { }) } } - ast::TyKind::TraitObject(ref bounds) => { + ast::TyKind::TraitObject(ref bounds, ..) => { // FIXME recurse into bounds let nested = pprust::bounds_to_string(bounds); Ok(text_sig(nested)) diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 482350d04b5..5b7879ea58e 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -32,4 +32,4 @@ syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } [target."cfg(windows)".dependencies] -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 179ef20b19f..775cf3ac4c9 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -31,8 +31,7 @@ pub struct ArchiveConfig<'a> { pub lib_search_paths: Vec, } -/// Helper for adding many files to an archive with a single invocation of -/// `ar`. +/// Helper for adding many files to an archive. #[must_use = "must call build() to finish building the archive"] pub struct ArchiveBuilder<'a> { config: ArchiveConfig<'a>, @@ -201,8 +200,8 @@ impl<'a> ArchiveBuilder<'a> { }); } - /// Indicate that the next call to `build` should updates all symbols in - /// the archive (run 'ar s' over it). + /// Indicate that the next call to `build` should update all symbols in + /// the archive (equivalent to running 'ar s' over it). pub fn update_symbols(&mut self) { self.should_update_symbols = true; } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3f25c182fa2..570a6bbac1e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -467,7 +467,7 @@ fn link_rlib<'a>(sess: &'a Session, // of when we do and don't keep .#module-name#.bc files around. let user_wants_numbered_bitcode = sess.opts.output_types.contains_key(&OutputType::Bitcode) && - sess.opts.codegen_units > 1; + sess.codegen_units() > 1; if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode { remove(sess, &bc_filename); } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 8f75b891a30..01d3d656dfe 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -130,6 +130,7 @@ pub fn run(cgcx: &CodegenContext, .filter_map(symbol_filter) .collect::>(); timeline.record("whitelist"); + info!("{} symbols to preserve in this crate", symbol_white_list.len()); // If we're performing LTO for the entire crate graph, then for each of our // upstream dependencies, find the corresponding rlib and load the bitcode @@ -437,7 +438,24 @@ fn run_pass_manager(cgcx: &CodegenContext, assert!(!pass.is_null()); llvm::LLVMRustAddPass(pm, pass); - with_llvm_pmb(llmod, config, &mut |b| { + // When optimizing for LTO we don't actually pass in `-O0`, but we force + // it to always happen at least with `-O1`. + // + // With ThinLTO we mess around a lot with symbol visibility in a way + // that will actually cause linking failures if we optimize at O0 which + // notable is lacking in dead code elimination. To ensure we at least + // get some optimizations and correctly link we forcibly switch to `-O1` + // to get dead code elimination. + // + // Note that in general this shouldn't matter too much as you typically + // only turn on ThinLTO when you're compiling with optimizations + // otherwise. + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); + let opt_level = match opt_level { + llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less, + level => level, + }; + with_llvm_pmb(llmod, config, opt_level, &mut |b| { if thin { if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) { panic!("this version of LLVM does not support ThinLTO"); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 306071223fc..66a27f1c4a9 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -98,8 +98,10 @@ //! DefPaths which are much more robust in the face of changes to the code base. use monomorphize::Instance; +use trans_item::{TransItemExt, InstantiationMode}; use rustc::middle::weak_lang_items; +use rustc::middle::trans::TransItem; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -150,7 +152,10 @@ pub fn provide(providers: &mut Providers) { fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the DefId of the item this name is for - def_id: Option, + def_id: DefId, + + // instance this name will be for + instance: Instance<'tcx>, // type of the item, without any generic // parameters substituted; this is @@ -160,7 +165,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // values for generic type parameters, // if any. - substs: Option<&'tcx Substs<'tcx>>) + substs: &'tcx Substs<'tcx>) -> u64 { debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); @@ -170,7 +175,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path - hasher.hash(def_id.map(|def_id| tcx.def_path_hash(def_id))); + hasher.hash(tcx.def_path_hash(def_id)); // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type @@ -186,19 +191,36 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // also include any type parameters (for generic items) - if let Some(substs) = substs { - assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); - substs.visit_with(&mut hasher); + assert!(!substs.has_erasable_regions()); + assert!(!substs.needs_subst()); + substs.visit_with(&mut hasher); - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - if substs.types().next().is_some() { - hasher.hash(tcx.crate_name.as_str()); - hasher.hash(tcx.sess.local_crate_disambiguator().as_str()); + let mut avoid_cross_crate_conflicts = false; + + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + if substs.types().next().is_some() { + avoid_cross_crate_conflicts = true; + } + + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match TransItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => { + avoid_cross_crate_conflicts = true; } + _ => {} + } + + if avoid_cross_crate_conflicts { + hasher.hash(tcx.crate_name.as_str()); + hasher.hash(tcx.sess.local_crate_disambiguator().as_str()); } }); @@ -309,7 +331,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance // and should not matter anyhow. let instance_ty = tcx.erase_regions(&instance_ty); - let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); + let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index b3b2384a027..f7e0ad029af 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -217,7 +217,7 @@ pub struct ModuleConfig { passes: Vec, /// Some(level) to optimize at a certain level, or None to run /// absolutely no optimizations (used for the metadata module). - opt_level: Option, + pub opt_level: Option, /// Some(level) to optimize binary size, or None to not affect program size. opt_size: Option, @@ -507,7 +507,8 @@ unsafe fn optimize(cgcx: &CodegenContext, if !config.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - with_llvm_pmb(llmod, &config, &mut |b| { + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); + with_llvm_pmb(llmod, &config, opt_level, &mut |b| { llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); }) @@ -1037,10 +1038,10 @@ fn produce_final_output_artifacts(sess: &Session, let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); let keep_numbered_bitcode = needs_crate_bitcode || - (user_wants_bitcode && sess.opts.codegen_units > 1); + (user_wants_bitcode && sess.codegen_units() > 1); let keep_numbered_objects = needs_crate_object || - (user_wants_objects && sess.opts.codegen_units > 1); + (user_wants_objects && sess.codegen_units() > 1); for module in compiled_modules.modules.iter() { let module_name = Some(&module.name[..]); @@ -1079,13 +1080,9 @@ fn produce_final_output_artifacts(sess: &Session, } pub fn dump_incremental_data(trans: &CrateTranslation) { - let mut reuse = 0; - for mtrans in trans.modules.iter() { - if mtrans.pre_existing { - reuse += 1; - } - } - eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len()); + println!("[incremental] Re-using {} out of {} modules", + trans.modules.iter().filter(|m| m.pre_existing).count(), + trans.modules.len()); } enum WorkItem { @@ -1247,7 +1244,7 @@ fn start_executing_work(tcx: TyCtxt, modules_config: Arc, metadata_config: Arc, allocator_config: Arc) - -> thread::JoinHandle { + -> thread::JoinHandle> { let coordinator_send = tcx.tx_to_llvm_workers.clone(); let mut exported_symbols = FxHashMap(); exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); @@ -1695,7 +1692,7 @@ fn start_executing_work(tcx: TyCtxt, Message::Done { result: Err(()), worker_id: _ } => { shared_emitter.fatal("aborting due to worker thread failure"); // Exit the coordinator thread - panic!("aborting due to worker thread failure") + return Err(()) } Message::TranslateItem => { bug!("the coordinator should not receive translation requests") @@ -1721,11 +1718,11 @@ fn start_executing_work(tcx: TyCtxt, let compiled_metadata_module = compiled_metadata_module .expect("Metadata module not compiled?"); - CompiledModules { + Ok(CompiledModules { modules: compiled_modules, metadata_module: compiled_metadata_module, allocator_module: compiled_allocator_module, - } + }) }); // A heuristic that determines if we have enough LLVM WorkItems in the @@ -1846,16 +1843,17 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { pub unsafe fn with_llvm_pmb(llmod: ModuleRef, config: &ModuleConfig, + opt_level: llvm::CodeGenOptLevel, f: &mut FnMut(llvm::PassManagerBuilderRef)) { // Create the PassManagerBuilder for LLVM. We configure it with // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; - llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level, + llvm::LLVMRustConfigurePassManagerBuilder(builder, + opt_level, config.merge_functions, config.vectorize_slp, config.vectorize_loop); @@ -2018,7 +2016,7 @@ pub struct OngoingCrateTranslation { coordinator_send: Sender>, trans_worker_receive: Receiver, shared_emitter_main: SharedEmitterMain, - future: thread::JoinHandle, + future: thread::JoinHandle>, output_filenames: Arc, } @@ -2026,7 +2024,11 @@ impl OngoingCrateTranslation { pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation { self.shared_emitter_main.check(sess, true); let compiled_modules = match self.future.join() { - Ok(compiled_modules) => compiled_modules, + Ok(Ok(compiled_modules)) => compiled_modules, + Ok(Err(())) => { + sess.abort_if_errors(); + panic!("expected abort due to worker thread errors") + }, Err(_) => { sess.fatal("Error during translation/LLVM phase."); } @@ -2048,7 +2050,7 @@ impl OngoingCrateTranslation { // FIXME: time_llvm_passes support - does this use a global context or // something? - if sess.opts.codegen_units == 1 && sess.time_llvm_passes() { + if sess.codegen_units() == 1 && sess.time_llvm_passes() { unsafe { llvm::LLVMRustPrintPassTimings(); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 17e00ac1346..6b53b5b6411 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1218,7 +1218,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() { PartitioningStrategy::PerModule } else { - PartitioningStrategy::FixedUnitCount(tcx.sess.opts.codegen_units) + PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) }; let codegen_units = time(time_passes, "codegen unit partitioning", || { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 18b91b18d8e..b515c9420bf 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -24,6 +24,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, TypeFoldable}; use rustc::traits; use rustc::ty::subst::Substs; +use rustc_back::PanicStrategy; use type_of; /// Translates a reference to a fn/method item, monomorphizing and @@ -105,8 +106,10 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // *in Rust code* may unwind. Foreign items like `extern "C" { // fn foo(); }` are assumed not to unwind **unless** they have // a `#[unwind]` attribute. - if !tcx.is_foreign_item(instance_def_id) { - attributes::unwind(llfn, true); + if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + if !tcx.is_foreign_item(instance_def_id) { + attributes::unwind(llfn, true); + } } // Apply an appropriate linkage/visibility value to our item that we diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 73df1b45c59..33a2e96ee66 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -401,9 +401,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - caller: TransItem<'tcx>, - callees: &[TransItem<'tcx>], - inlining_map: &mut InliningMap<'tcx>) { + caller: TransItem<'tcx>, + callees: &[TransItem<'tcx>], + inlining_map: &mut InliningMap<'tcx>) { let is_inlining_candidate = |trans_item: &TransItem<'tcx>| { trans_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy }; @@ -849,8 +849,8 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(!poly_trait_ref.has_escaping_regions()); // Walk all methods of the trait, including those of its supertraits - let methods = traits::get_vtable_methods(tcx, poly_trait_ref); - let methods = methods.filter_map(|method| method) + let methods = tcx.vtable_methods(poly_trait_ref); + let methods = methods.iter().cloned().filter_map(|method| method) .map(|(def_id, substs)| ty::Instance::resolve( tcx, ty::ParamEnv::empty(traits::Reveal::All), diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 3c8ff454997..f894bdf16e4 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -24,6 +24,7 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty::Ty; use rustc::session::config::Sanitizer; +use rustc_back::PanicStrategy; use abi::{Abi, FnType}; use attributes; use context::CrateContext; @@ -98,6 +99,10 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: _ => {}, } + if ccx.tcx().sess.panic_strategy() != PanicStrategy::Unwind { + attributes::unwind(llfn, false); + } + llfn } diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 88407947f0e..3253a0339a8 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -9,7 +9,6 @@ // except according to those terms. use llvm::ValueRef; -use rustc::traits; use callee; use common::*; use builder::Builder; @@ -87,7 +86,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let Some(trait_ref) = trait_ref { let trait_ref = trait_ref.with_self_ty(tcx, ty); - let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { + let methods = tcx.vtable_methods(trait_ref); + let methods = methods.iter().cloned().map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { callee::resolve_and_get_fn(ccx, def_id, substs) }) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index cd2a881451c..471be439a8f 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -15,8 +15,6 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use syntax::codemap::DUMMY_SP; - pub use rustc::ty::Instance; fn fn_once_adapter_instance<'a, 'tcx>( @@ -110,13 +108,14 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { + let def_id = tcx.lang_items().coerce_unsized_trait().unwrap(); + let trait_ref = ty::Binder(ty::TraitRef { - def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), + def_id: def_id, substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); - match tcx.trans_fulfill_obligation( - DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), trait_ref) { + match tcx.trans_fulfill_obligation( (ty::ParamEnv::empty(traits::Reveal::All), trait_ref)) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 4656d212f9b..386806e4c9c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -163,10 +163,27 @@ pub trait CodegenUnitExt<'tcx> { fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: TransItem<'tcx>) -> ItemSortKey { ItemSortKey(match item { - TransItem::Fn(instance) => { - tcx.hir.as_local_node_id(instance.def_id()) + TransItem::Fn(ref instance) => { + match instance.def { + // We only want to take NodeIds of user-defined + // instances into account. The others don't matter for + // the codegen tests and can even make item order + // unstable. + InstanceDef::Item(def_id) => { + tcx.hir.as_local_node_id(def_id) + } + InstanceDef::Intrinsic(..) | + InstanceDef::FnPtrShim(..) | + InstanceDef::Virtual(..) | + InstanceDef::ClosureOnceShim { .. } | + InstanceDef::DropGlue(..) | + InstanceDef::CloneShim(..) => { + None + } + } } - TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { Some(node_id) } }, item.symbol_name(tcx)) @@ -279,75 +296,74 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut internalization_candidates = FxHashSet(); for trans_item in trans_items { - let is_root = trans_item.instantiation_mode(tcx) == InstantiationMode::GloballyShared; + match trans_item.instantiation_mode(tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } - if is_root { - let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); - let is_volatile = is_incremental_build && - trans_item.is_generic_fn(); + let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); + let is_volatile = is_incremental_build && + trans_item.is_generic_fn(); - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile), - None => Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(), - }; + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile), + None => Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(), + }; - let make_codegen_unit = || { - CodegenUnit::new(codegen_unit_name.clone()) - }; + let make_codegen_unit = || { + CodegenUnit::new(codegen_unit_name.clone()) + }; - let codegen_unit = codegen_units.entry(codegen_unit_name.clone()) - .or_insert_with(make_codegen_unit); + let codegen_unit = codegen_units.entry(codegen_unit_name.clone()) + .or_insert_with(make_codegen_unit); - let (linkage, visibility) = match trans_item.explicit_linkage(tcx) { - Some(explicit_linkage) => (explicit_linkage, Visibility::Default), - None => { - match trans_item { - TransItem::Fn(ref instance) => { - let visibility = match instance.def { - InstanceDef::Item(def_id) => { - if def_id.is_local() { - if tcx.is_exported_symbol(def_id) { - Visibility::Default - } else { - internalization_candidates.insert(trans_item); - Visibility::Hidden - } + let (linkage, visibility) = match trans_item.explicit_linkage(tcx) { + Some(explicit_linkage) => (explicit_linkage, Visibility::Default), + None => { + match trans_item { + TransItem::Fn(ref instance) => { + let visibility = match instance.def { + InstanceDef::Item(def_id) => { + if def_id.is_local() { + if tcx.is_exported_symbol(def_id) { + Visibility::Default } else { - internalization_candidates.insert(trans_item); Visibility::Hidden } + } else { + Visibility::Hidden } - InstanceDef::FnPtrShim(..) | - InstanceDef::Virtual(..) | - InstanceDef::Intrinsic(..) | - InstanceDef::ClosureOnceShim { .. } | - InstanceDef::DropGlue(..) | - InstanceDef::CloneShim(..) => { - bug!("partitioning: Encountered unexpected - root translation item: {:?}", - trans_item) - } - }; - (Linkage::External, visibility) - } - TransItem::Static(node_id) | - TransItem::GlobalAsm(node_id) => { - let def_id = tcx.hir.local_def_id(node_id); - let visibility = if tcx.is_exported_symbol(def_id) { - Visibility::Default - } else { - internalization_candidates.insert(trans_item); + } + InstanceDef::FnPtrShim(..) | + InstanceDef::Virtual(..) | + InstanceDef::Intrinsic(..) | + InstanceDef::ClosureOnceShim { .. } | + InstanceDef::DropGlue(..) | + InstanceDef::CloneShim(..) => { Visibility::Hidden - }; - (Linkage::External, visibility) - } + } + }; + (Linkage::External, visibility) + } + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { + let def_id = tcx.hir.local_def_id(node_id); + let visibility = if tcx.is_exported_symbol(def_id) { + Visibility::Default + } else { + Visibility::Hidden + }; + (Linkage::External, visibility) } } - }; - - codegen_unit.items_mut().insert(trans_item, (linkage, visibility)); - roots.insert(trans_item); + } + }; + if visibility == Visibility::Hidden { + internalization_candidates.insert(trans_item); } + + codegen_unit.items_mut().insert(trans_item, (linkage, visibility)); + roots.insert(trans_item); } // always ensure we have at least one CGU; otherwise, if we have a diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 526b61303e1..060f02ee23e 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -26,11 +26,12 @@ use monomorphize::Instance; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::trans::{Linkage, Visibility}; +use rustc::session::config::OptLevel; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; use syntax::ast; -use syntax::attr; +use syntax::attr::{self, InlineAttr}; use syntax_pos::Span; use syntax_pos::symbol::Symbol; use type_of; @@ -44,7 +45,20 @@ pub use rustc::middle::trans::TransItem; pub enum InstantiationMode { /// There will be exactly one instance of the given TransItem. It will have /// external linkage so that it can be linked to from other codegen units. - GloballyShared, + GloballyShared { + /// In some compilation scenarios we may decide to take functions that + /// are typically `LocalCopy` and instead move them to `GloballyShared` + /// to avoid translating them a bunch of times. In this situation, + /// however, our local copy may conflict with other crates also + /// inlining the same function. + /// + /// This flag indicates that this situation is occuring, and informs + /// symbol name calculation that some extra mangling is needed to + /// avoid conflicts. Note that this may eventually go away entirely if + /// ThinLTO enables us to *always* have a globally shared instance of a + /// function within one crate's compilation. + may_conflict: bool, + }, /// Each codegen unit containing a reference to the given TransItem will /// have its own private copy of the function (with internal linkage). @@ -154,18 +168,47 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug { fn instantiation_mode(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> InstantiationMode { + let inline_in_all_cgus = + tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| { + tcx.sess.opts.optimize != OptLevel::No + }); + match *self.as_trans_item() { TransItem::Fn(ref instance) => { - if self.explicit_linkage(tcx).is_none() && - common::requests_inline(tcx, instance) + // If this function isn't inlined or otherwise has explicit + // linkage, then we'll be creating a globally shared version. + if self.explicit_linkage(tcx).is_some() || + !common::requests_inline(tcx, instance) { - InstantiationMode::LocalCopy - } else { - InstantiationMode::GloballyShared + return InstantiationMode::GloballyShared { may_conflict: false } + } + + // At this point we don't have explicit linkage and we're an + // inlined function. If we're inlining into all CGUs then we'll + // be creating a local copy per CGU + if inline_in_all_cgus { + return InstantiationMode::LocalCopy + } + + // Finally, if this is `#[inline(always)]` we're sure to respect + // that with an inline copy per CGU, but otherwise we'll be + // creating one copy of this `#[inline]` function which may + // conflict with upstream crates as it could be an exported + // symbol. + let attrs = instance.def.attrs(tcx); + match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) { + InlineAttr::Always => InstantiationMode::LocalCopy, + _ => { + InstantiationMode::GloballyShared { may_conflict: true } + } } } - TransItem::Static(..) => InstantiationMode::GloballyShared, - TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared, + TransItem::Static(..) => { + InstantiationMode::GloballyShared { may_conflict: false } + } + TransItem::GlobalAsm(..) => { + InstantiationMode::GloballyShared { may_conflict: false } + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index af8cc2c806a..7c9497badfb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -18,6 +18,7 @@ use hir; use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; +use namespace::Namespace; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; @@ -827,8 +828,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_did = bound.0.def_id; let (assoc_ident, def_scope) = tcx.adjust(assoc_name, trait_did, ref_id); - let item = tcx.associated_items(trait_did).find(|i| i.name.to_ident() == assoc_ident) - .expect("missing associated type"); + let item = tcx.associated_items(trait_did).find(|i| { + Namespace::from(i.kind) == Namespace::Type && + i.name.to_ident() == assoc_ident + }) + .expect("missing associated type"); let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound); let ty = self.normalize_ty(span, ty); @@ -1464,7 +1468,7 @@ impl<'tcx> ExplicitSelf<'tcx> { /// declaration like `self: SomeType` into either `self`, /// `&self`, `&mut self`, or `Box`. We do this here /// by some simple pattern matching. A more precise check - /// is done later in `check_method_self_type()`. + /// is done later in `check_method_receiver()`. /// /// Examples: /// @@ -1475,7 +1479,7 @@ impl<'tcx> ExplicitSelf<'tcx> { /// fn method2(self: &T); // ExplicitSelf::ByValue /// fn method3(self: Box<&T>); // ExplicitSelf::ByBox /// - /// // Invalid cases will be caught later by `check_method_self_type`: + /// // Invalid cases will be caught later by `check_method_receiver`: /// fn method_err1(self: &mut T); // ExplicitSelf::ByReference /// } /// ``` diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 7461df8bda5..91ce4511a31 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -271,6 +271,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.output(), fn_sig.inputs()); self.check_argument_types(call_expr.span, + call_expr.span, fn_sig.inputs(), &expected_arg_tys[..], arg_exprs, @@ -298,6 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.inputs()); self.check_argument_types(call_expr.span, + call_expr.span, fn_sig.inputs(), &expected_arg_tys, arg_exprs, @@ -315,6 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method_callee: MethodCallee<'tcx>) -> Ty<'tcx> { let output_type = self.check_method_argument_types(call_expr.span, + call_expr.span, Ok(method_callee), arg_exprs, TupleArgumentsFlag::TupleArguments, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 3ddeba9d440..d4eda13c6cd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -13,6 +13,7 @@ use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; +use namespace::Namespace; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; @@ -275,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = self.associated_item(trait_def_id, m_name).unwrap(); + let method_item = self.associated_item(trait_def_id, m_name, Namespace::Value).unwrap(); let def_id = method_item.def_id; let generics = tcx.generics_of(def_id); assert_eq!(generics.types.len(), 0); @@ -371,10 +372,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - pub fn associated_item(&self, def_id: DefId, item_name: ast::Name) + pub fn associated_item(&self, def_id: DefId, item_name: ast::Name, ns: Namespace) -> Option { self.tcx.associated_items(def_id) - .find(|item| self.tcx.hygienic_eq(item_name, item.name, def_id)) - + .find(|item| Namespace::from(item.kind) == ns && + self.tcx.hygienic_eq(item_name, item.name, def_id)) } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a3b196f99d6..78941cb3a56 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,6 +16,7 @@ use super::suggest; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; +use namespace::Namespace; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; @@ -1317,11 +1318,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.tcx.associated_items(def_id) .filter(|x| { let dist = lev_distance(&*name.as_str(), &x.name.as_str()); - dist > 0 && dist <= max_dist + Namespace::from(x.kind) == Namespace::Value && dist > 0 + && dist <= max_dist }) .collect() } else { - self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x]) + self.fcx + .associated_item(def_id, name, Namespace::Value) + .map_or(Vec::new(), |x| vec![x]) } } else { self.tcx.associated_items(def_id).collect() diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 90c5297b399..23148406a11 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; +use namespace::Namespace; use rustc::traits::{Obligation, SelectionContext}; use util::nodemap::FxHashSet; @@ -92,12 +93,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.associated_item(impl_did, item_name) + let item = self.associated_item(impl_did, item_name, Namespace::Value) .or_else(|| { self.associated_item( self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - - item_name + item_name, + Namespace::Value, ) }).unwrap(); let note_span = self.tcx.hir.span_if_local(item.def_id).or_else(|| { @@ -127,7 +128,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self.associated_item(trait_did, item_name).unwrap(); + let item = self + .associated_item(trait_did, item_name, Namespace::Value) + .unwrap(); let item_span = self.tcx.def_span(item.def_id); span_note!(err, item_span, @@ -402,7 +405,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // implementing a trait would be legal but is rejected // here). (type_is_local || info.def_id.is_local()) - && self.associated_item(info.def_id, item_name).is_some() + && self.associated_item(info.def_id, item_name, Namespace::Value).is_some() }) .collect::>(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c6a4abfbd7..0ebccbc835f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,6 +88,7 @@ use astconv::AstConv; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; +use namespace::Namespace; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; @@ -728,7 +729,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum debug_assert!(crate_num == LOCAL_CRATE); Ok(tcx.sess.track_errors(|| { for body_owner_def_id in tcx.body_owners() { - tcx.typeck_tables_of(body_owner_def_id); + ty::maps::queries::typeck_tables_of::ensure(tcx, body_owner_def_id); } })?) } @@ -1293,7 +1294,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for impl_item in impl_items() { let ty_impl_item = tcx.associated_item(tcx.hir.local_def_id(impl_item.id)); let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) - .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id)); + .find(|ac| Namespace::from(&impl_item.node) == Namespace::from(ac.kind) && + tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id)) + .or_else(|| { + // Not compatible, but needed for the error message + tcx.associated_items(impl_trait_ref.def_id) + .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id)) + }); // Check that impl definition matches trait definition if let Some(ty_trait_item) = ty_trait_item { @@ -2352,6 +2359,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_method_argument_types(&self, sp: Span, + expr_sp: Span, method: Result, ()>, args_no_rcvr: &'gcx [hir::Expr], tuple_arguments: TupleArgumentsFlag, @@ -2371,7 +2379,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)], }; - self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, + self.check_argument_types(sp, expr_sp, &err_inputs[..], &[], args_no_rcvr, false, tuple_arguments, None); return self.tcx.types.err; } @@ -2384,7 +2392,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method.sig.output(), &method.sig.inputs()[1..] ); - self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..], + self.check_argument_types(sp, expr_sp, &method.sig.inputs()[1..], &expected_arg_tys[..], args_no_rcvr, method.sig.variadic, tuple_arguments, self.tcx.hir.span_if_local(method.def_id)); method.sig.output() @@ -2394,6 +2402,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// method calls and overloaded operators. fn check_argument_types(&self, sp: Span, + expr_sp: Span, fn_inputs: &[Ty<'tcx>], expected_arg_tys: &[Ty<'tcx>], args: &'gcx [hir::Expr], @@ -2434,9 +2443,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp }; - fn parameter_count_error<'tcx>(sess: &Session, sp: Span, expected_count: usize, - arg_count: usize, error_code: &str, variadic: bool, - def_span: Option, sugg_unit: bool) { + fn parameter_count_error<'tcx>(sess: &Session, + sp: Span, + expr_sp: Span, + expected_count: usize, + arg_count: usize, + error_code: &str, + variadic: bool, + def_span: Option, + sugg_unit: bool) { let mut err = sess.struct_span_err_with_code(sp, &format!("this function takes {}{} parameter{} but {} parameter{} supplied", if variadic {"at least "} else {""}, @@ -2450,12 +2465,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.span_label(def_s, "defined here"); } if sugg_unit { - let sugg_span = sp.end_point(); + let sugg_span = expr_sp.end_point(); // remove closing `)` from the span let sugg_span = sugg_span.with_hi(sugg_span.lo()); err.span_suggestion( sugg_span, - "expected the unit value `()`. You can create one with a pair of parenthesis", + "expected the unit value `()`; create it with empty parentheses", String::from("()")); } else { err.span_label(sp, format!("expected {}{} parameter{}", @@ -2470,7 +2485,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::TyTuple(arg_types, _) if arg_types.len() != args.len() => { - parameter_count_error(tcx.sess, sp_args, arg_types.len(), args.len(), + parameter_count_error(tcx.sess, sp_args, expr_sp, arg_types.len(), args.len(), "E0057", false, def_span, false); expected_arg_tys = &[]; self.err_args(args.len()) @@ -2499,7 +2514,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { - parameter_count_error(tcx.sess, sp_args, expected_arg_count, + parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count, supplied_arg_count, "E0060", true, def_span, false); expected_arg_tys = &[]; self.err_args(supplied_arg_count) @@ -2513,7 +2528,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { false }; - parameter_count_error(tcx.sess, sp_args, expected_arg_count, + parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count, supplied_arg_count, "E0061", false, def_span, sugg_unit); expected_arg_tys = &[]; self.err_args(supplied_arg_count) @@ -2866,7 +2881,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types(span, method, + self.check_method_argument_types(span, + expr.span, + method, &args[1..], DontTupleArguments, expected) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 76dcfe36e4f..1355f711a4b 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use namespace::Namespace; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::traits; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) { @@ -28,19 +29,10 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> { impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId, overlap: traits::OverlapResult) { - #[derive(Copy, Clone, PartialEq)] - enum Namespace { - Type, - Value, - } let name_and_namespace = |def_id| { let item = self.tcx.associated_item(def_id); - (item.name, match item.kind { - ty::AssociatedKind::Type => Namespace::Type, - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => Namespace::Value, - }) + (item.name, Namespace::from(item.kind)) }; let impl_items1 = self.tcx.associated_item_def_ids(impl1); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7a6ee73b9b9..1c047ef98d8 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -123,6 +123,7 @@ mod constrained_type_params; mod impl_wf_check; mod coherence; mod variance; +mod namespace; pub struct TypeAndSubsts<'tcx> { substs: &'tcx Substs<'tcx>, diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs new file mode 100644 index 00000000000..6f0e46b3afe --- /dev/null +++ b/src/librustc_typeck/namespace.rs @@ -0,0 +1,39 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir; +use rustc::ty; + +// Whether an item exists in the type or value namespace. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Namespace { + Type, + Value, +} + +impl From for Namespace { + fn from(a_kind: ty::AssociatedKind) -> Self { + match a_kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + } + } +} + +impl<'a> From <&'a hir::ImplItemKind> for Namespace { + fn from(impl_kind: &'a hir::ImplItemKind) -> Self { + match *impl_kind { + hir::ImplItemKind::Type(..) => Namespace::Type, + hir::ImplItemKind::Const(..) | + hir::ImplItemKind::Method(..) => Namespace::Value, + } + } +} diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b295b414a03..e168222058f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -18,4 +18,4 @@ html-diff = "0.0.4" [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 424f48a17e9..e217978648e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -112,6 +112,7 @@ impl, U> Clean> for P<[T]> { #[derive(Clone, Debug)] pub struct Crate { pub name: String, + pub version: Option, pub src: PathBuf, pub module: Option, pub externs: Vec<(CrateNum, ExternalCrate)>, @@ -183,6 +184,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { Crate { name, + version: None, src, module: Some(module), externs, @@ -1681,6 +1683,21 @@ impl Type { _ => false } } + + pub fn generics(&self) -> Option<&[Type]> { + match *self { + ResolvedPath { ref path, .. } => { + path.segments.last().and_then(|seg| { + if let PathParameters::AngleBracketed { ref types, .. } = seg.params { + Some(&**types) + } else { + None + } + }) + } + _ => None, + } + } } impl GetDefId for Type { diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 111ae4ede27..2f7bd5e39a1 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -10,7 +10,6 @@ use std::fs::File; use std::io::prelude::*; -use std::io; use std::path::Path; use std::str; use html::markdown::{Markdown, RenderType}; @@ -70,17 +69,13 @@ pub fn load_string>(file_path: P) -> Result Ok(s.to_string()), Err(_) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: not UTF-8", - file_path.display()); + eprintln!("error reading `{}`: not UTF-8", file_path.display()); Err(LoadStringError::BadUtf8) } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index d08a7bde71c..873d978b9cb 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -97,9 +97,9 @@ r##"
Show this help dialog
S
Focus the search field
-
+
Move up in search results
-
+
Move down in search results
Go to active search result
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a3f446885f9..3c789cb3a15 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -125,6 +125,21 @@ pub struct SharedContext { /// Warnings for the user if rendering would differ using different markdown /// parsers. pub markdown_warnings: RefCell)>>, + /// The directories that have already been created in this doc run. Used to reduce the number + /// of spurious `create_dir_all` calls. + pub created_dirs: RefCell>, +} + +impl SharedContext { + fn ensure_dir(&self, dst: &Path) -> io::Result<()> { + let mut dirs = self.created_dirs.borrow_mut(); + if !dirs.contains(dst) { + fs::create_dir_all(dst)?; + dirs.insert(dst.to_path_buf()); + } + + Ok(()) + } } /// Indicates where an external crate can be found. @@ -256,6 +271,9 @@ pub struct Cache { // the access levels from crateanalysis. pub access_levels: Arc>, + /// The version of the crate being documented, if given fron the `--crate-version` flag. + pub crate_version: Option, + // Private fields only used when initially crawling a crate to build a cache stack: Vec, @@ -460,6 +478,7 @@ pub fn run(mut krate: clean::Crate, }, css_file_extension: css_file_extension.clone(), markdown_warnings: RefCell::new(vec![]), + created_dirs: RefCell::new(FxHashSet()), }; // If user passed in `--playground-url` arg, we fill in crate name here @@ -534,6 +553,7 @@ pub fn run(mut krate: clean::Crate, primitive_locations: FxHashMap(), stripped_mod: false, access_levels: krate.access_levels.clone(), + crate_version: krate.version.take(), orphan_impl_items: Vec::new(), traits: mem::replace(&mut krate.external_traits, FxHashMap()), deref_trait_did, @@ -790,7 +810,6 @@ fn write_shared(cx: &Context, // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. - try_err!(fs::create_dir_all(&cx.dst), &cx.dst); let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true); // Add all the static files. These may already exist, but we just @@ -1306,7 +1325,8 @@ impl DocFolder for Cache { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. // Note: matching twice to restrict the lifetime of the `i` borrow. - let did = if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { + let mut dids = vec![]; + if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { let masked_trait = i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)); if !masked_trait { @@ -1315,23 +1335,33 @@ impl DocFolder for Cache { clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { - Some(did) + dids.push(did); } ref t => { - t.primitive_type().and_then(|t| { + let did = t.primitive_type().and_then(|t| { self.primitive_locations.get(&t).cloned() - }) + }); + + if let Some(did) = did { + dids.push(did); + } + } + } + } + + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.push(did); } } - } else { - None } } else { unreachable!() }; - if let Some(did) = did { + for did in dids { self.impls.entry(did).or_insert(vec![]).push(Impl { - impl_item: item, + impl_item: item.clone(), }); } None @@ -1503,8 +1533,8 @@ impl Context { this.render_item(&mut buf, &item, false).unwrap(); // buf will be empty if the module is stripped and there is no redirect for it if !buf.is_empty() { + try_err!(this.shared.ensure_dir(&this.dst), &this.dst); let joint_dst = this.dst.join("index.html"); - try_err!(fs::create_dir_all(&this.dst), &this.dst); let mut dst = try_err!(File::create(&joint_dst), &joint_dst); try_err!(dst.write_all(&buf), &joint_dst); } @@ -1538,8 +1568,8 @@ impl Context { let name = item.name.as_ref().unwrap(); let item_type = item.type_(); let file_name = &item_path(item_type, name); + try_err!(self.shared.ensure_dir(&self.dst), &self.dst); let joint_dst = self.dst.join(file_name); - try_err!(fs::create_dir_all(&self.dst), &self.dst); let mut dst = try_err!(File::create(&joint_dst), &joint_dst); try_err!(dst.write_all(&buf), &joint_dst); @@ -1547,9 +1577,10 @@ impl Context { // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); - if let Ok(mut redirect_out) = OpenOptions::new().create_new(true) + if let Ok(redirect_out) = OpenOptions::new().create_new(true) .write(true) .open(&redir_dst) { + let mut redirect_out = BufWriter::new(redirect_out); try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); } @@ -1559,7 +1590,8 @@ impl Context { if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); let redir_dst = self.dst.join(redir_name); - let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst); + let redirect_out = try_err!(File::create(&redir_dst), &redir_dst); + let mut redirect_out = BufWriter::new(redirect_out); try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); } } @@ -3422,6 +3454,16 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "{}", it.name.as_ref().unwrap())?; write!(fmt, "

")?; + if it.is_crate() { + if let Some(ref version) = cache().crate_version { + write!(fmt, + "
\ +

Version {}

\ +
", + version)?; + } + } + match it.inner { clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?, clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?, diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index da4430d8a15..bccad6c89dc 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -342,6 +342,17 @@ } } + function findArg(obj, val) { + if (obj && obj.type && obj.type.inputs.length > 0) { + for (var i = 0; i < obj.type.inputs.length; i++) { + if (obj.type.inputs[i].name === val) { + return true; + } + } + } + return false; + } + function typePassesFilter(filter, type) { // No filter if (filter < 0) return true; @@ -376,18 +387,28 @@ if (typePassesFilter(typeFilter, searchIndex[i].ty)) { results.push({id: i, index: -1}); } + } else if (findArg(searchIndex[i], val.toLowerCase()) || + (searchIndex[i].type && + searchIndex[i].type.output && + searchIndex[i].type.output.name === val.toLowerCase())) { + if (typePassesFilter(typeFilter, searchIndex[i].ty)) { + results.push({id: i, index: -1, dontValidate: true}); + } } if (results.length === max) { break; } } + query.inputs = [val]; + query.output = val; + query.search = val; // searching by type } else if (val.search("->") > -1) { var trimmer = function (s) { return s.trim(); }; var parts = val.split("->").map(trimmer); var input = parts[0]; // sort inputs so that order does not matter - var inputs = input.split(",").map(trimmer).sort().toString(); + var inputs = input.split(",").map(trimmer).sort(); var output = parts[1]; for (var i = 0; i < nSearchWords; ++i) { @@ -403,12 +424,30 @@ // allow searching for void (no output) functions as well var typeOutput = type.output ? type.output.name : ""; - if ((inputs === "*" || inputs === typeInputs.toString()) && - (output === "*" || output == typeOutput)) { - results.push({id: i, index: -1, dontValidate: true}); + if (output === "*" || output == typeOutput) { + if (input === "*") { + results.push({id: i, index: -1, dontValidate: true}); + } else { + var allFound = true; + for (var it = 0; allFound === true && it < inputs.length; it++) { + var found = false; + for (var y = 0; found === false && y < typeInputs.length; y++) { + found = typeInputs[y] === inputs[it]; + } + allFound = found; + } + if (allFound === true) { + results.push({id: i, index: -1, dontValidate: true}); + } + } } } + query.inputs = inputs; + query.output = output; } else { + query.inputs = [val]; + query.output = val; + query.search = val; // gather matching search results up to a certain maximum val = val.replace(/\_/g, ""); for (var i = 0; i < split.length; ++i) { @@ -437,6 +476,15 @@ lev: lev_distance, }); } + } else if (findArg(searchIndex[j], val)) { + if (typePassesFilter(typeFilter, searchIndex[j].ty)) { + results.push({ + id: j, + index: 0, + // we want lev results to go lower than others + lev: lev_distance, + }); + } } if (results.length === max) { break; @@ -576,8 +624,7 @@ (parent !== undefined && parent.name.toLowerCase().indexOf(keys[i]) > -1) || // lastly check to see if the name was a levenshtein match - levenshtein(name.toLowerCase(), keys[i]) <= - MAX_LEV_DISTANCE)) { + levenshtein(name.toLowerCase(), keys[i]) <= MAX_LEV_DISTANCE)) { return false; } } @@ -692,18 +739,18 @@ return h1.innerHTML; } - function showResults(results) { - var output, shown, query = getQuery(); + function addTab(array, query, display) { + var extraStyle = ''; + if (display === false) { + extraStyle = ' style="display: none;"'; + } - currentResults = query.id; - output = '

Results for ' + escape(query.query) + - (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '

'; - output += ''; + var output = ''; + if (array.length > 0) { + output = `
`; + var shown = []; - if (results.length > 0) { - shown = []; - - results.forEach(function(item) { + array.forEach(function(item) { var name, type, href, displayPath; if (shown.indexOf(item) !== -1) { @@ -752,13 +799,32 @@ '' + escape(item.desc) + ' '; }); + output += '
'; } else { - output += 'No results :(
No results :(
` + + 'Try on
Try on DuckDuckGo?'; + '">DuckDuckGo?'; } + return output; + } + + function showResults(results) { + var output, query = getQuery(); + + currentResults = query.id; + output = '

Results for ' + escape(query.query) + + (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '

' + + '
' + + '
Types/modules
' + + '
As parameters
' + + '
As return value
'; + + output += addTab(results['others'], query); + output += addTab(results['in_args'], query, false); + output += addTab(results['returned'], query, false); + output += '
'; - output += "

"; addClass(document.getElementById('main'), 'hidden'); var search = document.getElementById('search'); removeClass(search, 'hidden'); @@ -773,13 +839,17 @@ e.style.width = width + 'px'; }); initSearchNav(); + var elems = document.getElementById('titles').childNodes; + elems[0].onclick = function() { printTab(0); }; + elems[1].onclick = function() { printTab(1); }; + elems[2].onclick = function() { printTab(2); }; } function search(e) { var query, filterdata = [], obj, i, len, - results = [], + results = {"in_args": [], "returned": [], "others": []}, maxResults = 200, resultIndex; var params = getQueryStringParams(); @@ -810,11 +880,43 @@ len = resultIndex.length; for (i = 0; i < len; ++i) { if (resultIndex[i].id > -1) { + var added = false; obj = searchIndex[resultIndex[i].id]; filterdata.push([obj.name, obj.ty, obj.path, obj.desc]); - results.push(obj); + if (obj.type) { + if (results['returned'].length < maxResults && + obj.type.output && + obj.type.output.name.toLowerCase() === query.output) { + results['returned'].push(obj); + added = true; + } + if (results['in_args'].length < maxResults && obj.type.inputs.length > 0) { + var all_founds = true; + for (var it = 0; + all_founds === true && it < query.inputs.length; + it++) { + var found = false; + for (var y = 0; + found === false && y < obj.type.inputs.length; + y++) { + found = query.inputs[it] === obj.type.inputs[y].name; + } + all_founds = found; + } + if (all_founds === true) { + results['in_args'].push(obj); + added = true; + } + } + } + if (results['others'].length < maxResults && + ((query.search && obj.name.indexOf(query.search)) || added === false)) { + results['others'].push(obj); + } } - if (results.length >= maxResults) { + if (results['others'].length >= maxResults && + results['in_args'].length >= maxResults && + results['returned'].length >= maxResults) { break; } } @@ -1290,6 +1392,27 @@ return wrapper; } + // In the search display, allows to switch between tabs. + function printTab(nb) { + var nb_copy = nb; + onEach(document.getElementById('titles').childNodes, function(elem) { + if (nb_copy === 0) { + addClass(elem, 'selected'); + } else { + removeClass(elem, 'selected'); + } + nb_copy -= 1; + }); + onEach(document.getElementById('results').childNodes, function(elem) { + if (nb === 0) { + elem.style.display = ''; + } else { + elem.style.display = 'none'; + } + nb -= 1; + }); + } + onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) { onEach(e.getElementsByClassName('attributes'), function(i_e) { i_e.parentNode.insertBefore(createToggleWrapper(), i_e); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 27574e67bc8..a132223a051 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -203,6 +203,15 @@ nav.sub { word-wrap: break-word; } +.sidebar .version { + font-size: 15px; + text-align: center; + border-bottom: #DDDDDD 1px solid; + overflow-wrap: break-word; + word-wrap: break-word; /* deprecated */ + word-break: break-word; /* Chrome, non-standard */ +} + .location:empty { border: none; } @@ -385,7 +394,7 @@ h4 > code, h3 > code, .invisible > code { padding: 0; } -.content .item-list li { margin-bottom: 3px; } +.content .item-list li { margin-bottom: 1em; } .content .multi-column { -moz-column-count: 5; @@ -764,17 +773,19 @@ span.since { } .sidebar { - height: 40px; + height: 45px; min-height: 40px; - width: 100%; - margin: 0px; - padding: 0px; + width: calc(100% + 30px); + margin: 0; + margin-left: -15px; + padding: 0 15px; position: static; } .sidebar .location { float: right; margin: 0px; + margin-top: 2px; padding: 3px 10px 1px 10px; min-height: 39px; background: inherit; @@ -789,7 +800,7 @@ span.since { .sidebar img { width: 35px; margin-top: 5px; - margin-bottom: 0px; + margin-bottom: 5px; float: left; } @@ -820,6 +831,10 @@ span.since { .toggle-wrapper { height: 1.5em; } + + #search { + margin-left: 0; + } } @media print { @@ -873,3 +888,29 @@ span.since { pre.rust { position: relative; } + +.search-failed { + text-align: center; + margin-top: 20px; +} + +#titles { + height: 35px; +} + +#titles > div { + float: left; + width: 33.3%; + text-align: center; + border-bottom: 1px solid #ccc; + font-size: 18px; + cursor: pointer; +} + +#titles > div.selected { + border-bottom: 3px solid #0078ee; +} + +#titles > div:hover { + border-bottom: 3px solid #0089ff; +} diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index 42d0ec704f4..4a4ca15170a 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -235,3 +235,7 @@ pre.ignore:hover, .information:hover + pre.ignore { .information > .ignore:hover { color: rgba(255,142,0,1); } + +.search-failed > a { + color: #0089ff; +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9563ccfcc65..890e1169c05 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -243,6 +243,12 @@ pub fn opts() -> Vec { unstable("display-warnings", |o| { o.optflag("", "display-warnings", "to print code warnings when testing doc") }), + unstable("crate-version", |o| { + o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") + }), + unstable("linker", |o| { + o.optopt("", "linker", "linker used for building executable test code", "PATH") + }), ] } @@ -354,15 +360,16 @@ pub fn main_args(args: &[String]) -> isize { let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let display_warnings = matches.opt_present("display-warnings"); + let linker = matches.opt_str("linker"); match (should_test, markdown_input) { (true, true) => { return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type, - display_warnings) + display_warnings, linker) } (true, false) => { return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot, - render_type, display_warnings) + render_type, display_warnings, linker) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), @@ -460,6 +467,7 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { let triple = matches.opt_str("target"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let crate_name = matches.opt_str("crate-name"); + let crate_version = matches.opt_str("crate-version"); let plugin_path = matches.opt_str("plugin-path"); let cr = PathBuf::from(cratefile); @@ -484,6 +492,8 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { krate.name = name } + krate.version = crate_version; + // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 57e8e88cd13..fe6bd985bb6 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -11,7 +11,6 @@ use std::default::Default; use std::fs::File; use std::io::prelude::*; -use std::io; use std::path::{PathBuf, Path}; use getopts; @@ -75,9 +74,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let mut out = match File::create(&output) { Err(e) => { - let _ = writeln!(&mut io::stderr(), - "rustdoc: {}: {}", - output.display(), e); + eprintln!("rustdoc: {}: {}", output.display(), e); return 4; } Ok(f) => f @@ -85,10 +82,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { - let _ = writeln!( - &mut io::stderr(), - "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`" - ); + eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"); return 5; } let title = metadata[0]; @@ -138,9 +132,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, match err { Err(e) => { - let _ = writeln!(&mut io::stderr(), - "rustdoc: cannot write to `{}`: {}", - output.display(), e); + eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e); 6 } Ok(_) => 0 @@ -150,7 +142,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec, maybe_sysroot: Option, - render_type: RenderType, display_warnings: bool) -> isize { + render_type: RenderType, display_warnings: bool, linker: Option) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -162,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, Some(input.to_owned()), - render_type); + render_type, linker); if render_type == RenderType::Pulldown { old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5ce73d38fdf..8b2c8d2da39 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -61,7 +61,8 @@ pub fn run(input: &str, crate_name: Option, maybe_sysroot: Option, render_type: RenderType, - display_warnings: bool) + display_warnings: bool, + linker: Option) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -121,7 +122,8 @@ pub fn run(input: &str, maybe_sysroot, Some(codemap), None, - render_type); + render_type, + linker); { let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); @@ -180,7 +182,8 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option) { + maybe_sysroot: Option, + linker: Option) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = make_test(test, Some(cratename), as_test_harness, opts); @@ -201,6 +204,7 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs, cg: config::CodegenOptions { prefer_dynamic: true, + linker, .. config::basic_codegen_options() }, test: as_test_harness, @@ -407,13 +411,33 @@ pub struct Collector { pub tests: Vec, // to be removed when hoedown will be definitely gone pub old_tests: HashMap>, + + // The name of the test displayed to the user, separated by `::`. + // + // In tests from Rust source, this is the path to the item + // e.g. `["std", "vec", "Vec", "push"]`. + // + // In tests from a markdown file, this is the titles of all headers (h1~h6) + // of the sections that contain the code block, e.g. if the markdown file is + // written as: + // + // ``````markdown + // # Title + // + // ## Subtitle + // + // ```rust + // assert!(true); + // ``` + // `````` + // + // the `names` vector of that test will be `["Title", "Subtitle"]`. names: Vec, + cfgs: Vec, libs: SearchPaths, externs: Externs, - cnt: usize, use_headers: bool, - current_header: Option, cratename: String, opts: TestOptions, maybe_sysroot: Option, @@ -422,13 +446,14 @@ pub struct Collector { filename: Option, // to be removed when hoedown will be removed as well pub render_type: RenderType, + linker: Option, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, codemap: Option>, filename: Option, - render_type: RenderType) -> Collector { + render_type: RenderType, linker: Option) -> Collector { Collector { tests: Vec::new(), old_tests: HashMap::new(), @@ -436,9 +461,7 @@ impl Collector { cfgs, libs, externs, - cnt: 0, use_headers, - current_header: None, cratename, opts, maybe_sysroot, @@ -446,32 +469,17 @@ impl Collector { codemap, filename, render_type, + linker, } } fn generate_name(&self, line: usize, filename: &str) -> String { - if self.use_headers { - if let Some(ref header) = self.current_header { - format!("{} - {} (line {})", filename, header, line) - } else { - format!("{} - (line {})", filename, line) - } - } else { - format!("{} - {} (line {})", filename, self.names.join("::"), line) - } + format!("{} - {} (line {})", filename, self.names.join("::"), line) } // to be removed once hoedown is gone fn generate_name_beginning(&self, filename: &str) -> String { - if self.use_headers { - if let Some(ref header) = self.current_header { - format!("{} - {} (line", filename, header) - } else { - format!("{} - (line", filename) - } - } else { - format!("{} - {} (line", filename, self.names.join("::")) - } + format!("{} - {} (line", filename, self.names.join("::")) } pub fn add_old_test(&mut self, test: String, filename: String) { @@ -495,11 +503,10 @@ impl Collector { found = entry.remove_item(&test).is_some(); } if !found { - let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will \ - in future versions of rustdoc. Please ensure this code block is \ - a runnable test, or use the `ignore` directive.", - name); + eprintln!("WARNING: {} Code block is not currently run as a test, but will \ + in future versions of rustdoc. Please ensure this code block is \ + a runnable test, or use the `ignore` directive.", + name); return } } @@ -509,6 +516,7 @@ impl Collector { let cratename = self.cratename.to_string(); let opts = self.opts.clone(); let maybe_sysroot = self.maybe_sysroot.clone(); + let linker = self.linker.clone(); debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { @@ -537,7 +545,8 @@ impl Collector { compile_fail, error_codes, &opts, - maybe_sysroot) + maybe_sysroot, + linker) }) } { Ok(()) => (), @@ -580,7 +589,7 @@ impl Collector { } pub fn register_header(&mut self, name: &str, level: u32) { - if self.use_headers && level == 1 { + if self.use_headers { // we use these headings as test names, so it's good if // they're valid identifiers. let name = name.chars().enumerate().map(|(i, c)| { @@ -592,9 +601,28 @@ impl Collector { } }).collect::(); - // new header => reset count. - self.cnt = 0; - self.current_header = Some(name); + // Here we try to efficiently assemble the header titles into the + // test name in the form of `h1::h2::h3::h4::h5::h6`. + // + // Suppose originally `self.names` contains `[h1, h2, h3]`... + let level = level as usize; + if level <= self.names.len() { + // ... Consider `level == 2`. All headers in the lower levels + // are irrelevant in this new level. So we should reset + // `self.names` to contain headers until

, and replace that + // slot with the new name: `[h1, name]`. + self.names.truncate(level); + self.names[level - 1] = name; + } else { + // ... On the other hand, consider `level == 5`. This means we + // need to extend `self.names` to contain five headers. We fill + // in the missing level (

) with `_`. Thus `self.names` will + // become `[h1, h2, h3, "_", name]`. + if level - 1 > self.names.len() { + self.names.resize(level - 1, "_".to_owned()); + } + self.names.push(name); + } } } } @@ -625,7 +653,6 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { attrs.collapse_doc_comments(); attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { - self.collector.cnt = 0; if self.collector.render_type == RenderType::Pulldown { markdown::old_find_testable_code(doc, self.collector, attrs.span.unwrap_or(DUMMY_SP)); diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index fb276448ffa..866c0038a7f 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" [features] backtrace = [] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 7ca762c801a..0e6214ea04f 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -11,7 +11,6 @@ #![deny(warnings)] extern crate build_helper; -extern crate cc; use std::env; use std::process::Command; @@ -77,12 +76,6 @@ fn main() { fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); - let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) - .collect::>().join(" "); - cflags.push_str(" -fvisibility=hidden"); run(Command::new("sh") .current_dir(&native.out_dir) .arg(native.src_dir.join("configure").to_str().unwrap() @@ -94,10 +87,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CC", compiler.path()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())) - .env("CFLAGS", cflags), + .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"), BuildExpectation::None); run(Command::new(build_helper::make(host)) diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 93929637e2f..7e623a0af17 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -717,26 +717,25 @@ fn calculate_offsets(hashes_size: usize, (pairs_offset, end_of_pairs, oflo) } -// Returns a tuple of (minimum required malloc alignment, hash_offset, +// Returns a tuple of (minimum required malloc alignment, // array_size), from the start of a mallocated array. fn calculate_allocation(hash_size: usize, hash_align: usize, pairs_size: usize, pairs_align: usize) - -> (usize, usize, usize, bool) { - let hash_offset = 0; + -> (usize, usize, bool) { let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); let align = cmp::max(hash_align, pairs_align); - (align, hash_offset, end_of_pairs, oflo) + (align, end_of_pairs, oflo) } #[test] fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false)); + assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); + assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); + assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); @@ -768,10 +767,10 @@ impl RawTable { // This is great in theory, but in practice getting the alignment // right is a little subtle. Therefore, calculating offsets has been // factored out into a different function. - let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (alignment, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. @@ -784,7 +783,7 @@ impl RawTable { let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) .unwrap_or_else(|e| Heap.oom(e)); - let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; + let hashes = buffer as *mut HashUint; RawTable { capacity_mask: capacity.wrapping_sub(1), @@ -1157,6 +1156,7 @@ impl Clone for RawTable { } new_ht.size = self.size(); + new_ht.set_tag(self.tag()); new_ht } @@ -1183,10 +1183,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let hashes_size = self.capacity() * size_of::(); let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, _, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (align, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); debug_assert!(!oflo, "should be impossible"); diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index f9d80336477..b5460391942 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,19 +23,69 @@ use ptr; use slice; use str::{self, Utf8Error}; -/// A type representing an owned C-compatible string. +/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the +/// middle. /// -/// This type serves the primary purpose of being able to safely generate a +/// This type serves the purpose of being able to safely generate a /// C-compatible string from a Rust byte slice or vector. An instance of this /// type is a static guarantee that the underlying bytes contain no interior 0 -/// bytes and the final byte is 0. +/// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// A `CString` is created from either a byte slice or a byte vector. A [`u8`] -/// slice can be obtained with the `as_bytes` method. Slices produced from a -/// `CString` do *not* contain the trailing nul terminator unless otherwise -/// specified. +/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former +/// in each pair are owned strings; the latter are borrowed +/// references. /// +/// # Creating a `CString` +/// +/// A `CString` is created from either a byte slice or a byte vector, +/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for +/// example, you can build a `CString` straight out of a [`String`] or +/// a [`&str`], since both implement that trait). +/// +/// The [`new`] method will actually check that the provided `&[u8]` +/// does not have 0 bytes in the middle, and return an error if it +/// finds one. +/// +/// # Extracting a raw pointer to the whole C string +/// +/// `CString` implements a [`as_ptr`] method through the [`Deref`] +/// trait. This method will give you a `*const c_char` which you can +/// feed directly to extern functions that expect a nul-terminated +/// string, like C's `strdup()`. +/// +/// # Extracting a slice of the whole C string +/// +/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a +/// `CString` with the [`as_bytes`] method. Slices produced in this +/// way do *not* contain the trailing nul terminator. This is useful +/// when you will be calling an extern function that takes a `*const +/// u8` argument which is not necessarily nul-terminated, plus another +/// argument with the length of the string — like C's `strndup()`. +/// You can of course get the slice's length with its +/// [`len`][slice.len] method. +/// +/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you +/// can use [`as_bytes_with_nul`] instead. +/// +/// Once you have the kind of slice you need (with or without a nul +/// terminator), you can call the slice's own +/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to +/// extern functions. See the documentation for that function for a +/// discussion on ensuring the lifetime of the raw pointer. +/// +/// [`Into`]: ../convert/trait.Into.html +/// [`Vec`]: ../vec/struct.Vec.html +/// [`String`]: ../string/struct.String.html +/// [`&str`]: ../primitive.str.html /// [`u8`]: ../primitive.u8.html +/// [`new`]: #method.new +/// [`as_bytes`]: #method.as_bytes +/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul +/// [`as_ptr`]: #method.as_ptr +/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr +/// [slice.len]: ../primitive.slice.html#method.len +/// [`Deref`]: ../ops/trait.Deref.html +/// [`CStr`]: struct.CStr.html /// /// # Examples /// @@ -48,6 +98,8 @@ use str::{self, Utf8Error}; /// fn my_printer(s: *const c_char); /// } /// +/// // We are certain that our string doesn't have 0 bytes in the middle, +/// // so we can .unwrap() /// let c_to_print = CString::new("Hello, world!").unwrap(); /// unsafe { /// my_printer(c_to_print.as_ptr()); @@ -58,7 +110,7 @@ use str::{self, Utf8Error}; /// # Safety /// /// `CString` is intended for working with traditional C-style strings -/// (a sequence of non-null bytes terminated by a single null byte); the +/// (a sequence of non-nul bytes terminated by a single nul byte); the /// primary use case for these kinds of strings is interoperating with C-like /// code. Often you will need to transfer ownership to/from that external /// code. It is strongly recommended that you thoroughly read through the @@ -77,17 +129,21 @@ pub struct CString { /// Representation of a borrowed C string. /// -/// This dynamically sized type is only safely constructed via a borrowed -/// version of an instance of `CString`. This type can be constructed from a raw -/// C string as well and represents a C string borrowed from another location. +/// This type represents a borrowed reference to a nul-terminated +/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// slice, or unsafely from a raw `*const c_char`. It can then be +/// converted to a Rust [`&str`] by performing UTF-8 validation, or +/// into an owned [`CString`]. +/// +/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// in each pair are borrowed references; the latter are owned +/// strings. /// /// Note that this structure is **not** `repr(C)` and is not recommended to be -/// placed in the signatures of FFI functions. Instead safe wrappers of FFI +/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI /// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe /// interface to other consumers. /// -/// [`from_ptr`]: #method.from_ptr -/// /// # Examples /// /// Inspecting a foreign C string: @@ -100,7 +156,7 @@ pub struct CString { /// /// unsafe { /// let slice = CStr::from_ptr(my_string()); -/// println!("string length: {}", slice.to_bytes().len()); +/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len()); /// } /// ``` /// @@ -122,8 +178,6 @@ pub struct CString { /// /// Converting a foreign C string into a Rust [`String`]: /// -/// [`String`]: ../string/struct.String.html -/// /// ```no_run /// use std::ffi::CStr; /// use std::os::raw::c_char; @@ -138,6 +192,12 @@ pub struct CString { /// /// println!("string: {}", my_string_safe()); /// ``` +/// +/// [`u8`]: ../primitive.u8.html +/// [`&str`]: ../primitive.str.html +/// [`String`]: ../string/struct.String.html +/// [`CString`]: struct.CString.html +/// [`from_ptr`]: #method.from_ptr #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CStr { @@ -148,9 +208,15 @@ pub struct CStr { inner: [c_char] } -/// An error returned from [`CString::new`] to indicate that a nul byte was found -/// in the vector provided. +/// An error indicating that an interior nul byte was found. /// +/// While Rust strings may contain nul bytes in the middle, C strings +/// can't, as that byte would effectively truncate the string. +/// +/// This error is created by the [`new`][`CString::new`] method on +/// [`CString`]. See its documentation for more. +/// +/// [`CString`]: struct.CString.html /// [`CString::new`]: struct.CString.html#method.new /// /// # Examples @@ -164,9 +230,16 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); -/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul -/// byte was found too early in the slice provided or one wasn't found at all. +/// An error indicating that a nul byte was not in the expected position. /// +/// The slice used to create a [`CStr`] must have one and only one nul +/// byte at the end of the slice. +/// +/// This error is created by the +/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on +/// [`CStr`]. See its documentation for more. +/// +/// [`CStr`]: struct.CStr.html /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul /// /// # Examples @@ -201,9 +274,18 @@ impl FromBytesWithNulError { } } -/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error -/// was encountered during the conversion. +/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`]. /// +/// `CString` is just a wrapper over a buffer of bytes with a nul +/// terminator; [`into_string`][`CString::into_string`] performs UTF-8 +/// validation on those bytes and may return this error. +/// +/// This `struct` is created by the +/// [`into_string`][`CString::into_string`] method on [`CString`]. See +/// its documentation for more. +/// +/// [`String`]: ../string/struct.String.html +/// [`CString`]: struct.CString.html /// [`CString::into_string`]: struct.CString.html#method.into_string #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstring_into", since = "1.7.0")] @@ -215,8 +297,11 @@ pub struct IntoStringError { impl CString { /// Creates a new C-compatible string from a container of bytes. /// - /// This method will consume the provided data and use the underlying bytes - /// to construct a new string, ensuring that there is a trailing 0 byte. + /// This function will consume the provided data and use the + /// underlying bytes to construct a new string, ensuring that + /// there is a trailing 0 byte. This trailing 0 byte will be + /// appended by this function; the provided data should *not* + /// contain any 0 bytes in it. /// /// # Examples /// @@ -234,9 +319,11 @@ impl CString { /// /// # Errors /// - /// This function will return an error if the bytes yielded contain an - /// internal 0 byte. The error returned will contain the bytes as well as + /// This function will return an error if the supplied bytes contain an + /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as /// the position of the nul byte. + /// + /// [`NulError`]: struct.NulError.html #[stable(feature = "rust1", since = "1.0.0")] pub fn new>>(t: T) -> Result { Self::_new(t.into()) @@ -249,8 +336,8 @@ impl CString { } } - /// Creates a C-compatible string from a byte vector without checking for - /// interior 0 bytes. + /// Creates a C-compatible string by consuming a byte vector, + /// without checking for interior 0 bytes. /// /// This method is equivalent to [`new`] except that no runtime assertion /// is made that `v` contains no 0 bytes, and it requires an actual @@ -275,7 +362,7 @@ impl CString { CString { inner: v.into_boxed_slice() } } - /// Retakes ownership of a `CString` that was transferred to C. + /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`]. /// /// Additionally, the length of the string will be recalculated from the pointer. /// @@ -286,7 +373,14 @@ impl CString { /// ownership of a string that was allocated by foreign code) is likely to lead /// to undefined behavior or allocator corruption. /// + /// > **Note:** If you need to borrow a string that was allocated by + /// > foreign code, use [`CStr`]. If you need to take ownership of + /// > a string that was allocated by foreign code, you will need to + /// > make your own provisions for freeing it appropriately, likely + /// > with the foreign code's API to do that. + /// /// [`into_raw`]: #method.into_raw + /// [`CStr`]: struct.CStr.html /// /// # Examples /// @@ -315,11 +409,11 @@ impl CString { CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } } - /// Transfers ownership of the string to a C caller. + /// Consumes the `CString` and transfers ownership of the string to a C caller. /// - /// The pointer must be returned to Rust and reconstituted using + /// The pointer which this function returns must be returned to Rust and reconstituted using /// [`from_raw`] to be properly deallocated. Specifically, one - /// should *not* use the standard C `free` function to deallocate + /// should *not* use the standard C `free()` function to deallocate /// this string. /// /// Failure to call [`from_raw`] will lead to a memory leak. @@ -351,11 +445,27 @@ impl CString { Box::into_raw(self.into_inner()) as *mut c_char } - /// Converts the `CString` into a [`String`] if it contains valid Unicode data. + /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data. /// /// On failure, ownership of the original `CString` is returned. /// /// [`String`]: ../string/struct.String.html + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let valid_utf8 = vec![b'f', b'o', b'o']; + /// let cstring = CString::new(valid_utf8).unwrap(); + /// assert_eq!(cstring.into_string().unwrap(), "foo"); + /// + /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o']; + /// let cstring = CString::new(invalid_utf8).unwrap(); + /// let err = cstring.into_string().err().unwrap(); + /// assert_eq!(err.utf8_error().valid_up_to(), 1); + /// ``` + #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_string(self) -> Result { String::from_utf8(self.into_bytes()) @@ -365,10 +475,11 @@ impl CString { }) } - /// Returns the underlying byte buffer. + /// Consumes the `CString` and returns the underlying byte buffer. /// - /// The returned buffer does **not** contain the trailing nul separator and - /// it is guaranteed to not have any interior nul bytes. + /// The returned buffer does **not** contain the trailing nul + /// terminator, and it is guaranteed to not have any interior nul + /// bytes. /// /// # Examples /// @@ -388,7 +499,7 @@ impl CString { } /// Equivalent to the [`into_bytes`] function except that the returned vector - /// includes the trailing nul byte. + /// includes the trailing nul terminator. /// /// [`into_bytes`]: #method.into_bytes /// @@ -408,8 +519,12 @@ impl CString { /// Returns the contents of this `CString` as a slice of bytes. /// - /// The returned slice does **not** contain the trailing nul separator and - /// it is guaranteed to not have any interior nul bytes. + /// The returned slice does **not** contain the trailing nul + /// terminator, and it is guaranteed to not have any interior nul + /// bytes. If you need the nul terminator, use + /// [`as_bytes_with_nul`] instead. + /// + /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul /// /// # Examples /// @@ -427,7 +542,7 @@ impl CString { } /// Equivalent to the [`as_bytes`] function except that the returned slice - /// includes the trailing nul byte. + /// includes the trailing nul terminator. /// /// [`as_bytes`]: #method.as_bytes /// @@ -598,8 +713,8 @@ impl Default for Box { } impl NulError { - /// Returns the position of the nul byte in the slice that was provided to - /// [`CString::new`]. + /// Returns the position of the nul byte in the slice that caused + /// [`CString::new`] to fail. /// /// [`CString::new`]: struct.CString.html#method.new /// @@ -711,9 +826,9 @@ impl fmt::Display for IntoStringError { } impl CStr { - /// Casts a raw C string to a safe C string wrapper. + /// Wraps a raw C string with a safe C string wrapper. /// - /// This function will cast the provided `ptr` to the `CStr` wrapper which + /// This function will wrap the provided `ptr` with a `CStr` wrapper, which /// allows inspection and interoperation of non-owned C strings. This method /// is unsafe for a number of reasons: /// @@ -753,9 +868,9 @@ impl CStr { /// Creates a C string wrapper from a byte slice. /// - /// This function will cast the provided `bytes` to a `CStr` wrapper after - /// ensuring that it is null terminated and does not contain any interior - /// nul bytes. + /// This function will cast the provided `bytes` to a `CStr` + /// wrapper after ensuring that the byte slice is nul-terminated + /// and does not contain any interior nul bytes. /// /// # Examples /// @@ -766,7 +881,7 @@ impl CStr { /// assert!(cstr.is_ok()); /// ``` /// - /// Creating a `CStr` without a trailing nul byte is an error: + /// Creating a `CStr` without a trailing nul terminator is an error: /// /// ``` /// use std::ffi::CStr; @@ -800,7 +915,7 @@ impl CStr { /// Unsafely creates a C string wrapper from a byte slice. /// /// This function will cast the provided `bytes` to a `CStr` wrapper without - /// performing any sanity checks. The provided slice must be null terminated + /// performing any sanity checks. The provided slice **must** be nul-terminated /// and not contain any interior nul bytes. /// /// # Examples @@ -822,7 +937,7 @@ impl CStr { /// Returns the inner pointer to this C string. /// - /// The returned pointer will be valid for as long as `self` is and points + /// The returned pointer will be valid for as long as `self` is, and points /// to a contiguous region of memory terminated with a 0 byte to represent /// the end of the string. /// @@ -843,9 +958,9 @@ impl CStr { /// ``` /// /// This happens because the pointer returned by `as_ptr` does not carry any - /// lifetime information and the string is deallocated immediately after + /// lifetime information and the [`CString`] is deallocated immediately after /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated. - /// To fix the problem, bind the string to a local variable: + /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run /// use std::ffi::{CString}; @@ -857,6 +972,11 @@ impl CStr { /// *ptr; /// } /// ``` + /// + /// This way, the lifetime of the `CString` in `hello` encompasses + /// the lifetime of `ptr` and the `unsafe` block. + /// + /// [`CString`]: struct.CString.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_ptr(&self) -> *const c_char { @@ -865,11 +985,7 @@ impl CStr { /// Converts this C string to a byte slice. /// - /// This function will calculate the length of this string (which normally - /// requires a linear amount of work to be done) and then return the - /// resulting slice of `u8` elements. - /// - /// The returned slice will **not** contain the trailing nul that this C + /// The returned slice will **not** contain the trailing nul terminator that this C /// string has. /// /// > **Note**: This method is currently implemented as a 0-cost cast, but @@ -894,7 +1010,7 @@ impl CStr { /// Converts this C string to a byte slice containing the trailing 0 byte. /// /// This function is the equivalent of [`to_bytes`] except that it will retain - /// the trailing nul instead of chopping it off. + /// the trailing nul terminator instead of chopping it off. /// /// > **Note**: This method is currently implemented as a 0-cost cast, but /// > it is planned to alter its definition in the future to perform the @@ -918,8 +1034,9 @@ impl CStr { /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. /// - /// This function will calculate the length of this string and check for - /// UTF-8 validity, and then return the [`&str`] if it's valid. + /// If the contents of the `CStr` are valid UTF-8 data, this + /// function will return the corresponding [`&str`] slice. Otherwise, + /// it will return an error with details of where UTF-8 validation failed. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the @@ -947,10 +1064,12 @@ impl CStr { /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. /// - /// This function will calculate the length of this string (which normally - /// requires a linear amount of work to be done) and then return the - /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences - /// with `U+FFFD REPLACEMENT CHARACTER`. + /// If the contents of the `CStr` are valid UTF-8 data, this + /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` + /// with the the corresponding [`&str`] slice. Otherwise, it will + /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT + /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` + /// with the result. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the @@ -958,7 +1077,9 @@ impl CStr { /// > check whenever this method is called. /// /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed /// [`str`]: ../primitive.str.html + /// [`String`]: ../string/struct.String.html /// /// # Examples /// diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index ca1ff18f1ca..a75596351e4 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -9,6 +9,157 @@ // except according to those terms. //! Utilities related to FFI bindings. +//! +//! This module provides utilities to handle data across non-Rust +//! interfaces, like other programming languages and the underlying +//! operating system. It is mainly of use for FFI (Foreign Function +//! Interface) bindings and code that needs to exchange C-like strings +//! with other languages. +//! +//! # Overview +//! +//! Rust represents owned strings with the [`String`] type, and +//! borrowed slices of strings with the [`str`] primitive. Both are +//! always in UTF-8 encoding, and may contain nul bytes in the middle, +//! i.e. if you look at the bytes that make up the string, there may +//! be a `\0` among them. Both `String` and `str` store their length +//! explicitly; there are no nul terminators at the end of strings +//! like in C. +//! +//! C strings are different from Rust strings: +//! +//! * **Encodings** - Rust strings are UTF-8, but C strings may use +//! other encodings. If you are using a string from C, you should +//! check its encoding explicitly, rather than just assuming that it +//! is UTF-8 like you can do in Rust. +//! +//! * **Character size** - C strings may use `char` or `wchar_t`-sized +//! characters; please **note** that C's `char` is different from Rust's. +//! The C standard leaves the actual sizes of those types open to +//! interpretation, but defines different APIs for strings made up of +//! each character type. Rust strings are always UTF-8, so different +//! Unicode characters will be encoded in a variable number of bytes +//! each. The Rust type [`char`] represents a '[Unicode scalar +//! value]', which is similar to, but not the same as, a '[Unicode +//! code point]'. +//! +//! * **Nul terminators and implicit string lengths** - Often, C +//! strings are nul-terminated, i.e. they have a `\0` character at the +//! end. The length of a string buffer is not stored, but has to be +//! calculated; to compute the length of a string, C code must +//! manually call a function like `strlen()` for `char`-based strings, +//! or `wcslen()` for `wchar_t`-based ones. Those functions return +//! the number of characters in the string excluding the nul +//! terminator, so the buffer length is really `len+1` characters. +//! Rust strings don't have a nul terminator; their length is always +//! stored and does not need to be calculated. While in Rust +//! accessing a string's length is a O(1) operation (becasue the +//! length is stored); in C it is an O(length) operation because the +//! length needs to be computed by scanning the string for the nul +//! terminator. +//! +//! * **Internal nul characters** - When C strings have a nul +//! terminator character, this usually means that they cannot have nul +//! characters in the middle — a nul character would essentially +//! truncate the string. Rust strings *can* have nul characters in +//! the middle, because nul does not have to mark the end of the +//! string in Rust. +//! +//! # Representations of non-Rust strings +//! +//! [`CString`] and [`CStr`] are useful when you need to transfer +//! UTF-8 strings to and from languages with a C ABI, like Python. +//! +//! * **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 +//! 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 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 +//! 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`] +//! 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, +//! [`env::var_os()`] is used to query environment variables; it +//! returns an `Option`. 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`. +//! +//! # Conversions +//! +//! ## On Unix +//! +//! On Unix, [`OsStr`] implements the +//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! augments it with two methods, [`from_bytes`] and [`as_bytes`]. +//! These do inexpensive conversions from and to UTF-8 byte slices. +//! +//! Additionally, on Unix [`OsString`] implements the +//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait, +//! which provides [`from_vec`] and [`into_vec`] methods that consume +//! their arguments, and take or produce vectors of [`u8`]. +//! +//! ## On Windows +//! +//! On Windows, [`OsStr`] implements the +//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, +//! which provides an [`encode_wide`] method. This provides an +//! iterator that can be [`collect`]ed into a vector of [`u16`]. +//! +//! 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 +//! string losslessly. +//! +//! [`String`]: ../string/struct.String.html +//! [`str`]: ../primitive.str.html +//! [`char`]: ../primitive.char.html +//! [`u8`]: ../primitive.u8.html +//! [`u16`]: ../primitive.u16.html +//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! [`CString`]: struct.CString.html +//! [`CStr`]: struct.CStr.html +//! [`OsString`]: struct.OsString.html +//! [`OsStr`]: struct.OsStr.html +//! [`env::set_var()`]: ../env/fn.set_var.html +//! [`env::var_os()`]: ../env/fn.var_os.html +//! [`Result<>`]: ../result/enum.Result.html +//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html +//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec +//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec +//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html +//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes +//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes +//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html +//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html +//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide +//! [`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 #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 88ee5c9a734..a97075ff8d8 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -32,18 +32,65 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust /// and platform-native string values, and in particular allowing a Rust string -/// to be converted into an "OS" string with no cost. +/// to be converted into an "OS" string with no cost if possible. +/// +/// `OsString` is to [`OsStr`] as [`String`] is to [`&str`]: the former +/// in each pair are owned strings; the latter are borrowed +/// references. +/// +/// # Creating an `OsString` +/// +/// **From a Rust string**: `OsString` implements +/// [`From`]`<`[`String`]`>`, so you can use `my_string.`[`from`] to +/// create an `OsString` from a normal Rust string. +/// +/// **From slices:** Just like you can start with an empty Rust +/// [`String`] and then [`push_str`][String.push_str] `&str` +/// sub-string slices into it, you can create an empty `OsString` with +/// the [`new`] method and then push string slices into it with the +/// [`push`] method. +/// +/// # Extracting a borrowed reference to the whole OS string +/// +/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from +/// an `OsString`; this is effectively a borrowed reference to the +/// whole string. +/// +/// # Conversions +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsString` implements for conversions from/to native representations. /// /// [`OsStr`]: struct.OsStr.html +/// [`From`]: ../convert/trait.From.html +/// [`from`]: ../convert/trait.From.html#tymethod.from +/// [`String`]: ../string/struct.String.html +/// [`&str`]: ../primitive.str.html +/// [`u8`]: ../primitive.u8.html +/// [`u16`]: ../primitive.u16.html +/// [String.push_str]: ../string/struct.String.html#method.push_str +/// [`new`]: #method.new +/// [`push`]: #method.push +/// [`as_os_str`]: #method.as_os_str #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf } -/// Slices into OS strings (see [`OsString`]). +/// Borrowed reference to an OS string (see [`OsString`]). +/// +/// This type represents a borrowed reference to a string in the operating system's preferred +/// representation. +/// +/// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed +/// references; the latter are owned strings. +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsStr` implements for conversions from/to native representations. /// /// [`OsString`]: struct.OsString.html +/// [conversions]: index.html#conversions #[stable(feature = "rust1", since = "1.0.0")] pub struct OsStr { inner: Slice diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9fc7e2c01aa..83cc9ce582e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -244,6 +244,7 @@ #![feature(allow_internal_unstable)] #![feature(align_offset)] #![feature(asm)] +#![feature(attr_literals)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -290,6 +291,7 @@ #![feature(prelude_import)] #![feature(rand)] #![feature(raw)] +#![feature(repr_align)] #![feature(repr_simd)] #![feature(rustc_attrs)] #![cfg_attr(not(stage0), feature(rustc_const_unstable))] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index b904641a336..4656cc5a7a7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1579,6 +1579,21 @@ mod tests { "bad error: {} {:?}", e, e.kind()); } + #[test] + fn connect_timeout_unbound() { + // bind and drop a socket to track down a "probably unassigned" port + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + drop(socket); + + let timeout = Duration::from_secs(1); + let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err(); + assert!(e.kind() == io::ErrorKind::ConnectionRefused || + e.kind() == io::ErrorKind::TimedOut || + e.kind() == io::ErrorKind::Other, + "bad error: {} {:?}", e, e.kind()); + } + #[test] fn connect_timeout_valid() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); diff --git a/src/libstd/process.rs b/src/libstd/process.rs index dbb58991215..f448cffd372 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -702,6 +702,15 @@ impl AsInnerMut for Command { } /// The output of a finished process. +/// +/// This is returned in a Result by either the [`output`] method of a +/// [`Command`], or the [`wait_with_output`] method of a [`Child`] +/// process. +/// +/// [`Command`]: struct.Command.html +/// [`Child`]: struct.Child.html +/// [`output`]: struct.Command.html#method.output +/// [`wait_with_output`]: struct.Child.html#method.wait_with_output #[derive(PartialEq, Eq, Clone)] #[stable(feature = "process", since = "1.0.0")] pub struct Output { @@ -742,21 +751,128 @@ impl fmt::Debug for Output { } } -/// Describes what to do with a standard I/O stream for a child process. +/// Describes what to do with a standard I/O stream for a child process when +/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. +/// +/// [`stdin`]: struct.Command.html#method.stdin +/// [`stdout`]: struct.Command.html#method.stdout +/// [`stderr`]: struct.Command.html#method.stderr +/// [`Command`]: struct.Command.html #[stable(feature = "process", since = "1.0.0")] pub struct Stdio(imp::Stdio); impl Stdio { /// A new pipe should be arranged to connect the parent and child processes. + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); + /// // Nothing echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::io::Write; + /// use std::process::{Command, Stdio}; + /// + /// let mut child = Command::new("rev") + /// .stdin(Stdio::piped()) + /// .stdout(Stdio::piped()) + /// .spawn() + /// .expect("Failed to spawn child process"); + /// + /// { + /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); + /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); + /// } + /// + /// let output = child.wait_with_output().expect("Failed to read stdout"); + /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) } /// The child inherits from the corresponding parent descriptor. + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::inherit()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // "Hello, world!" echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("rev") + /// .stdin(Stdio::inherit()) + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } /// This stream will be ignored. This is the equivalent of attaching the /// stream to `/dev/null` + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::null()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // Nothing echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("rev") + /// .stdin(Stdio::null()) + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // Ignores any piped-in input + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn null() -> Stdio { Stdio(imp::Stdio::Null) } } @@ -1083,8 +1199,6 @@ impl Child { /// function and compute the exit code from its return value: /// /// ``` -/// use std::io::{self, Write}; -/// /// fn run_app() -> Result<(), ()> { /// // Application logic here /// Ok(()) @@ -1094,7 +1208,7 @@ impl Child { /// ::std::process::exit(match run_app() { /// Ok(_) => 0, /// Err(err) => { -/// writeln!(io::stderr(), "error: {:?}", err).unwrap(); +/// eprintln!("error: {:?}", err); /// 1 /// } /// }); diff --git a/src/libstd/sync/mpsc/cache_aligned.rs b/src/libstd/sync/mpsc/cache_aligned.rs new file mode 100644 index 00000000000..5af01262573 --- /dev/null +++ b/src/libstd/sync/mpsc/cache_aligned.rs @@ -0,0 +1,37 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ops::{Deref, DerefMut}; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(align(64))] +pub(super) struct Aligner; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(super) struct CacheAligned(pub T, pub Aligner); + +impl Deref for CacheAligned { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for CacheAligned { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl CacheAligned { + pub(super) fn new(t: T) -> Self { + CacheAligned(t, Aligner) + } +} diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index dcd4c8dfdf5..45a26e594b0 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -297,6 +297,8 @@ mod sync; mod mpsc_queue; mod spsc_queue; +mod cache_aligned; + /// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type. /// This half can only be owned by one thread. /// @@ -919,7 +921,7 @@ impl Drop for Sender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Sender {{ .. }}") + f.debug_struct("Sender").finish() } } @@ -1049,7 +1051,7 @@ impl Drop for SyncSender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for SyncSender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SyncSender {{ .. }}") + f.debug_struct("SyncSender").finish() } } @@ -1551,7 +1553,7 @@ impl Drop for Receiver { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Receiver {{ .. }}") + f.debug_struct("Receiver").finish() } } @@ -3009,22 +3011,4 @@ mod sync_tests { repro() } } - - #[test] - fn fmt_debug_sender() { - let (tx, _) = channel::(); - assert_eq!(format!("{:?}", tx), "Sender { .. }"); - } - - #[test] - fn fmt_debug_recv() { - let (_, rx) = channel::(); - assert_eq!(format!("{:?}", rx), "Receiver { .. }"); - } - - #[test] - fn fmt_debug_sync_sender() { - let (tx, _) = sync_channel::(1); - assert_eq!(format!("{:?}", tx), "SyncSender { .. }"); - } } diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index e49f4cff024..a9f3cea243f 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -354,13 +354,13 @@ impl Iterator for Packets { impl fmt::Debug for Select { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Select {{ .. }}") + f.debug_struct("Select").finish() } } impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Handle {{ .. }}") + f.debug_struct("Handle").finish() } } @@ -774,18 +774,4 @@ mod tests { } } } - - #[test] - fn fmt_debug_select() { - let sel = Select::new(); - assert_eq!(format!("{:?}", sel), "Select { .. }"); - } - - #[test] - fn fmt_debug_handle() { - let (_, rx) = channel::(); - let sel = Select::new(); - let handle = sel.handle(&rx); - assert_eq!(format!("{:?}", handle), "Handle { .. }"); - } } diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 1148bc66fba..cc4be92276a 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -22,12 +22,15 @@ use core::cell::UnsafeCell; use sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; +use super::cache_aligned::CacheAligned; + // Node within the linked list queue of messages to send struct Node { // FIXME: this could be an uninitialized T if we're careful enough, and // that would reduce memory usage (and be a bit faster). // is it worth it? value: Option, // nullable for re-use of nodes + cached: bool, // This node goes into the node cache next: AtomicPtr>, // next node in the queue } @@ -35,38 +38,55 @@ struct Node { /// but it can be safely shared in an Arc if it is guaranteed that there /// is only one popper and one pusher touching the queue at any one point in /// time. -pub struct Queue { +pub struct Queue { // consumer fields - tail: UnsafeCell<*mut Node>, // where to pop from - tail_prev: AtomicPtr>, // where to pop from + consumer: CacheAligned>, // producer fields + producer: CacheAligned>, +} + +struct Consumer { + tail: UnsafeCell<*mut Node>, // where to pop from + tail_prev: AtomicPtr>, // where to pop from + cache_bound: usize, // maximum cache size + cached_nodes: AtomicUsize, // number of nodes marked as cachable + addition: Addition, +} + +struct Producer { head: UnsafeCell<*mut Node>, // where to push to first: UnsafeCell<*mut Node>, // where to get new nodes from tail_copy: UnsafeCell<*mut Node>, // between first/tail - - // Cache maintenance fields. Additions and subtractions are stored - // separately in order to allow them to use nonatomic addition/subtraction. - cache_bound: usize, - cache_additions: AtomicUsize, - cache_subtractions: AtomicUsize, + addition: Addition, } -unsafe impl Send for Queue { } +unsafe impl Send for Queue { } -unsafe impl Sync for Queue { } +unsafe impl Sync for Queue { } impl Node { fn new() -> *mut Node { Box::into_raw(box Node { value: None, + cached: false, next: AtomicPtr::new(ptr::null_mut::>()), }) } } -impl Queue { - /// Creates a new queue. +impl Queue { + + /// Creates a new queue. With given additional elements in the producer and + /// consumer portions of the queue. + /// + /// Due to the performance implications of cache-contention, + /// we wish to keep fields used mainly by the producer on a separate cache + /// line than those used by the consumer. + /// Since cache lines are usually 64 bytes, it is unreasonably expensive to + /// allocate one for small fields, so we allow users to insert additional + /// fields into the cache lines already allocated by this for the producer + /// and consumer. /// /// This is unsafe as the type system doesn't enforce a single /// consumer-producer relationship. It also allows the consumer to `pop` @@ -83,19 +103,28 @@ impl Queue { /// cache (if desired). If the value is 0, then the cache has /// no bound. Otherwise, the cache will never grow larger than /// `bound` (although the queue itself could be much larger. - pub unsafe fn new(bound: usize) -> Queue { + pub unsafe fn with_additions( + bound: usize, + producer_addition: ProducerAddition, + consumer_addition: ConsumerAddition, + ) -> Self { let n1 = Node::new(); let n2 = Node::new(); (*n1).next.store(n2, Ordering::Relaxed); Queue { - tail: UnsafeCell::new(n2), - tail_prev: AtomicPtr::new(n1), - head: UnsafeCell::new(n2), - first: UnsafeCell::new(n1), - tail_copy: UnsafeCell::new(n1), - cache_bound: bound, - cache_additions: AtomicUsize::new(0), - cache_subtractions: AtomicUsize::new(0), + consumer: CacheAligned::new(Consumer { + tail: UnsafeCell::new(n2), + tail_prev: AtomicPtr::new(n1), + cache_bound: bound, + cached_nodes: AtomicUsize::new(0), + addition: consumer_addition + }), + producer: CacheAligned::new(Producer { + head: UnsafeCell::new(n2), + first: UnsafeCell::new(n1), + tail_copy: UnsafeCell::new(n1), + addition: producer_addition + }), } } @@ -109,35 +138,25 @@ impl Queue { assert!((*n).value.is_none()); (*n).value = Some(t); (*n).next.store(ptr::null_mut(), Ordering::Relaxed); - (**self.head.get()).next.store(n, Ordering::Release); - *self.head.get() = n; + (**self.producer.head.get()).next.store(n, Ordering::Release); + *(&self.producer.head).get() = n; } } unsafe fn alloc(&self) -> *mut Node { // First try to see if we can consume the 'first' node for our uses. - // We try to avoid as many atomic instructions as possible here, so - // the addition to cache_subtractions is not atomic (plus we're the - // only one subtracting from the cache). - if *self.first.get() != *self.tail_copy.get() { - if self.cache_bound > 0 { - let b = self.cache_subtractions.load(Ordering::Relaxed); - self.cache_subtractions.store(b + 1, Ordering::Relaxed); - } - let ret = *self.first.get(); - *self.first.get() = (*ret).next.load(Ordering::Relaxed); + if *self.producer.first.get() != *self.producer.tail_copy.get() { + let ret = *self.producer.first.get(); + *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); return ret; } // If the above fails, then update our copy of the tail and try // again. - *self.tail_copy.get() = self.tail_prev.load(Ordering::Acquire); - if *self.first.get() != *self.tail_copy.get() { - if self.cache_bound > 0 { - let b = self.cache_subtractions.load(Ordering::Relaxed); - self.cache_subtractions.store(b + 1, Ordering::Relaxed); - } - let ret = *self.first.get(); - *self.first.get() = (*ret).next.load(Ordering::Relaxed); + *self.producer.0.tail_copy.get() = + self.consumer.tail_prev.load(Ordering::Acquire); + if *self.producer.first.get() != *self.producer.tail_copy.get() { + let ret = *self.producer.first.get(); + *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); return ret; } // If all of that fails, then we have to allocate a new node @@ -153,27 +172,27 @@ impl Queue { // sentinel from where we should start popping from. Hence, look at // tail's next field and see if we can use it. If we do a pop, then // the current tail node is a candidate for going into the cache. - let tail = *self.tail.get(); + let tail = *self.consumer.tail.get(); let next = (*tail).next.load(Ordering::Acquire); if next.is_null() { return None } assert!((*next).value.is_some()); let ret = (*next).value.take(); - *self.tail.get() = next; - if self.cache_bound == 0 { - self.tail_prev.store(tail, Ordering::Release); + *self.consumer.0.tail.get() = next; + if self.consumer.cache_bound == 0 { + self.consumer.tail_prev.store(tail, Ordering::Release); } else { - // FIXME: this is dubious with overflow. - let additions = self.cache_additions.load(Ordering::Relaxed); - let subtractions = self.cache_subtractions.load(Ordering::Relaxed); - let size = additions - subtractions; + let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed); + if cached_nodes < self.consumer.cache_bound && !(*tail).cached { + self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed); + (*tail).cached = true; + } - if size < self.cache_bound { - self.tail_prev.store(tail, Ordering::Release); - self.cache_additions.store(additions + 1, Ordering::Relaxed); + if (*tail).cached { + self.consumer.tail_prev.store(tail, Ordering::Release); } else { - (*self.tail_prev.load(Ordering::Relaxed)) - .next.store(next, Ordering::Relaxed); + (*self.consumer.tail_prev.load(Ordering::Relaxed)) + .next.store(next, Ordering::Relaxed); // We have successfully erased all references to 'tail', so // now we can safely drop it. let _: Box> = Box::from_raw(tail); @@ -194,17 +213,25 @@ impl Queue { // This is essentially the same as above with all the popping bits // stripped out. unsafe { - let tail = *self.tail.get(); + let tail = *self.consumer.tail.get(); let next = (*tail).next.load(Ordering::Acquire); if next.is_null() { None } else { (*next).value.as_mut() } } } + + pub fn producer_addition(&self) -> &ProducerAddition { + &self.producer.addition + } + + pub fn consumer_addition(&self) -> &ConsumerAddition { + &self.consumer.addition + } } -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { - let mut cur = *self.first.get(); + let mut cur = *self.producer.first.get(); while !cur.is_null() { let next = (*cur).next.load(Ordering::Relaxed); let _n: Box> = Box::from_raw(cur); @@ -224,7 +251,7 @@ mod tests { #[test] fn smoke() { unsafe { - let queue = Queue::new(0); + let queue = Queue::with_additions(0, (), ()); queue.push(1); queue.push(2); assert_eq!(queue.pop(), Some(1)); @@ -241,7 +268,7 @@ mod tests { #[test] fn peek() { unsafe { - let queue = Queue::new(0); + let queue = Queue::with_additions(0, (), ()); queue.push(vec![1]); // Ensure the borrowchecker works @@ -264,7 +291,7 @@ mod tests { #[test] fn drop_full() { unsafe { - let q: Queue> = Queue::new(0); + let q: Queue> = Queue::with_additions(0, (), ()); q.push(box 1); q.push(box 2); } @@ -273,7 +300,7 @@ mod tests { #[test] fn smoke_bound() { unsafe { - let q = Queue::new(0); + let q = Queue::with_additions(0, (), ()); q.push(1); q.push(2); assert_eq!(q.pop(), Some(1)); @@ -295,7 +322,7 @@ mod tests { } unsafe fn stress_bound(bound: usize) { - let q = Arc::new(Queue::new(bound)); + let q = Arc::new(Queue::with_additions(bound, (), ())); let (tx, rx) = channel(); let q2 = q.clone(); diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 47cd8977fda..d1515eba68c 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -41,15 +41,22 @@ const MAX_STEALS: isize = 5; const MAX_STEALS: isize = 1 << 20; pub struct Packet { - queue: spsc::Queue>, // internal queue for all message + // internal queue for all messages + queue: spsc::Queue, ProducerAddition, ConsumerAddition>, +} +struct ProducerAddition { cnt: AtomicIsize, // How many items are on this channel - steals: UnsafeCell, // How many times has a port received without blocking? to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up port_dropped: AtomicBool, // flag if the channel has been destroyed. } +struct ConsumerAddition { + steals: UnsafeCell, // How many times has a port received without blocking? +} + + pub enum Failure { Empty, Disconnected, @@ -78,13 +85,18 @@ enum Message { impl Packet { pub fn new() -> Packet { Packet { - queue: unsafe { spsc::Queue::new(128) }, + queue: unsafe { spsc::Queue::with_additions( + 128, + ProducerAddition { + cnt: AtomicIsize::new(0), + to_wake: AtomicUsize::new(0), - cnt: AtomicIsize::new(0), - steals: UnsafeCell::new(0), - to_wake: AtomicUsize::new(0), - - port_dropped: AtomicBool::new(false), + port_dropped: AtomicBool::new(false), + }, + ConsumerAddition { + steals: UnsafeCell::new(0), + } + )}, } } @@ -92,7 +104,7 @@ impl Packet { // If the other port has deterministically gone away, then definitely // must return the data back up the stack. Otherwise, the data is // considered as being sent. - if self.port_dropped.load(Ordering::SeqCst) { return Err(t) } + if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) } match self.do_send(Data(t)) { UpSuccess | UpDisconnected => {}, @@ -104,14 +116,16 @@ impl Packet { pub fn upgrade(&self, up: Receiver) -> UpgradeResult { // If the port has gone away, then there's no need to proceed any // further. - if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected } + if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { + return UpDisconnected + } self.do_send(GoUp(up)) } fn do_send(&self, t: Message) -> UpgradeResult { self.queue.push(t); - match self.cnt.fetch_add(1, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) { // As described in the mod's doc comment, -1 == wakeup -1 => UpWoke(self.take_to_wake()), // As as described before, SPSC queues must be >= -2 @@ -125,7 +139,7 @@ impl Packet { // will never remove this data. We can only have at most one item to // drain (the port drains the rest). DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); let first = self.queue.pop(); let second = self.queue.pop(); assert!(second.is_none()); @@ -144,8 +158,8 @@ impl Packet { // Consumes ownership of the 'to_wake' field. fn take_to_wake(&self) -> SignalToken { - let ptr = self.to_wake.load(Ordering::SeqCst); - self.to_wake.store(0, Ordering::SeqCst); + let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); assert!(ptr != 0); unsafe { SignalToken::cast_from_usize(ptr) } } @@ -154,14 +168,16 @@ impl Packet { // back if it shouldn't sleep. Note that this is the location where we take // steals into account. fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); let ptr = unsafe { token.cast_to_usize() }; - self.to_wake.store(ptr, Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst); - let steals = unsafe { ptr::replace(self.steals.get(), 0) }; + let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) }; - match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { - DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } + match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) { + DISCONNECTED => { + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); + } // If we factor in our steals and notice that the channel has no // data, we successfully sleep n => { @@ -170,7 +186,7 @@ impl Packet { } } - self.to_wake.store(0, Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); Err(unsafe { SignalToken::cast_from_usize(ptr) }) } @@ -201,7 +217,7 @@ impl Packet { // "steal" factored into the channel count above). data @ Ok(..) | data @ Err(Upgraded(..)) => unsafe { - *self.steals.get() -= 1; + *self.queue.consumer_addition().steals.get() -= 1; data }, @@ -223,20 +239,21 @@ impl Packet { // down as much as possible (without going negative), and then // adding back in whatever we couldn't factor into steals. Some(data) => unsafe { - if *self.steals.get() > MAX_STEALS { - match self.cnt.swap(0, Ordering::SeqCst) { + if *self.queue.consumer_addition().steals.get() > MAX_STEALS { + match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) { DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store( + DISCONNECTED, Ordering::SeqCst); } n => { - let m = cmp::min(n, *self.steals.get()); - *self.steals.get() -= m; + let m = cmp::min(n, *self.queue.consumer_addition().steals.get()); + *self.queue.consumer_addition().steals.get() -= m; self.bump(n - m); } } - assert!(*self.steals.get() >= 0); + assert!(*self.queue.consumer_addition().steals.get() >= 0); } - *self.steals.get() += 1; + *self.queue.consumer_addition().steals.get() += 1; match data { Data(t) => Ok(t), GoUp(up) => Err(Upgraded(up)), @@ -244,7 +261,7 @@ impl Packet { }, None => { - match self.cnt.load(Ordering::SeqCst) { + match self.queue.producer_addition().cnt.load(Ordering::SeqCst) { n if n != DISCONNECTED => Err(Empty), // This is a little bit of a tricky case. We failed to pop @@ -273,7 +290,7 @@ impl Packet { pub fn drop_chan(&self) { // Dropping a channel is pretty simple, we just flag it as disconnected // and then wakeup a blocker if there is one. - match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) { -1 => { self.take_to_wake().signal(); } DISCONNECTED => {} n => { assert!(n >= 0); } @@ -300,7 +317,7 @@ impl Packet { // sends are gated on this flag, so we're immediately guaranteed that // there are a bounded number of active sends that we'll have to deal // with. - self.port_dropped.store(true, Ordering::SeqCst); + self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst); // Now that we're guaranteed to deal with a bounded number of senders, // we need to drain the queue. This draining process happens atomically @@ -310,9 +327,9 @@ impl Packet { // continue to fail while active senders send data while we're dropping // data, but eventually we're guaranteed to break out of this loop // (because there is a bounded number of senders). - let mut steals = unsafe { *self.steals.get() }; + let mut steals = unsafe { *self.queue.consumer_addition().steals.get() }; while { - let cnt = self.cnt.compare_and_swap( + let cnt = self.queue.producer_addition().cnt.compare_and_swap( steals, DISCONNECTED, Ordering::SeqCst); cnt != DISCONNECTED && cnt != steals } { @@ -353,9 +370,9 @@ impl Packet { // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { - match self.cnt.fetch_add(amt, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) { DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); DISCONNECTED } n => n @@ -404,8 +421,8 @@ impl Packet { // this end. This is fine because we know it's a small bounded windows // of time until the data is actually sent. if was_upgrade { - assert_eq!(unsafe { *self.steals.get() }, 0); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); return Ok(true) } @@ -418,7 +435,7 @@ impl Packet { // If we were previously disconnected, then we know for sure that there // is no thread in to_wake, so just keep going let has_data = if prev == DISCONNECTED { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); true // there is data, that data is that we're disconnected } else { let cur = prev + steals + 1; @@ -441,13 +458,13 @@ impl Packet { if prev < 0 { drop(self.take_to_wake()); } else { - while self.to_wake.load(Ordering::SeqCst) != 0 { + while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 { thread::yield_now(); } } unsafe { - assert_eq!(*self.steals.get(), 0); - *self.steals.get() = steals; + assert_eq!(*self.queue.consumer_addition().steals.get(), 0); + *self.queue.consumer_addition().steals.get() = steals; } // if we were previously positive, then there's surely data to @@ -481,7 +498,7 @@ impl Drop for Packet { // disconnection, but also a proper fence before the read of // `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert. - assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); } } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 1d62853e906..eb507858b92 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -394,11 +394,18 @@ impl Default for Mutex { impl fmt::Debug for Mutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 4757faabfb8..5c49d6b5845 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -428,11 +428,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock { impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_read() { - Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index c8019d1c768..e775f857f2b 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -176,11 +176,16 @@ impl Socket { } 0 => {} _ => { - if pollfd.revents & libc::POLLOUT == 0 { - if let Some(e) = self.take_error()? { - return Err(e); - } + // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look + // for POLLHUP rather than read readiness + if pollfd.revents & libc::POLLHUP != 0 { + let e = self.take_error()? + .unwrap_or_else(|| { + io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") + }); + return Err(e); } + return Ok(()); } } diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 3f6c2827a3f..d6b8896ac09 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -9,6 +9,62 @@ // except according to those terms. //! Windows-specific extensions to the primitives in the `std::ffi` module. +//! +//! # Overview +//! +//! For historical reasons, the Windows API uses a form of potentially +//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit +//! code units in Windows strings may contain [isolated surrogate code +//! points which are not paired together][ill-formed-utf-16]. The +//! Unicode standard requires that surrogate code points (those in the +//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16 +//! encoding a *surrogate code unit pair* is used to encode a single +//! character. For compatibility with code that does not enforce +//! these pairings, Windows does not enforce them, either. +//! +//! While it is not always possible to convert such a string losslessly into +//! a valid UTF-16 string (or even UTF-8), it is often desirable to be +//! able to round-trip such a string from and to Windows APIs +//! losslessly. For example, some Rust code may be "bridging" some +//! Windows APIs together, just passing `WCHAR` strings among those +//! APIs without ever really looking into the strings. +//! +//! If Rust code *does* need to look into those strings, it can +//! convert them to valid UTF-8, possibly lossily, by substituting +//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is +//! conventionally done in other Rust APIs that deal with string +//! encodings. +//! +//! # `OsStringExt` and `OsStrExt` +//! +//! [`OsString`] is the Rust wrapper for owned strings in the +//! preferred representation of the operating system. On Windows, +//! this struct gets augmented with an implementation of the +//! [`OsStringExt`] trait, which has a [`from_wide`] method. This +//! lets you create an [`OsString`] from a `&[u16]` slice; presumably +//! you get such a slice out of a `WCHAR` Windows API. +//! +//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from +//! preferred representation of the operating system. On Windows, the +//! [`OsStrExt`] trait provides the [`encode_wide`] method, which +//! outputs an [`EncodeWide`] iterator. You can [`collect`] this +//! iterator, for example, to obtain a `Vec`; you can later get a +//! pointer to this vector's contents and feed it to Windows APIs. +//! +//! These traits, along with [`OsString`] and [`OsStr`], work in +//! conjunction so that it is possible to **round-trip** strings from +//! Windows and back, with no loss of data, even if the strings are +//! ill-formed UTF-16. +//! +//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 +//! [`OsString`]: ../../../ffi/struct.OsString.html +//! [`OsStr`]: ../../../ffi/struct.OsStr.html +//! [`OsStringExt`]: trait.OsStringExt.html +//! [`OsStrExt`]: trait.OsStrExt.html +//! [`EncodeWide`]: struct.EncodeWide.html +//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide +//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide +//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index 4d0407ccf6c..ce43ec6d9ab 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -116,11 +116,18 @@ impl Drop for ReentrantMutex { impl fmt::Debug for ReentrantMutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 30887b16c60..07bbddc62b9 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -485,15 +485,17 @@ impl Builder { /// let (tx, rx) = channel(); /// /// let sender = thread::spawn(move || { -/// let _ = tx.send("Hello, thread".to_owned()); +/// tx.send("Hello, thread".to_owned()) +/// .expect("Unable to send on channel"); /// }); /// /// let receiver = thread::spawn(move || { -/// println!("{}", rx.recv().unwrap()); +/// let value = rx.recv().expect("Unable to receive from channel"); +/// println!("{}", value); /// }); /// -/// let _ = sender.join(); -/// let _ = receiver.join(); +/// sender.join().expect("The sender thread has panicked"); +/// receiver.join().expect("The receiver thread has panicked"); /// ``` /// /// A thread can also return a value through its [`JoinHandle`], you can use @@ -1192,7 +1194,7 @@ impl JoinInner { /// }); /// }); /// -/// let _ = original_thread.join(); +/// original_thread.join().expect("The thread being joined has panicked"); /// println!("Original thread is joined."); /// /// // We make sure that the new thread has time to run, before the main diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 021f96aff8c..f445def9e03 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1419,7 +1419,7 @@ pub enum TyKind { Path(Option, Path), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(TyParamBounds), + TraitObject(TyParamBounds, TraitObjectSyntax), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. ImplTrait(TyParamBounds), @@ -1438,6 +1438,13 @@ pub enum TyKind { Err, } +/// Syntax used to declare a trait object. +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TraitObjectSyntax { + Dyn, + None, +} + /// Inline assembly dialect. /// /// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`` diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a2f29181a20..9060a613bc1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -398,6 +398,9 @@ declare_features! ( // Default match binding modes (RFC 2005) (active, match_default_bindings, "1.22.0", Some(42640)), + + // Trait object syntax with `dyn` prefix + (active, dyn_trait, "1.22.0", Some(44662)), ); declare_features! ( @@ -1417,6 +1420,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental"); }, + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { + gate_feature_post!(&self, dyn_trait, ty.span, + "`dyn Trait` syntax is unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 03c47b71d02..d7d491db71f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -400,8 +400,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyKind::Typeof(expr) => { TyKind::Typeof(fld.fold_expr(expr)) } - TyKind::TraitObject(bounds) => { - TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b))) + TyKind::TraitObject(bounds, syntax) => { + TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax) } TyKind::ImplTrait(bounds) => { TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b))) diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 39b5482a066..35afe8dd56d 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -144,7 +144,7 @@ const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[ ('‵', "Reversed Prime", '\''), ('՚', "Armenian Apostrophe", '\''), ('׳', "Hebrew Punctuation Geresh", '\''), - ('`', "Greek Accent", '\''), + ('`', "Grave Accent", '\''), ('`', "Greek Varia", '\''), ('`', "Fullwidth Grave Accent", '\''), ('´', "Acute Accent", '\''), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 978e06c75dd..bd400ef6dd6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -33,7 +33,7 @@ use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; use ast::StrStyle; use ast::SelfKind; -use ast::{TraitItem, TraitRef}; +use ast::{TraitItem, TraitRef, TraitObjectSyntax}; use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; @@ -364,6 +364,13 @@ fn is_ident_or_underscore(t: &token::Token) -> bool { t.is_ident() || *t == token::Underscore } +// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT`, +// `IDENT<::AssocTy>`, `IDENT(u8, u8) -> u8`. +fn can_continue_type_after_ident(t: &token::Token) -> bool { + t == &token::ModSep || t == &token::Lt || + t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren) +} + /// Information about the path to a module. pub struct ModulePath { pub name: String, @@ -1428,7 +1435,7 @@ impl<'a> Parser<'a> { TyKind::Path(None, ref path) if maybe_bounds => { self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? } - TyKind::TraitObject(ref bounds) + TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { let path = match bounds[0] { TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), @@ -1472,6 +1479,35 @@ impl<'a> Parser<'a> { } else if self.eat(&token::Underscore) { // A type to be inferred `_` TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? + } + } else if self.eat_keyword(keywords::Impl) { + // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). + TyKind::ImplTrait(self.parse_ty_param_bounds()?) + } else if self.check_keyword(keywords::Dyn) && + self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) { + // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511). + self.bump(); // `dyn` + TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn) + } else if self.check(&token::Question) || + self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) { + // Bound list (trait object type) + TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?, + TraitObjectSyntax::None) } else if self.eat_lt() { // Qualified path let (qself, path) = self.parse_qpath(PathStyle::Type)?; @@ -1493,29 +1529,6 @@ impl<'a> Parser<'a> { TyKind::Path(None, path) } } - } else if self.token_is_bare_fn_keyword() { - // Function pointer type - self.parse_ty_bare_fn(Vec::new())? - } else if self.check_keyword(keywords::For) { - // Function pointer type or bound list (trait object type) starting with a poly-trait. - // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` - // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs)? - } else { - let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); - self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? - } - } else if self.eat_keyword(keywords::Impl) { - // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). - TyKind::ImplTrait(self.parse_ty_param_bounds()?) - } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){ - // Bound list (trait object type) - TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); @@ -1538,7 +1551,7 @@ impl<'a> Parser<'a> { self.bump(); // `+` bounds.append(&mut self.parse_ty_param_bounds()?); } - Ok(TyKind::TraitObject(bounds)) + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { @@ -2314,6 +2327,7 @@ impl<'a> Parser<'a> { while self.token != token::CloseDelim(token::Brace) { if self.eat(&token::DotDot) { + let exp_span = self.prev_span; match self.parse_expr() { Ok(e) => { base = Some(e); @@ -2323,6 +2337,16 @@ impl<'a> Parser<'a> { self.recover_stmt(); } } + if self.token == token::Comma { + let mut err = self.sess.span_diagnostic.mut_span_err( + exp_span.to(self.prev_span), + "cannot use a comma after the base struct", + ); + err.span_suggestion_short(self.span, "remove this comma", "".to_owned()); + err.note("the base struct must always be the last field"); + err.emit(); + self.recover_stmt(); + } break; } @@ -2890,17 +2914,30 @@ impl<'a> Parser<'a> { match self.parse_path(PathStyle::Expr) { Ok(path) => { + let (op_noun, op_verb) = match self.token { + token::Lt => ("comparison", "comparing"), + token::BinOp(token::Shl) => ("shift", "shifting"), + _ => { + // We can end up here even without `<` being the next token, for + // example because `parse_ty_no_plus` returns `Err` on keywords, + // but `parse_path` returns `Ok` on them due to error recovery. + // Return original error and parser state. + mem::replace(self, parser_snapshot_after_type); + return Err(type_err); + } + }; + // Successfully parsed the type path leaving a `<` yet to parse. type_err.cancel(); // Report non-fatal diagnostics, keep `x as usize` as an expression // in AST and continue parsing. let msg = format!("`<` is interpreted as a start of generic \ - arguments for `{}`, not a comparison", path); + arguments for `{}`, not a {}", path, op_noun); let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg); err.span_label(self.look_ahead_span(1).to(parser_snapshot_after_type.span), "interpreted as generic arguments"); - err.span_label(self.span, "not interpreted as comparison"); + err.span_label(self.span, format!("not interpreted as {}", op_noun)); let expr = mk_expr(self, P(Ty { span: path.span, @@ -2911,7 +2948,7 @@ impl<'a> Parser<'a> { let expr_str = self.sess.codemap().span_to_snippet(expr.span) .unwrap_or(pprust::expr_to_string(&expr)); err.span_suggestion(expr.span, - "try comparing the casted value", + &format!("try {} the casted value", op_verb), format!("({})", expr_str)); err.emit(); @@ -2947,6 +2984,7 @@ impl<'a> Parser<'a> { { // Foo>> err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); + err.help("or use `(...)` if you meant to specify fn arguments"); } err.emit(); } @@ -4231,6 +4269,7 @@ impl<'a> Parser<'a> { fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { + // This needs to be syncronized with `Token::can_begin_bound`. let is_bound_start = self.check_path() || self.check_lifetime() || self.check(&token::Question) || self.check_keyword(keywords::For) || diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4888654fac9..20db87cfc82 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -258,6 +258,12 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of a generic bound. + pub fn can_begin_bound(&self) -> bool { + self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) || + self == &Question || self == &OpenDelim(Paren) + } + /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 959dd4ef30f..02f871c58c7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1049,8 +1049,9 @@ impl<'a> State<'a> { ast::TyKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false)? } - ast::TyKind::TraitObject(ref bounds) => { - self.print_bounds("", &bounds[..])?; + ast::TyKind::TraitObject(ref bounds, syntax) => { + let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" }; + self.print_bounds(prefix, &bounds[..])?; } ast::TyKind::ImplTrait(ref bounds) => { self.print_bounds("impl ", &bounds[..])?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 05077d42a0b..521c6030eba 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -348,7 +348,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { visitor.visit_ty(ty); visitor.visit_expr(expression) } - TyKind::TraitObject(ref bounds) | + TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(ref bounds) => { walk_list!(visitor, visit_ty_param_bound, bounds); } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 2000db9703c..d30d79ece15 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -339,8 +339,11 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", - span.lo(), span.hi(), span.ctxt()) + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() } impl fmt::Debug for Span { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 4d3db15ef29..872fc031cfb 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -309,10 +309,11 @@ declare_keywords! { (54, Yield, "yield") // Weak keywords, have special meaning only in specific contexts. - (55, Default, "default") - (56, StaticLifetime, "'static") - (57, Union, "union") - (58, Catch, "catch") + (55, Catch, "catch") + (56, Default, "default") + (57, Dyn, "dyn") + (58, StaticLifetime, "'static") + (59, Union, "union") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/llvm b/src/llvm index c7a16bd57c2..83b72cedfd7 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit c7a16bd57c2a9c643a52f0cebecdaf0b6a996da1 +Subproject commit 83b72cedfd7800ffc983d2855a85c5d06a545aa7 diff --git a/src/rustc/compiler_builtins_shim/Cargo.toml b/src/rustc/compiler_builtins_shim/Cargo.toml index 886e239246d..608e5f5f36d 100644 --- a/src/rustc/compiler_builtins_shim/Cargo.toml +++ b/src/rustc/compiler_builtins_shim/Cargo.toml @@ -30,7 +30,7 @@ doctest = false core = { path = "../../libcore" } [build-dependencies] -cc = "1.0" +cc = "1.0.1" [features] c = [] diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index e37f048dd47..1287b94159a 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -901,9 +901,7 @@ addPreservedGUID(const ModuleSummaryIndex &Index, } } - GlobalValueSummary *GVSummary = Summary.get(); - if (isa(GVSummary)) { - FunctionSummary *FS = cast(GVSummary); + if (auto *FS = dyn_cast(Summary.get())) { for (auto &Call: FS->calls()) { if (Call.first.isGUID()) { addPreservedGUID(Index, Preserved, Call.first.getGUID()); @@ -916,6 +914,10 @@ addPreservedGUID(const ModuleSummaryIndex &Index, addPreservedGUID(Index, Preserved, GUID); } } + if (auto *AS = dyn_cast(Summary.get())) { + auto GUID = AS->getAliasee().getOriginalName(); + addPreservedGUID(Index, Preserved, GUID); + } } } @@ -963,12 +965,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // combined index // // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` - computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols); + auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols); ComputeCrossModuleImport( Ret->Index, Ret->ModuleToDefinedGVSummaries, Ret->ImportLists, - Ret->ExportLists + Ret->ExportLists, + &DeadSymbols ); // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index bc616f64881..20ea8d70302 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -57,7 +57,7 @@ static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) { llvm_unreachable("Invalid LLVMAtomicOrdering value!"); } -static char *LastError; +static LLVM_THREAD_LOCAL char *LastError; extern "C" LLVMMemoryBufferRef LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index bd1325e7501..b8033b88fb7 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic0[Internal] struct StructWithDtor(u32); diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index 108a8b570de..65936d12e31 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 875cacb3907..e32366d15c3 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index a6081b2c5eb..5765f230e8b 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index 8eef5f00f2a..be560690e51 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index 7edb1c14525..ad1475a73f7 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index cf0c6643238..d7e457cde8a 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] #![feature(coerce_unsized)] diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 4e6ae167024..29528644ed0 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -13,6 +13,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue +// compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 20920c9ebe4..4bfd35b59bc 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -12,6 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/inlining-from-extern-crate +// compile-flags:-Zinline-in-all-cgus #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index d2ce847e108..65e91343ccf 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -12,6 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue +// compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs new file mode 100644 index 00000000000..84464a627be --- /dev/null +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -0,0 +1,54 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining-but-not-all +// compile-flags:-Zinline-in-all-cgus=no + +#![allow(dead_code)] +#![crate_type="lib"] + +mod inline { + + //~ TRANS_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External] + #[inline] + pub fn inlined_function() + { + + } +} + +mod user1 { + use super::inline; + + //~ TRANS_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[Internal] + fn foo() { + inline::inlined_function(); + } +} + +mod user2 { + use super::inline; + + //~ TRANS_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[Internal] + fn bar() { + inline::inlined_function(); + } +} + +mod non_user { + + //~ TRANS_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[Internal] + fn baz() { + + } +} diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index a4d9e60d228..f3176191241 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -12,6 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining +// compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 1beaa186d9e..bda76a8789f 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -12,6 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-transitive-inlining +// compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index 74f2f843567..302f9312b57 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -13,6 +13,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const +// compile-flags:-Zinline-in-all-cgus // This test case makes sure, that references made through constants are // recorded properly in the InliningMap. diff --git a/src/test/codegen/auxiliary/nounwind.rs b/src/test/codegen/auxiliary/nounwind.rs new file mode 100644 index 00000000000..5e40e8ede15 --- /dev/null +++ b/src/test/codegen/auxiliary/nounwind.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[no_mangle] +pub fn bar() { +} diff --git a/src/test/codegen/float_math.rs b/src/test/codegen/float_math.rs index bc458d45446..6a6d6f90b2e 100644 --- a/src/test/codegen/float_math.rs +++ b/src/test/codegen/float_math.rs @@ -19,7 +19,7 @@ use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; #[no_mangle] pub fn add(x: f32, y: f32) -> f32 { // CHECK: fadd float -// CHECK-NOT fast +// CHECK-NOT: fast x + y } diff --git a/src/test/codegen/nounwind.rs b/src/test/codegen/nounwind.rs new file mode 100644 index 00000000000..9fea907d3c8 --- /dev/null +++ b/src/test/codegen/nounwind.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:nounwind.rs +// compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a +// ignore-windows + +#![crate_type = "lib"] + +extern crate nounwind; + +#[no_mangle] +pub fn foo() { + nounwind::bar(); +// CHECK: @foo() unnamed_addr #0 +// CHECK: @bar() unnamed_addr #0 +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +} + diff --git a/src/test/codegen/panic-abort-windows.rs b/src/test/codegen/panic-abort-windows.rs index 2ab15277084..15688bdc2a1 100644 --- a/src/test/codegen/panic-abort-windows.rs +++ b/src/test/codegen/panic-abort-windows.rs @@ -28,7 +28,7 @@ #![crate_type = "lib"] -// CHECK: Function Attrs: uwtable +// CHECK: Function Attrs: nounwind uwtable // CHECK-NEXT: define void @normal_uwtable() #[no_mangle] pub fn normal_uwtable() { diff --git a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs index e63de3a3bed..548436c3ed8 100644 --- a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs @@ -22,7 +22,7 @@ fn a() { // immutable. Otherwise the type of &_q.x (&isize) would be wrong. p.x = 5; //[ast]~ ERROR cannot assign to `p.x` //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `p.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `p.x` because it is borrowed (Mir) q.x; } @@ -47,7 +47,7 @@ fn d() { let q = &p.y; p.y = 5; //[ast]~ ERROR cannot assign to `p.y` //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `p.1` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `p.y` because it is borrowed (Mir) *q; } diff --git a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs index 6c003ec2d48..0b6b9bf7d48 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs @@ -82,7 +82,7 @@ fn g() { let c1 = || get(&*x.f); *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `(*(*x).0)` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `(*x.f)` because it is borrowed (Mir) } fn h() { diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs new file mode 100644 index 00000000000..cff913b17be --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -0,0 +1,330 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +#![feature(slice_patterns)] +#![feature(advanced_slice_patterns)] + +pub struct Foo { + x: u32 +} + +pub struct Bar(u32); + +pub enum Baz { + X(u32) +} + +union U { + a: u8, + b: u64, +} + +impl Foo { + fn x(&mut self) -> &mut u32 { &mut self.x } +} + +impl Bar { + fn x(&mut self) -> &mut u32 { &mut self.0 } +} + +impl Baz { + fn x(&mut self) -> &mut u32 { + match *self { + Baz::X(ref mut value) => value + } + } +} + +static mut sfoo : Foo = Foo{x: 23 }; +static mut sbar : Bar = Bar(23); +static mut stuple : (i32, i32) = (24, 25); +static mut senum : Baz = Baz::X(26); +static mut sunion : U = U { a: 0 }; + +fn main() { + // Local and field from struct + { + let mut f = Foo { x: 22 }; + let _x = f.x(); + f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed + //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir) + } + // Local and field from tuple-struct + { + let mut g = Bar(22); + let _0 = g.x(); + g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir) + } + // Local and field from tuple + { + let mut h = (22, 23); + let _0 = &mut h.0; + h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir) + } + // Local and field from enum + { + let mut e = Baz::X(2); + let _e0 = e.x(); + match e { + Baz::X(value) => value + //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir) + }; + } + // Local and field from union + unsafe { + let mut u = U { b: 0 }; + let _ra = &mut u.a; + u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed + //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) + } + // Static and field from struct + unsafe { + let _x = sfoo.x(); + sfoo.x; //[mir]~ ERROR cannot use `sfoo.x` because it was mutably borrowed (Mir) + } + // Static and field from tuple-struct + unsafe { + let _0 = sbar.x(); + sbar.0; //[mir]~ ERROR cannot use `sbar.0` because it was mutably borrowed (Mir) + } + // Static and field from tuple + unsafe { + let _0 = &mut stuple.0; + stuple.0; //[mir]~ ERROR cannot use `stuple.0` because it was mutably borrowed (Mir) + } + // Static and field from enum + unsafe { + let _e0 = senum.x(); + match senum { + Baz::X(value) => value + //[mir]~^ ERROR cannot use `senum.0` because it was mutably borrowed (Mir) + }; + } + // Static and field from union + unsafe { + let _ra = &mut sunion.a; + sunion.a; //[mir]~ ERROR cannot use `sunion.a` because it was mutably borrowed (Mir) + } + // Deref and field from struct + { + let mut f = Box::new(Foo { x: 22 }); + let _x = f.x(); + f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed + //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir) + } + // Deref and field from tuple-struct + { + let mut g = Box::new(Bar(22)); + let _0 = g.x(); + g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir) + } + // Deref and field from tuple + { + let mut h = Box::new((22, 23)); + let _0 = &mut h.0; + h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir) + } + // Deref and field from enum + { + let mut e = Box::new(Baz::X(3)); + let _e0 = e.x(); + match *e { + Baz::X(value) => value + //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir) + }; + } + // Deref and field from union + unsafe { + let mut u = Box::new(U { b: 0 }); + let _ra = &mut u.a; + u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed + //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) + } + // Constant index + { + let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let _v = &mut v; + match v { + &[x, _, .., _, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x, .., _, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, _, .., x, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, _, .., _, x] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + } + // Subslices + { + let mut v = &[1, 2, 3, 4, 5]; + let _v = &mut v; + match v { + &[x..] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x..] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[x.., _] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x.., _] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + } + // Downcasted field + { + enum E { A(X), B { x: X } } + + let mut e = E::A(3); + let _e = &mut e; + match e { + E::A(ref ax) => + //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable (Mir) + //[mir]~| ERROR cannot use `e` because it was mutably borrowed (Mir) + println!("e.ax: {:?}", ax), + E::B { x: ref bx } => + //[ast]~^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable (Mir) + println!("e.bx: {:?}", bx), + } + } + // Field in field + { + struct F { x: u32, y: u32 }; + struct S { x: F, y: (u32, u32), }; + let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) }; + let _s = &mut s; + match s { + S { y: (ref y0, _), .. } => + //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable (Mir) + println!("y0: {:?}", y0), + _ => panic!("other case"), + } + match s { + S { x: F { y: ref x0, .. }, .. } => + //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable (Mir) + println!("x0: {:?}", x0), + _ => panic!("other case"), + } + } + // Field of ref + { + struct Block<'a> { + current: &'a u8, + unrelated: &'a u8, + }; + + fn bump<'a>(mut block: &mut Block<'a>) { + let x = &mut block; + let p: &'a u8 = &*block.current; + //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST because of issue rust#38899 + } + } + // Field of ptr + { + struct Block2 { + current: *const u8, + unrelated: *const u8, + } + + unsafe fn bump2(mut block: *mut Block2) { + let x = &mut block; + let p : *const u8 = &*(*block).current; + //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST because of issue rust#38899 + } + } + // Field of index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let _v = &mut v; + v[0].y; + //[ast]~^ ERROR cannot use `v[..].y` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..].y` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..].y` because it was mutably borrowed (Mir) + //[mir]~| ERROR cannot use `(*v)` because it was mutably borrowed (Mir) + } + // Field of constant index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let _v = &mut v; + match v { + &[_, F {x: ref xf, ..}] => println!("{}", xf), + //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST + _ => panic!("other case") + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs b/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs index 569ddb80c2f..017318b6b21 100644 --- a/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs +++ b/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + #[derive(Clone)] struct point { x: isize, @@ -16,6 +19,9 @@ struct point { fn main() { let mut origin: point; - origin = point {x: 10,.. origin}; //~ ERROR use of possibly uninitialized variable: `origin.y` + origin = point {x: 10,.. origin}; + //[ast]~^ ERROR use of possibly uninitialized variable: `origin.y` [E0381] + //[mir]~^^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] origin.clone(); } diff --git a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs new file mode 100644 index 00000000000..1d21f40fcca --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn main() { + let mut x = 1; + let _x = &mut x; + let _ = match x { + x => x + 1, //[ast]~ ERROR E0503 + //[mir]~^ ERROR (Mir) [E0503] + //[mir]~| ERROR (Ast) [E0503] + y => y + 2, //[ast]~ ERROR [E0503] + //[mir]~^ ERROR (Mir) [E0503] + //[mir]~| ERROR (Ast) [E0503] + }; +} diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs new file mode 100644 index 00000000000..957086f6af1 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs @@ -0,0 +1,49 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +// Check that do not allow access to fields of uninitialized or moved +// structs. + +#[derive(Default)] +struct Point { + x: isize, + y: isize, +} + +#[derive(Default)] +struct Line { + origin: Point, + middle: Point, + target: Point, +} + +impl Line { fn consume(self) { } } + +fn main() { + let mut a: Point; + let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` + //[mir]~^ ERROR [E0381] + //[mir]~| ERROR (Mir) [E0381] + + let mut line1 = Line::default(); + let _moved = line1.origin; + let _ = line1.origin.x + 1; //[ast]~ ERROR use of collaterally moved value: `line1.origin.x` + //[mir]~^ [E0382] + //[mir]~| (Mir) [E0381] + + let mut line2 = Line::default(); + let _moved = (line2.origin, line2.middle); + line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] + //[mir]~^ [E0382] + //[mir]~| (Mir) [E0381] +} diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs b/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs new file mode 100644 index 00000000000..71f8693b210 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs @@ -0,0 +1,60 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +struct S { + x: X, + y: Y, +} + +fn main() { + let x: &&Box; + let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] + //[mir]~^ (Ast) [E0381] + //[mir]~| (Mir) [E0381] + + let x: &&S; + let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] + //[mir]~^ (Ast) [E0381] + //[mir]~| (Mir) [E0381] + + let x: &&i32; + let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] + //[mir]~^ (Ast) [E0381] + //[mir]~| (Mir) [E0381] + + + let mut a: S; + a.x = 0; + let _b = &a.x; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + // (deliberately *not* an error under MIR-borrowck) + + let mut a: S<&&i32, &&i32>; + a.x = &&0; + let _b = &**a.x; //[ast]~ ERROR use of possibly uninitialized variable: `**a.x` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + // (deliberately *not* an error under MIR-borrowck) + + + let mut a: S; + a.x = 0; + let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] + + let mut a: S<&&i32, &&i32>; + a.x = &&0; + let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs index 73d323ea82c..0655d2914ee 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs @@ -34,13 +34,13 @@ fn main() { let ra = &u.a; let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Ast) - //[mir]~| ERROR cannot borrow `u.0` as mutable because it is also borrowed as immutable (Mir) + //[mir]~| ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Mir) } { let ra = &u.a; u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir) } // Imm borrow, other field { @@ -68,25 +68,25 @@ fn main() { let rma = &mut u.a; let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Ast) - //[mir]~| ERROR cannot borrow `u.0` as immutable because it is also borrowed as mutable (Mir) + //[mir]~| ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Mir) } { let ra = &mut u.a; let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) - //[mir]~| ERROR cannot use `u.0` because it was mutably borrowed (Mir) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) } { let rma = &mut u.a; let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time (Ast) - //[mir]~| ERROR cannot borrow `u.0` as mutable more than once at a time (Mir) + //[mir]~| ERROR cannot borrow `u.a` as mutable more than once at a time (Mir) } { let rma = &mut u.a; u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir) } // Mut borrow, other field { diff --git a/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs index 7291bcd2ce1..2b567ebd2db 100644 --- a/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs @@ -8,12 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + fn test() { let w: &mut [isize]; - w[5] = 0; //~ ERROR use of possibly uninitialized variable: `*w` + w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] let mut w: &mut [isize]; - w[5] = 0; //~ ERROR use of possibly uninitialized variable: `*w` + w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] } fn main() { test(); } diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs index 796b455f5c7..a48d09b195a 100644 --- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs +++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + // Variation on `borrowck-use-uninitialized-in-cast` in which we do a // trait cast from an uninitialized source. Issue #20791. @@ -16,5 +19,7 @@ impl Foo for i32 { } fn main() { let x: &i32; - let y = x as *const Foo; //~ ERROR use of possibly uninitialized variable: `*x` + let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x` + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] } diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs index 3f429bbd4b6..bdd90a3ce1e 100644 --- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs +++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -8,11 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + // Check that we detect unused values that are cast to other things. // The problem was specified to casting to `*`, as creating unsafe // pointers was not being fully checked. Issue #20791. fn main() { let x: &i32; - let y = x as *const i32; //~ ERROR use of possibly uninitialized variable: `*x` + let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381] + //[mir]~^ ERROR (Ast) [E0381] + //[mir]~| ERROR (Mir) [E0381] } diff --git a/src/test/compile-fail/dyn-trait-compatibility.rs b/src/test/compile-fail/dyn-trait-compatibility.rs new file mode 100644 index 00000000000..a7cfda504c7 --- /dev/null +++ b/src/test/compile-fail/dyn-trait-compatibility.rs @@ -0,0 +1,29 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type A0 = dyn; +//~^ ERROR cannot find type `dyn` in this scope +type A1 = dyn::dyn; +//~^ ERROR Use of undeclared type or module `dyn` +type A2 = dyn; +//~^ ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope +type A3 = dyn<::dyn>; +//~^ ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope +//~| ERROR Use of undeclared type or module `dyn` +type A4 = dyn(dyn, dyn) -> dyn; +//~^ ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope +//~| ERROR cannot find type `dyn` in this scope + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-dyn-trait.rs b/src/test/compile-fail/feature-gate-dyn-trait.rs new file mode 100644 index 00000000000..4b3803d019b --- /dev/null +++ b/src/test/compile-fail/feature-gate-dyn-trait.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} +type A = Box; //~ ERROR `dyn Trait` syntax is unstable + +fn main() {} diff --git a/src/test/compile-fail/hygiene/impl_items.rs b/src/test/compile-fail/hygiene/impl_items.rs index 445aa62f236..cdba559445d 100644 --- a/src/test/compile-fail/hygiene/impl_items.rs +++ b/src/test/compile-fail/hygiene/impl_items.rs @@ -19,7 +19,7 @@ mod foo { } pub macro m() { - let _: () = S.f(); //~ ERROR type `fn(&foo::S) {foo::S::f}` is private + let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private } } diff --git a/src/test/compile-fail/index-help.rs b/src/test/compile-fail/index-help.rs new file mode 100644 index 00000000000..2d37fc79250 --- /dev/null +++ b/src/test/compile-fail/index-help.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = vec![1]; + x[0i32]; //~ ERROR E0277 + //~| NOTE vector indices are of type `usize` or ranges of `usize` +} diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 276d7f7c9ed..85d91bb2db2 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,6 +15,6 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected type `fn(&mut __test::test::Bencher)` +//~| expected type `for<'r> fn(&'r mut __test::test::Bencher)` //~| found type `fn(isize) {bar}` //~| expected mutable reference, found isize diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs index fdd9166ef29..c0ba38b2402 100644 --- a/src/test/compile-fail/private-inferred-type-3.rs +++ b/src/test/compile-fail/private-inferred-type-3.rs @@ -15,7 +15,7 @@ // error-pattern:type `fn() {::method}` is private // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct::{{constructor}}}` is pr // error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv -// error-pattern:type `fn(&ext::Pub) {>::priv_method}` is private +// error-pattern:type `for<'r> fn(&'r ext::Pub) {>::priv_method}` is private #![feature(decl_macro)] diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 973d467b112..95e3732d613 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -56,7 +56,7 @@ mod m { PubTupleStruct; //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat Pub(0u8).priv_method(); - //~^ ERROR type `fn(&m::Pub) {>::priv_method}` is private + //~^ ERROR type `for<'r> fn(&'r m::Pub) {>::priv_method}` is private } trait Trait {} diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index ac7dd022c7c..6be65a5e359 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -58,8 +58,8 @@ fn supply_G() { want_G(bar); want_G(baz); //~^ ERROR mismatched types - //~| expected type `fn(&'cx S) -> &'static S` - //~| found type `fn(&S) -> &S {baz}` + //~| expected type `for<'cx> fn(&'cx S) -> &'static S` + //~| found type `for<'r> fn(&'r S) -> &'r S {baz}` //~| expected concrete lifetime, found bound lifetime parameter 'cx } diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs index cabe0fd48ed..6cd43916731 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(dyn_trait)] struct Foo; fn foo(_x: Box) { } //~ ERROR expected trait, found struct `Foo` +type A = Box>; //~ ERROR expected trait, found struct `Vec` + fn main() { } diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 9596f0287bc..2a28c895b79 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -44,6 +44,10 @@ // gdb-command: print some_string // gdb-check:$8 = Some = {"IAMA optional string!"} +// gdb-command: set print length 5 +// gdb-command: print some_string +// gdb-check:$8 = Some = {"IAMA "...} + // === LLDB TESTS ================================================================================== diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index 647ff5dedf3..0090c2aeef9 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -36,10 +36,8 @@ pub fn change_callee_function() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_callee_function() { @@ -55,10 +53,8 @@ pub fn change_argument_function() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_argument_function() { @@ -100,10 +96,8 @@ pub fn change_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_callee_method() { @@ -121,10 +115,8 @@ pub fn change_argument_method() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_argument_method() { @@ -142,10 +134,8 @@ pub fn change_ufcs_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_ufcs_callee_method() { @@ -163,10 +153,8 @@ pub fn change_argument_method_ufcs() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_argument_method_ufcs() { @@ -184,12 +172,12 @@ pub fn change_to_ufcs() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +// One might think this would be expanded in the HirBody/Mir, but it actually +// results in slightly different Hir/Mir. pub fn change_to_ufcs() { let s = Struct; Struct::method1(&s, 'x', true); @@ -208,10 +196,8 @@ mod change_ufcs_callee_indirectly { #[cfg(not(cfail1))] use super::Struct2 as Struct; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_ufcs_callee_indirectly() { diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs index 28e85c94b66..35641e978b7 100644 --- a/src/test/incremental/hashes/consts.rs +++ b/src/test/incremental/hashes/consts.rs @@ -30,8 +30,8 @@ const CONST_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub const CONST_VISIBILITY: u8 = 0; @@ -42,8 +42,8 @@ pub const CONST_VISIBILITY: u8 = 0; const CONST_CHANGE_TYPE_1: i32 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_1: u32 = 0; @@ -54,8 +54,8 @@ const CONST_CHANGE_TYPE_1: u32 = 0; const CONST_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_2: Option = None; @@ -66,11 +66,8 @@ const CONST_CHANGE_TYPE_2: Option = None; const CONST_CHANGE_VALUE_1: i16 = 1; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_1: i16 = 2; @@ -80,10 +77,8 @@ const CONST_CHANGE_VALUE_1: i16 = 2; const CONST_CHANGE_VALUE_2: i16 = 1 + 1; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_2: i16 = 1 + 2; @@ -93,10 +88,8 @@ const CONST_CHANGE_VALUE_2: i16 = 1 + 2; const CONST_CHANGE_VALUE_3: i16 = 2 + 3; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_3: i16 = 2 * 3; @@ -106,10 +99,8 @@ const CONST_CHANGE_VALUE_3: i16 = 2 * 3; const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4; @@ -126,14 +117,14 @@ mod const_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_2: Option = None; diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs index 7f991b30fc4..f826d47c3e5 100644 --- a/src/test/incremental/hashes/enum_constructors.rs +++ b/src/test/incremental/hashes/enum_constructors.rs @@ -45,10 +45,8 @@ fn change_field_value_struct_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_value_struct_like() -> Enum { @@ -72,12 +70,12 @@ fn change_field_order_struct_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +// FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it +// would if it were not all constants fn change_field_order_struct_like() -> Enum { Enum::Struct { y: 4, @@ -113,10 +111,8 @@ fn change_constructor_path_struct_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_path_struct_like() { @@ -140,10 +136,8 @@ fn change_constructor_variant_struct_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_variant_struct_like() { @@ -162,10 +156,12 @@ mod change_constructor_path_indirectly_struct_like { #[cfg(not(cfail1))] use super::Enum2 as TheEnum; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\ + TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> TheEnum { @@ -186,10 +182,8 @@ mod change_constructor_variant_indirectly_struct_like { #[cfg(not(cfail1))] use super::Enum2::Struct2 as Variant; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> Enum2 { @@ -209,10 +203,8 @@ fn change_field_value_tuple_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_value_tuple_like() -> Enum { @@ -228,10 +220,11 @@ fn change_constructor_path_tuple_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean( + cfg="cfail2", + except="HirBody,MirOptimized,MirValidated,TypeckTables" +)] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_path_tuple_like() { @@ -247,10 +240,11 @@ fn change_constructor_variant_tuple_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean( + cfg="cfail2", + except="HirBody,MirOptimized,MirValidated,TypeckTables" +)] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_variant_tuple_like() { @@ -265,10 +259,12 @@ mod change_constructor_path_indirectly_tuple_like { #[cfg(not(cfail1))] use super::Enum2 as TheEnum; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\ + TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> TheEnum { @@ -286,10 +282,8 @@ mod change_constructor_variant_indirectly_tuple_like { #[cfg(not(cfail1))] use super::Enum2::Tuple2 as Variant; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> Enum2 { @@ -317,11 +311,8 @@ fn change_constructor_path_c_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] -#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_path_c_like() { let _ = Clike2::B; @@ -336,10 +327,8 @@ fn change_constructor_variant_c_like() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_variant_c_like() { @@ -354,10 +343,12 @@ mod change_constructor_path_indirectly_c_like { #[cfg(not(cfail1))] use super::Clike2 as TheEnum; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\ + TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> TheEnum { @@ -375,10 +366,8 @@ mod change_constructor_variant_indirectly_c_like { #[cfg(not(cfail1))] use super::Clike::B as Variant; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> Clike { diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 8f84266d5a4..22393fad3d0 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -37,8 +37,8 @@ enum EnumVisibility { A } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub enum EnumVisibility { @@ -57,8 +57,8 @@ enum EnumChangeNameCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameCStyleVariant { @@ -79,8 +79,8 @@ enum EnumChangeNameTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameTupleStyleVariant { @@ -98,8 +98,8 @@ enum EnumChangeNameStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameStructStyleVariant { @@ -117,10 +117,8 @@ enum EnumChangeValueCStyleVariant0 { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeValueCStyleVariant0 { @@ -141,10 +139,8 @@ enum EnumChangeValueCStyleVariant1 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeValueCStyleVariant1 { @@ -161,8 +157,8 @@ enum EnumAddCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumAddCStyleVariant { @@ -180,8 +176,8 @@ enum EnumRemoveCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumRemoveCStyleVariant { @@ -197,8 +193,8 @@ enum EnumAddTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumAddTupleStyleVariant { @@ -216,8 +212,8 @@ enum EnumRemoveTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumRemoveTupleStyleVariant { @@ -233,8 +229,8 @@ enum EnumAddStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumAddStructStyleVariant { @@ -252,8 +248,8 @@ enum EnumRemoveStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumRemoveStructStyleVariant { @@ -269,8 +265,8 @@ enum EnumChangeFieldTypeTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeTupleStyleVariant { @@ -290,8 +286,8 @@ enum EnumChangeFieldTypeStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeStructStyleVariant { @@ -313,8 +309,8 @@ enum EnumChangeFieldNameStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldNameStructStyleVariant { @@ -330,8 +326,8 @@ enum EnumChangeOrderTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeOrderTupleStyleVariant { @@ -353,8 +349,8 @@ enum EnumChangeFieldOrderStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldOrderStructStyleVariant { @@ -370,8 +366,8 @@ enum EnumAddFieldTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumAddFieldTupleStyleVariant { @@ -387,8 +383,8 @@ enum EnumAddFieldStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumAddFieldStructStyleVariant { @@ -405,8 +401,8 @@ enum EnumAddMustUse { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[must_use] @@ -425,8 +421,8 @@ enum EnumAddReprC { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[repr(C)] @@ -444,11 +440,10 @@ enum EnumChangeNameOfTypeParameter { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumChangeNameOfTypeParameter { Variant1(T), } @@ -463,11 +458,10 @@ enum EnumAddTypeParameter { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddTypeParameter { Variant1(S), Variant2(T), @@ -482,11 +476,10 @@ enum EnumChangeNameOfLifetimeParameter<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumChangeNameOfLifetimeParameter<'b> { Variant1(&'b u32), } @@ -501,11 +494,10 @@ enum EnumAddLifetimeParameter<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddLifetimeParameter<'a, 'b> { Variant1(&'a u32), Variant2(&'b u32), @@ -521,11 +513,10 @@ enum EnumAddLifetimeParameterBound<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { Variant1(&'a u32), Variant2(&'b u32), @@ -539,11 +530,10 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), Variant2(&'a u32), @@ -558,11 +548,10 @@ enum EnumAddTraitBound { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddTraitBound { Variant1(T), } @@ -577,11 +566,10 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { Variant1(&'a u32), Variant2(&'b u32), @@ -597,11 +585,10 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2", except="TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), Variant2(&'a u32), @@ -616,11 +603,10 @@ enum EnumAddTraitBoundWhere { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -#[repr(C)] enum EnumAddTraitBoundWhere where T: Sync { Variant1(T), } @@ -635,8 +621,8 @@ enum EnumSwapUsageTypeParameters { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageTypeParameters { @@ -666,8 +652,8 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { @@ -701,8 +687,8 @@ mod change_field_type_indirectly_tuple_style { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum TupleStyle { @@ -725,8 +711,8 @@ mod change_field_type_indirectly_struct_style { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum StructStyle { @@ -754,8 +740,8 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum Enum { @@ -772,8 +758,8 @@ mod change_trait_bound_indirectly_where { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum Enum where T: Trait { diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 1d26e6c07d1..ec5e088088c 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -34,8 +34,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -51,8 +51,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -70,8 +70,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -89,8 +89,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -108,8 +108,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -127,8 +127,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -146,8 +146,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -165,8 +165,8 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern "rust-call" { @@ -184,8 +184,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -203,8 +203,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -222,8 +222,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[link_args = "-foo -bar -baz"] @@ -241,8 +241,8 @@ extern { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[link(name = "bar")] @@ -260,8 +260,8 @@ mod indirectly_change_parameter_type { #[cfg(not(cfail1))] use super::c_i64 as c_int; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { @@ -280,8 +280,8 @@ mod indirectly_change_return_type { #[cfg(not(cfail1))] use super::c_i64 as c_int; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index daddc0c9f54..5067b571ee6 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -34,12 +34,12 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] pub fn method_name2() { } } @@ -53,15 +53,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn method_body() { @@ -80,15 +78,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[inline] @@ -105,13 +101,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="AssociatedItems,Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn method_privacy() { } @@ -124,13 +120,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(cfg="cfail2", except="TypeOfItem,PredicatesOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn method_selfness(&self) { } @@ -143,13 +139,16 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn method_selfmutness(&mut self) { } @@ -164,18 +163,18 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_to_impl1(&self) { } - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_to_impl2(&self) { } } @@ -189,13 +188,16 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_parameter(&self, _: i32) { } @@ -210,15 +212,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_name(&self, b: i64) { } @@ -233,13 +233,15 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,FnSignature,MirOptimized,MirValidated,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_return_type(&self) -> u8 { 0 } @@ -254,13 +256,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[inline] @@ -276,15 +278,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } @@ -299,13 +299,16 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub unsafe fn make_method_unsafe(&self) { } @@ -320,13 +323,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,FnSignature,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub extern fn make_method_extern(&self) { } @@ -341,13 +344,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,FnSignature,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub extern "system" fn change_method_calling_convention(&self) { } @@ -362,13 +365,15 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + // FIXME(michaelwoerister): This is curious but an unused lifetime parameter doesn't seem to + // show up in any of the derived data structures. + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } @@ -383,13 +388,16 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem", + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_type_parameter_to_method(&self) { } @@ -404,13 +412,16 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem,TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -425,13 +436,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } @@ -446,13 +457,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_type_param_of_method(&self) { } @@ -467,13 +478,13 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[no_mangle] @@ -491,13 +502,16 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Bar { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="GenericsOfItem,FnSignature,TypeckTables,TypeOfItem,MirOptimized,MirValidated" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_type_parameter_to_impl(&self) { } @@ -512,13 +526,13 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Bar { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="FnSignature,MirOptimized,MirValidated,TypeckTables")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_impl_self_type(&self) { } @@ -533,13 +547,13 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Bar { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_impl_parameter(&self) { } @@ -554,13 +568,13 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Bar { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_impl_parameter(&self) { } diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 9e532548e11..d46fbd36760 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -38,6 +38,20 @@ pub fn change_name() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_clean(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_name() { let _y = 2u64; } @@ -57,6 +71,20 @@ pub fn add_type() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_clean(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_clean(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn add_type() { let _x: u32 = 2u32; } @@ -76,6 +104,20 @@ pub fn change_type() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_type() { let _x: u8 = 2; } @@ -95,6 +137,20 @@ pub fn change_mutability_of_reference_type() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_clean(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; } @@ -114,6 +170,20 @@ pub fn change_mutability_of_slot() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; } @@ -133,6 +203,20 @@ pub fn change_simple_binding_to_pattern() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_simple_binding_to_pattern() { let (_a, _b) = (0u8, 'x'); } @@ -152,6 +236,20 @@ pub fn change_name_in_pattern() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_clean(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_name_in_pattern() { let (_a, _c) = (1u8, 'y'); } @@ -171,6 +269,20 @@ pub fn add_ref_in_pattern() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn add_ref_in_pattern() { let (ref _a, _b) = (1u8, 'y'); } @@ -190,6 +302,12 @@ pub fn add_amp_in_pattern() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] pub fn add_amp_in_pattern() { let (&_a, _b) = (&1u8, 'y'); } @@ -209,6 +327,20 @@ pub fn change_mutability_of_binding_in_pattern() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); } @@ -228,6 +360,20 @@ pub fn add_initializer() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn add_initializer() { let _x: i16 = 3i16; } @@ -247,6 +393,20 @@ pub fn change_initializer() { #[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] +#[rustc_dirty(label="MirValidated", cfg="cfail2")] +#[rustc_clean(label="MirValidated", cfg="cfail3")] +#[rustc_dirty(label="MirOptimized", cfg="cfail2")] +#[rustc_clean(label="MirOptimized", cfg="cfail3")] +#[rustc_clean(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="TypeckTables", cfg="cfail3")] +#[rustc_clean(label="TypeOfItem", cfg="cfail2")] +#[rustc_clean(label="TypeOfItem", cfg="cfail3")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail2")] +#[rustc_clean(label="GenericsOfItem", cfg="cfail3")] +#[rustc_clean(label="FnSignature", cfg="cfail2")] +#[rustc_clean(label="FnSignature", cfg="cfail3")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")] +#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")] pub fn change_initializer() { let _x = 5u16; } diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs index 7c6da3ba9fe..4ff80ead89d 100644 --- a/src/test/incremental/hashes/statics.rs +++ b/src/test/incremental/hashes/statics.rs @@ -32,8 +32,8 @@ static STATIC_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub static STATIC_VISIBILITY: u8 = 0; @@ -44,8 +44,8 @@ pub static STATIC_VISIBILITY: u8 = 0; static STATIC_MUTABILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static mut STATIC_MUTABILITY: u8 = 0; @@ -56,8 +56,8 @@ static mut STATIC_MUTABILITY: u8 = 0; static STATIC_LINKAGE: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[linkage="weak_odr"] @@ -69,8 +69,8 @@ static STATIC_LINKAGE: u8 = 0; static STATIC_NO_MANGLE: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[no_mangle] @@ -82,8 +82,8 @@ static STATIC_NO_MANGLE: u8 = 0; static STATIC_THREAD_LOCAL: u8 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] #[thread_local] @@ -95,8 +95,8 @@ static STATIC_THREAD_LOCAL: u8 = 0; static STATIC_CHANGE_TYPE_1: i16 = 0; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_1: u64 = 0; @@ -107,8 +107,8 @@ static STATIC_CHANGE_TYPE_1: u64 = 0; static STATIC_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_2: Option = None; @@ -119,10 +119,8 @@ static STATIC_CHANGE_TYPE_2: Option = None; static STATIC_CHANGE_VALUE_1: i16 = 1; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_1: i16 = 2; @@ -133,10 +131,8 @@ static STATIC_CHANGE_VALUE_1: i16 = 2; static STATIC_CHANGE_VALUE_2: i16 = 1 + 1; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_2: i16 = 1 + 2; @@ -146,10 +142,8 @@ static STATIC_CHANGE_VALUE_2: i16 = 1 + 2; static STATIC_CHANGE_VALUE_3: i16 = 2 + 3; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_3: i16 = 2 * 3; @@ -159,10 +153,8 @@ static STATIC_CHANGE_VALUE_3: i16 = 2 * 3; static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3; #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4; @@ -179,14 +171,14 @@ mod static_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs index 0e23d953baf..231e29b79c4 100644 --- a/src/test/incremental/hashes/struct_constructors.rs +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -42,10 +42,8 @@ fn change_field_value_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_value_regular_struct() -> RegularStruct { @@ -69,10 +67,8 @@ fn change_field_order_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_order_regular_struct() -> RegularStruct { @@ -101,10 +97,8 @@ fn add_field_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn add_field_regular_struct() -> RegularStruct { @@ -140,10 +134,8 @@ fn change_field_label_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_label_regular_struct() -> RegularStruct { @@ -179,10 +171,8 @@ fn change_constructor_path_regular_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_path_regular_struct() { @@ -202,10 +192,11 @@ mod change_constructor_path_indirectly_regular_struct { #[cfg(not(cfail1))] use super::RegularStruct2 as Struct; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> Struct { @@ -228,10 +219,8 @@ fn change_field_value_tuple_struct() -> TupleStruct { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_field_value_tuple_struct() -> TupleStruct { @@ -249,10 +238,8 @@ fn change_constructor_path_tuple_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn change_constructor_path_tuple_struct() { @@ -268,10 +255,11 @@ mod change_constructor_path_indirectly_tuple_struct { #[cfg(not(cfail1))] use super::TupleStruct2 as Struct; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean( + cfg="cfail2", + except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,TypeckTables" + )] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn function() -> Struct { diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs index 35fb583cd4e..b0a93eea523 100644 --- a/src/test/incremental/hashes/type_defs.rs +++ b/src/test/incremental/hashes/type_defs.rs @@ -35,8 +35,8 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -47,8 +47,8 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -59,8 +59,8 @@ type ChangeMutability = &'static mut i32; type ChangeLifetime<'a> = (&'static i32, &'a i32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeLifetime<'a> = (&'a i32, &'a i32); @@ -74,8 +74,8 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -86,8 +86,8 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -107,8 +107,8 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -119,8 +119,8 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -131,8 +131,8 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); @@ -143,8 +143,8 @@ type ChangeNestedTupleField = (i32, (i64, i8)); type AddTypeParam = (T1, T1); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddTypeParam = (T1, T2); @@ -155,8 +155,8 @@ type AddTypeParam = (T1, T2); type AddTypeParamBound = (T1, u32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddTypeParamBound = (T1, u32); @@ -167,8 +167,8 @@ type AddTypeParamBound = (T1, u32); type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); @@ -179,8 +179,8 @@ type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); type AddLifetimeParam<'a> = (&'a u32, &'a u32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); @@ -191,8 +191,8 @@ type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); @@ -205,8 +205,8 @@ where 'b: 'a = (&'a u32, &'b u32, &'c u32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> where 'b: 'a, @@ -225,8 +225,8 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly = (T, u32); @@ -241,8 +241,8 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly where T : Trait = (T, u32); diff --git a/src/test/compile-fail/incr_comp_with_macro_export.rs b/src/test/incremental/macro_export.rs similarity index 90% rename from src/test/compile-fail/incr_comp_with_macro_export.rs rename to src/test/incremental/macro_export.rs index eafef172303..914632e96ba 100644 --- a/src/test/compile-fail/incr_comp_with_macro_export.rs +++ b/src/test/incremental/macro_export.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Zincremental=tmp/cfail-tests/incr_comp_with_macro_export +// revisions: cfail1 cfail2 cfail3 // must-compile-successfully - // This test case makes sure that we can compile with incremental compilation // enabled when there are macros exported from this crate. (See #37756) diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md index d999ff97551..b00b35aa29f 100644 --- a/src/test/mir-opt/README.md +++ b/src/test/mir-opt/README.md @@ -7,13 +7,13 @@ The test format is: // END RUST SOURCE // START $file_name_of_some_mir_dump_0 // $expected_line_0 -// ... +// (lines or elision) // $expected_line_N // END $file_name_of_some_mir_dump_0 -// ... +// (lines or elision) // START $file_name_of_some_mir_dump_N // $expected_line_0 -// ... +// (lines or elision) // $expected_line_N // END $file_name_of_some_mir_dump_N ``` @@ -22,10 +22,15 @@ All the test information is in comments so the test is runnable. For each $file_name, compiletest expects [$expected_line_0, ..., $expected_line_N] to appear in the dumped MIR in order. Currently it allows -other non-matched lines before, after and in-between. Note that this includes -lines that end basic blocks or begin new ones; it is good practice -in your tests to include the terminator for each of your basic blocks as an -internal sanity check guarding against a test like: +other non-matched lines before and after, but not between $expected_lines, +should you want to skip lines, you must include an elision comment, of the form +(as a regex) `//\s*...\s*`. The lines will be skipped lazily, that is, if there +are two identical lines in the output that match the line after the elision +comment, the first one wil be matched. + +Examples: + +The following blocks will not match the one after it. ``` bb0: { @@ -35,8 +40,6 @@ bb0: { } ``` -that will inadvertantly pattern-matching against: - ``` bb0: { StorageLive(_1); @@ -49,6 +52,18 @@ bb1: { } ``` +But this will match the one above, + +``` +bb0: { + StorageLive(_1); + _1 = const true; + ... + StorageDead(_1); + ... +} +``` + Lines match ignoring whitespace, and the prefix "//" is removed. It also currently strips trailing comments -- partly because the full file path diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index 4015930ef76..5c3b418e950 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -30,7 +30,10 @@ impl Drop for S { // END RUST SOURCE // START rustc.node4.ElaborateDrops.before.mir // let mut _0: (); -// let _1: std::boxed::Box; +// scope 1 { +// let _1: std::boxed::Box; +// } +// ... // let mut _2: std::boxed::Box; // let mut _3: (); // let mut _4: std::boxed::Box; diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index 26b042d0343..0b0d2f45f1c 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -18,17 +18,23 @@ fn main() { } // END RUST SOURCE // START rustc.node4.CopyPropagation.before.mir // bb0: { +// ... // _2 = _1; +// ... // _4 = _2; // _3 = _4; +// ... // _5 = _3; // _0 = _5; +// ... // return; // } // END rustc.node4.CopyPropagation.before.mir // START rustc.node4.CopyPropagation.after.mir // bb0: { +// ... // _0 = _1; +// ... // return; // } // END rustc.node4.CopyPropagation.after.mir diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index 81dd1932894..ce2b13ecda7 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -23,19 +23,25 @@ fn main() {} // END RUST SOURCE // START rustc.node13.Deaggregator.before.mir // bb0: { +// ... // _2 = _1; +// ... // _3 = _2; // _0 = Baz { x: _3, y: const 0f32, z: const false }; +// ... // return; // } // END rustc.node13.Deaggregator.before.mir // START rustc.node13.Deaggregator.after.mir // bb0: { +// ... // _2 = _1; +// ... // _3 = _2; // (_0.0: usize) = _3; // (_0.1: f32) = const 0f32; // (_0.2: bool) = const false; +// ... // return; // } // END rustc.node13.Deaggregator.after.mir diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs index 25fa0e90835..d77dcb62781 100644 --- a/src/test/mir-opt/deaggregator_test_enum.rs +++ b/src/test/mir-opt/deaggregator_test_enum.rs @@ -28,18 +28,26 @@ fn main() { // END RUST SOURCE // START rustc.node10.Deaggregator.before.mir // bb0: { +// StorageLive(_2); // _2 = _1; +// StorageLive(_3); // _3 = _2; // _0 = Baz::Foo { x: _3 }; +// StorageDead(_3); +// StorageDead(_2); // return; // } // END rustc.node10.Deaggregator.before.mir // START rustc.node10.Deaggregator.after.mir // bb0: { +// StorageLive(_2); // _2 = _1; +// StorageLive(_3); // _3 = _2; // ((_0 as Foo).0: usize) = _3; // discriminant(_0) = 1; +// StorageDead(_3); +// StorageDead(_2); // return; // } // END rustc.node10.Deaggregator.after.mir diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs index 02d496b2901..e65830bddc4 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.rs +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -28,29 +28,35 @@ fn main() {} // END RUST SOURCE // START rustc.node12.Deaggregator.before.mir // bb1: { +// StorageLive(_6); // _6 = _4; // _0 = Foo::A(_6,); +// StorageDead(_6); // goto -> bb3; // } -// // bb2: { +// StorageLive(_7); // _7 = _4; // _0 = Foo::B(_7,); +// StorageDead(_7); // goto -> bb3; // } // END rustc.node12.Deaggregator.before.mir // START rustc.node12.Deaggregator.after.mir // bb1: { +// StorageLive(_6); // _6 = _4; // ((_0 as A).0: i32) = _6; // discriminant(_0) = 0; +// StorageDead(_6); // goto -> bb3; // } -// // bb2: { +// StorageLive(_7); // _7 = _4; // ((_0 as B).0: i32) = _7; // discriminant(_0) = 1; +// StorageDead(_7); // goto -> bb3; // } // END rustc.node12.Deaggregator.after.mir diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs index a180a69be55..ed68d3bf5f7 100644 --- a/src/test/mir-opt/deaggregator_test_multiple.rs +++ b/src/test/mir-opt/deaggregator_test_multiple.rs @@ -24,25 +24,35 @@ fn main() { } // END RUST SOURCE // START rustc.node10.Deaggregator.before.mir // bb0: { +// ... // _2 = _1; +// ... // _4 = _2; // _3 = Foo::A(_4,); +// ... // _6 = _2; // _5 = Foo::A(_6,); +// ... // _0 = [_3, _5]; +// ... // return; // } // END rustc.node10.Deaggregator.before.mir // START rustc.node10.Deaggregator.after.mir // bb0: { +// ... // _2 = _1; +// ... // _4 = _2; // ((_3 as A).0: i32) = _4; // discriminant(_3) = 0; +// ... // _6 = _2; // ((_5 as A).0: i32) = _6; // discriminant(_5) = 0; +// ... // _0 = [_3, _5]; +// ... // return; // } // END rustc.node10.Deaggregator.after.mir diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs index 1941d1bc7be..a0edcc82fe1 100644 --- a/src/test/mir-opt/end_region_1.rs +++ b/src/test/mir-opt/end_region_1.rs @@ -21,9 +21,11 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); +// ... // let _1: i32; +// ... // let _2: &'10_1rs i32; -// +// ... // bb0: { // StorageLive(_1); // _1 = const 3i32; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index d8dd4aeadf4..69042fecc7d 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -26,11 +26,16 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); +// ... // let _2: bool; +// ... // let _3: &'23_1rs bool; +// ... // let _7: &'23_3rs bool; +// ... // let mut _4: (); // let mut _5: bool; +// ... // bb0: { // goto -> bb1; // } @@ -52,6 +57,7 @@ fn main() { // return; // } // bb3: { +// _4 = (); // StorageDead(_5); // StorageLive(_7); // _7 = &'23_3rs _2; diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index e404af838ce..da423163e84 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -27,13 +27,17 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); +// ... // let mut _1: bool; +// ... // let _3: &'26_1rs bool; +// ... // let _7: &'26_3rs bool; +// ... // let mut _2: (); // let mut _4: (); // let mut _5: bool; -// +// let mut _6: !; // bb0: { // StorageLive(_1); // goto -> bb1; diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs index d51c627d14b..2087485b913 100644 --- a/src/test/mir-opt/end_region_4.rs +++ b/src/test/mir-opt/end_region_4.rs @@ -31,10 +31,15 @@ fn foo(i: i32) { // END RUST SOURCE // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); +// ... // let _1: D; +// ... // let _2: i32; +// ... // let _3: &'26_2rs i32; +// ... // let _6: &'26_4rs i32; +// ... // let mut _4: (); // let mut _5: i32; // bb0: { diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs index 6299ec3815c..4663b71bd7c 100644 --- a/src/test/mir-opt/end_region_5.rs +++ b/src/test/mir-opt/end_region_5.rs @@ -28,8 +28,11 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END RUST SOURCE // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // fn main() -> () { +// ... // let mut _0: (); +// ... // let _1: D; +// ... // let mut _2: (); // let mut _3: [closure@NodeId(18) d:&'14s D]; // let mut _4: &'14s D; diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index 13ab3e4f2dd..7d2868ee4ba 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -29,7 +29,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // fn main() -> () { // let mut _0: (); +// ... // let _1: D; +// ... // let mut _2: (); // let mut _3: [closure@NodeId(22) d:&'19s D]; // let mut _4: &'19s D; @@ -65,9 +67,10 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.node22.SimplifyCfg-qualify-consts.after.mir // fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 { // let mut _0: i32; +// ... // let _2: &'15_0rs D; +// ... // let mut _3: i32; -// // bb0: { // StorageLive(_2); // _2 = &'15_0rs (*(_1.0: &'19s D)); diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index 826d3749167..0156c1be7ed 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -29,11 +29,12 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // fn main() -> () { // let mut _0: (); +// ... // let _1: D; +// ... // let mut _2: (); // let mut _3: [closure@NodeId(22) d:D]; // let mut _4: D; -// // bb0: { // StorageLive(_1); // _1 = D::{{constructor}}(const 0i32,); @@ -74,9 +75,10 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.node22.SimplifyCfg-qualify-consts.after.mir // fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 { // let mut _0: i32; +// ... // let _2: &'15_0rs D; +// ... // let mut _3: i32; -// // bb0: { // StorageLive(_2); // _2 = &'15_0rs (_1.0: D); diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 6438484fcfa..6e8cf4204ee 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -30,8 +30,11 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // fn main() -> () { // let mut _0: (); +// ... // let _1: D; +// ... // let _2: &'21_1rs D; +// ... // let mut _3: (); // let mut _4: [closure@NodeId(22) r:&'21_1rs D]; // let mut _5: &'21_1rs D; diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index 59d5d934391..fd23d813452 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -40,15 +40,18 @@ fn main() { // START rustc.node4.SimplifyCfg-qualify-consts.after.mir // fn main() -> () { // let mut _0: (); +// ... // let mut _1: bool; +// ... // let _2: i32; +// ... // let mut _4: &'33_0rs i32; +// ... // let mut _3: (); // let mut _5: !; // let mut _6: (); // let mut _7: bool; // let mut _8: !; -// // bb0: { // StorageLive(_1); // _1 = const false; @@ -63,7 +66,6 @@ fn main() { // _7 = _1; // switchInt(_7) -> [0u8: bb3, otherwise: bb2]; // } -// // bb2: { // _0 = (); // StorageDead(_7); @@ -73,7 +75,6 @@ fn main() { // StorageDead(_1); // return; // } -// // bb3: { // _4 = &'33_0rs _2; // _6 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 8f9dd79cd75..f70f6519275 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -45,6 +45,7 @@ fn query() -> bool { true } // scope 1 { // let _2: S<'35_0rs>; // } +// ... // let mut _1: (); // let mut _3: std::cell::Cell>>; // let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>; diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index 3a8b5c449c2..384201b7c12 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -35,22 +35,26 @@ impl S { // END RUST SOURCE // START rustc.node4.ElaborateDrops.after.mir // let mut _0: (); -// let _1: (); +// scope 1 { +// let _1: (); +// } +// ... // let mut _2: S; // let mut _3: S; // let mut _4: S; // let mut _5: bool; -// // bb0: { // END rustc.node4.ElaborateDrops.after.mir // START rustc.node13.ElaborateDrops.after.mir // let mut _0: (); +// ... // let _1: S; +// ... // let mut _2: S; +// ... // let mut _3: (); // let mut _4: S; // let mut _5: S; // let mut _6: bool; -// // bb0: { // END rustc.node13.ElaborateDrops.after.mir diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs index 9fb725a980e..370ab599eca 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.rs +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -45,56 +45,156 @@ fn main() { // END RUST SOURCE // START rustc.node4.mir_map.0.mir +// let mut _0: &'static Foo; +// let mut _1: &'static Foo; +// let mut _2: Foo; +// let mut _3: &'static [(u32, u32)]; +// let mut _4: &'static [(u32, u32); 42]; +// let mut _5: &'static [(u32, u32); 42]; +// let mut _6: [(u32, u32); 42]; +// let mut _7: (u32, u32); +// let mut _8: (u32, u32); +// let mut _9: (u32, u32); +// let mut _10: (u32, u32); +// let mut _11: (u32, u32); +// let mut _12: (u32, u32); +// let mut _13: (u32, u32); +// let mut _14: (u32, u32); +// let mut _15: (u32, u32); +// let mut _16: (u32, u32); +// let mut _17: (u32, u32); +// let mut _18: (u32, u32); +// let mut _19: (u32, u32); +// let mut _20: (u32, u32); +// let mut _21: (u32, u32); +// let mut _22: (u32, u32); +// let mut _23: (u32, u32); +// let mut _24: (u32, u32); +// let mut _25: (u32, u32); +// let mut _26: (u32, u32); +// let mut _27: (u32, u32); +// let mut _28: (u32, u32); +// let mut _29: (u32, u32); +// let mut _30: (u32, u32); +// let mut _31: (u32, u32); +// let mut _32: (u32, u32); +// let mut _33: (u32, u32); +// let mut _34: (u32, u32); +// let mut _35: (u32, u32); +// let mut _36: (u32, u32); +// let mut _37: (u32, u32); +// let mut _38: (u32, u32); +// let mut _39: (u32, u32); +// let mut _40: (u32, u32); +// let mut _41: (u32, u32); +// let mut _42: (u32, u32); +// let mut _43: (u32, u32); +// let mut _44: (u32, u32); +// let mut _45: (u32, u32); +// let mut _46: (u32, u32); +// let mut _47: (u32, u32); +// let mut _48: (u32, u32); // bb0: { -// _7 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:9: 29:15 -// _8 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:17: 29:23 -// _9 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:25: 29:31 -// _10 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:9: 30:15 -// _11 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:17: 30:23 -// _12 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:25: 30:31 -// _13 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:9: 31:15 -// _14 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:17: 31:23 -// _15 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:25: 31:31 -// _16 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:9: 32:15 -// _17 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:17: 32:23 -// _18 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:25: 32:31 -// _19 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:9: 33:15 -// _20 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:17: 33:23 -// _21 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:25: 33:31 -// _22 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:9: 34:15 -// _23 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:17: 34:23 -// _24 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:25: 34:31 -// _25 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:9: 35:15 -// _26 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:17: 35:23 -// _27 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:25: 35:31 -// _28 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:9: 36:15 -// _29 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:17: 36:23 -// _30 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:25: 36:31 -// _31 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:9: 37:15 -// _32 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:17: 37:23 -// _33 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:25: 37:31 -// _34 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:9: 38:15 -// _35 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:17: 38:23 -// _36 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:25: 38:31 -// _37 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:9: 39:15 -// _38 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:17: 39:23 -// _39 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:25: 39:31 -// _40 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:9: 40:15 -// _41 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:17: 40:23 -// _42 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:25: 40:31 -// _43 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:9: 41:15 -// _44 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:17: 41:23 -// _45 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:25: 41:31 -// _46 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:9: 42:15 -// _47 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:17: 42:23 -// _48 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:25: 42:31 -// _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48]; // scope 0 at src/test/mir-opt/basic_assignment.rs:28:12: 43:6 -// _5 = &_6; // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 -// _4 = &(*_5); // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 -// _3 = _4 as &'static [(u32, u32)] (Unsize); // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 -// _2 = Foo { tup: const "hi", data: _3 }; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:29: 44:2 -// _1 = &_2; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2 -// _0 = &(*_1); // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2 -// return; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:1: 44:3 +// StorageLive(_1); +// StorageLive(_2); +// StorageLive(_3); +// StorageLive(_4); +// StorageLive(_5); +// StorageLive(_6); +// StorageLive(_7); +// _7 = (const 0u32, const 1u32); +// StorageLive(_8); +// _8 = (const 0u32, const 2u32); +// StorageLive(_9); +// _9 = (const 0u32, const 3u32); +// StorageLive(_10); +// _10 = (const 0u32, const 1u32); +// StorageLive(_11); +// _11 = (const 0u32, const 2u32); +// StorageLive(_12); +// _12 = (const 0u32, const 3u32); +// StorageLive(_13); +// _13 = (const 0u32, const 1u32); +// StorageLive(_14); +// _14 = (const 0u32, const 2u32); +// StorageLive(_15); +// _15 = (const 0u32, const 3u32); +// StorageLive(_16); +// _16 = (const 0u32, const 1u32); +// StorageLive(_17); +// _17 = (const 0u32, const 2u32); +// StorageLive(_18); +// _18 = (const 0u32, const 3u32); +// StorageLive(_19); +// _19 = (const 0u32, const 1u32); +// StorageLive(_20); +// _20 = (const 0u32, const 2u32); +// StorageLive(_21); +// _21 = (const 0u32, const 3u32); +// StorageLive(_22); +// _22 = (const 0u32, const 1u32); +// StorageLive(_23); +// _23 = (const 0u32, const 2u32); +// StorageLive(_24); +// _24 = (const 0u32, const 3u32); +// StorageLive(_25); +// _25 = (const 0u32, const 1u32); +// StorageLive(_26); +// _26 = (const 0u32, const 2u32); +// StorageLive(_27); +// _27 = (const 0u32, const 3u32); +// StorageLive(_28); +// _28 = (const 0u32, const 1u32); +// StorageLive(_29); +// _29 = (const 0u32, const 2u32); +// StorageLive(_30); +// _30 = (const 0u32, const 3u32); +// StorageLive(_31); +// _31 = (const 0u32, const 1u32); +// StorageLive(_32); +// _32 = (const 0u32, const 2u32); +// StorageLive(_33); +// _33 = (const 0u32, const 3u32); +// StorageLive(_34); +// _34 = (const 0u32, const 1u32); +// StorageLive(_35); +// _35 = (const 0u32, const 2u32); +// StorageLive(_36); +// _36 = (const 0u32, const 3u32); +// StorageLive(_37); +// _37 = (const 0u32, const 1u32); +// StorageLive(_38); +// _38 = (const 0u32, const 2u32); +// StorageLive(_39); +// _39 = (const 0u32, const 3u32); +// StorageLive(_40); +// _40 = (const 0u32, const 1u32); +// StorageLive(_41); +// _41 = (const 0u32, const 2u32); +// StorageLive(_42); +// _42 = (const 0u32, const 3u32); +// StorageLive(_43); +// _43 = (const 0u32, const 1u32); +// StorageLive(_44); +// _44 = (const 0u32, const 2u32); +// StorageLive(_45); +// _45 = (const 0u32, const 3u32); +// StorageLive(_46); +// _46 = (const 0u32, const 1u32); +// StorageLive(_47); +// _47 = (const 0u32, const 2u32); +// StorageLive(_48); +// _48 = (const 0u32, const 3u32); +// _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48]; +// _5 = &_6; +// _4 = &(*_5); +// _3 = _4 as &'static [(u32, u32)] (Unsize); +// _2 = Foo { tup: const "hi", data: _3 }; +// _1 = &_2; +// _0 = &(*_1); +// StorageDead(_1); +// StorageDead(_5); +// return; // } +//} // END rustc.node4.mir_map.0.mir diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 3fbd1a36f2f..7dbcf82af34 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -38,5 +38,6 @@ fn main() { // _0 = (); // StorageDead(_6); // StorageDead(_1); +// return; // } // END rustc.node4.TypeckMir.before.mir diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index d2ca65775a4..5a31be8bd50 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -31,12 +31,15 @@ fn main() { // START rustc.node12.EraseRegions.after.mir // bb0: { // Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]); +// ... // return; // } // END rustc.node12.EraseRegions.after.mir // START rustc.node23.EraseRegions.after.mir // fn main() -> () { +// ... // bb0: { +// ... // Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]); // _6 = &ReErased mut _1; // Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]); @@ -50,14 +53,16 @@ fn main() { // bb1: { // Validate(Acquire, [_2: ()]); // EndRegion(ReScope(Node(ItemLocalId(10)))); +// ... // return; // } // } // END rustc.node23.EraseRegions.after.mir // START rustc.node50.EraseRegions.after.mir // fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 { +// ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); // StorageLive(_3); // _3 = _2; // StorageLive(_4); diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 37ebd720d52..aacf5a5ed0f 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -18,10 +18,18 @@ fn main() { // END RUST SOURCE // START rustc.node4.EraseRegions.after.mir // fn main() -> () { +// ... // bb1: { +// Validate(Acquire, [_2: std::boxed::Box<[i32; 3]>]); // Validate(Release, [_2: std::boxed::Box<[i32; 3]>]); // _1 = _2 as std::boxed::Box<[i32]> (Unsize); // Validate(Acquire, [_1: std::boxed::Box<[i32]>]); +// StorageDead(_2); +// StorageDead(_3); +// _0 = (); +// Validate(Release, [_1: std::boxed::Box<[i32]>]); +// drop(_1) -> bb2; // } +// ... // } // END rustc.node4.EraseRegions.after.mir diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 116e35b2d6f..d7d3e023c9e 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -30,8 +30,17 @@ fn main() { // END RUST SOURCE // START rustc.node16.EraseRegions.after.mir // fn main() -> () { +// ... // let mut _5: &ReErased i32; // bb0: { +// StorageLive(_1); +// _1 = Test { x: const 0i32 }; +// StorageLive(_2); +// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))), [_1: Test]); +// _2 = &ReErased _1; +// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); +// StorageLive(_4); +// StorageLive(_5); // Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); // _5 = &ReErased ((*_2).0: i32); // Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]); @@ -42,8 +51,14 @@ fn main() { // _3 = const foo(_4) -> bb1; // } // bb1: { +// Validate(Acquire, [_3: ()]); // EndRegion(ReScope(Node(ItemLocalId(17)))); +// StorageDead(_4); +// StorageDead(_5); +// _0 = (); // EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))); +// StorageDead(_2); +// StorageDead(_1); // return; // } // } diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs index d240b51e222..bcb21c60b26 100644 --- a/src/test/mir-opt/validate_4.rs +++ b/src/test/mir-opt/validate_4.rs @@ -38,18 +38,21 @@ fn main() { // END RUST SOURCE // START rustc.node4.EraseRegions.after.mir // fn write_42(_1: *mut i32) -> bool { +// ... // bb0: { // Validate(Acquire, [_1: *mut i32]); // Validate(Release, [_1: *mut i32]); +// ... // return; // } // } // END rustc.node4.EraseRegions.after.mir // START rustc.node22.EraseRegions.after.mir // fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () { +// ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]); -// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]); +// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]); // StorageLive(_3); // _3 = _2; // (*_3) = const 23i32; @@ -60,24 +63,30 @@ fn main() { // END rustc.node22.EraseRegions.after.mir // START rustc.node31.EraseRegions.after.mir // fn test(_1: &ReErased mut i32) -> () { +// ... // bb0: { // Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]); // Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]); +// ... // _3 = const write_42(_4) -> bb1; // } // bb1: { // Validate(Acquire, [_3: bool]); // Validate(Release, [_3: bool]); +// ... // } // } // END rustc.node31.EraseRegions.after.mir // START rustc.node60.EraseRegions.after.mir // fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool { +// ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); -// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); // StorageLive(_3); +// ... // _0 = const write_42(_4) -> bb1; // } +// ... // } // END rustc.node60.EraseRegions.after.mir diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs index e1eeb2102d1..44280539c41 100644 --- a/src/test/mir-opt/validate_5.rs +++ b/src/test/mir-opt/validate_5.rs @@ -35,17 +35,21 @@ fn main() { // END RUST SOURCE // START rustc.node17.EraseRegions.after.mir // fn test(_1: &ReErased mut i32) -> () { +// ... // bb0: { // Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_5[8cd8]::test[0] }, BrAnon(0)) mut i32]); +// ... // Validate(Release, [_3: bool, _4: *mut i32]); // _3 = const write_42(_4) -> bb1; // } +// ... // } // END rustc.node17.EraseRegions.after.mir // START rustc.node46.EraseRegions.after.mir // fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool { +// ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); // StorageLive(_3); // _3 = _2; // StorageLive(_4); @@ -59,5 +63,6 @@ fn main() { // Validate(Release, [_0: bool, _4: *mut i32]); // _0 = const write_42(_4) -> bb1; // } +// ... // } // END rustc.node46.EraseRegions.after.mir diff --git a/src/test/parse-fail/require-parens-for-chained-comparison.rs b/src/test/parse-fail/require-parens-for-chained-comparison.rs index 7e76dbd31f0..1ee6996ce9c 100644 --- a/src/test/parse-fail/require-parens-for-chained-comparison.rs +++ b/src/test/parse-fail/require-parens-for-chained-comparison.rs @@ -21,5 +21,6 @@ fn main() { f(); //~^ ERROR: chained comparison operators require parentheses - //~^^ HELP: use `::<...>` instead of `<...>` + //~| HELP: use `::<...>` instead of `<...>` + //~| HELP: or use `(...)` } diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs index a44c0c3f32f..3e8c140eb19 100644 --- a/src/test/parse-fail/trait-object-bad-parens.rs +++ b/src/test/parse-fail/trait-object-bad-parens.rs @@ -17,4 +17,6 @@ fn main() { //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)` let _: Box<(Copy +) + Copy>; //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)` + let _: Box<(dyn Copy) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Copy)` } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 14a499644df..02b8425d88b 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -40,31 +40,31 @@ pub fn bar() ({ ((::fmt::format as - fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test" - as - &'static str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test" + as + &'static str)] + as + [&str; 1]) + as + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) as std::string::String); } as ()) pub type Foo = [i32; (3 as usize)]; diff --git a/src/test/run-fail/mir_drop_panics.rs b/src/test/run-fail/mir_drop_panics.rs index 98311525ad0..51191dd7087 100644 --- a/src/test/run-fail/mir_drop_panics.rs +++ b/src/test/run-fail/mir_drop_panics.rs @@ -10,7 +10,6 @@ // error-pattern:panic 1 // error-pattern:drop 2 -use std::io::{self, Write}; struct Droppable(u32); impl Drop for Droppable { @@ -18,7 +17,7 @@ impl Drop for Droppable { if self.0 == 1 { panic!("panic 1"); } else { - write!(io::stderr(), "drop {}", self.0); + eprint!("drop {}", self.0); } } } diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs index 6cf2851d93d..69f934272b7 100644 --- a/src/test/run-fail/mir_dynamic_drops_1.rs +++ b/src/test/run-fail/mir_dynamic_drops_1.rs @@ -9,7 +9,6 @@ // except according to those terms. // error-pattern:drop 1 // error-pattern:drop 2 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs index 7a90298e422..d2fe50401ab 100644 --- a/src/test/run-fail/mir_dynamic_drops_2.rs +++ b/src/test/run-fail/mir_dynamic_drops_2.rs @@ -9,7 +9,6 @@ // except according to those terms. // error-pattern:drop 1 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs index 79ecbbb35bc..ecc35ee9b24 100644 --- a/src/test/run-fail/mir_dynamic_drops_3.rs +++ b/src/test/run-fail/mir_dynamic_drops_3.rs @@ -12,7 +12,6 @@ // error-pattern:drop 3 // error-pattern:drop 2 // error-pattern:drop 1 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -20,10 +19,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs index 7a7526c5fc1..9c851eb7346 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs @@ -12,17 +12,15 @@ // error-pattern:0 dropped // error-pattern:exit -use std::io::{self, Write}; - struct Droppable(u8); impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "{} dropped\n", self.0); + eprintln!("{} dropped", self.0); } } fn converging_fn() { - write!(io::stderr(), "converging_fn called\n"); + eprintln!("converging_fn called"); } fn mir(d: Droppable) { diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs index 1301630cc85..6f105211556 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs @@ -12,18 +12,16 @@ // error-pattern:dropped // error-pattern:exit -use std::io::{self, Write}; - struct Droppable; impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "dropped\n"); + eprintln!("dropped"); } } // return value of this function is copied into the return slot fn complex() -> u64 { - write!(io::stderr(), "complex called\n"); + eprintln!("complex called"); 42 } diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs index c1918704929..f8fbe8f79cc 100644 --- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs @@ -11,12 +11,10 @@ // error-pattern:diverging_fn called // error-pattern:0 dropped -use std::io::{self, Write}; - struct Droppable(u8); impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "{} dropped", self.0); + eprintln!("{} dropped", self.0); } } diff --git a/src/test/run-fail/panic-set-handler.rs b/src/test/run-fail/panic-set-handler.rs index b589544ae15..68f1c4ed0bc 100644 --- a/src/test/run-fail/panic-set-handler.rs +++ b/src/test/run-fail/panic-set-handler.rs @@ -13,11 +13,10 @@ #![feature(panic_handler)] use std::panic; -use std::io::{self, Write}; fn main() { panic::set_hook(Box::new(|i| { - write!(io::stderr(), "greetings from the panic handler"); + eprint!("greetings from the panic handler"); })); panic!("foobar"); } diff --git a/src/test/run-fail/panic-set-unset-handler.rs b/src/test/run-fail/panic-set-unset-handler.rs index 6741c2d9c2c..072139a8c9b 100644 --- a/src/test/run-fail/panic-set-unset-handler.rs +++ b/src/test/run-fail/panic-set-unset-handler.rs @@ -13,11 +13,10 @@ #![feature(panic_handler)] use std::panic; -use std::io::{self, Write}; fn main() { panic::set_hook(Box::new(|i| { - write!(io::stderr(), "greetings from the panic handler"); + eprint!("greetings from the panic handler"); })); panic::take_hook(); panic!("foobar"); diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile index 5202e6dea54..93711c41d79 100644 --- a/src/test/run-make/archive-duplicate-names/Makefile +++ b/src/test/run-make/archive-duplicate-names/Makefile @@ -5,7 +5,7 @@ all: mkdir $(TMPDIR)/b $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c) $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c) - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o $(RUSTC) foo.rs $(RUSTC) bar.rs $(call RUN,bar) diff --git a/src/test/run-make/compiler-rt-works-on-mingw/Makefile b/src/test/run-make/compiler-rt-works-on-mingw/Makefile index 4ec54f73e67..06d1bb6698e 100644 --- a/src/test/run-make/compiler-rt-works-on-mingw/Makefile +++ b/src/test/run-make/compiler-rt-works-on-mingw/Makefile @@ -3,8 +3,8 @@ ifneq (,$(findstring MINGW,$(UNAME))) ifndef IS_MSVC all: - g++ foo.cpp -c -o $(TMPDIR)/foo.o - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o + $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o $(RUSTC) foo.rs -lfoo -lstdc++ $(call RUN,foo) else diff --git a/src/test/run-make/inline-always-many-cgu/Makefile b/src/test/run-make/inline-always-many-cgu/Makefile new file mode 100644 index 00000000000..edf88a6327c --- /dev/null +++ b/src/test/run-make/inline-always-many-cgu/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2 + if grep -w call $(TMPDIR)/*.ll; then \ + echo "found call instruction when one wasn't expected"; \ + exit 1; \ + fi diff --git a/src/test/run-make/inline-always-many-cgu/foo.rs b/src/test/run-make/inline-always-many-cgu/foo.rs new file mode 100644 index 00000000000..539dcdfa9b3 --- /dev/null +++ b/src/test/run-make/inline-always-many-cgu/foo.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +pub mod a { + #[inline(always)] + pub fn foo() { + } + + pub fn bar() { + } +} + +#[no_mangle] +pub fn bar() { + a::foo(); +} diff --git a/src/test/run-make/invalid-library/Makefile b/src/test/run-make/invalid-library/Makefile index 0dbe655b77d..5c9cc993509 100644 --- a/src/test/run-make/invalid-library/Makefile +++ b/src/test/run-make/invalid-library/Makefile @@ -2,5 +2,5 @@ all: touch $(TMPDIR)/rust.metadata.bin - ar crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin + $(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin $(RUSTC) foo.rs 2>&1 | grep "can't find crate for" diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 461df49b468..4db027aaeef 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -18,7 +18,6 @@ extern crate rustc_errors; extern crate rustc_trans; extern crate syntax; -use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; use rustc::session::config::{basic_options, build_configuration, Input, OutputType, OutputTypes}; @@ -56,6 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let mut opts = basic_options(); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); + if let Ok(linker) = std::env::var("RUSTC_LINKER") { + opts.cg.linker = Some(linker); + } let descriptions = Registry::new(&rustc::DIAGNOSTICS); let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader))); @@ -67,8 +69,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); - let cfg = build_configuration(&sess, HashSet::new()); let control = CompileController::basic(); let input = Input::Str { name: anon_src(), input: code }; - compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); + let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); } diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile index 64af91b487b..cb4f1462733 100644 --- a/src/test/run-make/issue-22131/Makefile +++ b/src/test/run-make/issue-22131/Makefile @@ -2,6 +2,6 @@ all: foo.rs $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs - $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \ + $(RUSTDOC) --test --cfg 'feature="bar"' \ -L $(TMPDIR) foo.rs |\ grep -q 'foo.rs - foo (line 11) ... ok' diff --git a/src/test/run-make/rustdoc-output-path/Makefile b/src/test/run-make/rustdoc-output-path/Makefile index 4e570718a62..8ce1c699526 100644 --- a/src/test/run-make/rustdoc-output-path/Makefile +++ b/src/test/run-make/rustdoc-output-path/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs + $(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs diff --git a/src/test/run-make/sepcomp-cci-copies/Makefile b/src/test/run-make/sepcomp-cci-copies/Makefile index 8324a074d6c..ccd4e1b0e71 100644 --- a/src/test/run-make/sepcomp-cci-copies/Makefile +++ b/src/test/run-make/sepcomp-cci-copies/Makefile @@ -5,5 +5,6 @@ all: $(RUSTC) cci_lib.rs - $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 + $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \ + -Z inline-in-all-cgus [ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ] diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index 6dc837b8a78..1d20d940000 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -7,7 +7,8 @@ # in only one compilation unit. all: - $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 + $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \ + -Z inline-in-all-cgus [ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] [ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] [ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ] diff --git a/src/test/run-make/staticlib-blank-lib/Makefile b/src/test/run-make/staticlib-blank-lib/Makefile index 5878eec66ba..92a278825c2 100644 --- a/src/test/run-make/staticlib-blank-lib/Makefile +++ b/src/test/run-make/staticlib-blank-lib/Makefile @@ -1,6 +1,6 @@ -include ../tools.mk all: - ar crus $(TMPDIR)/libfoo.a foo.rs - ar d $(TMPDIR)/libfoo.a foo.rs + $(AR) crus $(TMPDIR)/libfoo.a foo.rs + $(AR) d $(TMPDIR)/libfoo.a foo.rs $(RUSTC) foo.rs diff --git a/src/test/run-make/target-specs/Makefile b/src/test/run-make/target-specs/Makefile index 6b58ad7b6df..5ea96daa3ef 100644 --- a/src/test/run-make/target-specs/Makefile +++ b/src/test/run-make/target-specs/Makefile @@ -5,5 +5,5 @@ all: $(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | grep -q "Error loading target specification" $(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | grep 'Field llvm-target' RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm - RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=x86_64-unknown-linux-gnu --crate-type=lib --emit=asm + RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json similarity index 61% rename from src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json rename to src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json index c1dd0cf4063..3ae01d72fcc 100644 --- a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json +++ b/src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json @@ -1,6 +1,6 @@ { "pre-link-args": ["-m64"], - "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 27f235d54d4..c5d5626bf72 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -7,7 +7,13 @@ TARGET_RPATH_ENV = \ RUSTC_ORIGINAL := $(RUSTC) BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)' +BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) +RUSTDOC := $(BARE_RUSTDOC) +ifdef RUSTC_LINKER +RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) +RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options +endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py @@ -102,13 +108,13 @@ REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1)) REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1)) %.a: %.o - ar crus $@ $< + $(AR) crus $@ $< ifdef IS_MSVC %.lib: lib%.o $(MSVC_LIB) -out:`cygpath -w $@` $< else %.lib: lib%.o - ar crus $@ $< + $(AR) crus $@ $< endif %.dylib: %.o $(CC) -dynamiclib -Wl,-dylib -o $@ $< diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index f81352e1773..f9233026a1e 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -19,8 +19,6 @@ // ignore-pretty issue #37195 // ignore-emscripten spawning processes is not supported -use std::io; -use std::io::prelude::*; use std::env; #[path = "backtrace-debuginfo-aux.rs"] mod aux; @@ -163,7 +161,7 @@ fn main() { let args: Vec = env::args().collect(); if args.len() >= 2 { let case = args[1].parse().unwrap(); - writeln!(&mut io::stderr(), "test case {}", case).unwrap(); + eprintln!("test case {}", case); outer(case, pos!()); println!("done."); } else { diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs new file mode 100644 index 00000000000..91930852a57 --- /dev/null +++ b/src/test/run-pass/dyn-trait.rs @@ -0,0 +1,24 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dyn_trait)] + +use std::fmt::Display; + +static BYTE: u8 = 33; + +fn main() { + let x: &(dyn 'static + Display) = &BYTE; + let y: Box = Box::new(BYTE); + let xstr = format!("{}", x); + let ystr = format!("{}", y); + assert_eq!(xstr, "33"); + assert_eq!(ystr, "33"); +} diff --git a/src/test/run-pass/issue-35600.rs b/src/test/run-pass/issue-35600.rs new file mode 100644 index 00000000000..88358eff08d --- /dev/null +++ b/src/test/run-pass/issue-35600.rs @@ -0,0 +1,24 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + type bar; + fn bar(); +} + +impl Foo for () { + type bar = (); + fn bar() {} +} + +fn main() { + let x: <() as Foo>::bar = (); + <()>::bar(); +} diff --git a/src/test/run-pass/issue-44247.rs b/src/test/run-pass/issue-44247.rs new file mode 100644 index 00000000000..27b0aeaac55 --- /dev/null +++ b/src/test/run-pass/issue-44247.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait T { + type X; + const X: Self::X; +} +fn foo() { + let _: X::X = X::X; +} + +trait S { + const X: Self::X; + type X; +} +fn bar() { + let _: X::X = X::X; +} + +fn main() {} diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs deleted file mode 100644 index bcbd3fd3786..00000000000 --- a/src/test/run-pass/smallest-hello-world.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Smallest "hello world" with a libc runtime - -// ignore-windows -// ignore-android - -#![feature(intrinsics, lang_items, start, no_core, alloc_system)] -#![feature(global_allocator, allocator_api)] -#![no_std] - -extern crate alloc_system; - -use alloc_system::System; - -#[global_allocator] -static A: System = System; - -extern { - fn puts(s: *const u8); -} - -#[no_mangle] -#[lang = "eh_personality"] pub extern fn rust_eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } - -#[start] -fn main(_: isize, _: *const *const u8) -> isize { - unsafe { - puts("Hello!\0".as_ptr() as *const u8); - } - return 0 -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/allowed-cross-crate.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs rename to src/test/run-pass/specialization/defaultimpl/allowed-cross-crate.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs rename to src/test/run-pass/specialization/defaultimpl/assoc-fns.rs diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs rename to src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs rename to src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs rename to src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/basics.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-basics.rs rename to src/test/run-pass/specialization/defaultimpl/basics.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs similarity index 87% rename from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs rename to src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs index 62c7e3e2e44..19e1af15bdd 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs +++ b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:specialization_cross_crate_defaults.rs +// aux-build:cross_crate_defaults.rs #![feature(specialization)] -extern crate specialization_cross_crate_defaults; +extern crate cross_crate_defaults; -use specialization_cross_crate_defaults::*; +use cross_crate_defaults::*; struct LocalDefault; struct LocalOverride; diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs similarity index 89% rename from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs rename to src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs index b9548539e16..67cc694ae12 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs +++ b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs @@ -10,11 +10,11 @@ // Test that specialization works even if only the upstream crate enables it -// aux-build:specialization_cross_crate.rs +// aux-build:cross_crate.rs -extern crate specialization_cross_crate; +extern crate cross_crate; -use specialization_cross_crate::*; +use cross_crate::*; fn main() { assert!(0u8.foo() == "generic Clone"); diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs similarity index 93% rename from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs rename to src/test/run-pass/specialization/defaultimpl/cross-crate.rs index 7517824b62b..f1ad105db8f 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs +++ b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:specialization_cross_crate.rs +// aux-build:cross_crate.rs #![feature(specialization)] -extern crate specialization_cross_crate; +extern crate cross_crate; -use specialization_cross_crate::*; +use cross_crate::*; struct NotClone; diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/default-methods.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs rename to src/test/run-pass/specialization/defaultimpl/default-methods.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/out-of-order.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs rename to src/test/run-pass/specialization/defaultimpl/out-of-order.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/overlap-projection.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs rename to src/test/run-pass/specialization/defaultimpl/overlap-projection.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/projection-alias.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs rename to src/test/run-pass/specialization/defaultimpl/projection-alias.rs diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/projection.rs similarity index 100% rename from src/test/run-pass/specialization/defaultimpl/specialization-projection.rs rename to src/test/run-pass/specialization/defaultimpl/projection.rs diff --git a/src/test/run-pass/thin-lto-global-allocator.rs b/src/test/run-pass/thin-lto-global-allocator.rs new file mode 100644 index 00000000000..1c15da5469e --- /dev/null +++ b/src/test/run-pass/thin-lto-global-allocator.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z thinlto -C codegen-units=2 +// min-llvm-version 4.0 + +#![feature(allocator_api, global_allocator)] + +#[global_allocator] +static A: std::heap::System = std::heap::System; + +fn main() {} diff --git a/src/test/run-pass/thinlto/auxiliary/dylib.rs b/src/test/run-pass/thinlto/auxiliary/dylib.rs new file mode 100644 index 00000000000..cdb3f49cae8 --- /dev/null +++ b/src/test/run-pass/thinlto/auxiliary/dylib.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z thinlto -C codegen-units=8 + +#[inline] +pub fn foo(b: u8) { + b.to_string(); +} diff --git a/src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs similarity index 100% rename from src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs rename to src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs diff --git a/src/test/run-pass/thinlto/dylib-works.rs b/src/test/run-pass/thinlto/dylib-works.rs new file mode 100644 index 00000000000..3f54519d0d8 --- /dev/null +++ b/src/test/run-pass/thinlto/dylib-works.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:dylib.rs +// min-llvm-version 4.0 + +extern crate dylib; + +fn main() { + dylib::foo(1); +} diff --git a/src/test/run-pass/thin-lto-inlines.rs b/src/test/run-pass/thinlto/thin-lto-inlines.rs similarity index 100% rename from src/test/run-pass/thin-lto-inlines.rs rename to src/test/run-pass/thinlto/thin-lto-inlines.rs diff --git a/src/test/run-pass/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs similarity index 100% rename from src/test/run-pass/thin-lto-inlines2.rs rename to src/test/run-pass/thinlto/thin-lto-inlines2.rs diff --git a/src/test/rustdoc/crate-version.rs b/src/test/rustdoc/crate-version.rs new file mode 100644 index 00000000000..07ab5ceedfa --- /dev/null +++ b/src/test/rustdoc/crate-version.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --crate-version=1.3.37 -Z unstable-options + +// @has 'crate_version/index.html' '//div[@class="block version"]/p' 'Version 1.3.37' diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs new file mode 100644 index 00000000000..f2d04c16d99 --- /dev/null +++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs @@ -0,0 +1,40 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + f1(|_: (), _: ()| {}); + f2(|_: (), _: ()| {}); + f3(|_: (), _: ()| {}); + f4(|_: (), _: ()| {}); + f5(|_: (), _: ()| {}); + g1(|_: (), _: ()| {}); + g2(|_: (), _: ()| {}); + g3(|_: (), _: ()| {}); + g4(|_: (), _: ()| {}); + h1(|_: (), _: (), _: (), _: ()| {}); + h2(|_: (), _: (), _: (), _: ()| {}); +} + +// Basic +fn f1(_: F) where F: Fn(&(), &()) {} +fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} +fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} +fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} +fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} + +// Nested +fn g1(_: F) where F: Fn(&(), Box) {} +fn g2(_: F) where F: Fn(&(), fn(&())) {} +fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} +fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} + +// Mixed +fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} +fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr new file mode 100644 index 00000000000..f962b772203 --- /dev/null +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -0,0 +1,112 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 + | +12 | f1(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` + | + = note: required by `f1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5 + | +13 | f2(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` + | + = note: required by `f2` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 + | +14 | f3(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&(), &'r ()) -> _` + | + = note: required by `f3` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5 + | +15 | f4(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` + | + = note: required by `f4` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 + | +16 | f5(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` + | + = note: required by `f5` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5 + | +17 | g1(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>) -> _` + | + = note: required by `g1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 + | +18 | g2(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` + | + = note: required by `g2` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:19:5 + | +19 | g3(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s> fn(&'s (), std::boxed::Box std::ops::Fn(&'r ()) + 'static>) -> _` + | + = note: required by `g3` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 + | +20 | g4(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` + | + = note: required by `g4` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:21:5 + | +21 | h1(|_: (), _: (), _: (), _: ()| {}); + | ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _` + | | + | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` + | + = note: required by `h1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 + | +22 | h2(|_: (), _: (), _: (), _: ()| {}); + | ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _` + | | + | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` + | + = note: required by `h2` + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 1a0c74dc01a..11279f5c612 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -5,6 +5,7 @@ error: chained comparison operators require parentheses | ^^^^^^^^ | = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:16:25 @@ -13,6 +14,7 @@ error: chained comparison operators require parentheses | ^^^^^^^ | = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:20:37 @@ -21,6 +23,7 @@ error: chained comparison operators require parentheses | ^^^^^^^^ | = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:20:41 @@ -29,6 +32,7 @@ error: chained comparison operators require parentheses | ^^^^^^ | = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments error: aborting due to 4 previous errors diff --git a/src/test/ui/issue-22644.rs b/src/test/ui/issue-22644.rs index b482d0595f7..c8e0cd1763f 100644 --- a/src/test/ui/issue-22644.rs +++ b/src/test/ui/issue-22644.rs @@ -35,5 +35,7 @@ fn main() { < 5); + println!("{}", a as usize << long_name); + println!("{}", a: &mut 4); } diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr index 54c325b24a3..f4967c4803b 100644 --- a/src/test/ui/issue-22644.stderr +++ b/src/test/ui/issue-22644.stderr @@ -76,9 +76,18 @@ help: try comparing the casted value 33 | ... -error: expected type, found `4` - --> $DIR/issue-22644.rs:38:28 +error: `<` is interpreted as a start of generic arguments for `usize`, not a shift + --> $DIR/issue-22644.rs:38:31 | -38 | println!("{}", a: &mut 4); +38 | println!("{}", a as usize << long_name); + | ---------- ^^ --------- interpreted as generic arguments + | | | + | | not interpreted as shift + | help: try shifting the casted value: `(a as usize)` + +error: expected type, found `4` + --> $DIR/issue-22644.rs:40:28 + | +40 | println!("{}", a: &mut 4); | ^ expecting a type here because of type ascription diff --git a/src/test/ui/issue-44406.rs b/src/test/ui/issue-44406.rs new file mode 100644 index 00000000000..abf572118fc --- /dev/null +++ b/src/test/ui/issue-44406.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! foo { + ($rest: tt) => { + bar(baz: $rest) + } +} + +fn main() { + foo!(true); +} diff --git a/src/test/ui/issue-44406.stderr b/src/test/ui/issue-44406.stderr new file mode 100644 index 00000000000..9beae91540a --- /dev/null +++ b/src/test/ui/issue-44406.stderr @@ -0,0 +1,26 @@ +error: expected identifier, found keyword `true` + --> $DIR/issue-44406.rs:18:10 + | +18 | foo!(true); + | ^^^^ + +error: expected type, found keyword `true` + --> $DIR/issue-44406.rs:18:10 + | +13 | bar(baz: $rest) + | - help: did you mean to use `;` here? +... +18 | foo!(true); + | ^^^^ expecting a type here because of type ascription + +error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true` + --> $DIR/issue-44406.rs:18:10 + | +13 | bar(baz: $rest) + | - expected one of 20 possible tokens here +... +18 | foo!(true); + | ^^^^ unexpected token + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 5b2a4f589f7..9a69c52e6cf 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -14,6 +14,20 @@ warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was | = note: #[warn(deprecated)] on by default +warning: variable does not need to be mutable + --> $DIR/suggestions.rs:17:13 + | +17 | let mut a = (1); // should suggest no `mut`, no parens + | ---^^ + | | + | help: remove this `mut` + | +note: lint level defined here + --> $DIR/suggestions.rs:11:9 + | +11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896 + | ^^^^^^^^^^ + warning: denote infinite loops with `loop { ... }` --> $DIR/suggestions.rs:16:5 | @@ -29,17 +43,3 @@ warning: denote infinite loops with `loop { ... }` | = note: #[warn(while_true)] on by default -warning: variable does not need to be mutable - --> $DIR/suggestions.rs:17:13 - | -17 | let mut a = (1); // should suggest no `mut`, no parens - | ---^^ - | | - | help: remove this `mut` - | -note: lint level defined here - --> $DIR/suggestions.rs:11:9 - | -11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896 - | ^^^^^^^^^^ - diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/ui/method-call-err-msg.rs similarity index 100% rename from src/test/compile-fail/method-call-err-msg.rs rename to src/test/ui/method-call-err-msg.rs diff --git a/src/test/ui/method-call-err-msg.stderr b/src/test/ui/method-call-err-msg.stderr new file mode 100644 index 00000000000..c39c62daf9e --- /dev/null +++ b/src/test/ui/method-call-err-msg.stderr @@ -0,0 +1,44 @@ +error[E0061]: this function takes 0 parameters but 1 parameter was supplied + --> $DIR/method-call-err-msg.rs:25:12 + | +15 | fn zero(self) -> Foo { self } + | ----------------------------- defined here +... +25 | x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied + | ^ expected 0 parameters + +error[E0061]: this function takes 1 parameter but 0 parameters were supplied + --> $DIR/method-call-err-msg.rs:27:7 + | +17 | fn one(self, _: isize) -> Foo { self } + | -------------------------------------- defined here +... +27 | .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied + | ^^^ expected 1 parameter + +error[E0061]: this function takes 2 parameters but 1 parameter was supplied + --> $DIR/method-call-err-msg.rs:29:11 + | +19 | fn two(self, _: isize, _: isize) -> Foo { self } + | ------------------------------------------------ defined here +... +29 | .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied + | ^ expected 2 parameters + +error[E0599]: no method named `take` found for type `Foo` in the current scope + --> $DIR/method-call-err-msg.rs:34:7 + | +34 | .take() //~ ERROR no method named `take` found for type `Foo` in the current scope + | ^^^^ + | + = note: the method `take` exists but the following trait bounds were not satisfied: + `&mut Foo : std::iter::Iterator` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `take`, perhaps you need to implement one of them: + candidate #1: `std::collections::hash::Recover` + candidate #2: `std::io::Read` + candidate #3: `std::iter::Iterator` + candidate #4: `alloc::btree::Recover` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index f94471a73ca..5d2d1d2b04c 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -16,4 +16,8 @@ fn main() { [1, 2, 3].sort_by(|tuple| panic!()); [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); f(|| panic!()); + + let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); + let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); + let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); } diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 3031a77b1e8..9d4ac630546 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -1,16 +1,16 @@ -error[E0593]: closure takes 0 arguments but 2 arguments are required +error[E0593]: closure is expected to take 2 arguments, but it takes 0 arguments --> $DIR/closure-arg-count.rs:15:15 | 15 | [1, 2, 3].sort_by(|| panic!()); - | ^^^^^^^ ----------- takes 0 arguments + | ^^^^^^^ -- takes 0 arguments | | | expected closure that takes 2 arguments -error[E0593]: closure takes 1 argument but 2 arguments are required +error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument --> $DIR/closure-arg-count.rs:16:15 | 16 | [1, 2, 3].sort_by(|tuple| panic!()); - | ^^^^^^^ ---------------- takes 1 argument + | ^^^^^^^ ------- takes 1 argument | | | expected closure that takes 2 arguments @@ -23,23 +23,47 @@ error[E0308]: mismatched types = note: expected type `&{integer}` found type `(_, _)` -error[E0593]: closure takes 1 argument but 2 arguments are required +error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument --> $DIR/closure-arg-count.rs:17:15 | 17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^ -------------------------- takes 1 argument + | ^^^^^^^ ----------------- takes 1 argument | | | expected closure that takes 2 arguments -error[E0593]: closure takes 0 arguments but 1 argument is required +error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:18:5 | 18 | f(|| panic!()); - | ^ ----------- takes 0 arguments + | ^ -- takes 0 arguments | | | expected closure that takes 1 argument | = note: required by `f` -error: aborting due to 5 previous errors +error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:20:53 + | +20 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); + | ^^^ ------ help: consider changing the closure to accept a tuple: `|(i, x)|` + | | + | expected closure that takes a single tuple as argument + +error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:21:53 + | +21 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); + | ^^^ ------------- help: consider changing the closure to accept a tuple: `|(i, x): (usize, _)|` + | | + | expected closure that takes a single tuple as argument + +error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments + --> $DIR/closure-arg-count.rs:22:53 + | +22 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); + | ^^^ --------- takes 3 distinct arguments + | | + | expected closure that takes a single 2-tuple as argument + +error: aborting due to 8 previous errors diff --git a/src/test/ui/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions-fn-subtyping-return-static.stderr index 1598a8a40d2..4a97537223c 100644 --- a/src/test/ui/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 51 | want_F(bar); //~ ERROR E0308 | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | - = note: expected type `fn(&'cx S) -> &'cx S` - found type `fn(&'a S) -> &S {bar::<'_>}` + = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` + found type `for<'a> fn(&'a S) -> &S {bar::<'_>}` error: aborting due to previous error diff --git a/src/test/ui/span/missing-unit-argument.rs b/src/test/ui/span/missing-unit-argument.rs index 2cdab5bedc4..ba1a999121c 100644 --- a/src/test/ui/span/missing-unit-argument.rs +++ b/src/test/ui/span/missing-unit-argument.rs @@ -11,9 +11,17 @@ fn foo(():(), ():()) {} fn bar(():()) {} +struct S; +impl S { + fn baz(self, (): ()) { } + fn generic(self, _: T) { } +} + fn main() { let _: Result<(), String> = Ok(); foo(); foo(()); bar(); + S.baz(); + S.generic::<()>(); } diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index e508a30d182..af558d0ab83 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -1,45 +1,73 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied - --> $DIR/missing-unit-argument.rs:15:33 + --> $DIR/missing-unit-argument.rs:21:33 | -15 | let _: Result<(), String> = Ok(); +21 | let _: Result<(), String> = Ok(); | ^^^^ | -help: expected the unit value `()`. You can create one with a pair of parenthesis +help: expected the unit value `()`; create it with empty parentheses | -15 | let _: Result<(), String> = Ok(()); +21 | let _: Result<(), String> = Ok(()); | ^^ error[E0061]: this function takes 2 parameters but 0 parameters were supplied - --> $DIR/missing-unit-argument.rs:16:5 + --> $DIR/missing-unit-argument.rs:22:5 | 11 | fn foo(():(), ():()) {} | ----------------------- defined here ... -16 | foo(); +22 | foo(); | ^^^^^ expected 2 parameters error[E0061]: this function takes 2 parameters but 1 parameter was supplied - --> $DIR/missing-unit-argument.rs:17:9 + --> $DIR/missing-unit-argument.rs:23:9 | 11 | fn foo(():(), ():()) {} | ----------------------- defined here ... -17 | foo(()); +23 | foo(()); | ^^ expected 2 parameters error[E0061]: this function takes 1 parameter but 0 parameters were supplied - --> $DIR/missing-unit-argument.rs:18:5 + --> $DIR/missing-unit-argument.rs:24:5 | 12 | fn bar(():()) {} | ---------------- defined here ... -18 | bar(); +24 | bar(); | ^^^^^ | -help: expected the unit value `()`. You can create one with a pair of parenthesis +help: expected the unit value `()`; create it with empty parentheses | -18 | bar(()); +24 | bar(()); | ^^ -error: aborting due to 4 previous errors +error[E0061]: this function takes 1 parameter but 0 parameters were supplied + --> $DIR/missing-unit-argument.rs:25:7 + | +16 | fn baz(self, (): ()) { } + | ------------------------ defined here +... +25 | S.baz(); + | ^^^ + | +help: expected the unit value `()`; create it with empty parentheses + | +25 | S.baz(()); + | ^^ + +error[E0061]: this function takes 1 parameter but 0 parameters were supplied + --> $DIR/missing-unit-argument.rs:26:7 + | +17 | fn generic(self, _: T) { } + | ----------------------------- defined here +... +26 | S.generic::<()>(); + | ^^^^^^^ + | +help: expected the unit value `()`; create it with empty parentheses + | +26 | S.generic::<()>(()); + | ^^ + +error: aborting due to 6 previous errors diff --git a/src/test/ui/struct-field-init-syntax.rs b/src/test/ui/struct-field-init-syntax.rs new file mode 100644 index 00000000000..8ea62fef9fa --- /dev/null +++ b/src/test/ui/struct-field-init-syntax.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +// issue #41834 + +fn main() { + let foo = Foo { + one: 111, + ..Foo::default(), + //~^ ERROR cannot use a comma after struct expansion + }; + + let foo = Foo { + ..Foo::default(), + //~^ ERROR cannot use a comma after struct expansion + one: 111, + }; +} diff --git a/src/test/ui/struct-field-init-syntax.stderr b/src/test/ui/struct-field-init-syntax.stderr new file mode 100644 index 00000000000..0bca3f83eb1 --- /dev/null +++ b/src/test/ui/struct-field-init-syntax.stderr @@ -0,0 +1,18 @@ +error: cannot use a comma after the base struct + --> $DIR/struct-field-init-syntax.rs:18:9 + | +18 | ..Foo::default(), + | ^^^^^^^^^^^^^^^^- help: remove this comma + | + = note: the base struct must always be the last field + +error: cannot use a comma after the base struct + --> $DIR/struct-field-init-syntax.rs:23:9 + | +23 | ..Foo::default(), + | ^^^^^^^^^^^^^^^^- help: remove this comma + | + = note: the base struct must always be the last field + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs b/src/test/ui/suggestions/closure-immutable-outer-variable.rs new file mode 100644 index 00000000000..fe8e2bc6c8e --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Point at the captured immutable outer variable + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let y = true; + foo(Box::new(move || y = false) as Box<_>); +} diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr new file mode 100644 index 00000000000..19f1cd07171 --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr @@ -0,0 +1,10 @@ +error[E0594]: cannot assign to captured outer variable in an `FnMut` closure + --> $DIR/closure-immutable-outer-variable.rs:19:26 + | +18 | let y = true; + | - help: consider making `y` mutable: `mut y` +19 | foo(Box::new(move || y = false) as Box<_>); + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/suggest-labels.rs b/src/test/ui/suggestions/suggest-labels.rs new file mode 100644 index 00000000000..5bebce79ecc --- /dev/null +++ b/src/test/ui/suggestions/suggest-labels.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(unreachable_code)] +fn main() { + 'foo: loop { + break 'fo; + } + + 'bar: loop { + continue 'bor; + } + + 'longlabel: loop { + 'longlabel1: loop { + break 'longlable; + } + } +} diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggestions/suggest-labels.stderr new file mode 100644 index 00000000000..23aa18a3655 --- /dev/null +++ b/src/test/ui/suggestions/suggest-labels.stderr @@ -0,0 +1,20 @@ +error[E0426]: use of undeclared label `'fo` + --> $DIR/suggest-labels.rs:14:15 + | +14 | break 'fo; + | ^^^ did you mean `'foo`? + +error[E0426]: use of undeclared label `'bor` + --> $DIR/suggest-labels.rs:18:18 + | +18 | continue 'bor; + | ^^^^ did you mean `'bar`? + +error[E0426]: use of undeclared label `'longlable` + --> $DIR/suggest-labels.rs:23:19 + | +23 | break 'longlable; + | ^^^^^^^^^^ did you mean `'longlabel1`? + +error: aborting due to 3 previous errors + diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index daeac35a017..8c1b130b116 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -95,6 +95,7 @@ static TARGETS: &'static [&'static str] = &[ "x86_64-unknown-freebsd", "x86_64-unknown-fuchsia", "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-gnux32", "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", "x86_64-unknown-redox", diff --git a/src/tools/clippy b/src/tools/clippy index 25444585592..b62b1b68edc 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 25444585592f5da648edd5317fcdd21f2db8bb64 +Subproject commit b62b1b68edcdf23a70cb12f31403c80e97f13634 diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cee7e52c7f3..aa98f818f40 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -201,6 +201,8 @@ pub struct Config { pub cc: String, pub cxx: String, pub cflags: String, + pub ar: String, + pub linker: Option, pub llvm_components: String, pub llvm_cxxflags: String, pub nodejs: Option, diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index b7fb3670165..251dd4d5edb 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -45,7 +45,7 @@ impl FromStr for ErrorKind { impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ErrorKind::Help => write!(f, "help"), + ErrorKind::Help => write!(f, "help message"), ErrorKind::Error => write!(f, "error"), ErrorKind::Note => write!(f, "note"), ErrorKind::Suggestion => write!(f, "suggestion"), diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index bb9bf57d55e..19195838791 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -567,6 +567,19 @@ impl Config { None } } + + pub fn find_rust_src_root(&self) -> Option { + let mut path = self.src_base.clone(); + let path_postfix = Path::new("src/etc/lldb_batchmode.py"); + + while path.pop() { + if path.join(&path_postfix).is_file() { + return Some(path); + } + } + + None + } } pub fn lldb_version_to_int(version_string: &str) -> isize { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 26c447d01d3..1701c8a3e43 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -102,6 +102,8 @@ pub fn parse_config(args: Vec ) -> Config { .reqopt("", "cc", "path to a C compiler", "PATH") .reqopt("", "cxx", "path to a C++ compiler", "PATH") .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "linker", "path to a linker", "PATH") .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") .reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS") .optopt("", "nodejs", "the name of nodejs", "PATH") @@ -198,6 +200,8 @@ pub fn parse_config(args: Vec ) -> Config { cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), cflags: matches.opt_str("cflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or("ar".into()), + linker: matches.opt_str("linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), nodejs: matches.opt_str("nodejs"), @@ -234,6 +238,8 @@ pub fn log_config(config: &Config) { logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("linker: {:?}", config.linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("quiet: {}", config.quiet)); logv(c, "\n".to_string()); @@ -489,15 +495,28 @@ fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf { } fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> bool { + let rust_src_dir = config.find_rust_src_root().expect( + "Could not find Rust source root", + ); let stamp = mtime(&stamp(config, testpaths)); - let mut inputs = vec![ - mtime(&testpaths.file), - mtime(&config.rustc_path), - ]; + let mut inputs = vec![mtime(&testpaths.file), mtime(&config.rustc_path)]; for aux in props.aux.iter() { - inputs.push(mtime(&testpaths.file.parent().unwrap() - .join("auxiliary") - .join(aux))); + inputs.push(mtime( + &testpaths.file.parent().unwrap().join("auxiliary").join( + aux, + ), + )); + } + // Relevant pretty printer files + let pretty_printer_files = [ + "src/etc/debugger_pretty_printers_common.py", + "src/etc/gdb_load_rust_pretty_printers.py", + "src/etc/gdb_rust_pretty_printing.py", + "src/etc/lldb_batchmode.py", + "src/etc/lldb_rust_formatters.py", + ]; + for pretty_printer_file in &pretty_printer_files { + inputs.push(mtime(&rust_src_dir.join(pretty_printer_file))); } for lib in config.run_lib_path.read_dir().unwrap() { let lib = lib.unwrap(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 10ef326d9db..d61077643f1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -25,6 +25,7 @@ use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs::{self, File, create_dir_all}; +use std::fmt; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; @@ -571,9 +572,10 @@ actual:\n\ } } - _=> { - let rust_src_root = self.find_rust_src_root() - .expect("Could not find Rust source root"); + _ => { + let rust_src_root = self.config.find_rust_src_root().expect( + "Could not find Rust source root", + ); let rust_pp_module_rel_path = Path::new("./src/etc"); let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path) .to_str() @@ -664,19 +666,6 @@ actual:\n\ self.check_debugger_output(&debugger_run_result, &check_lines); } - fn find_rust_src_root(&self) -> Option { - let mut path = self.config.src_base.clone(); - let path_postfix = Path::new("src/etc/lldb_batchmode.py"); - - while path.pop() { - if path.join(&path_postfix).is_file() { - return Some(path); - } - } - - None - } - fn run_debuginfo_lldb_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); @@ -735,7 +724,9 @@ actual:\n\ script_str.push_str("version\n"); // Switch LLDB into "Rust mode" - let rust_src_root = self.find_rust_src_root().expect("Could not find Rust source root"); + let rust_src_root = self.config.find_rust_src_root().expect( + "Could not find Rust source root", + ); let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py"); let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path) .to_str() @@ -1050,7 +1041,7 @@ actual:\n\ None => { if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) { self.error( - &format!("{}:{}: unexpected {:?}: '{}'", + &format!("{}:{}: unexpected {}: '{}'", file_name, actual_error.line_num, actual_error.kind.as_ref() @@ -1164,6 +1155,9 @@ actual:\n\ .arg("-o").arg(out_dir) .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if let Some(ref linker) = self.config.linker { + rustdoc.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } self.compose_and_run_compiler(rustdoc, None) } @@ -1450,6 +1444,9 @@ actual:\n\ } else { rustc.args(self.split_maybe_args(&self.config.target_rustcflags)); } + if let Some(ref linker) = self.config.linker { + rustc.arg(format!("-Clinker={}", linker)); + } rustc.args(&self.props.compile_flags); @@ -1717,11 +1714,13 @@ actual:\n\ if self.props.check_test_line_numbers_match { self.check_rustdoc_test_option(proc_res); } else { - let root = self.find_rust_src_root().unwrap(); - let res = self.cmd2procres(Command::new(&self.config.docck_python) - .arg(root.join("src/etc/htmldocck.py")) - .arg(out_dir) - .arg(&self.testpaths.file)); + let root = self.config.find_rust_src_root().unwrap(); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/etc/htmldocck.py")) + .arg(out_dir) + .arg(&self.testpaths.file), + ); if !res.status.success() { self.fatal_proc_rec("htmldocck failed!", &res); } @@ -2036,7 +2035,6 @@ actual:\n\ // Add an extra flag pointing at the incremental directory. let mut revision_props = self.props.clone(); revision_props.incremental_dir = Some(incremental_dir); - revision_props.compile_flags.push(String::from("-Zincremental-info")); let revision_cx = TestCx { config: self.config, @@ -2109,6 +2107,10 @@ actual:\n\ .env("LLVM_COMPONENTS", &self.config.llvm_components) .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags); + if let Some(ref linker) = self.config.linker { + cmd.env("RUSTC_LINKER", linker); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); @@ -2131,7 +2133,8 @@ actual:\n\ .env("CXX", &self.config.cxx); } else { cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)); + .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)) + .env("AR", &self.config.ar); if self.config.target.contains("windows") { cmd.env("IS_WINDOWS", "1"); @@ -2237,7 +2240,7 @@ actual:\n\ let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len()); let tests_text_str = String::from(tests_text); let mut curr_test : Option<&str> = None; - let mut curr_test_contents = Vec::new(); + let mut curr_test_contents = vec![ExpectedLine::Elision]; for l in tests_text_str.lines() { debug!("line: {:?}", l); if l.starts_with("// START ") { @@ -2251,11 +2254,14 @@ actual:\n\ self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents); curr_test = None; curr_test_contents.clear(); + curr_test_contents.push(ExpectedLine::Elision); } else if l.is_empty() { // ignore + } else if l.starts_with("//") && l.split_at("//".len()).1.trim() == "..." { + curr_test_contents.push(ExpectedLine::Elision) } else if l.starts_with("// ") { let (_, test_content) = l.split_at("// ".len()); - curr_test_contents.push(test_content); + curr_test_contents.push(ExpectedLine::Text(test_content)); } } } @@ -2273,7 +2279,7 @@ actual:\n\ } } - fn compare_mir_test_output(&self, test_name: &str, expected_content: &[&str]) { + fn compare_mir_test_output(&self, test_name: &str, expected_content: &[ExpectedLine<&str>]) { let mut output_file = PathBuf::new(); output_file.push(self.get_mir_dump_dir()); output_file.push(test_name); @@ -2285,38 +2291,77 @@ actual:\n\ let mut dumped_string = String::new(); dumped_file.read_to_string(&mut dumped_string).unwrap(); let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty()); - let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty()); - - // We expect each non-empty line from expected_content to appear - // in the dump in order, but there may be extra lines interleaved - while let Some(expected_line) = expected_lines.next() { - let e_norm = normalize_mir_line(expected_line); - if e_norm.is_empty() { - continue; - }; - let mut found = false; - while let Some(dumped_line) = dumped_lines.next() { - let d_norm = normalize_mir_line(dumped_line); - debug!("found: {:?}", d_norm); - debug!("expected: {:?}", e_norm); - if e_norm == d_norm { - found = true; - break; - }; + let mut expected_lines = expected_content.iter().filter(|&l| { + if let &ExpectedLine::Text(l) = l { + !l.is_empty() + } else { + true } - if !found { - let normalize_all = dumped_string.lines() - .map(nocomment_mir_line) - .filter(|l| !l.is_empty()) - .collect::>() - .join("\n"); - panic!("ran out of mir dump output to match against.\n\ - Did not find expected line: {:?}\n\ - Expected:\n{}\n\ - Actual:\n{}", - expected_line, - expected_content.join("\n"), - normalize_all); + }).peekable(); + + let compare = |expected_line, dumped_line| { + let e_norm = normalize_mir_line(expected_line); + let d_norm = normalize_mir_line(dumped_line); + debug!("found: {:?}", d_norm); + debug!("expected: {:?}", e_norm); + e_norm == d_norm + }; + + let error = |expected_line, extra_msg| { + let normalize_all = dumped_string.lines() + .map(nocomment_mir_line) + .filter(|l| !l.is_empty()) + .collect::>() + .join("\n"); + let f = |l: &ExpectedLine<_>| match l { + &ExpectedLine::Elision => "... (elided)".into(), + &ExpectedLine::Text(t) => t + }; + let expected_content = expected_content.iter() + .map(|l| f(l)) + .collect::>() + .join("\n"); + panic!("Did not find expected line, error: {}\n\ + Actual Line: {:?}\n\ + Expected:\n{}\n\ + Actual:\n{}", + extra_msg, + expected_line, + expected_content, + normalize_all); + }; + + // We expect each non-empty line to appear consecutively, non-consecutive lines + // must be separated by at least one Elision + while let Some(dumped_line) = dumped_lines.next() { + match expected_lines.next() { + Some(&ExpectedLine::Text(expected_line)) => + if !compare(expected_line, dumped_line) { + error(expected_line, + format!("Mismatch in lines\nExpected Line: {:?}", dumped_line)); + }, + Some(&ExpectedLine::Elision) => { + // skip any number of elisions in a row. + while let Some(&&ExpectedLine::Elision) = expected_lines.peek() { + expected_lines.next(); + } + if let Some(&ExpectedLine::Text(expected_line)) = expected_lines.next() { + let mut found = compare(expected_line, dumped_line); + if found { + continue; + } + while let Some(dumped_line) = dumped_lines.next() { + found = compare(expected_line, dumped_line); + if found { + break; + } + } + if !found { + error(expected_line, "ran out of mir dump to match against".into()); + } + } + }, + None => {}, } } } @@ -2439,6 +2484,25 @@ enum TargetLocation { ThisDirectory(PathBuf), } +#[derive(Clone, PartialEq, Eq)] +enum ExpectedLine> { + Elision, + Text(T) +} + +impl fmt::Debug for ExpectedLine +where + T: AsRef + fmt::Debug +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if let &ExpectedLine::Text(ref t) = self { + write!(formatter, "{:?}", t) + } else { + write!(formatter, "\"...\" (Elision)") + } + } +} + fn normalize_mir_line(line: &str) -> String { nocomment_mir_line(line).replace(char::is_whitespace, "") } diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 22eb5241c0e..16a478368c8 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 22eb5241c0ee5bb7eaf95e270a2b1500e82bf767 +Subproject commit 16a478368c8dcc0c0ee47372a9f663b23d28b097 diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 90bf7a5e0a6..c316ec46762 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -33,10 +33,9 @@ macro_rules! t { macro_rules! tidy_error { ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ - use std::io::Write; *$bad = true; - write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); - writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); + eprint!("tidy error: "); + eprintln!($fmt, $($arg)*); }); } diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 433192a21ec..f6640c902bc 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -22,7 +22,6 @@ use tidy::*; use std::process; use std::path::PathBuf; use std::env; -use std::io::{self, Write}; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -44,7 +43,7 @@ fn main() { } if bad { - writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr"); + eprintln!("some tidy checks failed"); process::exit(1); } } diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml index 1700daa0aff..e62597c5216 100644 --- a/src/tools/toolstate.toml +++ b/src/tools/toolstate.toml @@ -3,7 +3,7 @@ # # There are three states a tool can be in: # 1. Broken: The tool doesn't build -# 2. Building: The tool builds but its tests are failing +# 2. Compiling: The tool builds but its tests are failing # 3. Testing: The tool builds and its tests are passing # # In the future there will be further states like "Distributing", which @@ -26,11 +26,10 @@ miri = "Broken" # ping @Manishearth @llogiq @mcarton @oli-obk -clippy = "Broken" +clippy = "Compiling" # ping @nrc rls = "Testing" # ping @nrc rustfmt = "Testing" -