Merge branch 'master' into inform_type_annotations
This commit is contained in:
commit
2cf683edc0
94 changed files with 1985 additions and 1412 deletions
|
@ -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
|
||||
|
|
|
@ -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
54
src/Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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
|
|
@ -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)]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
#![feature(unwind_attributes)]
|
||||
#![feature(doc_spotlight)]
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![feature(iterator_repeat_with)]
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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`).
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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..] {
|
||||
|
|
|
@ -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>>,
|
||||
|
||||
|
|
|
@ -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>)>>,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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![];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
153
src/librustc_mir/transform/uniform_array_move_out.rs
Normal file
153
src/librustc_mir/transform/uniform_array_move_out.rs
Normal 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 }}))));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {}",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
72
src/rustllvm/Linker.cpp
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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(){}
|
59
src/test/mir-opt/uniform_array_move_out.rs
Normal file
59
src/test/mir-opt/uniform_array_move_out.rs
Normal 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
|
20
src/test/run-pass/cast-does-fallback.rs
Normal file
20
src/test/run-pass/cast-does-fallback.rs
Normal 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);
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
33
src/test/run-pass/issue-47703-1.rs
Normal file
33
src/test/run-pass/issue-47703-1.rs
Normal 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() {}
|
28
src/test/run-pass/issue-47703.rs
Normal file
28
src/test/run-pass/issue-47703.rs
Normal 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() {}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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)");
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
20
src/test/ui/cast_char.rs
Normal 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);
|
||||
}
|
20
src/test/ui/cast_char.stderr
Normal file
20
src/test/ui/cast_char.stderr
Normal 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
|
||||
|
13
src/test/ui/invalid-variadic-function.rs
Normal file
13
src/test/ui/invalid-variadic-function.rs
Normal 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 `;`
|
14
src/test/ui/invalid-variadic-function.stderr
Normal file
14
src/test/ui/invalid-variadic-function.stderr
Normal 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
|
||||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue