Merge branch 'master' into inform_type_annotations

This commit is contained in:
moe 2018-02-17 22:22:26 +08:00 committed by GitHub
commit 2cf683edc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
94 changed files with 1985 additions and 1412 deletions

View file

@ -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

View file

@ -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

54
src/Cargo.lock generated
View file

@ -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"

View file

@ -95,7 +95,7 @@ pub struct RunConfig<'a> {
pub builder: &'a Builder<'a>,
pub host: Interned<String>,
pub target: Interned<String>,
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<PathBuf>,
}
impl PathSet {
fn empty() -> PathSet {
PathSet { set: BTreeSet::new() }
}
fn one<P: Into<PathBuf>>(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::<S>() },
}
}
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::<Vec<_>>();
// 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<PathBuf>,
paths: BTreeSet<PathSet>,
// 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);
}

View file

@ -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) {

View file

@ -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`

View file

@ -56,6 +56,7 @@ pub struct Config {
pub sanitizers: bool,
pub profiler: bool,
pub ignore_git: bool,
pub exclude: Vec<PathBuf>,
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;

View file

@ -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,

View file

@ -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) {

View file

@ -42,6 +42,7 @@ pub struct Flags {
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
pub exclude: Vec<PathBuf>,
}
pub enum Subcommand {
@ -109,6 +110,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -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::<Vec<_>>();
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::<Vec<PathBuf>>();
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::<Vec<_>>(),
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::<Vec<_>>(),
src,
}
}
}

View file

@ -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<String>, &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);
}
}
}
}

View file

@ -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

View file

@ -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<String>) -> 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<String>,
}
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<String>,
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<String>,
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<String>,
test_kind: TestKind,
krate: Option<Interned<String>>,
krate: Interned<String>,
}
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<Interned<String>>| {
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<String>,
mode: Mode,
test_kind: TestKind,
krate: Option<Interned<String>>,
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<Interned<String>>| {
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<String>,
mode: Mode,
test_kind: TestKind,
krate: Interned<String>,
}
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<String>,
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,
});

View file

@ -805,22 +805,7 @@ impl<T> Vec<T> {
pub fn retain<F>(&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

@ -1 +1 @@
Subproject commit 345447948f7a51eca970fa036cefd613d54a4f79
Subproject commit 266ea0740a5bdd262a38bbd88fb55fc3d2a7a96e

View file

@ -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<I>
{}
#[doc(hidden)]
default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
where I: TrustedRandomAccess<Item=&'a T>, 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)]

View file

@ -57,6 +57,12 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
///
/// [`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<T: Clone>(elt: T) -> Repeat<T> {
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<F> {
repeater: F
}
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> { Some((self.repeater)()) }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
}
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
impl<A, F: FnMut() -> A> DoubleEndedIterator for RepeatWith<F> {
#[inline]
fn next_back(&mut self) -> Option<A> { self.next() }
}
#[unstable(feature = "fused", issue = "35602")]
impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
/// 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::<Vec<_>>()` is equivalent to
/// `repeat_with(f).collect::<Vec<_>>()`.
///
/// # 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, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
RepeatWith { repeater }
}
/// An iterator that yields nothing.
///
/// This `struct` is created by the [`empty`] function. See its documentation for more.

View file

@ -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));

View file

@ -92,6 +92,7 @@
#![feature(unwind_attributes)]
#![feature(doc_spotlight)]
#![feature(rustc_const_unstable)]
#![feature(iterator_repeat_with)]
#[prelude_import]
#[allow(unused)]

View file

@ -63,9 +63,13 @@ impl<T: ?Sized> !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)]

View file

@ -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;
}

View file

@ -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<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
}
}
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
impl<Idx: PartialOrd<Idx>> Range<Idx> {
/// Returns `true` if `item` is contained in the range.
///
@ -109,9 +108,37 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
/// 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<Idx: PartialOrd<Idx>> RangeTo<Idx> {
/// 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<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
}
}
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
/// Returns `true` if `item` is contained in the range.
///
@ -298,9 +331,48 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
/// 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`).

View file

@ -2573,7 +2573,7 @@ impl<T: ?Sized> Clone for NonNull<T> {
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> Copy for NonNull<T> { }
#[stable(feature = "nonnull", since = "1.25.0")]
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
#[stable(feature = "nonnull", since = "1.25.0")]
@ -2621,7 +2621,7 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
}
}
#[stable(feature = "nonnull", since = "1.25.0")]
#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
fn from(unique: Unique<T>) -> Self {
NonNull { pointer: unique.pointer }

View file

@ -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
// })
}
}

