diff --git a/.travis.yml b/.travis.yml index 1007aad925d9..280da0569950 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto - env: > @@ -70,7 +70,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto # OSX builders producing releases. These do not run the full test suite and diff --git a/RELEASES.md b/RELEASES.md index d6f95f52075d..7a9d256be282 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -78,6 +78,7 @@ Compatibility Notes - [`column!()` macro is one-based instead of zero-based][46977] - [`fmt::Arguments` can no longer be shared across threads][45198] - [Access to `#[repr(packed)]` struct fields is now unsafe][44884] +- [Cargo sets a different working directory for the compiler][cargo/4788] [44884]: https://github.com/rust-lang/rust/pull/44884 [45198]: https://github.com/rust-lang/rust/pull/45198 @@ -106,6 +107,7 @@ Compatibility Notes [47080]: https://github.com/rust-lang/rust/pull/47080 [47084]: https://github.com/rust-lang/rust/pull/47084 [cargo/4743]: https://github.com/rust-lang/cargo/pull/4743 +[cargo/4788]: https://github.com/rust-lang/cargo/pull/4788 [cargo/4817]: https://github.com/rust-lang/cargo/pull/4817 [`RefCell::replace`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace [`RefCell::swap`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.swap diff --git a/src/Cargo.lock b/src/Cargo.lock index 6b722db53ed3..4b3099eed016 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -328,6 +328,26 @@ dependencies = [ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clippy_lints" +version = "0.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cmake" version = "0.1.29" @@ -1003,7 +1023,7 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.27.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1640,17 +1660,20 @@ name = "rls" version = "0.125.0" dependencies = [ "cargo 0.26.0", + "clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1663,27 +1686,21 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rls-data" -version = "0.14.0" +name = "rls-blacklist" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rls-data" @@ -1692,6 +1709,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2986,6 +3005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" +"checksum clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)" = "a3864104a4e6092e644b985dd7543e5f24e99aa7262f5ee400bcb17cfeec1bf5" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" @@ -3050,7 +3070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kuchiki 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e03098e8e719c92b7794515dfd5c1724e2b12f5ce1788e61cfa4663f82eba8d8" -"checksum languageserver-types 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a2036fc8576a22689b7e3171c07eb8e8f700678d7a8a53f6f65abbeb35261e1" +"checksum languageserver-types 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1541f9b22687f060511d213036e1f058797c48e3501e177f01cb6e88de802f5b" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" @@ -3114,8 +3134,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" -"checksum rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "38841e3c5271715a574ac220d9b408b59ed9e2626909c3bc54b5853b4eaadb7b" -"checksum rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8024f1feaca72d0aa4ae1e2a8d454a31b9a33ed02f8d0e9c8559bf53c267ec3c" +"checksum rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30b08808959205a5cf23c68ace2d9d6defdd6867f3cd5d62981cf50fb52f8882" +"checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" "checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 74dd4a6fa014..66a1c9724620 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -95,7 +95,7 @@ pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, pub host: Interned, pub target: Interned, - pub path: Option<&'a Path>, + pub path: PathBuf, } struct StepDescription { @@ -105,6 +105,32 @@ struct StepDescription { only_build: bool, should_run: fn(ShouldRun) -> ShouldRun, make_run: fn(RunConfig), + name: &'static str, +} + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +struct PathSet { + set: BTreeSet, +} + +impl PathSet { + fn empty() -> PathSet { + PathSet { set: BTreeSet::new() } + } + + fn one>(path: P) -> PathSet { + let mut set = BTreeSet::new(); + set.insert(path.into()); + PathSet { set } + } + + fn has(&self, needle: &Path) -> bool { + self.set.iter().any(|p| p.ends_with(needle)) + } + + fn path(&self, builder: &Builder) -> PathBuf { + self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf() + } } impl StepDescription { @@ -116,10 +142,18 @@ impl StepDescription { only_build: S::ONLY_BUILD, should_run: S::should_run, make_run: S::make_run, + name: unsafe { ::std::intrinsics::type_name::() }, } } - fn maybe_run(&self, builder: &Builder, path: Option<&Path>) { + fn maybe_run(&self, builder: &Builder, pathset: &PathSet) { + if builder.config.exclude.iter().any(|e| pathset.has(e)) { + eprintln!("Skipping {:?} because it is excluded", pathset); + return; + } else if !builder.config.exclude.is_empty() { + eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset, + self.name, builder.config.exclude); + } let build = builder.build; let hosts = if self.only_build_targets || self.only_build { build.build_triple() @@ -144,7 +178,7 @@ impl StepDescription { for target in targets { let run = RunConfig { builder, - path, + path: pathset.path(builder), host: *host, target: *target, }; @@ -157,24 +191,33 @@ impl StepDescription { let should_runs = v.iter().map(|desc| { (desc.should_run)(ShouldRun::new(builder)) }).collect::>(); + + // sanity checks on rules + for (desc, should_run) in v.iter().zip(&should_runs) { + assert!(!should_run.paths.is_empty(), + "{:?} should have at least one pathset", desc.name); + } + if paths.is_empty() { for (desc, should_run) in v.iter().zip(should_runs) { if desc.default && should_run.is_really_default { - desc.maybe_run(builder, None); + for pathset in &should_run.paths { + desc.maybe_run(builder, pathset); + } } } } else { for path in paths { let mut attempted_run = false; for (desc, should_run) in v.iter().zip(&should_runs) { - if should_run.run(path) { + if let Some(pathset) = should_run.pathset_for_path(path) { attempted_run = true; - desc.maybe_run(builder, Some(path)); + desc.maybe_run(builder, pathset); } } if !attempted_run { - eprintln!("Warning: no rules matched {}.", path.display()); + panic!("Error: no rules matched {}.", path.display()); } } } @@ -185,7 +228,7 @@ impl StepDescription { pub struct ShouldRun<'a> { pub builder: &'a Builder<'a>, // use a BTreeSet to maintain sort order - paths: BTreeSet, + paths: BTreeSet, // If this is a default rule, this is an additional constraint placed on // it's run. Generally something like compiler docs being enabled. @@ -206,25 +249,46 @@ impl<'a> ShouldRun<'a> { self } + // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually + // ever be used, but as we transition to having all rules properly handle passing krate(...) by + // actually doing something different for every crate passed. + pub fn all_krates(mut self, name: &str) -> Self { + let mut set = BTreeSet::new(); + for krate in self.builder.in_tree_crates(name) { + set.insert(PathBuf::from(&krate.path)); + } + self.paths.insert(PathSet { set }); + self + } + pub fn krate(mut self, name: &str) -> Self { - for (_, krate_path) in self.builder.crates(name) { - self.paths.insert(PathBuf::from(krate_path)); + for krate in self.builder.in_tree_crates(name) { + self.paths.insert(PathSet::one(&krate.path)); } self } - pub fn path(mut self, path: &str) -> Self { - self.paths.insert(PathBuf::from(path)); + // single, non-aliased path + pub fn path(self, path: &str) -> Self { + self.paths(&[path]) + } + + // multiple aliases for the same job + pub fn paths(mut self, paths: &[&str]) -> Self { + self.paths.insert(PathSet { + set: paths.iter().map(PathBuf::from).collect(), + }); self } // allows being more explicit about why should_run in Step returns the value passed to it - pub fn never(self) -> ShouldRun<'a> { + pub fn never(mut self) -> ShouldRun<'a> { + self.paths.insert(PathSet::empty()); self } - fn run(&self, path: &Path) -> bool { - self.paths.iter().any(|p| path.ends_with(p)) + fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> { + self.paths.iter().find(|pathset| pathset.has(path)) } } @@ -254,19 +318,23 @@ impl<'a> Builder<'a> { tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, native::Llvm, tool::Rustfmt, tool::Miri), Kind::Check => describe!(check::Std, check::Test, check::Rustc), - Kind::Test => describe!(test::Tidy, test::Bootstrap, test::DefaultCompiletest, - test::HostCompiletest, test::Crate, test::CrateLibrustc, test::Rustdoc, - test::Linkcheck, test::Cargotest, test::Cargo, test::Rls, test::Docs, - test::ErrorIndex, test::Distcheck, test::Rustfmt, test::Miri, test::Clippy, - test::RustdocJS, test::RustdocTheme), + Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, + test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, + test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo, + test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps, + test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty, + test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty, + test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake, + test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest, + test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck, + test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook), Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, - dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign, - dist::DontDistWithMiriEnabled), + dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign), Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls, install::Rustfmt, install::Analysis, install::Src, install::Rustc), } @@ -297,8 +365,10 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); - for path in should_run.paths { - help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + for pathset in should_run.paths { + for path in pathset.set { + help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + } } Some(help) } @@ -315,6 +385,12 @@ impl<'a> Builder<'a> { Subcommand::Clean { .. } => panic!(), }; + if let Some(path) = paths.get(0) { + if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { + return; + } + } + let builder = Builder { build, top_stage: build.config.stage.unwrap_or(2), @@ -323,6 +399,12 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), }; + if kind == Kind::Dist { + assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\ + The distributed libraries would include all MIR (increasing binary size). + The distributed MIR would include validation statements."); + } + StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths); } @@ -600,25 +682,9 @@ impl<'a> Builder<'a> { // // FIXME: the guard against msvc shouldn't need to be here if !target.contains("msvc") { - let ccache = self.config.ccache.as_ref(); - let ccacheify = |s: &Path| { - let ccache = match ccache { - Some(ref s) => s, - None => return s.display().to_string(), - }; - // FIXME: the cc-rs crate only recognizes the literal strings - // `ccache` and `sccache` when doing caching compilations, so we - // mirror that here. It should probably be fixed upstream to - // accept a new env var or otherwise work with custom ccache - // vars. - match &ccache[..] { - "ccache" | "sccache" => format!("{} {}", ccache, s.display()), - _ => s.display().to_string(), - } - }; - let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc) - .env("CC", &cc); + 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()) @@ -633,9 +699,8 @@ impl<'a> Builder<'a> { } if let Ok(cxx) = self.cxx(target) { - let cxx = ccacheify(&cxx); - cargo.env(format!("CXX_{}", target), &cxx) - .env("CXX", &cxx) + cargo.env(format!("CXX_{}", target), cxx) + .env("CXX", cxx) .env(format!("CXXFLAGS_{}", target), cflags.clone()) .env("CXXFLAGS", cflags); } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index ede403491d7f..767ee4016c6f 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -26,7 +26,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libstd").krate("std") + run.all_krates("std") } fn make_run(run: RunConfig) { @@ -67,7 +67,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc").krate("rustc-main") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { @@ -114,7 +114,7 @@ impl Step for Test { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libtest").krate("test") + run.all_krates("test") } fn make_run(run: RunConfig) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1d5e11c5d6d4..2dcc0e0e7cd9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,7 +48,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libstd").krate("std") + run.all_krates("std") } fn make_run(run: RunConfig) { @@ -320,7 +320,7 @@ impl Step for Test { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libtest").krate("test") + run.all_krates("test") } fn make_run(run: RunConfig) { @@ -436,7 +436,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc").krate("rustc-main") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { @@ -593,7 +593,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc_trans") + run.all_krates("rustc_trans") } fn make_run(run: RunConfig) { @@ -828,7 +828,7 @@ impl Step for Assemble { type Output = Compiler; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/rustc") + run.all_krates("rustc-main") } /// Prepare a new compiler from the artifacts in `stage` diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4f4fd14ae8ca..812ca6d64fb6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -56,6 +56,7 @@ pub struct Config { pub sanitizers: bool, pub profiler: bool, pub ignore_git: bool, + pub exclude: Vec, pub run_host_only: bool, @@ -311,6 +312,7 @@ impl Config { let flags = Flags::parse(&args); let file = flags.config.clone(); let mut config = Config::default(); + config.exclude = flags.exclude; config.llvm_enabled = true; config.llvm_optimize = true; config.llvm_version_check = true; diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 460fb016f16e..e7aed7eb4fea 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1233,31 +1233,6 @@ impl Step for Rustfmt { } } - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct DontDistWithMiriEnabled; - -impl Step for DontDistWithMiriEnabled { - type Output = PathBuf; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - let build_miri = run.builder.build.config.test_miri; - run.default_condition(build_miri) - } - - fn make_run(run: RunConfig) { - run.builder.ensure(DontDistWithMiriEnabled); - } - - fn run(self, _: &Builder) -> PathBuf { - panic!("Do not distribute with miri enabled.\n\ - The distributed libraries would include all MIR (increasing binary size). - The distributed MIR would include validation statements."); - } -} - - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 6a75fc5112f5..55d9723527e6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -429,7 +429,7 @@ impl Step for Std { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("std").default_condition(builder.build.config.docs) + run.all_krates("std").default_condition(builder.build.config.docs) } fn make_run(run: RunConfig) { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 478e496078ad..42b949527e09 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,7 @@ pub struct Flags { pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, + pub exclude: Vec, } pub enum Subcommand { @@ -109,6 +110,7 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); + opts.optmulti("", "exclude", "build paths to exclude", "PATH"); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optopt("", "stage", "stage to build", "N"); opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); @@ -273,7 +275,10 @@ Arguments: }; // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); - let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + let src = matches.opt_str("src").map(PathBuf::from) + .or_else(|| env::var_os("SRC").map(PathBuf::from)) + .unwrap_or(cwd.clone()); + let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -358,11 +363,6 @@ Arguments: stage = Some(1); } - let cwd = t!(env::current_dir()); - let src = matches.opt_str("src").map(PathBuf::from) - .or_else(|| env::var_os("SRC").map(PathBuf::from)) - .unwrap_or(cwd); - Flags { verbose: matches.opt_count("verbose"), stage, @@ -374,10 +374,12 @@ Arguments: target: split(matches.opt_strs("target")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), config: cfg_file, - src, jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd, incremental: matches.opt_present("incremental"), + exclude: split(matches.opt_strs("exclude")) + .into_iter().map(|p| p.into()).collect::>(), + src, } } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 83c270865c0b..afd740ce5484 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -113,9 +113,8 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![deny(warnings)] -#![allow(stable_features)] -#![feature(associated_consts)] +//#![deny(warnings)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -267,6 +266,18 @@ struct Crate { bench_step: String, } +impl Crate { + fn is_local(&self, build: &Build) -> bool { + self.path.starts_with(&build.config.src) && + !self.path.to_string_lossy().ends_with("_shim") + } + + fn local_path(&self, build: &Build) -> PathBuf { + assert!(self.is_local(build)); + self.path.strip_prefix(&build.config.src).unwrap().into() + } +} + /// The various "modes" of invoking Cargo. /// /// These entries currently correspond to the various output directories of the @@ -949,22 +960,18 @@ impl Build { } } - /// Get a list of crates from a root crate. - /// - /// Returns Vec<(crate, path to crate, is_root_crate)> - fn crates(&self, root: &str) -> Vec<(Interned, &Path)> { - let interned = INTERNER.intern_string(root.to_owned()); + fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); - let mut list = vec![interned]; + let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - // If we can't strip prefix, then out-of-tree path - let path = krate.path.strip_prefix(&self.src).unwrap_or(&krate.path); - ret.push((krate.name, path)); - for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { - list.push(*dep); + if krate.is_local(self) { + ret.push(krate); + for dep in &krate.deps { + if visited.insert(dep) && dep != "build_helper" { + list.push(*dep); + } } } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 2ea026244034..29cd23bdbb19 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -51,9 +51,7 @@ impl Step for Llvm { } fn make_run(run: RunConfig) { - let emscripten = run.path.map(|p| { - p.ends_with("llvm-emscripten") - }).unwrap_or(false); + let emscripten = run.path.ends_with("llvm-emscripten"); run.builder.ensure(Llvm { target: run.target, emscripten, @@ -159,6 +157,14 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + // By default, LLVM will automatically find OCaml and, if it finds it, + // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults + // to /usr/bin/ocaml. + // This causes problem for non-root builds of Rust. Side-step the issue + // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs + // in the prefix. + cfg.define("LLVM_OCAML_INSTALL_PATH", + env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f6b95f0bf974..64ede4f4ecc8 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -13,7 +13,6 @@ //! This file implements the various regression test suites that we execute on //! our CI. -use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::iter; @@ -26,6 +25,7 @@ use std::io::Read; use build_helper::{self, output}; use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; +use Crate as CargoCrate; use cache::{INTERNER, Interned}; use compile; use dist; @@ -550,180 +550,213 @@ fn testdir(build: &Build, host: Interned) -> PathBuf { build.out.join(host).join("test") } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -struct Test { - path: &'static str, - mode: &'static str, - suite: &'static str, +macro_rules! default_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false }); + } } -static DEFAULT_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui", mode: "ui", suite: "ui" }, - Test { path: "src/test/run-pass", mode: "run-pass", suite: "run-pass" }, - Test { path: "src/test/compile-fail", mode: "compile-fail", suite: "compile-fail" }, - Test { path: "src/test/parse-fail", mode: "parse-fail", suite: "parse-fail" }, - Test { path: "src/test/run-fail", mode: "run-fail", suite: "run-fail" }, - Test { - path: "src/test/run-pass-valgrind", - mode: "run-pass-valgrind", - suite: "run-pass-valgrind" - }, - Test { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" }, - Test { path: "src/test/codegen", mode: "codegen", suite: "codegen" }, - Test { path: "src/test/codegen-units", mode: "codegen-units", suite: "codegen-units" }, - Test { path: "src/test/incremental", mode: "incremental", suite: "incremental" }, +macro_rules! host_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true }); + } +} +macro_rules! test { + ($name:ident { + path: $path:expr, + mode: $mode:expr, + suite: $suite:expr, + default: $default:expr, + host: $host:expr + }) => { + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub struct $name { + pub compiler: Compiler, + pub target: Interned, + } + + impl Step for $name { + type Output = (); + const DEFAULT: bool = $default; + const ONLY_HOSTS: bool = $host; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path($path) + } + + fn make_run(run: RunConfig) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + + run.builder.ensure($name { + compiler, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Compiletest { + compiler: self.compiler, + target: self.target, + mode: $mode, + suite: $suite, + }) + } + } + } +} + +default_test!(Ui { + path: "src/test/ui", + mode: "ui", + suite: "ui" +}); + +default_test!(RunPass { + path: "src/test/run-pass", + mode: "run-pass", + suite: "run-pass" +}); + +default_test!(CompileFail { + path: "src/test/compile-fail", + mode: "compile-fail", + suite: "compile-fail" +}); + +default_test!(ParseFail { + path: "src/test/parse-fail", + mode: "parse-fail", + suite: "parse-fail" +}); + +default_test!(RunFail { + path: "src/test/run-fail", + mode: "run-fail", + suite: "run-fail" +}); + +default_test!(RunPassValgrind { + path: "src/test/run-pass-valgrind", + mode: "run-pass-valgrind", + suite: "run-pass-valgrind" +}); + +default_test!(MirOpt { + path: "src/test/mir-opt", + mode: "mir-opt", + suite: "mir-opt" +}); + +default_test!(Codegen { + path: "src/test/codegen", + mode: "codegen", + suite: "codegen" +}); + +default_test!(CodegenUnits { + path: "src/test/codegen-units", + mode: "codegen-units", + suite: "codegen-units" +}); + +default_test!(Incremental { + path: "src/test/incremental", + mode: "incremental", + suite: "incremental" +}); + +default_test!(Debuginfo { + path: "src/test/debuginfo", // What this runs varies depending on the native platform being apple - Test { path: "src/test/debuginfo", mode: "debuginfo-XXX", suite: "debuginfo" }, -]; + mode: "debuginfo-XXX", + suite: "debuginfo" +}); -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct DefaultCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} +host_test!(UiFullDeps { + path: "src/test/ui-fulldeps", + mode: "ui", + suite: "ui-fulldeps" +}); -impl Step for DefaultCompiletest { - type Output = (); - const DEFAULT: bool = true; +host_test!(RunPassFullDeps { + path: "src/test/run-pass-fulldeps", + mode: "run-pass", + suite: "run-pass-fulldeps" +}); - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in DEFAULT_COMPILETESTS { - run = run.path(test.path); - } - run - } +host_test!(RunFailFullDeps { + path: "src/test/run-fail-fulldeps", + mode: "run-fail", + suite: "run-fail-fulldeps" +}); - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); +host_test!(CompileFailFullDeps { + path: "src/test/compile-fail-fulldeps", + mode: "compile-fail", + suite: "compile-fail-fulldeps" +}); - let test = run.path.map(|path| { - DEFAULT_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); +host_test!(IncrementalFullDeps { + path: "src/test/incremental-fulldeps", + mode: "incremental", + suite: "incremental-fulldeps" +}); - if let Some(test) = test { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in DEFAULT_COMPILETESTS { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } +host_test!(Rustdoc { + path: "src/test/rustdoc", + mode: "rustdoc", + suite: "rustdoc" +}); - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} +test!(Pretty { + path: "src/test/pretty", + mode: "pretty", + suite: "pretty", + default: false, + host: true +}); +test!(RunPassPretty { + path: "src/test/run-pass/pretty", + mode: "pretty", + suite: "run-pass", + default: false, + host: true +}); +test!(RunFailPretty { + path: "src/test/run-fail/pretty", + mode: "pretty", + suite: "run-fail", + default: false, + host: true +}); +test!(RunPassValgrindPretty { + path: "src/test/run-pass-valgrind/pretty", + mode: "pretty", + suite: "run-pass-valgrind", + default: false, + host: true +}); +test!(RunPassFullDepsPretty { + path: "src/test/run-pass-fulldeps/pretty", + mode: "pretty", + suite: "run-pass-fulldeps", + default: false, + host: true +}); +test!(RunFailFullDepsPretty { + path: "src/test/run-fail-fulldeps/pretty", + mode: "pretty", + suite: "run-fail-fulldeps", + default: false, + host: true +}); -// Also default, but host-only. -static HOST_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" }, - Test { path: "src/test/run-pass-fulldeps", mode: "run-pass", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps", mode: "run-fail", suite: "run-fail-fulldeps" }, - Test { - path: "src/test/compile-fail-fulldeps", - mode: "compile-fail", - suite: "compile-fail-fulldeps", - }, - Test { - path: "src/test/incremental-fulldeps", - mode: "incremental", - suite: "incremental-fulldeps", - }, - Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }, - - Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" }, - Test { path: "src/test/run-pass/pretty", mode: "pretty", suite: "run-pass" }, - Test { path: "src/test/run-fail/pretty", mode: "pretty", suite: "run-fail" }, - Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" }, - Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" }, - Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" }, -]; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct HostCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} - -impl Step for HostCompiletest { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in HOST_COMPILETESTS { - run = run.path(test.path); - } - run - } - - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - - let test = run.path.map(|path| { - HOST_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); - - if let Some(test) = test { - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in HOST_COMPILETESTS { - if test.mode == "pretty" { - continue; - } - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } - - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} +host_test!(RunMake { + path: "src/test/run-make", + mode: "run-make", + suite: "run-make" +}); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct Compiletest { @@ -902,7 +935,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally don't work without LLVM"); + println!("Ignoring run-make test suite as they generally dont work without LLVM"); return; } @@ -1099,7 +1132,7 @@ pub struct CrateLibrustc { compiler: Compiler, target: Interned, test_kind: TestKind, - krate: Option>, + krate: Interned, } impl Step for CrateLibrustc { @@ -1115,35 +1148,26 @@ impl Step for CrateLibrustc { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let make = |name: Option>| { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + for krate in builder.in_tree_crates("rustc-main") { + if run.path.ends_with(&krate.path) { + let test_kind = if builder.kind == Kind::Test { + TestKind::Test + } else if builder.kind == Kind::Bench { + TestKind::Bench + } else { + panic!("unexpected builder.kind in crate: {:?}", builder.kind); + }; - builder.ensure(CrateLibrustc { - compiler, - target: run.target, - test_kind, - krate: name, - }); - }; - - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("rustc-main") { - if path.ends_with(krate_path) { - make(Some(name)); - } + builder.ensure(CrateLibrustc { + compiler, + target: run.target, + test_kind, + krate: krate.name, + }); } - } else { - make(None); } } - fn run(self, builder: &Builder) { builder.ensure(Crate { compiler: self.compiler, @@ -1156,27 +1180,95 @@ impl Step for CrateLibrustc { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Crate { +pub struct CrateNotDefault { compiler: Compiler, target: Interned, - mode: Mode, test_kind: TestKind, - krate: Option>, + krate: &'static str, } -impl Step for Crate { +impl Step for CrateNotDefault { type Output = (); - const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.krate("std").krate("test") + run.path("src/liballoc_jemalloc") + .path("src/librustc_asan") + .path("src/librustc_lsan") + .path("src/librustc_msan") + .path("src/librustc_tsan") } fn make_run(run: RunConfig) { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let make = |mode: Mode, name: Option>| { + let test_kind = if builder.kind == Kind::Test { + TestKind::Test + } else if builder.kind == Kind::Bench { + TestKind::Bench + } else { + panic!("unexpected builder.kind in crate: {:?}", builder.kind); + }; + + builder.ensure(CrateNotDefault { + compiler, + target: run.target, + test_kind, + krate: match run.path { + _ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc", + _ if run.path.ends_with("src/librustc_asan") => "rustc_asan", + _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan", + _ if run.path.ends_with("src/librustc_msan") => "rustc_msan", + _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan", + _ => panic!("unexpected path {:?}", run.path), + }, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Crate { + compiler: self.compiler, + target: self.target, + mode: Mode::Libstd, + test_kind: self.test_kind, + krate: INTERNER.intern_str(self.krate), + }); + } +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Crate { + compiler: Compiler, + target: Interned, + mode: Mode, + test_kind: TestKind, + krate: Interned, +} + +impl Step for Crate { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(mut run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run = run.krate("test"); + for krate in run.builder.in_tree_crates("std") { + if krate.is_local(&run.builder) && + !krate.name.contains("jemalloc") && + !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) && + krate.name != "dlmalloc" { + run = run.path(krate.local_path(&builder).to_str().unwrap()); + } + } + run + } + + fn make_run(run: RunConfig) { + let builder = run.builder; + let compiler = builder.compiler(builder.top_stage, run.host); + + let make = |mode: Mode, krate: &CargoCrate| { let test_kind = if builder.kind == Kind::Test { TestKind::Test } else if builder.kind == Kind::Bench { @@ -1190,29 +1282,24 @@ impl Step for Crate { target: run.target, mode, test_kind, - krate: name, + krate: krate.name, }); }; - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("std") { - if path.ends_with(krate_path) { - make(Mode::Libstd, Some(name)); - } + for krate in builder.in_tree_crates("std") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libstd, krate); } - for (name, krate_path) in builder.crates("test") { - if path.ends_with(krate_path) { - make(Mode::Libtest, Some(name)); - } + } + for krate in builder.in_tree_crates("test") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libtest, krate); } - } else { - make(Mode::Libstd, None); - make(Mode::Libtest, None); } } - /// Run all unit tests plus documentation tests for an entire crate DAG defined - /// by a `Cargo.toml` + /// Run all unit tests plus documentation tests for a given crate defined + /// by a `Cargo.toml` (single manifest) /// /// This is what runs tests for crates like the standard library, compiler, etc. /// It essentially is the driver for running `cargo test`. @@ -1241,27 +1328,23 @@ impl Step for Crate { }; let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); - let (name, root) = match mode { + match mode { Mode::Libstd => { compile::std_cargo(build, &compiler, target, &mut cargo); - ("libstd", "std") } Mode::Libtest => { compile::test_cargo(build, &compiler, target, &mut cargo); - ("libtest", "test") } Mode::Librustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(build, &mut cargo); - ("librustc", "rustc-main") } _ => panic!("can only test libraries"), }; - let root = INTERNER.intern_string(String::from(root)); let _folder = build.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name) + format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) }); - println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage, + println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, &compiler.host, target); // Build up the base `cargo test` command. @@ -1273,37 +1356,7 @@ impl Step for Crate { cargo.arg("--no-fail-fast"); } - match krate { - Some(krate) => { - cargo.arg("-p").arg(krate); - } - None => { - let mut visited = HashSet::new(); - let mut next = vec![root]; - while let Some(name) = next.pop() { - // Right now jemalloc and the sanitizer crates are - // target-specific crate in the sense that it's not present - // on all platforms. Custom skip it here for now, but if we - // add more this probably wants to get more generalized. - // - // Also skip `build_helper` as it's not compiled normally - // for target during the bootstrap and it's just meant to be - // a helper crate, not tested. If it leaks through then it - // ends up messing with various mtime calculations and such. - if !name.contains("jemalloc") && - *name != *"build_helper" && - !(name.starts_with("rustc_") && name.ends_with("san")) && - name != "dlmalloc" { - cargo.arg("-p").arg(&format!("{}:0.0.0", name)); - } - for dep in build.crates[&name].deps.iter() { - if visited.insert(dep) { - next.push(*dep); - } - } - } - } - } + cargo.arg("-p").arg(krate); // The tests are going to run with the *target* libraries, so we need to // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent. @@ -1355,18 +1408,18 @@ impl Step for Crate { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rustdoc { +pub struct CrateRustdoc { host: Interned, test_kind: TestKind, } -impl Step for Rustdoc { +impl Step for CrateRustdoc { type Output = (); const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustdoc").path("src/tools/rustdoc") + run.paths(&["src/librustdoc", "src/tools/rustdoc"]) } fn make_run(run: RunConfig) { @@ -1380,7 +1433,7 @@ impl Step for Rustdoc { panic!("unexpected builder.kind in crate: {:?}", builder.kind); }; - builder.ensure(Rustdoc { + builder.ensure(CrateRustdoc { host: run.host, test_kind, }); diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b26979c7f6d8..5c7f8ef73217 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -805,22 +805,7 @@ impl Vec { pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool { - let len = self.len(); - let mut del = 0; - { - let v = &mut **self; - - for i in 0..len { - if !f(&v[i]) { - del += 1; - } else if del > 0 { - v.swap(i - del, i); - } - } - } - if del > 0 { - self.truncate(len - del); - } + self.drain_filter(|x| !f(x)); } /// Removes all but the first of consecutive elements in the vector that resolve to the same diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 345447948f7a..266ea0740a5b 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 345447948f7a51eca970fa036cefd613d54a4f79 +Subproject commit 266ea0740a5bdd262a38bbd88fb55fc3d2a7a96e diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 29b62c901f31..1a2da83429af 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,6 +333,8 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; +#[unstable(feature = "iterator_repeat_with", issue = "48169")] +pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; #[stable(feature = "iter_once", since = "1.2.0")] @@ -593,15 +595,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned {} #[doc(hidden)] -default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned where I: TrustedRandomAccess, T: Clone { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { self.it.get_unchecked(i).clone() } #[inline] - fn may_have_side_effect() -> bool { true } + default fn may_have_side_effect() -> bool { true } } #[doc(hidden)] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b05a893e6610..3e9d799c0894 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -57,6 +57,12 @@ unsafe impl TrustedLen for Repeat {} /// /// [`take`]: trait.Iterator.html#method.take /// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with`] function. +/// +/// [`repeat_with`]: fn.repeat_with.html +/// /// # Examples /// /// Basic usage: @@ -99,6 +105,115 @@ pub fn repeat(elt: T) -> Repeat { Repeat{element: elt} } +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with`] function. +/// See its documentation for more. +/// +/// [`repeat_with`]: fn.repeat_with.html +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] +pub struct RepeatWith { + repeater: F +} + +#[unstable(feature = "iterator_repeat_with", issue = "48169")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { Some((self.repeater)()) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } +} + +#[unstable(feature = "iterator_repeat_with", issue = "48169")] +impl A> DoubleEndedIterator for RepeatWith { + #[inline] + fn next_back(&mut self) -> Option { self.next() } +} + +#[unstable(feature = "fused", issue = "35602")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} + +/// Creates a new iterator that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over and over and +/// over and over and 🔁. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`take`], in order to make them finite. +/// +/// [`take`]: trait.Iterator.html#method.take +/// +/// If the element type of the iterator you need implements `Clone`, and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat`] function. +/// +/// [`repeat`]: fn.repeat.html +/// +/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. +/// It is important to not that reversing `repeat_with(f)` will produce +/// the exact same sequence as the non-reversed iterator. In other words, +/// `repeat_with(f).rev().collect::>()` is equivalent to +/// `repeat_with(f).collect::>()`. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(iterator_repeat_with)] +/// +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// #![feature(iterator_repeat_with)] +/// +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + /// An iterator that yields nothing. /// /// This `struct` is created by the [`empty`] function. See its documentation for more. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index be4889f24877..860742d9eab6 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator { /// ``` /// #![feature(exact_size_is_empty)] /// - /// let mut one_element = 0..1; + /// let mut one_element = std::iter::once(0); /// assert!(!one_element.is_empty()); /// /// assert_eq!(one_element.next(), Some(0)); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 59a296c2a762..447e144bf0fd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(unwind_attributes)] #![feature(doc_spotlight)] #![feature(rustc_const_unstable)] +#![feature(iterator_repeat_with)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3032fb2de33a..98e0f71eb935 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -63,9 +63,13 @@ impl !Send for *mut T { } /// struct BarUse(Bar<[i32]>); // OK /// ``` /// -/// The one exception is the implicit `Self` type of a trait, which does not -/// get an implicit `Sized` bound. This is because a `Sized` bound prevents -/// the trait from being used to form a [trait object]: +/// The one exception is the implicit `Self` type of a trait. A trait does not +/// have an implicit `Sized` bound as this is incompatible with [trait object]s +/// where, by definition, the trait needs to work with all possible implementors, +/// and thus could be any size. +/// +/// Although Rust will let you bind `Sized` to a trait, you won't +/// be able to use it to form a trait object later: /// /// ``` /// # #![allow(unused_variables)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c777..21d4a486b983 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb6..1d9c0f873b34 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// let arr = ['a', 'b', 'c', 'd']; +/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); +/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); +/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); +/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -92,7 +92,6 @@ impl fmt::Debug for Range { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { /// Returns `true` if `item` is contained in the range. /// @@ -109,9 +108,37 @@ impl> Range { /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty)] + /// + /// assert!(!(3..5).is_empty()); + /// assert!( (3..3).is_empty()); + /// assert!( (3..2).is_empty()); + /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..5.0).is_empty()); + /// assert!( (3.0..NAN).is_empty()); + /// assert!( (NAN..5.0).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + pub fn is_empty(&self) -> bool { + !(self.start < self.end) + } } /// A range only bounded inclusively below (`start..`). @@ -244,7 +271,14 @@ impl> RangeTo { /// An range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. +/// and `x <= end`. It is empty unless `start <= end`. +/// +/// This iterator is [fused], but the specific values of `start` and `end` after +/// iteration has finished are **unspecified** other than that [`.is_empty()`] +/// will return `true` once no more values will be produced. +/// +/// [fused]: ../iter/trait.FusedIterator.html +/// [`.is_empty()`]: #method.is_empty /// /// # Examples /// @@ -280,7 +314,6 @@ impl fmt::Debug for RangeInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// @@ -298,9 +331,48 @@ impl> RangeInclusive { /// assert!( (3..=3).contains(3)); /// assert!(!(3..=2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// assert!(!(3..=5).is_empty()); + /// assert!(!(3..=3).is_empty()); + /// assert!( (3..=2).is_empty()); + /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..=5.0).is_empty()); + /// assert!( (3.0..=NAN).is_empty()); + /// assert!( (NAN..=5.0).is_empty()); + /// ``` + /// + /// This method returns `true` after iteration has finished: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// let mut r = 3..=5; + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(r.is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + pub fn is_empty(&self) -> bool { + !(self.start <= self.end) + } } /// A range only bounded inclusively above (`..=end`). diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe66..b266771b818e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index aacbbd5058e0..ac390313a679 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1246,15 +1246,18 @@ macro_rules! iterator { { // The addition might panic on overflow // Use the len of the slice to hint optimizer to remove result index bounds check. - let n = make_slice!(self.ptr, self.end).len(); + let _n = make_slice!(self.ptr, self.end).len(); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } #[inline] @@ -1271,10 +1274,13 @@ macro_rules! iterator { if predicate(x) { Err(i) } else { Ok(i) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67..f91c919d7447 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1322,42 +1322,84 @@ fn test_range() { (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))); } +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + #[test] fn test_range_inclusive_exhaustion() { let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); assert_eq!(r.next(), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.next_back(), Some(12)); assert_eq!(r.next_back(), Some(11)); assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 100..=10; assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); assert_eq!(r, 100..=10); let mut r = 100..=10; assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); assert_eq!(r, 100..=10); } @@ -1428,9 +1470,10 @@ fn test_range_inclusive_nth() { assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); assert_eq!(r.is_empty(), true); - assert_eq!(r, 1..=0); // We may not want to document/promise this detail + assert_eq!(ExactSizeIterator::is_empty(&r), true); } #[test] @@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() { let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); } #[test] @@ -1549,6 +1592,51 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +fn test_repeat_with() { + #[derive(PartialEq, Debug)] + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_rev() { + let mut curr = 1; + let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .rev().take(4); + assert_eq!(pow2.next(), Some(1)); + assert_eq!(pow2.next(), Some(2)); + assert_eq!(pow2.next(), Some(4)); + assert_eq!(pow2.next(), Some(8)); + assert_eq!(pow2.next(), None); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), + (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_with_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .take(5).collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + #[test] fn test_fuse() { let mut it = 0..3; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9e90313bc0e9..3e901a9d442c 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,8 +27,10 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] +#![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 9d2fa1abff65..bed08f86d72c 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -68,3 +68,27 @@ fn test_range_inclusive() { assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } + + +#[test] +fn test_range_is_empty() { + use core::f32::*; + + assert!(!(0.0 .. 10.0).is_empty()); + assert!( (-0.0 .. 0.0).is_empty()); + assert!( (10.0 .. 0.0).is_empty()); + + assert!(!(NEG_INFINITY .. INFINITY).is_empty()); + assert!( (EPSILON .. NAN).is_empty()); + assert!( (NAN .. EPSILON).is_empty()); + assert!( (NAN .. NAN).is_empty()); + + assert!(!(0.0 ..= 10.0).is_empty()); + assert!(!(-0.0 ..= 0.0).is_empty()); + assert!( (10.0 ..= 0.0).is_empty()); + + assert!(!(NEG_INFINITY ..= INFINITY).is_empty()); + assert!( (EPSILON ..= NAN).is_empty()); + assert!( (NAN ..= EPSILON).is_empty()); + assert!( (NAN ..= NAN).is_empty()); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25b..b8d0719b9b99 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 0e1c66277163..99b1e5783e01 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -9,14 +9,15 @@ // except according to those terms. use super::*; - use dep_graph::{DepGraph, DepKind, DepNodeIndex}; +use hir::def_id::{LOCAL_CRATE, CrateNum}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::svh::Svh; use middle::cstore::CrateStore; use session::CrateDisambiguator; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID}; +use syntax::codemap::CodeMap; use syntax_pos::Span; use ich::StableHashingContext; @@ -123,6 +124,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn finalize_and_compute_crate_hash(self, crate_disambiguator: CrateDisambiguator, cstore: &CrateStore, + codemap: &CodeMap, commandline_args_hash: u64) -> (Vec>, Svh) { let mut node_hashes: Vec<_> = self @@ -147,11 +149,25 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { (name1, dis1).cmp(&(name2, dis2)) }); + // We hash the final, remapped names of all local source files so we + // don't have to include the path prefix remapping commandline args. + // If we included the full mapping in the SVH, we could only have + // reproducible builds by compiling from the same directory. So we just + // hash the result of the mapping instead of the mapping itself. + let mut source_file_names: Vec<_> = codemap + .files() + .iter() + .filter(|filemap| CrateNum::from_u32(filemap.crate_of_origin) == LOCAL_CRATE) + .map(|filemap| filemap.name_hash) + .collect(); + + source_file_names.sort_unstable(); + let (_, crate_dep_node_index) = self .dep_graph .with_task(DepNode::new_no_params(DepKind::Krate), &self.hcx, - ((node_hashes, upstream_crates), + (((node_hashes, upstream_crates), source_file_names), (commandline_args_hash, crate_disambiguator.to_fingerprint())), identity_fn); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5feea602d281..b6b3e8955351 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1065,6 +1065,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, let cmdline_args = sess.opts.dep_tracking_hash(); collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, + sess.codemap(), cmdline_args) }; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da0..cfbf233297cf 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1269,9 +1269,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the optimization fuel quota for a crate"), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make Rustc print the total optimization fuel used by a crate"), - remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a source pattern to the file path remapping config"), - remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a mapping target to the file path remapping config"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable"), @@ -1320,6 +1320,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "The epoch to build Rust with. Newer epochs may include features that require breaking changes. The default epoch is 2015 (the first epoch). Crates compiled with different epochs can be linked together."), + run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], + "run `dsymutil` and delete intermediate object files"), } pub fn default_lib_output() -> CrateType { @@ -1717,7 +1719,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len(); - let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len(); + let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len(); if remap_path_prefix_targets < remap_path_prefix_sources { for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 85fca68187fe..21ffe6b895e7 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -78,6 +78,11 @@ pub use self::on_disk_cache::OnDiskCache; // a way that memoizes and does dep-graph tracking, // wrapping around the actual chain of providers that // the driver creates (using several `rustc_*` crates). +// +// The result of query must implement Clone. They must also implement ty::maps::values::Value +// which produces an appropiate error value if the query resulted in a query cycle. +// Queries marked with `fatal_cycle` do not need that implementation +// as they will raise an fatal error on query cycles instead. define_maps! { <'tcx> /// Records the type of every item. [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, @@ -267,13 +272,13 @@ define_maps! { <'tcx> [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) -> Rc>, - [] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, - [] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, - [] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, - [] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, - [] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, - [] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, - [] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, + [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, + [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, + [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, + [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, + [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, [] fn extern_crate: ExternCrate(DefId) -> Rc>, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9..f02c7cbd0ea3 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -183,6 +183,19 @@ macro_rules! profq_key { } } +macro_rules! handle_cycle_error { + ([][$this: expr]) => {{ + Value::from_cycle_error($this.global_tcx()) + }}; + ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ + $this.tcx.sess.abort_if_errors(); + unreachable!(); + }}; + ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { + handle_cycle_error!([$($modifiers),*][$($args)*]) + }; +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -564,7 +577,7 @@ macro_rules! define_maps { pub fn $name(self, key: $K) -> $V { queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|mut e| { e.emit(); - Value::from_cycle_error(self.global_tcx()) + handle_cycle_error!([$($modifiers)*][self]) }) })* } @@ -583,7 +596,7 @@ macro_rules! define_maps { macro_rules! define_map_struct { (tcx: $tcx:tt, - input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { + input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Maps<$tcx> { providers: IndexVec>, query_stack: RefCell)>>, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 1593b452cdff..961c2650afde 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1297,6 +1297,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_ty_infer(&self) -> bool { + match self.sty { + TyInfer(_) => true, + _ => false, + } + } + pub fn is_phantom_data(&self) -> bool { if let TyAdt(def, _) = self.sty { def.is_phantom_data() diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f344624666a6..b8a1fe991054 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -660,6 +660,15 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, disambiguator, ); + if sess.opts.incremental.is_some() { + time(time_passes, "garbage collect incremental cache directory", || { + if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { + warn!("Error while trying to garbage collect incremental \ + compilation cache directory: {}", e); + } + }); + } + // If necessary, compute the dependency graph (in the background). let future_dep_graph = if sess.opts.build_dep_graph() { Some(rustc_incremental::load_dep_graph(sess, time_passes)) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index b53ee1daada4..65fbd9d0bf8f 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -46,3 +46,4 @@ pub use persist::in_incr_comp_dir; pub use persist::prepare_session_directory; pub use persist::finalize_session_directory; pub use persist::delete_workproduct_files; +pub use persist::garbage_collect_session_directories; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index f4171f951f40..795825f180c9 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -603,7 +603,7 @@ fn timestamp_to_string(timestamp: SystemTime) -> String { } fn string_to_timestamp(s: &str) -> Result { - let micros_since_unix_epoch = u64::from_str_radix(s, 36); + let micros_since_unix_epoch = u64::from_str_radix(s, INT_ENCODE_BASE as u32); if micros_since_unix_epoch.is_err() { return Err(()) @@ -733,6 +733,20 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { }) .collect(); + // Delete all session directories that don't have a lock file. + for directory_name in session_directories { + if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) { + let path = crate_directory.join(directory_name); + if let Err(err) = safe_remove_dir_all(&path) { + sess.warn(&format!("Failed to garbage collect invalid incremental \ + compilation session directory `{}`: {}", + path.display(), + err)); + } + } + } + + // Now garbage collect the valid session directories. let mut deletion_candidates = vec![]; let mut definitely_delete = vec![]; diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 82a43d85bc60..2f864aaefba8 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -20,9 +20,10 @@ mod save; mod work_product; mod file_format; -pub use self::fs::prepare_session_directory; pub use self::fs::finalize_session_directory; +pub use self::fs::garbage_collect_session_directories; pub use self::fs::in_incr_comp_dir; +pub use self::fs::prepare_session_directory; pub use self::load::dep_graph_tcx_init; pub use self::load::load_dep_graph; pub use self::load::load_query_result_cache; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e7e4119b9999..f734f3182a93 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,6 +11,7 @@ #![allow(non_snake_case)] use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; @@ -176,6 +177,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => bug!(), }; if lit_val < min || lit_val > max { + let parent_id = cx.tcx.hir.get_parent_node(e.id); + if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) { + if let hir::ExprCast(..) = parent_expr.node { + if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + parent_expr.span, + "only u8 can be casted into char"); + err.span_suggestion(parent_expr.span, + &"use a char literal instead", + format!("'\\u{{{:X}}}'", lit_val)); + err.emit(); + return + } + } + } cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 49b93f3c7d6a..54e3f544acb6 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -155,6 +155,7 @@ fn main() { cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") + .file("../rustllvm/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("rustllvm"); diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 99e43a2ddf98..e71bef512cf0 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Linker_opaque {} +pub type LinkerRef = *mut Linker_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); @@ -1608,7 +1611,6 @@ extern "C" { pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool; pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t); pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); @@ -1724,4 +1726,10 @@ extern "C" { CU2: *mut *mut c_void); pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void); pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef); + + pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef; + pub fn LLVMRustLinkerAdd(linker: LinkerRef, + bytecode: *const c_char, + bytecode_len: usize) -> bool; + pub fn LLVMRustLinkerFree(linker: LinkerRef); } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c4df7349391e..650f99828ae4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -463,13 +463,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx target: _, unwind: _, } => { - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); + let gcx = self.tcx.global_tcx(); + + // Compute the type with accurate region information. + let drop_place_ty = drop_place.ty(self.mir, self.tcx); + + // Erase the regions. + let drop_place_ty = self.tcx.erase_regions(&drop_place_ty).to_ty(self.tcx); + + // "Lift" into the gcx -- once regions are erased, this type should be in the + // global arenas; this "lift" operation basically just asserts that is true, but + // that is useful later. + let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); + + self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -717,6 +724,65 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } + /// Invokes `access_place` as appropriate for dropping the value + /// at `drop_place`. Note that the *actual* `Drop` in the MIR is + /// always for a variable (e.g., `Drop(x)`) -- but we recursively + /// break this variable down into subpaths (e.g., `Drop(x.foo)`) + /// to indicate more precisely which fields might actually be + /// accessed by a destructor. + fn visit_terminator_drop( + &mut self, + loc: Location, + term: &Terminator<'tcx>, + flow_state: &Flows<'cx, 'gcx, 'tcx>, + drop_place: &Place<'tcx>, + erased_drop_place_ty: ty::Ty<'gcx>, + span: Span, + ) { + match erased_drop_place_ty.sty { + // When a struct is being dropped, we need to check + // whether it has a destructor, if it does, then we can + // call it, if it does not then we need to check the + // individual fields instead. This way if `foo` has a + // destructor but `bar` does not, we will only check for + // borrows of `x.foo` and not `x.bar`. See #47703. + ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { + for (index, field) in def.all_fields().enumerate() { + let gcx = self.tcx.global_tcx(); + let field_ty = field.ty(gcx, substs); + let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env); + let place = drop_place.clone().field(Field::new(index), field_ty); + + self.visit_terminator_drop( + loc, + term, + flow_state, + &place, + field_ty, + span, + ); + } + }, + _ => { + // We have now refined the type of the value being + // dropped (potentially) to just the type of a + // subfield; so check whether that field's type still + // "needs drop". If so, we assume that the destructor + // may access any data it likes (i.e., a Deep Write). + let gcx = self.tcx.global_tcx(); + if erased_drop_place_ty.needs_drop(gcx, self.param_env) { + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + } + }, + } + } + /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c4..7cc4ba848952 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { self.tcx.data_layout.pointer_size.bytes() } - pub fn endianess(&self) -> layout::Endian { + pub fn endianness(&self) -> layout::Endian { self.tcx.data_layout.endian } @@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! @@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } // Now we do the actual reading let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 + read_target_int(endianness, bytes).unwrap() as u128 } else { - read_target_uint(endianess, bytes).unwrap() + read_target_uint(endianness, bytes).unwrap() }; // See if we got a pointer if size != self.pointer_size() { @@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { @@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); + write_target_int(endianness, dst, bytes as i128).unwrap(); } else { - write_target_uint(endianess, dst, bytes).unwrap(); + write_target_uint(endianness, dst, bytes).unwrap(); } } @@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } //////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess +// Methods to access integers in the target endianness //////////////////////////////////////////////////////////////////////////////// fn write_target_uint( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_uint128::(data, len), layout::Endian::Big => target.write_uint128::(data, len), } } fn write_target_int( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: i128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_int128::(data, len), layout::Endian::Big => target.write_int128::(data, len), } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 563405fccc97..7ed250e94c52 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -44,6 +44,7 @@ pub mod copy_prop; pub mod generator; pub mod inline; pub mod lower_128bit; +pub mod uniform_array_move_out; pub(crate) fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); @@ -197,6 +198,7 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea simplify::SimplifyCfg::new("initial"), type_check::TypeckMir, rustc_peek::SanityCheck, + uniform_array_move_out::UniformArrayMoveOut, ]; tcx.alloc_steal_mir(mir) } @@ -253,6 +255,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx lower_128bit::Lower128Bit, + // Optimizations begin. inline::Inline, instcombine::InstCombine, diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs new file mode 100644 index 000000000000..0db5ecf0eb27 --- /dev/null +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -0,0 +1,153 @@ +// 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. + +// This pass converts move out from array by Subslice and +// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin +// of array. It allows detect error by mir borrowck and elaborate +// drops for array without additional work. +// +// Example: +// +// let a = [ box 1,box 2, box 3]; +// if b { +// let [_a.., _] = a; +// } else { +// let [.., _b] = a; +// } +// +// mir statement _10 = move _2[:-1]; replaced by: +// StorageLive(_12); +// _12 = move _2[0 of 3]; +// StorageLive(_13); +// _13 = move _2[1 of 3]; +// _10 = [move _12, move _13] +// StorageDead(_12); +// StorageDead(_13); +// +// and mir statement _11 = move _2[-1 of 1]; replaced by: +// _11 = move _2[2 of 3]; +// +// FIXME: convert to Subslice back for performance reason +// FIXME: integrate this transformation to the mir build + +use rustc::ty; +use rustc::ty::TyCtxt; +use rustc::mir::*; +use rustc::mir::visit::Visitor; +use transform::{MirPass, MirSource}; +use util::patch::MirPatch; + +pub struct UniformArrayMoveOut; + +impl MirPass for UniformArrayMoveOut { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _src: MirSource, + mir: &mut Mir<'tcx>) { + let mut patch = MirPatch::new(mir); + { + let mut visitor = UniformArrayMoveOutVisitor{mir, patch: &mut patch, tcx}; + visitor.visit_mir(mir); + } + patch.apply(mir); + } +} + +struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + patch: &'a mut MirPatch<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location) { + if let StatementKind::Assign(ref dst_place, + Rvalue::Use(Operand::Move(ref src_place))) = statement.kind { + if let Place::Projection(ref proj) = *src_place { + if let ProjectionElem::ConstantIndex{offset: _, + min_length: _, + from_end: false} = proj.elem { + // no need to transformation + } else { + let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + if let ty::TyArray(item_ty, const_size) = place_ty.sty { + if let Some(size) = const_size.val.to_const_int().and_then(|v| v.to_u64()) { + assert!(size <= (u32::max_value() as u64), + "unform array move out doesn't supported + for array bigger then u32"); + self.uniform(location, dst_place, proj, item_ty, size as u32); + } + } + + } + } + } + return self.super_statement(block, statement, location); + } +} + +impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { + fn uniform(&mut self, + location: Location, + dst_place: &Place<'tcx>, + proj: &PlaceProjection<'tcx>, + item_ty: &'tcx ty::TyS<'tcx>, + size: u32) { + match proj.elem { + // uniform _10 = move _2[:-1]; + ProjectionElem::Subslice{from, to} => { + self.patch.make_nop(location); + let temps : Vec<_> = (from..(size-to)).map(|i| { + let temp = self.patch.new_temp(item_ty, self.mir.source_info(location).span); + self.patch.add_statement(location, StatementKind::StorageLive(temp)); + self.patch.add_assign(location, + Place::Local(temp), + Rvalue::Use( + Operand::Move( + Place::Projection(box PlaceProjection{ + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex{ + offset: i, + min_length: size, + from_end: false} + })))); + temp + }).collect(); + self.patch.add_assign(location, + dst_place.clone(), + Rvalue::Aggregate(box AggregateKind::Array(item_ty), + temps.iter().map( + |x| Operand::Move(Place::Local(*x))).collect() + )); + for temp in temps { + self.patch.add_statement(location, StatementKind::StorageDead(temp)); + } + } + // _11 = move _2[-1 of 1]; + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { + self.patch.make_nop(location); + self.patch.add_assign(location, + dst_place.clone(), + Rvalue::Use( + Operand::Move( + Place::Projection(box PlaceProjection{ + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex{ + offset: size - offset, + min_length: size, + from_end: false }})))); + } + _ => {} + } + } +} diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 9da593fb48e3..f1bdcfcd22f9 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -23,6 +23,7 @@ pub struct MirPatch<'tcx> { new_locals: Vec>, resume_block: BasicBlock, next_local: usize, + make_nop: Vec, } impl<'tcx> MirPatch<'tcx> { @@ -33,7 +34,8 @@ impl<'tcx> MirPatch<'tcx> { new_statements: vec![], new_locals: vec![], next_local: mir.local_decls.len(), - resume_block: START_BLOCK + resume_block: START_BLOCK, + make_nop: vec![] }; // make sure the MIR we create has a resume block. It is @@ -131,7 +133,15 @@ impl<'tcx> MirPatch<'tcx> { self.add_statement(loc, StatementKind::Assign(place, rv)); } + pub fn make_nop(&mut self, loc: Location) { + self.make_nop.push(loc); + } + pub fn apply(self, mir: &mut Mir<'tcx>) { + debug!("MirPatch: make nops at: {:?}", self.make_nop); + for loc in self.make_nop { + mir.make_statement_nop(loc); + } debug!("MirPatch: {:?} new temps, starting from index {}: {:?}", self.new_locals.len(), mir.local_decls.len(), self.new_locals); debug!("MirPatch: {} new blocks, starting from index {}", diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8cb25f449b66..a8070c553bdb 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -1026,6 +1026,8 @@ fn import_path_to_string(names: &[SpannedIdent], if names.is_empty() { import_directive_subclass_to_string(subclass) } else { + // FIXME: Remove this entire logic after #48116 is fixed. + // // Note that this code looks a little wonky, it's currently here to // hopefully help debug #48116, but otherwise isn't intended to // cause any problems. @@ -1034,8 +1036,17 @@ fn import_path_to_string(names: &[SpannedIdent], names_to_string(names), import_directive_subclass_to_string(subclass), ); - assert!(!names.is_empty()); - assert!(!x.starts_with("::")); + if names.is_empty() || x.starts_with("::") { + span_bug!( + span, + "invalid name `{}` at {:?}; global = {}, names = {:?}, subclass = {:?}", + x, + span, + global, + names, + subclass + ); + } return x } } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 6c8088375c4b..8309c91ab257 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -142,7 +142,7 @@ pub fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|c| c.to_str().unwrap().to_string()) + .map(|c| c.to_string()) .collect()) }; @@ -212,7 +212,8 @@ fn from_target_feature( let value = value.as_str(); for feature in value.split(',') { if whitelist.contains(feature) { - target_features.push(format!("+{}", feature)); + let llvm_feature = llvm_util::to_llvm_feature(feature); + target_features.push(format!("+{}", llvm_feature)); continue } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index f050edcd513b..4fe294a790fc 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -166,7 +166,9 @@ pub(crate) fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() { + if sess.opts.output_types.should_trans() && + !preserve_objects_for_their_debuginfo(sess) + { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { remove(sess, obj); } @@ -190,6 +192,52 @@ pub(crate) fn link_binary(sess: &Session, out_filenames } +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == NoDebugInfo { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { let out_filename = outputs.single_output_file.clone() .unwrap_or(outputs @@ -736,8 +784,12 @@ fn link_natively(sess: &Session, // On macOS, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != NoDebugInfo && + !preserve_objects_for_their_debuginfo(sess) + { match Command::new("dsymutil").arg(out_filename).output() { Ok(..) => {} Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 9ff5bcf7a33c..a33270380196 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext, // know much about the memory management here so we err on the side of being // save and persist everything with the original module. let mut serialized_bitcode = Vec::new(); + let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { info!("linking {:?}", name); - time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe { + time(cgcx.time_passes, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); - if llvm::LLVMRustLinkInExternalBitcode(llmod, - data.as_ptr() as *const libc::c_char, - data.len() as libc::size_t) { - Ok(()) - } else { + linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - Err(write::llvm_err(&diag_handler, msg)) - } + write::llvm_err(&diag_handler, msg) + }) })?; timeline.record(&format!("link {:?}", name)); serialized_bitcode.push(bc_decoded); } + drop(linker); cgcx.save_temp_bitcode(&module, "lto.input"); // Internalize everything that *isn't* in our whitelist to help strip out @@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext, }]) } +struct Linker(llvm::LinkerRef); + +impl Linker { + fn new(llmod: ModuleRef) -> Linker { + unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } + } + + fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + unsafe { + if llvm::LLVMRustLinkerAdd(self.0, + bytecode.as_ptr() as *const libc::c_char, + bytecode.len()) { + Ok(()) + } else { + Err(()) + } + } + } +} + +impl Drop for Linker { + fn drop(&mut self) { + unsafe { llvm::LLVMRustLinkerFree(self.0); } + } +} + /// Prepare "thin" LTO to get run on these modules. /// /// The general structure of ThinLTO is quite different from the structure of diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 843231d376f6..b25562252e72 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -14,7 +14,7 @@ use llvm; use rustc::session::Session; use rustc::session::config::PrintRequest; use libc::c_int; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; @@ -79,46 +79,53 @@ unsafe fn configure_llvm(sess: &Session) { // detection code will walk past the end of the feature array, // leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"]; +const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"]; -const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"]; +const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"]; -const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", - "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", - "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", - "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", - "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", - "avx512bw\0", "avx512cd\0", - "avx512dq\0", "avx512er\0", - "avx512f\0", "avx512ifma\0", - "avx512pf\0", "avx512vbmi\0", - "avx512vl\0", "avx512vpopcntdq\0", - "mmx\0", "fxsr\0"]; +const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse", + "sse2", "sse3", "sse4.1", "sse4.2", + "ssse3", "tbm", "lzcnt", "popcnt", + "sse4a", "rdrnd", "rdseed", "fma", + "xsave", "xsaveopt", "xsavec", + "xsaves", "aes", "pclmulqdq", + "avx512bw", "avx512cd", + "avx512dq", "avx512er", + "avx512f", "avx512ifma", + "avx512pf", "avx512vbmi", + "avx512vl", "avx512vpopcntdq", + "mmx", "fxsr"]; -const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"]; +const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"]; -const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0", - "power8-altivec\0", "power9-altivec\0", - "power8-vector\0", "power9-vector\0", - "vsx\0"]; +const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", + "power8-altivec", "power9-altivec", + "power8-vector", "power9-vector", + "vsx"]; -const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"]; +const MIPS_WHITELIST: &'static [&'static str] = &["msa"]; -pub fn target_features(sess: &Session) -> Vec { - let whitelist = target_feature_whitelist(sess); - let target_machine = create_target_machine(sess); - let mut features = Vec::new(); - for feat in whitelist { - if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } { - features.push(Symbol::intern(feat.to_str().unwrap())); - } +pub fn to_llvm_feature(s: &str) -> &str { + match s { + "pclmulqdq" => "pclmul", + s => s, } - features } -pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { - let whitelist = match &*sess.target.target.arch { +pub fn target_features(sess: &Session) -> Vec { + let target_machine = create_target_machine(sess); + target_feature_whitelist(sess) + .iter() + .filter(|feature| { + let llvm_feature = to_llvm_feature(feature); + let cstr = CString::new(llvm_feature).unwrap(); + unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } + }) + .map(|feature| Symbol::intern(feature)).collect() +} + +pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { + match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, "x86" | "x86_64" => X86_WHITELIST, @@ -126,10 +133,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { "mips" | "mips64" => MIPS_WHITELIST, "powerpc" | "powerpc64" => POWERPC_WHITELIST, _ => &[], - }; - whitelist.iter().map(|m| { - CStr::from_bytes_with_nul(m.as_bytes()).unwrap() - }).collect() + } } pub fn print_version() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e760636230d1..91fa3c5da699 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -871,10 +871,21 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze(body); + // All type checking constraints were added, try to fallback unsolved variables. fcx.select_obligations_where_possible(); + for ty in &fcx.unsolved_variables() { + fcx.fallback_if_possible(ty); + } + fcx.select_obligations_where_possible(); + + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. fcx.check_casts(); + + // Closure and generater analysis may run after fallback + // because they don't constrain other type variables. + fcx.closure_analyze(body); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -1395,7 +1406,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|node_item| !node_item.node.is_from_trait()) .unwrap_or(false); - if !is_implemented { + if !is_implemented && !tcx.impl_is_default(impl_id) { if !trait_item.defaultness.has_value() { missing_items.push(trait_item); } else if associated_type_overridden { @@ -2143,74 +2154,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether - /// feature(never_type) is enabled), unconstrained ints with i32, and - /// unconstrained floats with f64. - fn default_type_parameters(&self) { + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to TyError. + fn fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. Therefore, if we think we saw - // some errors in this function, just resolve all uninstanted type - // varibles to TyError. - if self.is_tainted_by_errors() { - for ty in &self.unsolved_variables() { - if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } - } - return; - } - - for ty in &self.unsolved_variables() { - let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - debug!("default_type_parameters: defaulting `{:?}` to `i32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - debug!("default_type_parameters: defaulting `{:?}` to `f32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64) - } - Neither => { } - } - } - } - } - - // Implements type inference fallback algorithm - fn select_all_obligations_and_apply_defaults(&self) { - self.select_obligations_where_possible(); - self.default_type_parameters(); - self.select_obligations_where_possible(); + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().types.err, + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => return + }; + debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); } fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - - self.select_all_obligations_and_apply_defaults(); - - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); - - match fulfillment_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id); } } @@ -5074,37 +5043,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) - -> Ty<'tcx> - where F: Fn() -> Ty<'tcx> - { - let mut ty = self.resolve_type_vars_with_obligations(ty); - - if ty.is_ty_var() { - let alternative = f(); - - // If not, error. - if alternative.is_ty_var() || alternative.references_error() { - if !self.is_tainted_by_errors() { - self.need_type_info((**self).body_id, sp, ty); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; - } else { - self.demand_suptype(sp, alternative, ty); - ty = alternative; - } - } - - ty - } - - // Resolves `typ` by a single level if `typ` is a type variable. If no - // resolution is possible, then an error is reported. + // Resolves `typ` by a single level if `typ` is a type variable. + // If no resolution is possible, then an error is reported. + // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - self.structurally_resolve_type_or_else(sp, ty, || { + let ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { + if !self.is_tainted_by_errors() { + self.need_type_info((**self).body_id, sp, ty); + } + self.demand_suptype(sp, self.tcx.types.err, ty); self.tcx.types.err - }) + } } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c224..1c8d22e4666a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; + let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); @@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { + ItemImpl(_, _, defaultness, ref generics, ..) => { + if defaultness.is_default() { + is_default_impl_trait = tcx.impl_trait_ref(def_id); + } + generics + } ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } + // In default impls, we can assume that the self type implements + // the trait. So in: + // + // default impl Foo for Bar { .. } + // + // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // (see below). Recall that a default impl is not itself an impl, but rather a + // set of defaults that can be incorporated into another impl. + if let Some(trait_ref) = is_default_impl_trait { + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index b45c3bf8e5f4..2d0fe55f70d2 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #00708a; } .content span.enum, .content a.enum, .block a.current.enum { color: #82b089; } -.content span.struct, .content a.struct, .block a.current.struct { color: #ff794d; } +.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ff7f00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; } .content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; } diff --git a/src/librustdoc/html/static/themes/main.css b/src/librustdoc/html/static/themes/main.css index e0764640e916..2334a2728554 100644 --- a/src/librustdoc/html/static/themes/main.css +++ b/src/librustdoc/html/static/themes/main.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #9aecff; } .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #df3600; } +.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 82a687ae5e49..a82ff915093c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -398,8 +398,9 @@ pub struct HashMap { } /// Search for a pre-hashed key. +/// If you don't already know the hash, use search or search_mut instead #[inline] -fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry +fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { @@ -410,6 +411,18 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } + search_hashed_nonempty(table, hash, is_match) +} + +/// Search for a pre-hashed key when the hash map is known to be non-empty. +#[inline] +fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ + // Do not check the capacity as an extra branch could slow the lookup. + let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; @@ -543,24 +556,36 @@ impl HashMap } /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. + /// If you already have the hash for the key lying around, or if you need an + /// InternalEntry, use search_hashed or search_hashed_nonempty. #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry> + fn search<'a, Q: ?Sized>(&'a self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { + if self.is_empty() { + return None; + } + let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry> + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { + if self.is_empty() { + return None; + } + let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } // The caller should ensure that invariants by Robin Hood Hashing hold @@ -1118,7 +1143,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1145,7 +1170,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().is_some() + self.search(k).is_some() } /// Returns a mutable reference to the value corresponding to the key. @@ -1174,7 +1199,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Inserts a key-value pair into the map. @@ -1234,11 +1259,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - - self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } /// Removes a key from the map, returning the stored key and value if the @@ -1269,12 +1290,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - self.search_mut(k) - .into_occupied_bucket() .map(|bucket| { let (k, v, _) = pop_internal(bucket); (k, v) @@ -2632,15 +2648,11 @@ impl super::Recover for HashMap #[inline] fn get(&self, key: &Q) -> Option<&K> { - self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) + self.search(key).map(|bucket| bucket.into_refs().0) } fn take(&mut self, key: &Q) -> Option { - if self.table.size() == 0 { - return None; - } - - self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) + self.search_mut(key).map(|bucket| pop_internal(bucket).0) } #[inline] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27bf326631fb..c4946b6b2824 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,6 +723,12 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for Args {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for Args {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; @@ -754,6 +760,12 @@ impl fmt::Debug for Args { } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for ArgsOs {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for ArgsOs {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ecf68f29d6f1..a760922115ae 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1023,7 +1023,7 @@ impl f32 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 29ba7d0dac63..6f34f176a971 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -978,7 +978,7 @@ impl f64 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5ba..76bcb5fedc94 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949ed..e03a182653e5 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3601b9ba8a8c..ff6f32fc3be0 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -690,14 +690,16 @@ impl CodeMap { return 1; } + let src = local_begin.fm.external_src.borrow(); + // We need to extend the snippet to the end of the src rather than to end_index so when // searching forwards for boundaries we've got somewhere to search. let snippet = if let Some(ref src) = local_begin.fm.src { let len = src.len(); - (&src[start_index..len]).to_string() - } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() { + (&src[start_index..len]) + } else if let Some(src) = src.get_source() { let len = src.len(); - (&src[start_index..len]).to_string() + (&src[start_index..len]) } else { return 1; }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c3..3b137f9570a3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -541,7 +541,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc3745fc4a3e..ac582627f88f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4859,19 +4859,30 @@ impl<'a> Parser<'a> { |p| { if p.token == token::DotDotDot { p.bump(); + variadic = true; if allow_variadic { if p.token != token::CloseDelim(token::Paren) { let span = p.span; p.span_err(span, "`...` must be last in argument list for variadic function"); } + Ok(None) } else { - let span = p.span; - p.span_err(span, - "only foreign functions are allowed to be variadic"); + let span = p.prev_span; + if p.token == token::CloseDelim(token::Paren) { + // continue parsing to present any further errors + p.struct_span_err( + span, + "only foreign functions are allowed to be variadic" + ).emit(); + Ok(Some(dummy_arg(span))) + } else { + // this function definition looks beyond recovery, stop parsing + p.span_err(span, + "only foreign functions are allowed to be variadic"); + Ok(None) + } } - variadic = true; - Ok(None) } else { match p.parse_arg_general(named_args) { Ok(arg) => Ok(Some(arg)), diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp new file mode 100644 index 000000000000..534e4b910902 --- /dev/null +++ b/src/rustllvm/Linker.cpp @@ -0,0 +1,72 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#include "llvm/Linker/Linker.h" + +#include "rustllvm.h" + +using namespace llvm; + +struct RustLinker { + Linker L; + LLVMContext &Ctx; + + RustLinker(Module &M) : + L(M), + Ctx(M.getContext()) + {} +}; + +extern "C" RustLinker* +LLVMRustLinkerNew(LLVMModuleRef DstRef) { + Module *Dst = unwrap(DstRef); + + auto Ret = llvm::make_unique(*Dst); + return Ret.release(); +} + +extern "C" void +LLVMRustLinkerFree(RustLinker *L) { + delete L; +} + +extern "C" bool +LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { + std::unique_ptr Buf = + MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); + +#if LLVM_VERSION_GE(4, 0) + Expected> SrcOrError = + llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx); + if (!SrcOrError) { + LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); + return false; + } + + auto Src = std::move(*SrcOrError); +#else + ErrorOr> Src = + llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx); + if (!Src) { + LLVMRustSetLastError(Src.getError().message().c_str()); + return false; + } +#endif + +#if LLVM_VERSION_GE(4, 0) + if (L->L.linkInModule(std::move(Src))) { +#else + if (L->L.linkInModule(std::move(Src.get()))) { +#endif + LLVMRustSetLastError(""); + return false; + } + return true; +} diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4dfc4029d75d..27d5496f5762 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC, - size_t Len) { - Module *Dst = unwrap(DstRef); - - std::unique_ptr Buf = - MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); - -#if LLVM_VERSION_GE(4, 0) - Expected> SrcOrError = - llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext()); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return false; - } - - auto Src = std::move(*SrcOrError); -#else - ErrorOr> Src = - llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext()); - if (!Src) { - LLVMRustSetLastError(Src.getError().message().c_str()); - return false; - } -#endif - - std::string Err; - - raw_string_ostream Stream(Err); - DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_GE(4, 0) - if (Linker::linkModules(*Dst, std::move(Src))) { -#else - if (Linker::linkModules(*Dst, std::move(Src.get()))) { -#endif - LLVMRustSetLastError(Err.c_str()); - return false; - } - return true; -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs new file mode 100644 index 000000000000..e01161734623 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs @@ -0,0 +1,30 @@ +// Copyright 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. + +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(box_syntax, slice_patterns, advanced_slice_patterns)] + +fn move_out_from_begin_and_end() { + let a = [box 1, box 2]; + let [_, _x] = a; + let [.., _y] = a; //[ast]~ ERROR [E0382] + //[mir]~^ ERROR [E0382] +} + +fn move_out_by_const_index_and_subslice() { + let a = [box 1, box 2]; + let [_x, _] = a; + let [_y..] = a; //[ast]~ ERROR [E0382] + //[mir]~^ ERROR [E0382] +} + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs deleted file mode 100644 index ad55f44255b4..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -#![feature(specialization)] - -// Make sure we can't project defaulted associated types - -trait Foo { - type Assoc; -} - -default impl Foo for T { - type Assoc = (); -} - -impl Foo for u8 { - type Assoc = String; -} - -fn generic() -> ::Assoc { - // `T` could be some downstream crate type that specializes (or, - // for that matter, `u8`). - - () //~ ERROR mismatched types -} - -fn monomorphic() -> () { - // Even though we know that `()` is not specialized in a - // downstream crate, typeck refuses to project here. - - generic::<()>() //~ ERROR mismatched types -} - -fn main() { - // No error here, we CAN project from `u8`, as there is no `default` - // in that impl. - let s: String = generic::(); - println!("{}", s); // bad news if this all compiles -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs deleted file mode 100644 index 7353f7ac8c5c..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -// It should not be possible to use the concrete value of a defaulted -// associated type in the impl defining it -- otherwise, what happens -// if it's overridden? - -#![feature(specialization)] - -trait Example { - type Output; - fn generate(self) -> Self::Output; -} - -default impl Example for T { - type Output = Box; - fn generate(self) -> Self::Output { - Box::new(self) //~ ERROR mismatched types - } -} - -impl Example for bool { - type Output = bool; - fn generate(self) -> bool { self } -} - -fn trouble(t: T) -> Box { - Example::generate(t) //~ ERROR mismatched types -} - -fn weaponize() -> bool { - let b: Box = trouble(true); - *b -} - -fn main() { - weaponize(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs similarity index 57% rename from src/test/run-pass/specialization/defaultimpl/assoc-fns.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index b99ba3d0f1c9..eacec2e40f07 100644 --- a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,30 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that non-method associated functions can be specialized +// Tests that default impls do not have to supply all items but regular impls do. #![feature(specialization)] trait Foo { - fn mk() -> Self; + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; } -default impl Foo for T { - fn mk() -> T { - T::default() +struct MyStruct; + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" } } -impl Foo for Vec { - fn mk() -> Vec { - vec![0] - } -} +impl Foo for MyStruct {} +//~^ ERROR not all trait items implemented, missing: `foo_two` [E0046] fn main() { - let v1: Vec = Foo::mk(); - let v2: Vec = Foo::mk(); - - assert!(v1.len() == 0); - assert!(v2.len() == 1); + println!("{}", MyStruct.foo_one()); } diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs new file mode 100644 index 000000000000..04ddf9ebb177 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -0,0 +1,34 @@ +// 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. + +// Tests that: +// - default impls do not have to supply all items and +// - a default impl does not count as an impl (in this case, an incomplete default impl). + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +struct MyStruct; + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + + +fn main() { + println!("{}", MyStruct.foo_one()); + //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope +} diff --git a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs similarity index 56% rename from src/test/run-pass/specialization/defaultimpl/projection-alias.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 2397c3e2bff5..445a59a373e5 100644 --- a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,25 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that a default impl still has to have a WF trait ref. + #![feature(specialization)] -// Regression test for ICE when combining specialized associated types and type -// aliases +trait Foo<'a, T: Eq + 'a> { } -trait Id_ { - type Out; -} +default impl Foo<'static, U> for () {} +//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied -type Id = ::Out; - -default impl Id_ for T { - type Out = T; -} - -fn test_proection() { - let x: Id = panic!(); -} - -fn main() { - -} +fn main(){} diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs new file mode 100644 index 000000000000..4a310255aac5 --- /dev/null +++ b/src/test/mir-opt/uniform_array_move_out.rs @@ -0,0 +1,59 @@ +// 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(box_syntax, slice_patterns, advanced_slice_patterns)] + +fn move_out_from_end() { + let a = [box 1, box 2]; + let [.., _y] = a; +} + +fn move_out_by_subslice() { + let a = [box 1, box 2]; + let [_y..] = a; +} + +fn main() { + move_out_by_subslice(); + move_out_from_end(); +} + +// END RUST SOURCE + +// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir +// StorageLive(_6); +// _6 = move _1[-1 of 1]; +// _0 = (); +// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir + +// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir +// StorageLive(_6); +// _6 = move _1[1 of 2]; +// nop; +// _0 = (); +// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir + +// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir +// StorageLive(_6); +// _6 = move _1[0:]; +// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir + +// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir +// StorageLive(_6); +// StorageLive(_7); +// _7 = move _1[0 of 2]; +// StorageLive(_8); +// _8 = move _1[1 of 2]; +// _6 = [move _7, move _8]; +// StorageDead(_7); +// StorageDead(_8); +// nop; +// _0 = (); +// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs new file mode 100644 index 000000000000..aa6752ffc35b --- /dev/null +++ b/src/test/run-pass/cast-does-fallback.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. + +pub fn main() { + // Test that these type check correctly. + (&42u8 >> 4) as usize; + (&42u8 << 4) as usize; + + let cap = 512 * 512; + cap as u8; + // Assert `cap` did not get inferred to `u8` and overflowed. + assert_ne!(cap, 0); +} diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index e2a51bbf14b8..4d0bd3f3412f 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -225,6 +225,43 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { }; } +fn subslice_pattern_from_end(a: &Allocator, arg: bool) { + let a = [a.alloc(), a.alloc(), a.alloc()]; + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + +fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { + let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + if arg2 { + drop(a); + return; + } + + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + +fn slice_pattern_reassign(a: &Allocator) { + let mut ar = [a.alloc(), a.alloc()]; + let[_, _x] = ar; + ar = [a.alloc(), a.alloc()]; + let[.., _y] = ar; +} + +fn subslice_pattern_reassign(a: &Allocator) { + let mut ar = [a.alloc(), a.alloc(), a.alloc()]; + let[_, _, _x] = ar; + ar = [a.alloc(), a.alloc(), a.alloc()]; + let[_, _y..] = ar; +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -303,5 +340,14 @@ fn main() { run_test(|a| slice_pattern_one_of(a, 2)); run_test(|a| slice_pattern_one_of(a, 3)); + run_test(|a| subslice_pattern_from_end(a, true)); + run_test(|a| subslice_pattern_from_end(a, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test(|a| slice_pattern_reassign(a)); + run_test(|a| subslice_pattern_reassign(a)); + run_test_nopanic(|a| union1(a)); } diff --git a/src/test/run-pass/issue-47703-1.rs b/src/test/run-pass/issue-47703-1.rs new file mode 100644 index 000000000000..facdee5cc176 --- /dev/null +++ b/src/test/run-pass/issue-47703-1.rs @@ -0,0 +1,33 @@ +// Copyright 2012 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(nll)] + +struct AtomicRefMut<'a> { + value: &'a mut i32, + borrow: AtomicBorrowRefMut, +} + +struct AtomicBorrowRefMut { +} + +impl Drop for AtomicBorrowRefMut { + fn drop(&mut self) { + } +} + +fn map(orig: AtomicRefMut) -> AtomicRefMut { + AtomicRefMut { + value: orig.value, + borrow: orig.borrow, + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-47703.rs b/src/test/run-pass/issue-47703.rs new file mode 100644 index 000000000000..2146986377a0 --- /dev/null +++ b/src/test/run-pass/issue-47703.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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(nll)] + +struct MyStruct<'a> { + field: &'a mut (), + field2: WithDrop +} + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +impl<'a> MyStruct<'a> { + fn consume(self) -> &'a mut () { self.field } +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs deleted file mode 100644 index 71dd7c99009e..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs +++ /dev/null @@ -1,82 +0,0 @@ -// 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. - -#![feature(specialization)] - -pub trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -pub trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs deleted file mode 100644 index 9d0ea64fed42..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - - -#![feature(specialization)] - -// First, test only use of explicit `default` items: - -pub trait Foo { - fn foo(&self) -> bool; -} - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -// Next, test mixture of explicit `default` and provided methods: - -pub trait Bar { - fn bar(&self) -> i32 { 0 } -} - -impl Bar for T {} // use the provided method - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} diff --git a/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs deleted file mode 100644 index 7daecc842f3f..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 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. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -unsafe trait Foo { - fn foo(&self) -> &'static str; -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default unsafe impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default unsafe impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default unsafe impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default unsafe impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -default unsafe impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -default unsafe impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -unsafe trait MyMarker {} -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -unsafe impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/basics.rs b/src/test/run-pass/specialization/defaultimpl/basics.rs deleted file mode 100644 index 594f1e4fcdfc..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 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. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs deleted file mode 100644 index 19e1af15bdd5..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - -// aux-build:cross_crate_defaults.rs - -#![feature(specialization)] - -extern crate cross_crate_defaults; - -use cross_crate_defaults::*; - -struct LocalDefault; -struct LocalOverride; - -impl Foo for LocalDefault {} - -impl Foo for LocalOverride { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); - - assert!(!LocalDefault.foo()); - assert!(LocalOverride.foo()); -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs deleted file mode 100644 index 67cc694ae12c..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -// Test that specialization works even if only the upstream crate enables it - -// aux-build:cross_crate.rs - -extern crate cross_crate; - -use cross_crate::*; - -fn main() { - assert!(0u8.foo() == "generic Clone"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs deleted file mode 100644 index f1ad105db8f7..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -// aux-build:cross_crate.rs - -#![feature(specialization)] - -extern crate cross_crate; - -use cross_crate::*; - -struct NotClone; - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -struct MyType(T); -default impl Foo for MyType { - fn foo(&self) -> &'static str { - "generic MyType" - } -} - -impl Foo for MyType { - fn foo(&self) -> &'static str { - "MyType" - } -} - -struct MyOtherType; -impl Foo for MyOtherType {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); - - assert!(MyType(()).foo() == "generic MyType"); - assert!(MyType(0u8).foo() == "MyType"); - assert!(MyOtherType.foo() == "generic"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/default-methods.rs b/src/test/run-pass/specialization/defaultimpl/default-methods.rs deleted file mode 100644 index 4ac9afc1c897..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/default-methods.rs +++ /dev/null @@ -1,94 +0,0 @@ -// 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. - -#![feature(specialization)] - -// Test that default methods are cascaded correctly - -// First, test only use of explicit `default` items: - -trait Foo { - fn foo(&self) -> bool; -} - -// Specialization tree for Foo: -// -// T -// / \ -// i32 i64 - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); -} - -// Next, test mixture of explicit `default` and provided methods: - -trait Bar { - fn bar(&self) -> i32 { 0 } -} - -// Specialization tree for Bar. -// Uses of $ designate that method is provided -// -// $Bar (the trait) -// | -// T -// /|\ -// / | \ -// / | \ -// / | \ -// / | \ -// / | \ -// $i32 &str $Vec -// /\ -// / \ -// Vec $Vec - -// use the provided method -impl Bar for T {} - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs new file mode 100644 index 000000000000..fc7312020053 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -0,0 +1,42 @@ +// 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. + +// Tests that we can combine a default impl that supplies one method with a +// full impl that supplies the other, and they can invoke one another. + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; + fn foo_three(&self) -> &'static str; +} + +struct MyStruct; + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + self.foo_three() + } +} + +impl Foo for MyStruct { + fn foo_two(&self) -> &'static str { + self.foo_one() + } + + fn foo_three(&self) -> &'static str { + "generic" + } +} + +fn main() { + assert!(MyStruct.foo_two() == "generic"); +} diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs new file mode 100644 index 000000000000..cd8ade5e51a1 --- /dev/null +++ b/src/test/ui/cast_char.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(overflowing_literals)] + +fn main() { + const XYZ: char = 0x1F888 as char; + //~^ ERROR only u8 can be casted into char + const XY: char = 129160 as char; + //~^ ERROR only u8 can be casted into char + const ZYX: char = '\u{01F888}'; + println!("{}", XYZ); +} diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr new file mode 100644 index 000000000000..e42a38dace9d --- /dev/null +++ b/src/test/ui/cast_char.stderr @@ -0,0 +1,20 @@ +error: only u8 can be casted into char + --> $DIR/cast_char.rs:14:23 + | +14 | const XYZ: char = 0x1F888 as char; + | ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + | +note: lint level defined here + --> $DIR/cast_char.rs:11:9 + | +11 | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: only u8 can be casted into char + --> $DIR/cast_char.rs:16:22 + | +16 | const XY: char = 129160 as char; + | ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/invalid-variadic-function.rs b/src/test/ui/invalid-variadic-function.rs new file mode 100644 index 000000000000..3d421e00b08e --- /dev/null +++ b/src/test/ui/invalid-variadic-function.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "C" fn foo(x: u8, ...); +//~^ ERROR only foreign functions are allowed to be variadic +//~| ERROR expected one of `->`, `where`, or `{`, found `;` diff --git a/src/test/ui/invalid-variadic-function.stderr b/src/test/ui/invalid-variadic-function.stderr new file mode 100644 index 000000000000..15a908b3f00f --- /dev/null +++ b/src/test/ui/invalid-variadic-function.stderr @@ -0,0 +1,14 @@ +error: only foreign functions are allowed to be variadic + --> $DIR/invalid-variadic-function.rs:11:26 + | +11 | extern "C" fn foo(x: u8, ...); + | ^^^ + +error: expected one of `->`, `where`, or `{`, found `;` + --> $DIR/invalid-variadic-function.rs:11:30 + | +11 | extern "C" fn foo(x: u8, ...); + | ^ expected one of `->`, `where`, or `{` here + +error: aborting due to 2 previous errors + diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 1d8816c7db13..486c0d81e3f4 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -58,9 +58,12 @@ mod imp { fds[0].events = libc::POLLIN; fds[1].fd = err_pipe.as_raw_fd(); fds[1].events = libc::POLLIN; - loop { + let mut nfds = 2; + let mut errfd = 1; + + while nfds > 0 { // wait for either pipe to become readable using `select` - let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) }; + let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; if r == -1 { let err = io::Error::last_os_error(); if err.kind() == io::ErrorKind::Interrupted { @@ -86,19 +89,20 @@ mod imp { } } }; - if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { - out_done = true; - } - data(true, &mut out, out_done); - if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { + if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { err_done = true; + nfds -= 1; } data(false, &mut err, err_done); - - if out_done && err_done { - return Ok(()) + if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { + out_done = true; + fds[0].fd = err_pipe.as_raw_fd(); + errfd = 0; + nfds -= 1; } + data(true, &mut out, out_done); } + Ok(()) } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a87809dd7bcf..bef085e17ea1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -250,6 +250,7 @@ impl<'test> TestCx<'test> { fn run_cfail_test(&self) { let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); + self.check_no_compiler_crash(&proc_res); let output_to_check = self.get_output(&proc_res); let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); @@ -262,7 +263,6 @@ impl<'test> TestCx<'test> { self.check_error_patterns(&output_to_check, &proc_res); } - self.check_no_compiler_crash(&proc_res); self.check_forbid_output(&output_to_check, &proc_res); } diff --git a/src/tools/rls b/src/tools/rls index dee42bda8156..f01491115e82 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e +Subproject commit f01491115e821e10217574ad4091b08015b7b1c8 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 159c9e035b7a..4dedf6bfe779 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -41,6 +41,7 @@ static EXCEPTIONS: &'static [&'static str] = &[ "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) "cssparser-macros", // MPL-2.0, rustdoc "selectors", // MPL-2.0, rustdoc + "clippy_lints", // MPL-2.0 rls ]; pub fn check(path: &Path, bad: &mut bool) {