View file

@ -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;

View file

@ -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)]

View file

@ -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());
}

View file

@ -7,7 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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,

View file

@ -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<MapEntry<'hir>>, 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);

View file

@ -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)
};

View file

@ -1269,9 +1269,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"set the optimization fuel quota for a crate"),
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
"make Rustc print the total optimization fuel used by a crate"),
remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [TRACKED],
remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
"add a source pattern to the file path remapping config"),
remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [TRACKED],
remap_path_prefix_to: Vec<PathBuf> = (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<bool> = (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..] {

View file

@ -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<Vec<(CrateNum, LinkagePreference)>>,
[] 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<Option<ExternCrate>>,

View file

@ -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<CrateNum, Providers<$tcx>>,
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,

View file

@ -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()

View file

@ -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))

View file

@ -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;

View file

@ -603,7 +603,7 @@ fn timestamp_to_string(timestamp: SystemTime) -> String {
}
fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
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![];

View file

@ -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;

View file

@ -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));

View file

@ -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");

View file

@ -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);
}

View file

@ -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

View file

@ -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::<LittleEndian>(data, len),
layout::Endian::Big => target.write_uint128::<BigEndian>(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::<LittleEndian>(data, len),
layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
}
}
fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
match endianess {
fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
match endianness {
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
}
}
fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
match endianess {
fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
match endianness {
layout::Endian::Little => source.read_int128::<LittleEndian>(source.len()),
layout::Endian::Big => source.read_int128::<BigEndian>(source.len()),
}

View file

@ -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,

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This 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 }}))));
}
_ => {}
}
}
}

View file

@ -23,6 +23,7 @@ pub struct MirPatch<'tcx> {
new_locals: Vec<LocalDecl<'tcx>>,
resume_block: BasicBlock,
next_local: usize,
make_nop: Vec<Location>,
}
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 {}",

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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)),

View file

@ -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

View file

@ -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<Symbol> {
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<Symbol> {
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() {

View file

@ -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<F>(&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<F: FnOnce() -> R, R>(&self, id: ast::NodeId,

View file

@ -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.

View file

@ -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; }

View file

@ -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; }

View file

@ -398,8 +398,9 @@ pub struct HashMap<K, V, S = RandomState> {
}
/// Search for a pre-hashed key.
/// If you don't already know the hash, use search or search_mut instead
#[inline]
fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry<K, V, M>
fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalEntry<K, V, M>
where M: Deref<Target = RawTable<K, V>>,
F: FnMut(&K) -> bool
{
@ -410,6 +411,18 @@ fn search_hashed<K, V, M, F>(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<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F)
-> InternalEntry<K, V, M>
where M: Deref<Target = RawTable<K, V>>,
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<K, V, S> HashMap<K, V, S>
}
/// 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<K, V, &'a RawTable<K, V>>
fn search<'a, Q: ?Sized>(&'a self, q: &Q)
-> Option<FullBucket<K, V, &'a RawTable<K, V>>>
where K: Borrow<Q>,
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<K, V, &'a mut RawTable<K, V>>
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q)
-> Option<FullBucket<K, V, &'a mut RawTable<K, V>>>
where K: Borrow<Q>,
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<K, V, S> HashMap<K, V, S>
where K: Borrow<Q>,
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<K, V, S> HashMap<K, V, S>
where K: Borrow<Q>,
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<K, V, S> HashMap<K, V, S>
where K: Borrow<Q>,
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<K, V, S> HashMap<K, V, S>
where K: Borrow<Q>,
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<K, V, S> HashMap<K, V, S>
where K: Borrow<Q>,
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<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
#[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<K> {
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]

View file

@ -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;

View file

@ -1023,7 +1023,7 @@ impl f32 {
/// This is currently identical to `transmute::<u32, f32>(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

View file

@ -978,7 +978,7 @@ impl f64 {
/// This is currently identical to `transmute::<u64, f64>(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

View file

@ -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<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)

View file

@ -576,7 +576,7 @@ impl<'a> AsRef<OsStr> for Component<'a> {
}
}
#[stable(feature = "path_component_asref", since = "1.24.0")]
#[stable(feature = "path_component_asref", since = "1.25.0")]
impl<'a> AsRef<Path> for Component<'a> {
fn as_ref(&self) -> &Path {
self.as_os_str().as_ref()

View file

@ -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;
};

View file

@ -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)

View file

@ -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)),

72
src/rustllvm/Linker.cpp Normal file
View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#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<RustLinker>(*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<MemoryBuffer> Buf =
MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
#if LLVM_VERSION_GE(4, 0)
Expected<std::unique_ptr<Module>> SrcOrError =
llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx);
if (!SrcOrError) {
LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
return false;
}
auto Src = std::move(*SrcOrError);
#else
ErrorOr<std::unique_ptr<Module>> 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;
}

View file

@ -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<MemoryBuffer> Buf =
MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
#if LLVM_VERSION_GE(4, 0)
Expected<std::unique_ptr<Module>> SrcOrError =
llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext());
if (!SrcOrError) {
LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
return false;
}
auto Src = std::move(*SrcOrError);
#else
ErrorOr<std::unique_ptr<Module>> 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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Make sure we can't project defaulted associated types
trait Foo {
type Assoc;
}
default impl<T> Foo for T {
type Assoc = ();
}
impl Foo for u8 {
type Assoc = String;
}
fn generic<T>() -> <T as Foo>::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::<u8>();
println!("{}", s); // bad news if this all compiles
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T> Example for T {
type Output = Box<T>;
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: T) -> Box<T> {
Example::generate(t) //~ ERROR mismatched types
}
fn weaponize() -> bool {
let b: Box<bool> = trouble(true);
*b
}
fn main() {
weaponize();
}

View file

@ -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<T: Default> Foo for T {
fn mk() -> T {
T::default()
struct MyStruct;
default impl<T> Foo for T {
fn foo_one(&self) -> &'static str {
"generic"
}
}
impl Foo for Vec<u8> {
fn mk() -> Vec<u8> {
vec![0]
}
}
impl Foo for MyStruct {}
//~^ ERROR not all trait items implemented, missing: `foo_two` [E0046]
fn main() {
let v1: Vec<i32> = Foo::mk();
let v2: Vec<u8> = Foo::mk();
assert!(v1.len() == 0);
assert!(v2.len() == 1);
println!("{}", MyStruct.foo_one());
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T> 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
}

View file

@ -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<U> Foo<'static, U> for () {}
//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied
type Id<T> = <T as Id_>::Out;
default impl<T> Id_ for T {
type Out = T;
}
fn test_proection() {
let x: Id<bool> = panic!();
}
fn main() {
}
fn main(){}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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);
}

View file

@ -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<F>(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));
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
pub trait Foo {
fn foo(&self) -> &'static str;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> 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<T: Clone> Foo for Vec<T> {
fn foo(&self) -> &'static str {
"generic Vec"
}
}
impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
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<T: Clone + MyMarker> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone + MyMarker"
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// First, test only use of explicit `default` items:
pub trait Foo {
fn foo(&self) -> bool;
}
default impl<T> 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<T> Bar for T {} // use the provided method
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default unsafe impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default unsafe impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default unsafe impl<T: Clone> 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<T: Clone> Foo for Vec<T> {
fn foo(&self) -> &'static str {
"generic Vec"
}
}
default unsafe impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
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<T: Clone + MyMarker> 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<i32>");
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");
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Tests a variety of basic specialization scenarios and method
// dispatch for them.
trait Foo {
fn foo(&self) -> &'static str;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> 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<T: Clone> Foo for Vec<T> {
fn foo(&self) -> &'static str {
"generic Vec"
}
}
impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
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<T: Clone + MyMarker> 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<i32>");
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");
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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();
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<i32>");
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)");
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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>(T);
default impl<T> Foo for MyType<T> {
fn foo(&self) -> &'static str {
"generic MyType"
}
}
impl Foo for MyType<u8> {
fn foo(&self) -> &'static str {
"MyType<u8>"
}
}
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<i32>");
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<u8>");
assert!(MyOtherType.foo() == "generic");
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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<T> 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<T>
// /\
// / \
// Vec<i32> $Vec<i64>
// use the provided method
impl<T> Bar for T {}
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
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();
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T> 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");
}

20
src/test/ui/cast_char.rs Normal file
View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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);
}

View file

@ -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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern "C" fn foo(x: u8, ...);
//~^ ERROR only foreign functions are allowed to be variadic
//~| ERROR expected one of `->`, `where`, or `{`, found `;`

View file

@ -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

View file

@ -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(())
}
}

View file

@ -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);
}

@ -1 +1 @@
Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e
Subproject commit f01491115e821e10217574ad4091b08015b7b1c8

View file

@ -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) {