Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
4c853adce9
362 changed files with 7972 additions and 4180 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -103,3 +103,6 @@ version.texi
|
|||
.cargo
|
||||
!src/vendor/**
|
||||
/src/target/
|
||||
|
||||
no_llvm_build
|
||||
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@ For people new to Rust, and just starting to contribute, or even for
|
|||
more seasoned developers, some useful places to look for information
|
||||
are:
|
||||
|
||||
* [Rust Forge][rustforge] contains additional documentation, including write-ups of how to achieve common tasks
|
||||
* The [Rust Internals forum][rif], a place to ask questions and
|
||||
discuss Rust's internals
|
||||
* The [generated documentation for rust's compiler][gdfrustc]
|
||||
|
|
@ -476,6 +477,7 @@ are:
|
|||
[gsearchdocs]: https://www.google.com/search?q=site:doc.rust-lang.org+your+query+here
|
||||
[rif]: http://internals.rust-lang.org
|
||||
[rr]: https://doc.rust-lang.org/book/README.html
|
||||
[rustforge]: https://forge.rust-lang.org/
|
||||
[tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
|
||||
[ro]: http://www.rustaceans.org/
|
||||
[rctd]: ./src/test/COMPILER_TESTS.md
|
||||
|
|
|
|||
449
src/Cargo.lock
generated
449
src/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -38,6 +38,8 @@ members = [
|
|||
"tools/rls/test_data/infer_custom_bin",
|
||||
"tools/rls/test_data/infer_lib",
|
||||
"tools/rls/test_data/omit_init_build",
|
||||
"tools/rls/test_data/unicødë",
|
||||
"tools/rls/test_data/workspace_symbol",
|
||||
]
|
||||
|
||||
# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit
|
||||
|
|
@ -60,10 +62,5 @@ debug-assertions = false
|
|||
[patch."https://github.com/rust-lang/cargo"]
|
||||
cargo = { path = "tools/cargo" }
|
||||
|
||||
# Override rustfmt dependencies both on the repo and the crate (the RLS
|
||||
# sometimes uses either).
|
||||
# FIXME should only need the crates.io patch, long term.
|
||||
[patch."https://github.com/rust-lang-nursery/rustfmt"]
|
||||
rustfmt-nightly = { path = "tools/rustfmt" }
|
||||
[patch.crates-io]
|
||||
rustfmt-nightly = { path = "tools/rustfmt" }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ cmake = "0.1.23"
|
|||
filetime = "0.1"
|
||||
num_cpus = "1.0"
|
||||
getopts = "0.2"
|
||||
gcc = "0.3.54"
|
||||
cc = "1.0"
|
||||
libc = "0.2"
|
||||
serde = "1.0.8"
|
||||
serde_derive = "1.0.8"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
use std::env;
|
||||
use std::process::{self, Command};
|
||||
|
|
@ -18,7 +18,7 @@ fn main() {
|
|||
// Locate the actual compiler that we're invoking
|
||||
env::remove_var("CC");
|
||||
env::remove_var("CXX");
|
||||
let mut cfg = gcc::Build::new();
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.cargo_metadata(false)
|
||||
.out_dir("/")
|
||||
.target(&target)
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ def bootstrap():
|
|||
try:
|
||||
with open(args.config or 'config.toml') as config:
|
||||
build.config_toml = config.read()
|
||||
except OSError:
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
if '\nverbose = 2' in build.config_toml:
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ impl<'a> Builder<'a> {
|
|||
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
|
||||
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
||||
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
||||
Subcommand::Clean => panic!(),
|
||||
Subcommand::Clean { .. } => panic!(),
|
||||
};
|
||||
|
||||
let builder = Builder {
|
||||
|
|
@ -531,7 +531,10 @@ impl<'a> Builder<'a> {
|
|||
// For other crates, however, we know that we've already got a standard
|
||||
// library up and running, so we can use the normal compiler to compile
|
||||
// build scripts in that situation.
|
||||
if mode == Mode::Libstd {
|
||||
//
|
||||
// If LLVM support is disabled we need to use the snapshot compiler to compile
|
||||
// build scripts, as the new compiler doesnt support executables.
|
||||
if mode == Mode::Libstd || !self.build.config.llvm_enabled {
|
||||
cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
|
||||
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
//! 6. "cc"
|
||||
//!
|
||||
//! Some of this logic is implemented here, but much of it is farmed out to the
|
||||
//! `gcc` crate itself, so we end up having the same fallbacks as there.
|
||||
//! `cc` crate itself, so we end up having the same fallbacks as there.
|
||||
//! Similar logic is then used to find a C++ compiler, just some s/cc/c++/ is
|
||||
//! used.
|
||||
//!
|
||||
|
|
@ -35,7 +35,7 @@ use std::process::Command;
|
|||
use std::iter;
|
||||
|
||||
use build_helper::{cc2ar, output};
|
||||
use gcc;
|
||||
use cc;
|
||||
|
||||
use Build;
|
||||
use config::Target;
|
||||
|
|
@ -45,7 +45,7 @@ pub fn find(build: &mut Build) {
|
|||
// For all targets we're going to need a C compiler for building some shims
|
||||
// and such as well as for being a linker for Rust code.
|
||||
for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) {
|
||||
let mut cfg = gcc::Build::new();
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false)
|
||||
.target(&target).host(&build.build);
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ pub fn find(build: &mut Build) {
|
|||
|
||||
// For all host triples we need to find a C++ compiler as well
|
||||
for host in build.hosts.iter().cloned().chain(iter::once(build.build)) {
|
||||
let mut cfg = gcc::Build::new();
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true)
|
||||
.target(&host).host(&build.build);
|
||||
let config = build.config.target_config.get(&host);
|
||||
|
|
@ -82,7 +82,7 @@ pub fn find(build: &mut Build) {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_compiler(cfg: &mut gcc::Build,
|
||||
fn set_compiler(cfg: &mut cc::Build,
|
||||
gnu_compiler: &str,
|
||||
target: Interned<String>,
|
||||
config: Option<&Target>,
|
||||
|
|
@ -254,7 +254,11 @@ impl Step for Rls {
|
|||
|
||||
builder.add_rustc_lib_path(compiler, &mut cargo);
|
||||
|
||||
try_run(build, &mut cargo);
|
||||
try_run_expecting(
|
||||
build,
|
||||
&mut cargo,
|
||||
builder.build.config.toolstate.rls.passes(ToolState::Testing),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +299,11 @@ impl Step for Rustfmt {
|
|||
|
||||
builder.add_rustc_lib_path(compiler, &mut cargo);
|
||||
|
||||
try_run(build, &mut cargo);
|
||||
try_run_expecting(
|
||||
build,
|
||||
&mut cargo,
|
||||
builder.build.config.toolstate.rustfmt.passes(ToolState::Testing),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
//! Responsible for cleaning out a build directory of all old and stale
|
||||
//! artifacts to prepare for a fresh build. Currently doesn't remove the
|
||||
//! `build/cache` directory (download cache) or the `build/$target/llvm`
|
||||
//! directory as we want that cached between builds.
|
||||
//! directory unless the --all flag is present.
|
||||
|
||||
use std::fs;
|
||||
use std::io::{self, ErrorKind};
|
||||
|
|
@ -21,24 +21,29 @@ use std::path::Path;
|
|||
|
||||
use Build;
|
||||
|
||||
pub fn clean(build: &Build) {
|
||||
pub fn clean(build: &Build, all: bool) {
|
||||
rm_rf("tmp".as_ref());
|
||||
rm_rf(&build.out.join("tmp"));
|
||||
rm_rf(&build.out.join("dist"));
|
||||
|
||||
for host in &build.hosts {
|
||||
let entries = match build.out.join(host).read_dir() {
|
||||
Ok(iter) => iter,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if all {
|
||||
rm_rf(&build.out);
|
||||
} else {
|
||||
rm_rf(&build.out.join("tmp"));
|
||||
rm_rf(&build.out.join("dist"));
|
||||
|
||||
for entry in entries {
|
||||
let entry = t!(entry);
|
||||
if entry.file_name().to_str() == Some("llvm") {
|
||||
continue
|
||||
for host in &build.hosts {
|
||||
let entries = match build.out.join(host).read_dir() {
|
||||
Ok(iter) => iter,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
for entry in entries {
|
||||
let entry = t!(entry);
|
||||
if entry.file_name().to_str() == Some("llvm") {
|
||||
continue
|
||||
}
|
||||
let path = t!(entry.path().canonicalize());
|
||||
rm_rf(&path);
|
||||
}
|
||||
let path = t!(entry.path().canonicalize());
|
||||
rm_rf(&path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root",
|
|||
"arm-unknown-linux-musleabihf install directory")
|
||||
v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root",
|
||||
"armv7-unknown-linux-musleabihf install directory")
|
||||
v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root",
|
||||
"aarch64-unknown-linux-musl install directory")
|
||||
v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
|
||||
"rootfs in qemu testing, you probably don't want to use this")
|
||||
v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
|
||||
|
|
|
|||
|
|
@ -1098,13 +1098,8 @@ impl Step for Rls {
|
|||
.arg("--output-dir").arg(&distdir(build))
|
||||
.arg("--non-installed-overlay").arg(&overlay)
|
||||
.arg(format!("--package-name={}-{}", name, target))
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo");
|
||||
|
||||
if build.config.channel == "nightly" {
|
||||
cmd.arg("--component-name=rls");
|
||||
} else {
|
||||
cmd.arg("--component-name=rls-preview");
|
||||
}
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo")
|
||||
.arg("--component-name=rls-preview");
|
||||
|
||||
build.run(&mut cmd);
|
||||
distdir(build).join(format!("{}-{}.tar.gz", name, target))
|
||||
|
|
@ -1333,12 +1328,8 @@ impl Step for Extended {
|
|||
cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
|
||||
.join(format!("rust-std-{}", target)),
|
||||
&exe.join("rust-std"));
|
||||
let rls_path = if build.config.channel == "nightly" {
|
||||
work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls")
|
||||
} else {
|
||||
work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview")
|
||||
};
|
||||
cp_r(&rls_path, &exe.join("rls"));
|
||||
cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview"),
|
||||
&exe.join("rls"));
|
||||
cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
|
||||
.join(format!("rust-analysis-{}", target)),
|
||||
&exe.join("rust-analysis"));
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ pub enum Subcommand {
|
|||
paths: Vec<PathBuf>,
|
||||
test_args: Vec<String>,
|
||||
},
|
||||
Clean,
|
||||
Clean {
|
||||
all: bool,
|
||||
},
|
||||
Dist {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
|
|
@ -147,6 +149,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
|
|||
opts.optmulti("", "test-args", "extra arguments", "ARGS");
|
||||
},
|
||||
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
|
||||
"clean" => { opts.optflag("", "all", "clean all build artifacts"); },
|
||||
_ => { },
|
||||
};
|
||||
|
||||
|
|
@ -250,7 +253,7 @@ Arguments:
|
|||
}
|
||||
});
|
||||
|
||||
// All subcommands can have an optional "Available paths" section
|
||||
// All subcommands except `clean` can have an optional "Available paths" section
|
||||
if matches.opt_present("verbose") {
|
||||
let config = Config::parse(&["build".to_string()]);
|
||||
let mut build = Build::new(config);
|
||||
|
|
@ -258,9 +261,10 @@ Arguments:
|
|||
|
||||
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
|
||||
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
|
||||
} else {
|
||||
extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
|
||||
subcommand).as_str());
|
||||
} else if subcommand.as_str() != "clean" {
|
||||
extra_help.push_str(format!(
|
||||
"Run `./x.py {} -h -v` to see a list of available paths.",
|
||||
subcommand).as_str());
|
||||
}
|
||||
|
||||
// User passed in -h/--help?
|
||||
|
|
@ -290,10 +294,13 @@ Arguments:
|
|||
}
|
||||
"clean" => {
|
||||
if paths.len() > 0 {
|
||||
println!("\nclean takes no arguments\n");
|
||||
println!("\nclean does not take a path argument\n");
|
||||
usage(1, &opts, &subcommand_help, &extra_help);
|
||||
}
|
||||
Subcommand::Clean
|
||||
|
||||
Subcommand::Clean {
|
||||
all: matches.opt_present("all"),
|
||||
}
|
||||
}
|
||||
"dist" => {
|
||||
Subcommand::Dist {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ extern crate lazy_static;
|
|||
extern crate serde_json;
|
||||
extern crate cmake;
|
||||
extern crate filetime;
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
extern crate getopts;
|
||||
extern crate num_cpus;
|
||||
extern crate toml;
|
||||
|
|
@ -148,7 +148,7 @@ use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppresse
|
|||
|
||||
use util::{exe, libdir, OutputFolder, CiEnv};
|
||||
|
||||
mod cc;
|
||||
mod cc_detect;
|
||||
mod channel;
|
||||
mod check;
|
||||
mod clean;
|
||||
|
|
@ -241,9 +241,9 @@ pub struct Build {
|
|||
|
||||
// Runtime state filled in later on
|
||||
// target -> (cc, ar)
|
||||
cc: HashMap<Interned<String>, (gcc::Tool, Option<PathBuf>)>,
|
||||
cc: HashMap<Interned<String>, (cc::Tool, Option<PathBuf>)>,
|
||||
// host -> (cc, ar)
|
||||
cxx: HashMap<Interned<String>, gcc::Tool>,
|
||||
cxx: HashMap<Interned<String>, cc::Tool>,
|
||||
crates: HashMap<Interned<String>, Crate>,
|
||||
is_sudo: bool,
|
||||
ci_env: CiEnv,
|
||||
|
|
@ -345,12 +345,12 @@ impl Build {
|
|||
job::setup(self);
|
||||
}
|
||||
|
||||
if let Subcommand::Clean = self.config.cmd {
|
||||
return clean::clean(self);
|
||||
if let Subcommand::Clean { all } = self.config.cmd {
|
||||
return clean::clean(self, all);
|
||||
}
|
||||
|
||||
self.verbose("finding compilers");
|
||||
cc::find(self);
|
||||
cc_detect::find(self);
|
||||
self.verbose("running sanity check");
|
||||
sanity::check(self);
|
||||
// If local-rust is the same major.minor as the current version, then force a local-rebuild
|
||||
|
|
@ -619,7 +619,7 @@ impl Build {
|
|||
/// specified.
|
||||
fn cflags(&self, target: Interned<String>) -> Vec<String> {
|
||||
// Filter out -O and /O (the optimization flags) that we picked up from
|
||||
// gcc-rs because the build scripts will determine that for themselves.
|
||||
// cc-rs because the build scripts will determine that for themselves.
|
||||
let mut base = self.cc[&target].0.args().iter()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.filter(|s| !s.starts_with("-O") && !s.starts_with("/O"))
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use std::process::Command;
|
|||
|
||||
use build_helper::output;
|
||||
use cmake;
|
||||
use gcc;
|
||||
use cc;
|
||||
|
||||
use Build;
|
||||
use util;
|
||||
|
|
@ -289,7 +289,7 @@ impl Step for TestHelpers {
|
|||
let _folder = build.fold_output(|| "build_test_helpers");
|
||||
println!("Building test helpers");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
let mut cfg = gcc::Build::new();
|
||||
let mut cfg = cc::Build::new();
|
||||
|
||||
// We may have found various cross-compilers a little differently due to our
|
||||
// extra configuration, so inform gcc of these compilers. Note, though, that
|
||||
|
|
@ -367,7 +367,7 @@ impl Step for Openssl {
|
|||
if !ok {
|
||||
panic!("failed to download openssl source")
|
||||
}
|
||||
let mut shasum = if target.contains("apple") {
|
||||
let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
|
||||
let mut cmd = Command::new("shasum");
|
||||
cmd.arg("-a").arg("256");
|
||||
cmd
|
||||
|
|
@ -387,7 +387,7 @@ impl Step for Openssl {
|
|||
let dst = build.openssl_install_dir(target).unwrap();
|
||||
drop(fs::remove_dir_all(&obj));
|
||||
drop(fs::remove_dir_all(&dst));
|
||||
build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
|
||||
build.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
|
||||
|
||||
let mut configure = Command::new("perl");
|
||||
configure.arg(obj.join("Configure"));
|
||||
|
|
@ -399,6 +399,7 @@ impl Step for Openssl {
|
|||
let os = match &*target {
|
||||
"aarch64-linux-android" => "linux-aarch64",
|
||||
"aarch64-unknown-linux-gnu" => "linux-aarch64",
|
||||
"aarch64-unknown-linux-musl" => "linux-aarch64",
|
||||
"arm-linux-androideabi" => "android",
|
||||
"arm-unknown-linux-gnueabi" => "linux-armv4",
|
||||
"arm-unknown-linux-gnueabihf" => "linux-armv4",
|
||||
|
|
|
|||
|
|
@ -221,8 +221,9 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
|
|||
let run = |cmd: &mut Command| {
|
||||
cmd.output().map(|output| {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.lines().next().unwrap()
|
||||
.to_string()
|
||||
.lines().next().unwrap_or_else(|| {
|
||||
panic!("{:?} failed {:?}", cmd, output)
|
||||
}).to_string()
|
||||
})
|
||||
};
|
||||
build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ pub fn prepare_tool_cargo(
|
|||
cargo.env("LIBZ_SYS_STATIC", "1");
|
||||
}
|
||||
|
||||
// if tools are using lzma we want to force the build script to build its
|
||||
// own copy
|
||||
cargo.env("LZMA_API_STATIC", "1");
|
||||
|
||||
cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
|
||||
cargo.env("CFG_VERSION", build.rust_version());
|
||||
|
||||
|
|
@ -304,6 +308,11 @@ impl Step for Rustdoc {
|
|||
target,
|
||||
"build",
|
||||
"src/tools/rustdoc");
|
||||
|
||||
// Most tools don't get debuginfo, but rustdoc should.
|
||||
cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
|
||||
.env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());
|
||||
|
||||
build.run(&mut cargo);
|
||||
// Cargo adds a number of paths to the dylib search path on windows, which results in
|
||||
// the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
|
||||
|
|
@ -449,7 +458,7 @@ impl Step for Rls {
|
|||
tool: "rls",
|
||||
mode: Mode::Librustc,
|
||||
path: "src/tools/rls",
|
||||
expectation: BuildExpectation::None,
|
||||
expectation: builder.build.config.toolstate.rls.passes(ToolState::Compiling),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -484,7 +493,7 @@ impl Step for Rustfmt {
|
|||
tool: "rustfmt",
|
||||
mode: Mode::Librustc,
|
||||
path: "src/tools/rustfmt",
|
||||
expectation: BuildExpectation::None,
|
||||
expectation: builder.build.config.toolstate.rustfmt.passes(ToolState::Compiling),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,4 +46,6 @@ impl Default for ToolState {
|
|||
pub struct ToolStates {
|
||||
pub miri: ToolState,
|
||||
pub clippy: ToolState,
|
||||
pub rls: ToolState,
|
||||
pub rustfmt: ToolState,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
zlib1g-dev \
|
||||
g++-arm-linux-gnueabi \
|
||||
g++-arm-linux-gnueabihf \
|
||||
g++-aarch64-linux-gnu \
|
||||
gcc-sparc64-linux-gnu \
|
||||
libc6-dev-sparc64-cross \
|
||||
bzip2 \
|
||||
|
|
@ -46,6 +47,7 @@ ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl
|
|||
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
|
||||
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
|
||||
ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
|
||||
ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl
|
||||
ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu
|
||||
ENV TARGETS=$TARGETS,x86_64-unknown-redox
|
||||
|
||||
|
|
@ -62,7 +64,8 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--target=$TARGETS \
|
||||
--musl-root-arm=/usr/local/arm-linux-musleabi \
|
||||
--musl-root-armhf=/usr/local/arm-linux-musleabihf \
|
||||
--musl-root-armv7=/usr/local/armv7-linux-musleabihf
|
||||
--musl-root-armv7=/usr/local/armv7-linux-musleabihf \
|
||||
--musl-root-aarch64=/usr/local/aarch64-linux-musl
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
||||
# sccache
|
||||
|
|
|
|||
|
|
@ -65,11 +65,24 @@ CFLAGS="-march=armv7-a" \
|
|||
hide_output make -j$(nproc)
|
||||
hide_output make install
|
||||
cd ..
|
||||
rm -rf musl-$MUSL
|
||||
|
||||
tar xf musl-$MUSL.tar.gz
|
||||
cd musl-$MUSL
|
||||
CC=aarch64-linux-gnu-gcc \
|
||||
CFLAGS="" \
|
||||
hide_output ./configure \
|
||||
--prefix=/usr/local/aarch64-linux-musl \
|
||||
--enable-wrapper=gcc
|
||||
hide_output make -j$(nproc)
|
||||
hide_output make install
|
||||
cd ..
|
||||
rm -rf musl-$MUSL*
|
||||
|
||||
ln -nsf ../arm-linux-musleabi/bin/musl-gcc /usr/local/bin/arm-linux-musleabi-gcc
|
||||
ln -nsf ../arm-linux-musleabihf/bin/musl-gcc /usr/local/bin/arm-linux-musleabihf-gcc
|
||||
ln -nsf ../armv7-linux-musleabihf/bin/musl-gcc /usr/local/bin/armv7-linux-musleabihf-gcc
|
||||
ln -nsf ../aarch64-linux-musl/bin/musl-gcc /usr/local/bin/aarch64-unknown-linux-musl-gcc
|
||||
|
||||
curl -L https://github.com/llvm-mirror/llvm/archive/release_39.tar.gz | tar xzf -
|
||||
curl -L https://github.com/llvm-mirror/libunwind/archive/release_39.tar.gz | tar xzf -
|
||||
|
|
@ -116,5 +129,19 @@ cp lib/libunwind.a /usr/local/armv7-linux-musleabihf/lib
|
|||
cd ..
|
||||
rm -rf libunwind-build
|
||||
|
||||
mkdir libunwind-build
|
||||
cd libunwind-build
|
||||
cmake ../libunwind-release_39 \
|
||||
-DLLVM_PATH=/tmp/llvm-release_39 \
|
||||
-DLIBUNWIND_ENABLE_SHARED=0 \
|
||||
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
|
||||
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
|
||||
-DCMAKE_C_FLAGS="" \
|
||||
-DCMAKE_CXX_FLAGS=""
|
||||
make -j$(nproc)
|
||||
cp lib/libunwind.a /usr/local/aarch64-linux-musl/lib
|
||||
cd ..
|
||||
rm -rf libunwind-build
|
||||
|
||||
rm -rf libunwind-release_39
|
||||
rm -rf llvm-release_39
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ WORKDIR /build
|
|||
# The `config` config file was a previously generated config file for
|
||||
# the kernel. This file was generated by running `make defconfig`
|
||||
# followed by `make menuconfig` and then enabling the IPv6 protocol page.
|
||||
COPY disabled/aarch64-gnu/config /build/.config
|
||||
COPY aarch64-gnu/config /build/.config
|
||||
RUN curl https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.42.tar.xz | \
|
||||
tar xJf - && \
|
||||
cd /build/linux-4.4.42 && \
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
|
||||
# emscripten
|
||||
COPY scripts/emscripten-wasm.sh /scripts/
|
||||
COPY disabled/wasm32-exp/node.sh /usr/local/bin/node
|
||||
COPY wasm32-exp/node.sh /usr/local/bin/node
|
||||
RUN bash /scripts/emscripten-wasm.sh
|
||||
|
||||
# cache
|
||||
|
|
|
|||
|
|
@ -1,27 +1,26 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y \
|
||||
build-essential \
|
||||
bzip2 \
|
||||
ca-certificates \
|
||||
cmake \
|
||||
curl \
|
||||
file \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
libedit-dev \
|
||||
make \
|
||||
ninja-build \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
nodejs \
|
||||
python2.7-dev \
|
||||
git \
|
||||
sudo \
|
||||
bzip2 \
|
||||
xz-utils \
|
||||
swig \
|
||||
libedit-dev \
|
||||
libncurses5-dev \
|
||||
patch
|
||||
|
||||
RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \
|
||||
tar xzf - -C /usr/local --strip-components=1
|
||||
unzip
|
||||
|
||||
WORKDIR /tmp
|
||||
COPY dist-fuchsia/shared.sh dist-fuchsia/build-toolchain.sh dist-fuchsia/compiler-rt-dso-handle.patch /tmp/
|
||||
COPY dist-fuchsia/shared.sh dist-fuchsia/build-toolchain.sh /tmp/
|
||||
RUN /tmp/build-toolchain.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
|
|
@ -39,4 +38,4 @@ ENV TARGETS=x86_64-unknown-fuchsia
|
|||
ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
|
@ -14,105 +14,44 @@
|
|||
set -ex
|
||||
source shared.sh
|
||||
|
||||
ZIRCON=e9a26dbc70d631029f8ee9763103910b7e3a2fe1
|
||||
|
||||
mkdir -p zircon
|
||||
pushd zircon > /dev/null
|
||||
|
||||
# Download sources
|
||||
SRCS=(
|
||||
"https://fuchsia.googlesource.com/magenta magenta d17073dc8de344ead3b65e8cc6a12280dec38c84"
|
||||
"https://llvm.googlesource.com/llvm llvm 3f58a16d8eec385e2b3ebdfbb84ff9d3bf27e025"
|
||||
"https://llvm.googlesource.com/clang llvm/tools/clang 727ea63e6e82677f6e10e05e08bc7d6bdbae3111"
|
||||
"https://llvm.googlesource.com/lld llvm/tools/lld a31286c1366e5e89b8872803fded13805a1a084b"
|
||||
"https://llvm.googlesource.com/lldb llvm/tools/lldb 0b2384abec4cb99ad66687712e07dee4dd9d187e"
|
||||
"https://llvm.googlesource.com/compiler-rt llvm/runtimes/compiler-rt 9093a35c599fe41278606a20b51095ea8bd5a081"
|
||||
"https://llvm.googlesource.com/libcxx llvm/runtimes/libcxx 607e0c71ec4f7fd377ad3f6c47b08dbe89f66eaa"
|
||||
"https://llvm.googlesource.com/libcxxabi llvm/runtimes/libcxxabi 0a3a1a8a5ca5ef69e0f6b7d5b9d13e63e6fd2c19"
|
||||
"https://llvm.googlesource.com/libunwind llvm/runtimes/libunwind e128003563d99d9ee62247c4cee40f07d21c03e3"
|
||||
)
|
||||
git init
|
||||
git remote add origin https://fuchsia.googlesource.com/zircon
|
||||
git fetch --depth=1 origin $ZIRCON
|
||||
git reset --hard FETCH_HEAD
|
||||
|
||||
fetch() {
|
||||
mkdir -p $2
|
||||
pushd $2 > /dev/null
|
||||
git init
|
||||
git remote add origin $1
|
||||
git fetch --depth=1 origin $3
|
||||
git reset --hard FETCH_HEAD
|
||||
popd > /dev/null
|
||||
}
|
||||
# Download toolchain
|
||||
./scripts/download-toolchain
|
||||
chmod -R a+rx prebuilt/downloads/clang+llvm-x86_64-linux
|
||||
cp -a prebuilt/downloads/clang+llvm-x86_64-linux/. /usr/local
|
||||
|
||||
for i in "${SRCS[@]}"; do
|
||||
fetch $i
|
||||
done
|
||||
|
||||
# Remove this once https://reviews.llvm.org/D28791 is resolved
|
||||
cd llvm/runtimes/compiler-rt
|
||||
patch -Np1 < /tmp/compiler-rt-dso-handle.patch
|
||||
cd ../../..
|
||||
|
||||
# Build toolchain
|
||||
cd llvm
|
||||
mkdir build
|
||||
cd build
|
||||
hide_output cmake -GNinja \
|
||||
-DFUCHSIA_SYSROOT=${PWD}/../../magenta/third_party/ulib/musl \
|
||||
-DLLVM_ENABLE_LTO=OFF \
|
||||
-DCLANG_BOOTSTRAP_PASSTHROUGH=LLVM_ENABLE_LTO \
|
||||
-C ../tools/clang/cmake/caches/Fuchsia.cmake \
|
||||
..
|
||||
hide_output ninja stage2-distribution
|
||||
hide_output ninja stage2-install-distribution
|
||||
cd ../..
|
||||
|
||||
# Build sysroot
|
||||
rm -rf llvm/runtimes/compiler-rt
|
||||
./magenta/scripts/download-toolchain
|
||||
|
||||
build_sysroot() {
|
||||
build() {
|
||||
local arch="$1"
|
||||
|
||||
case "${arch}" in
|
||||
x86_64) tgt="magenta-pc-x86-64" ;;
|
||||
aarch64) tgt="magenta-qemu-arm64" ;;
|
||||
x86_64) tgt="zircon-pc-x86-64" ;;
|
||||
aarch64) tgt="zircon-qemu-arm64" ;;
|
||||
esac
|
||||
|
||||
hide_output make -C magenta -j$(getconf _NPROCESSORS_ONLN) $tgt
|
||||
hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt
|
||||
dst=/usr/local/${arch}-unknown-fuchsia
|
||||
mkdir -p $dst
|
||||
cp -r magenta/build-${tgt}/sysroot/include $dst/
|
||||
cp -r magenta/build-${tgt}/sysroot/lib $dst/
|
||||
|
||||
cd llvm
|
||||
mkdir build-runtimes-${arch}
|
||||
cd build-runtimes-${arch}
|
||||
hide_output cmake -GNinja \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_AR=/usr/local/bin/llvm-ar \
|
||||
-DCMAKE_RANLIB=/usr/local/bin/llvm-ranlib \
|
||||
-DCMAKE_INSTALL_PREFIX= \
|
||||
-DLLVM_MAIN_SRC_DIR=${PWD}/.. \
|
||||
-DLLVM_BINARY_DIR=${PWD}/../build \
|
||||
-DLLVM_ENABLE_WERROR=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLVM_INCLUDE_TESTS=ON \
|
||||
-DCMAKE_SYSTEM_NAME=Fuchsia \
|
||||
-DCMAKE_C_COMPILER_TARGET=${arch}-fuchsia \
|
||||
-DCMAKE_CXX_COMPILER_TARGET=${arch}-fuchsia \
|
||||
-DUNIX=1 \
|
||||
-DLIBCXX_HAS_MUSL_LIBC=ON \
|
||||
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
|
||||
-DCMAKE_SYSROOT=${dst} \
|
||||
-DCMAKE_C_COMPILER_FORCED=TRUE \
|
||||
-DCMAKE_CXX_COMPILER_FORCED=TRUE \
|
||||
-DLLVM_ENABLE_LIBCXX=ON \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-nodefaultlibs -lc" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="$(clang --target=${arch}-fuchsia -print-libgcc-file-name)" \
|
||||
../runtimes
|
||||
hide_output env DESTDIR="${dst}" ninja install
|
||||
cd ../..
|
||||
cp -a build-${tgt}/sysroot/include $dst/
|
||||
cp -a build-${tgt}/sysroot/lib $dst/
|
||||
}
|
||||
|
||||
build_sysroot "x86_64"
|
||||
build_sysroot "aarch64"
|
||||
# Build sysroot
|
||||
for arch in x86_64 aarch64; do
|
||||
build ${arch}
|
||||
done
|
||||
|
||||
rm -rf magenta llvm
|
||||
popd > /dev/null
|
||||
rm -rf zircon
|
||||
|
||||
for arch in x86_64 aarch64; do
|
||||
for tool in clang clang++; do
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
|
||||
index fc4384af2..b442264c0 100644
|
||||
--- a/lib/builtins/CMakeLists.txt
|
||||
+++ b/lib/builtins/CMakeLists.txt
|
||||
@@ -194,6 +194,12 @@ if(APPLE)
|
||||
atomic_thread_fence.c)
|
||||
endif()
|
||||
|
||||
+if(FUCHSIA)
|
||||
+ set(GENERIC_SOURCES
|
||||
+ ${GENERIC_SOURCES}
|
||||
+ dso_handle.c)
|
||||
+endif()
|
||||
+
|
||||
if(NOT WIN32 OR MINGW)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
diff --git a/lib/builtins/dso_handle.c b/lib/builtins/dso_handle.c
|
||||
new file mode 100644
|
||||
index 000000000..7766cd0aa
|
||||
--- /dev/null
|
||||
+++ b/lib/builtins/dso_handle.c
|
||||
@@ -0,0 +1,18 @@
|
||||
+/* ===-- dso_handle.c - Provide __dso_handle -------------------------------===
|
||||
+ *
|
||||
+ * The LLVM Compiler Infrastructure
|
||||
+ *
|
||||
+ * This file is dual licensed under the MIT and the University of Illinois Open
|
||||
+ * Source Licenses. See LICENSE.TXT for details.
|
||||
+ *
|
||||
+ * ===----------------------------------------------------------------------===
|
||||
+ */
|
||||
+
|
||||
+/* __dso_handle symbol is mandated by C++ ABI with a value which is an address
|
||||
+ * in one of the object's segments, and as such this symbol has to be included
|
||||
+ * statically and cannot be a part of a shared library. Traditionally, it has
|
||||
+ * been defined in crtbegin.o but there's no principled reason for it to be
|
||||
+ * there. We defined this symbol in the builtin library which is built as a
|
||||
+ * static library and always included in the final link.
|
||||
+ */
|
||||
+__attribute__((visibility("hidden"))) void *const __dso_handle;
|
||||
|
|
@ -36,12 +36,14 @@ elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
|
|||
echo Cannot run disabled images on travis!
|
||||
exit 1
|
||||
fi
|
||||
retry docker \
|
||||
# retry messes with the pipe from tar to docker. Not needed on non-travis
|
||||
# Transform changes the context of disabled Dockerfiles to match the enabled ones
|
||||
tar --transform 's#^./disabled/#./#' -C $docker_dir -c . | docker \
|
||||
build \
|
||||
--rm \
|
||||
-t rust-ci \
|
||||
-f "$docker_dir/disabled/$image/Dockerfile" \
|
||||
"$docker_dir"
|
||||
-f "$image/Dockerfile" \
|
||||
-
|
||||
else
|
||||
echo Invalid image: $image
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ The tracking issue for this feature is: [#28237]
|
|||
------------------------
|
||||
|
||||
To get a range that goes from 0 to 10 and includes the value 10, you
|
||||
can write `0...10`:
|
||||
can write `0..=10`:
|
||||
|
||||
```rust
|
||||
#![feature(inclusive_range_syntax)]
|
||||
|
||||
fn main() {
|
||||
for i in 0...10 {
|
||||
for i in 0..=10 {
|
||||
println!("{}", i);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,13 +72,13 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
|||
/// first: after all, isn't the point of `Arc<T>` thread safety? The key is
|
||||
/// this: `Arc<T>` makes it thread safe to have multiple ownership of the same
|
||||
/// data, but it doesn't add thread safety to its data. Consider
|
||||
/// `Arc<RefCell<T>>`. `RefCell<T>` isn't [`Sync`], and if `Arc<T>` was always
|
||||
/// [`Send`], `Arc<RefCell<T>>` would be as well. But then we'd have a problem:
|
||||
/// `RefCell<T>` is not thread safe; it keeps track of the borrowing count using
|
||||
/// `Arc<`[`RefCell<T>`]`>`. [`RefCell<T>`] isn't [`Sync`], and if `Arc<T>` was always
|
||||
/// [`Send`], `Arc<`[`RefCell<T>`]`>` would be as well. But then we'd have a problem:
|
||||
/// [`RefCell<T>`] is not thread safe; it keeps track of the borrowing count using
|
||||
/// non-atomic operations.
|
||||
///
|
||||
/// In the end, this means that you may need to pair `Arc<T>` with some sort of
|
||||
/// `std::sync` type, usually `Mutex<T>`.
|
||||
/// [`std::sync`] type, usually [`Mutex<T>`][mutex].
|
||||
///
|
||||
/// ## Breaking cycles with `Weak`
|
||||
///
|
||||
|
|
@ -106,7 +106,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
|||
/// // a and b both point to the same memory location as foo.
|
||||
/// ```
|
||||
///
|
||||
/// The `Arc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly
|
||||
/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly
|
||||
/// the meaning of the code. In the example above, this syntax makes it easier to see that
|
||||
/// this code is creating a new reference rather than copying the whole content of foo.
|
||||
///
|
||||
|
|
@ -141,6 +141,9 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
|||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [`None`]: ../../std/option/enum.Option.html#variant.None
|
||||
/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions
|
||||
/// [`RefCell<T>`]: ../../std/cell/struct.RefCell.html
|
||||
/// [`std::sync`]: ../../std/sync/index.html
|
||||
/// [`Arc::clone(&from)`]: #method.clone
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@
|
|||
#![feature(generic_param_attrs)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(iter_rfold)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(needs_allocator)]
|
||||
#![feature(nonzero)]
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ fn test_range_small() {
|
|||
fn test_range_inclusive() {
|
||||
let size = 500;
|
||||
|
||||
let map: BTreeMap<_, _> = (0...size).map(|i| (i, i)).collect();
|
||||
let map: BTreeMap<_, _> = (0..=size).map(|i| (i, i)).collect();
|
||||
|
||||
fn check<'a, L, R>(lhs: L, rhs: R)
|
||||
where L: IntoIterator<Item=(&'a i32, &'a i32)>,
|
||||
|
|
@ -193,18 +193,18 @@ fn test_range_inclusive() {
|
|||
assert_eq!(lhs, rhs);
|
||||
}
|
||||
|
||||
check(map.range(size + 1...size + 1), vec![]);
|
||||
check(map.range(size...size), vec![(&size, &size)]);
|
||||
check(map.range(size...size + 1), vec![(&size, &size)]);
|
||||
check(map.range(0...0), vec![(&0, &0)]);
|
||||
check(map.range(0...size - 1), map.range(..size));
|
||||
check(map.range(-1...-1), vec![]);
|
||||
check(map.range(-1...size), map.range(..));
|
||||
check(map.range(...size), map.range(..));
|
||||
check(map.range(...200), map.range(..201));
|
||||
check(map.range(5...8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]);
|
||||
check(map.range(-1...0), vec![(&0, &0)]);
|
||||
check(map.range(-1...2), vec![(&0, &0), (&1, &1), (&2, &2)]);
|
||||
check(map.range(size + 1..=size + 1), vec![]);
|
||||
check(map.range(size..=size), vec![(&size, &size)]);
|
||||
check(map.range(size..=size + 1), vec![(&size, &size)]);
|
||||
check(map.range(0..=0), vec![(&0, &0)]);
|
||||
check(map.range(0..=size - 1), map.range(..size));
|
||||
check(map.range(-1..=-1), vec![]);
|
||||
check(map.range(-1..=size), map.range(..));
|
||||
check(map.range(..=size), map.range(..));
|
||||
check(map.range(..=200), map.range(..201));
|
||||
check(map.range(5..=8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]);
|
||||
check(map.range(-1..=0), vec![(&0, &0)]);
|
||||
check(map.range(-1..=2), vec![(&0, &0), (&1, &1), (&2, &2)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -212,7 +212,7 @@ fn test_range_inclusive_max_value() {
|
|||
let max = ::std::usize::MAX;
|
||||
let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
|
||||
|
||||
assert_eq!(map.range(max...max).collect::<Vec<_>>(), &[(&max, &0)]);
|
||||
assert_eq!(map.range(max..=max).collect::<Vec<_>>(), &[(&max, &0)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -361,13 +361,13 @@ fn test_slice_fail() {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn test_str_slice_rangetoinclusive_max_panics() {
|
||||
&"hello"[...usize::max_value()];
|
||||
&"hello"[..=usize::max_value()];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_str_slice_rangeinclusive_max_panics() {
|
||||
&"hello"[1...usize::max_value()];
|
||||
&"hello"[1..=usize::max_value()];
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -375,7 +375,7 @@ fn test_str_slice_rangeinclusive_max_panics() {
|
|||
fn test_str_slicemut_rangetoinclusive_max_panics() {
|
||||
let mut s = "hello".to_owned();
|
||||
let s: &mut str = &mut s;
|
||||
&mut s[...usize::max_value()];
|
||||
&mut s[..=usize::max_value()];
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -383,7 +383,7 @@ fn test_str_slicemut_rangetoinclusive_max_panics() {
|
|||
fn test_str_slicemut_rangeinclusive_max_panics() {
|
||||
let mut s = "hello".to_owned();
|
||||
let s: &mut str = &mut s;
|
||||
&mut s[1...usize::max_value()];
|
||||
&mut s[1..=usize::max_value()];
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -391,13 +391,13 @@ fn test_str_get_maxinclusive() {
|
|||
let mut s = "hello".to_owned();
|
||||
{
|
||||
let s: &str = &s;
|
||||
assert_eq!(s.get(...usize::max_value()), None);
|
||||
assert_eq!(s.get(1...usize::max_value()), None);
|
||||
assert_eq!(s.get(..=usize::max_value()), None);
|
||||
assert_eq!(s.get(1..=usize::max_value()), None);
|
||||
}
|
||||
{
|
||||
let s: &mut str = &mut s;
|
||||
assert_eq!(s.get(...usize::max_value()), None);
|
||||
assert_eq!(s.get(1...usize::max_value()), None);
|
||||
assert_eq!(s.get(..=usize::max_value()), None);
|
||||
assert_eq!(s.get(1..=usize::max_value()), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -456,9 +456,9 @@ fn test_splice_char_boundary() {
|
|||
#[test]
|
||||
fn test_splice_inclusive_range() {
|
||||
let mut v = String::from("12345");
|
||||
v.splice(2...3, "789");
|
||||
v.splice(2..=3, "789");
|
||||
assert_eq!(v, "127895");
|
||||
v.splice(1...2, "A");
|
||||
v.splice(1..=2, "A");
|
||||
assert_eq!(v, "1A895");
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +473,7 @@ fn test_splice_out_of_bounds() {
|
|||
#[should_panic]
|
||||
fn test_splice_inclusive_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.splice(5...5, "789");
|
||||
s.splice(5..=5, "789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -537,27 +537,27 @@ fn test_drain_range() {
|
|||
#[test]
|
||||
fn test_drain_inclusive_range() {
|
||||
let mut v = vec!['a', 'b', 'c', 'd', 'e'];
|
||||
for _ in v.drain(1...3) {
|
||||
for _ in v.drain(1..=3) {
|
||||
}
|
||||
assert_eq!(v, &['a', 'e']);
|
||||
|
||||
let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(1...5) {
|
||||
let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(1..=5) {
|
||||
}
|
||||
assert_eq!(v, &["0".to_string()]);
|
||||
|
||||
let mut v: Vec<String> = (0...5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(0...5) {
|
||||
let mut v: Vec<String> = (0..=5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(0..=5) {
|
||||
}
|
||||
assert_eq!(v, Vec::<String>::new());
|
||||
|
||||
let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(0...3) {
|
||||
let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(0..=3) {
|
||||
}
|
||||
assert_eq!(v, &["4".to_string(), "5".to_string()]);
|
||||
|
||||
let mut v: Vec<_> = (0...1).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(...0) {
|
||||
let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect();
|
||||
for _ in v.drain(..=0) {
|
||||
}
|
||||
assert_eq!(v, &["1".to_string()]);
|
||||
}
|
||||
|
|
@ -572,7 +572,7 @@ fn test_drain_max_vec_size() {
|
|||
|
||||
let mut v = Vec::<()>::with_capacity(usize::max_value());
|
||||
unsafe { v.set_len(usize::max_value()); }
|
||||
for _ in v.drain(usize::max_value() - 1...usize::max_value() - 1) {
|
||||
for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) {
|
||||
}
|
||||
assert_eq!(v.len(), usize::max_value() - 1);
|
||||
}
|
||||
|
|
@ -581,7 +581,7 @@ fn test_drain_max_vec_size() {
|
|||
#[should_panic]
|
||||
fn test_drain_inclusive_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
v.drain(5...5);
|
||||
v.drain(5..=5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -598,10 +598,10 @@ fn test_splice() {
|
|||
fn test_splice_inclusive_range() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
let a = [10, 11, 12];
|
||||
let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect();
|
||||
let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect();
|
||||
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
|
||||
assert_eq!(t1, &[3, 4]);
|
||||
let t2: Vec<_> = v.splice(1...2, Some(20)).collect();
|
||||
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
|
||||
assert_eq!(v, &[1, 20, 11, 12, 5]);
|
||||
assert_eq!(t2, &[2, 10]);
|
||||
}
|
||||
|
|
@ -619,7 +619,7 @@ fn test_splice_out_of_bounds() {
|
|||
fn test_splice_inclusive_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
let a = [10, 11, 12];
|
||||
v.splice(5...5, a.iter().cloned());
|
||||
v.splice(5..=5, a.iter().cloned());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1950,7 +1950,7 @@ impl<T> Vec<T> {
|
|||
/// assert_eq!(u, &[1, 2]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<I::IntoIter>
|
||||
where R: RangeArgument<usize>, I: IntoIterator<Item=T>
|
||||
{
|
||||
|
|
@ -2553,13 +2553,13 @@ impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
|
|||
/// [`splice()`]: struct.Vec.html#method.splice
|
||||
/// [`Vec`]: struct.Vec.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
pub struct Splice<'a, I: Iterator + 'a> {
|
||||
drain: Drain<'a, I::Item>,
|
||||
replace_with: I,
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
impl<'a, I: Iterator> Iterator for Splice<'a, I> {
|
||||
type Item = I::Item;
|
||||
|
||||
|
|
@ -2572,18 +2572,18 @@ impl<'a, I: Iterator> Iterator for Splice<'a, I> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.drain.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {}
|
||||
|
||||
|
||||
#[stable(feature = "vec_splice", since = "1.22.0")]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
impl<'a, I: Iterator> Drop for Splice<'a, I> {
|
||||
fn drop(&mut self) {
|
||||
// exhaust drain first
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ impl<T> VecDeque<T> {
|
|||
.and_then(|needed_cap| needed_cap.checked_next_power_of_two())
|
||||
.expect("capacity overflow");
|
||||
|
||||
if new_cap > self.capacity() {
|
||||
if new_cap > old_cap {
|
||||
self.buf.reserve_exact(used_cap, new_cap - used_cap);
|
||||
unsafe {
|
||||
self.handle_cap_increase(old_cap);
|
||||
|
|
@ -1973,6 +1973,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
|||
self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
|
||||
unsafe { Some(self.ring.get_unchecked(self.head)) }
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = back.iter().rfold(accum, &mut f);
|
||||
front.iter().rfold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2058,6 +2066,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
|||
Some(&mut *(elem as *mut _))
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = back.iter_mut().rfold(accum, &mut f);
|
||||
front.iter_mut().rfold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ libc = { path = "../rustc/libc_shim" }
|
|||
|
||||
[build-dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
gcc = "0.3.50"
|
||||
cc = "1.0"
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#![deny(warnings)]
|
||||
|
||||
extern crate build_helper;
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -63,7 +63,7 @@ fn main() {
|
|||
_ => return,
|
||||
};
|
||||
|
||||
let compiler = gcc::Build::new().get_compiler();
|
||||
let compiler = cc::Build::new().get_compiler();
|
||||
// only msvc returns None for ar so unwrap is okay
|
||||
let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
|
||||
let cflags = compiler.args()
|
||||
|
|
@ -150,7 +150,7 @@ fn main() {
|
|||
// sure the symbols are available.
|
||||
if target.contains("androideabi") {
|
||||
println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
|
||||
gcc::Build::new()
|
||||
cc::Build::new()
|
||||
.flag("-fvisibility=hidden")
|
||||
.file("pthread_atfork_dummy.c")
|
||||
.compile("libpthread_atfork_dummy.a");
|
||||
|
|
|
|||
|
|
@ -147,40 +147,131 @@ fn bench_for_each_chain_ref_fold(b: &mut Bencher) {
|
|||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
.map(black_box)
|
||||
.sum()
|
||||
});
|
||||
|
||||
/// Helper to benchmark `sum` for iterators taken by value which
|
||||
/// can optimize `fold`, and by reference which cannot.
|
||||
macro_rules! bench_sums {
|
||||
($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => {
|
||||
#[bench]
|
||||
fn $bench_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
$iter.map(black_box).sum()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn $bench_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
$iter.map(black_box).by_ref().sum()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
.map(black_box)
|
||||
.by_ref()
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_flat_map_sum,
|
||||
bench_flat_map_ref_sum,
|
||||
(0i64..1000).flat_map(|x| x..x+1000)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_chain_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
.map(black_box)
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_flat_map_chain_sum,
|
||||
bench_flat_map_chain_ref_sum,
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_flat_map_chain_ref_sum(b: &mut Bencher) {
|
||||
b.iter(|| -> i64 {
|
||||
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
|
||||
.map(black_box)
|
||||
.by_ref()
|
||||
.sum()
|
||||
});
|
||||
bench_sums! {
|
||||
bench_enumerate_sum,
|
||||
bench_enumerate_ref_sum,
|
||||
(0i64..1000000).enumerate().map(|(i, x)| x * i as i64)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_enumerate_chain_sum,
|
||||
bench_enumerate_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_sum,
|
||||
bench_filter_ref_sum,
|
||||
(0i64..1000000).filter(|x| x % 2 == 0)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_chain_sum,
|
||||
bench_filter_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).filter(|x| x % 2 == 0)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_map_sum,
|
||||
bench_filter_map_ref_sum,
|
||||
(0i64..1000000).filter_map(|x| x.checked_mul(x))
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_filter_map_chain_sum,
|
||||
bench_filter_map_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x))
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_fuse_sum,
|
||||
bench_fuse_ref_sum,
|
||||
(0i64..1000000).fuse()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_fuse_chain_sum,
|
||||
bench_fuse_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).fuse()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_inspect_sum,
|
||||
bench_inspect_ref_sum,
|
||||
(0i64..1000000).inspect(|_| {})
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_inspect_chain_sum,
|
||||
bench_inspect_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).inspect(|_| {})
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_peekable_sum,
|
||||
bench_peekable_ref_sum,
|
||||
(0i64..1000000).peekable()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_peekable_chain_sum,
|
||||
bench_peekable_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).peekable()
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_sum,
|
||||
bench_skip_ref_sum,
|
||||
(0i64..1000000).skip(1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_chain_sum,
|
||||
bench_skip_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).skip(1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_while_sum,
|
||||
bench_skip_while_ref_sum,
|
||||
(0i64..1000000).skip_while(|&x| x < 1000)
|
||||
}
|
||||
|
||||
bench_sums! {
|
||||
bench_skip_while_chain_sum,
|
||||
bench_skip_while_chain_ref_sum,
|
||||
(0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
|||
/// assert_eq!(2, 1.max(2));
|
||||
/// assert_eq!(2, 2.max(2));
|
||||
/// ```
|
||||
#[stable(feature = "ord_max_min", since = "1.22.0")]
|
||||
#[stable(feature = "ord_max_min", since = "1.21.0")]
|
||||
fn max(self, other: Self) -> Self
|
||||
where Self: Sized {
|
||||
if other >= self { other } else { self }
|
||||
|
|
@ -472,7 +472,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
|||
/// assert_eq!(1, 1.min(2));
|
||||
/// assert_eq!(2, 2.min(2));
|
||||
/// ```
|
||||
#[stable(feature = "ord_max_min", since = "1.22.0")]
|
||||
#[stable(feature = "ord_max_min", since = "1.21.0")]
|
||||
fn min(self, other: Self) -> Self
|
||||
where Self: Sized {
|
||||
if self <= other { self } else { other }
|
||||
|
|
|
|||
|
|
@ -48,8 +48,25 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use str::FromStr;
|
||||
use fmt;
|
||||
|
||||
/// A type used as the error type for implementations of fallible conversion
|
||||
/// traits in cases where conversions cannot actually fail.
|
||||
///
|
||||
/// Because `Infallible` has no variants, a value of this type can never exist.
|
||||
/// It is used only to satisfy trait signatures that expect an error type, and
|
||||
/// signals to both the compiler and the user that the error case is impossible.
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Infallible {}
|
||||
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl fmt::Display for Infallible {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
}
|
||||
}
|
||||
}
|
||||
/// A cheap reference-to-reference conversion. Used to convert a value to a
|
||||
/// reference value within generic code.
|
||||
///
|
||||
|
|
@ -417,6 +434,17 @@ impl<T, U> TryInto<U> for T where U: TryFrom<T>
|
|||
}
|
||||
}
|
||||
|
||||
// Infallible conversions are semantically equivalent to fallible conversions
|
||||
// with an uninhabited error type.
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<T, U> TryFrom<U> for T where T: From<U> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn try_from(value: U) -> Result<Self, Self::Error> {
|
||||
Ok(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CONCRETE IMPLS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -442,14 +470,3 @@ impl AsRef<str> for str {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
// FromStr implies TryFrom<&str>
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<'a, T> TryFrom<&'a str> for T where T: FromStr
|
||||
{
|
||||
type Error = <T as FromStr>::Err;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<T, Self::Error> {
|
||||
FromStr::from_str(s)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -488,13 +488,14 @@ impl<'a> Display for Arguments<'a> {
|
|||
/// The origin is: Point { x: 0, y: 0 }
|
||||
/// ```
|
||||
///
|
||||
/// There are a number of `debug_*` methods on `Formatter` to help you with manual
|
||||
/// There are a number of `debug_*` methods on [`Formatter`] to help you with manual
|
||||
/// implementations, such as [`debug_struct`][debug_struct].
|
||||
///
|
||||
/// `Debug` implementations using either `derive` or the debug builder API
|
||||
/// on `Formatter` support pretty printing using the alternate flag: `{:#?}`.
|
||||
/// on [`Formatter`] support pretty printing using the alternate flag: `{:#?}`.
|
||||
///
|
||||
/// [debug_struct]: ../../std/fmt/struct.Formatter.html#method.debug_struct
|
||||
/// [`Formatter`]: ../../std/fmt/struct.Formatter.html
|
||||
///
|
||||
/// Pretty printing with `#?`:
|
||||
///
|
||||
|
|
@ -1321,8 +1322,11 @@ impl<'a> Formatter<'a> {
|
|||
self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
|
||||
}
|
||||
|
||||
/// Creates a `DebugStruct` builder designed to assist with creation of
|
||||
/// `fmt::Debug` implementations for structs.
|
||||
/// Creates a [`DebugStruct`] builder designed to assist with creation of
|
||||
/// [`fmt::Debug`] implementations for structs.
|
||||
///
|
||||
/// [`DebugStruct`]: ../../std/fmt/struct.DebugStruct.html
|
||||
/// [`fmt::Debug`]: ../../std/fmt/trait.Debug.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1700,8 +1704,18 @@ impl<T: ?Sized + Debug> Debug for RefCell<T> {
|
|||
.finish()
|
||||
}
|
||||
Err(_) => {
|
||||
// The RefCell is mutably borrowed so we can't look at its value
|
||||
// here. Show a placeholder instead.
|
||||
struct BorrowedPlaceholder;
|
||||
|
||||
impl Debug for BorrowedPlaceholder {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.write_str("<borrowed>")
|
||||
}
|
||||
}
|
||||
|
||||
f.debug_struct("RefCell")
|
||||
.field("value", &"<borrowed>")
|
||||
.field("value", &BorrowedPlaceholder)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,3 +68,22 @@ macro_rules! forward_ref_binop {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// implements "T op= &U", based on "T op= U"
|
||||
// where U is expected to be `Copy`able
|
||||
macro_rules! forward_ref_op_assign {
|
||||
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
|
||||
forward_ref_op_assign!(impl $imp, $method for $t, $u,
|
||||
#[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
|
||||
};
|
||||
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
|
||||
#[$attr]
|
||||
impl<'a> $imp<&'a $u> for $t {
|
||||
#[inline]
|
||||
fn $method(&mut self, other: &'a $u) {
|
||||
$imp::$method(self, *other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ pub trait Iterator {
|
|||
/// .for_each(|(i, x)| println!("{}:{}", i, x));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iterator_for_each", since = "1.22.0")]
|
||||
#[stable(feature = "iterator_for_each", since = "1.21.0")]
|
||||
fn for_each<F>(self, mut f: F) where
|
||||
Self: Sized, F: FnMut(Self::Item),
|
||||
{
|
||||
|
|
@ -1337,7 +1337,7 @@ pub trait Iterator {
|
|||
(left, right)
|
||||
}
|
||||
|
||||
/// An iterator adaptor that applies a function, producing a single, final value.
|
||||
/// An iterator method that applies a function, producing a single, final value.
|
||||
///
|
||||
/// `fold()` takes two arguments: an initial value, and a closure with two
|
||||
/// arguments: an 'accumulator', and an element. The closure returns the value that
|
||||
|
|
|
|||
|
|
@ -359,6 +359,12 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
|
|||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.rfold(init, f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
|
|
@ -379,6 +385,12 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.fold(init, f)
|
||||
}
|
||||
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
|
|
@ -449,6 +461,12 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
|
|||
fn next_back(&mut self) -> Option<T> {
|
||||
self.it.next_back().cloned()
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.rfold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
|
|
@ -470,7 +488,7 @@ impl<'a, I, T: 'a> FusedIterator for Cloned<I>
|
|||
{}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
|
||||
default 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 {
|
||||
|
|
@ -481,6 +499,18 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
|
|||
fn may_have_side_effect() -> bool { true }
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
|
||||
where I: TrustedRandomAccess<Item=&'a T>, T: Copy
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
*self.it.get_unchecked(i)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn may_have_side_effect() -> bool { false }
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
|
||||
where I: TrustedLen<Item=&'a T>,
|
||||
|
|
@ -528,7 +558,7 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
|
||||
|
||||
/// An adapter for stepping iterators by a custom amount.
|
||||
/// An iterator for stepping iterators by a custom amount.
|
||||
///
|
||||
/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
|
||||
/// its documentation for more.
|
||||
|
|
@ -761,6 +791,26 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
|
|||
ChainState::Back => self.b.next_back(),
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut accum = init;
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Back => {
|
||||
accum = self.b.rfold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Front => {
|
||||
accum = self.a.rfold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
accum
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Note: *both* must be fused to handle double-ended iterators.
|
||||
|
|
@ -1094,6 +1144,13 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F> where
|
|||
fn next_back(&mut self) -> Option<B> {
|
||||
self.iter.next_back().map(&mut self.f)
|
||||
}
|
||||
|
||||
fn rfold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||
where G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, elt| g(acc, f(elt)))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1193,6 +1250,18 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
|
|||
}
|
||||
count
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.fold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1208,6 +1277,18 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.rfold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -1259,6 +1340,17 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
|
|||
let (_, upper) = self.iter.size_hint();
|
||||
(0, upper) // can't know a lower bound, due to the predicate
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1274,6 +1366,17 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -1338,6 +1441,19 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
|
|||
fn count(self) -> usize {
|
||||
self.iter.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut count = self.count;
|
||||
self.iter.fold(init, move |acc, item| {
|
||||
let acc = fold(acc, (count, item));
|
||||
count += 1;
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1353,6 +1469,19 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
|
|||
(self.count + len, a)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
// Can safely add and subtract the count, as `ExactSizeIterator` promises
|
||||
// that the number of elements fits into a `usize`.
|
||||
let mut count = self.count + self.iter.len();
|
||||
self.iter.rfold(init, move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1464,6 +1593,18 @@ impl<I: Iterator> Iterator for Peekable<I> {
|
|||
let hi = hi.and_then(|x| x.checked_add(peek_len));
|
||||
(lo, hi)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let acc = match self.peeked {
|
||||
Some(None) => return init,
|
||||
Some(Some(v)) => fold(init, v),
|
||||
None => init,
|
||||
};
|
||||
self.iter.fold(acc, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1572,6 +1713,19 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
|
|||
let (_, upper) = self.iter.size_hint();
|
||||
(0, upper) // can't know a lower bound, due to the predicate
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if !self.flag {
|
||||
match self.next() {
|
||||
Some(v) => init = fold(init, v),
|
||||
None => return init,
|
||||
}
|
||||
}
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -1712,6 +1866,19 @@ impl<I> Iterator for Skip<I> where I: Iterator {
|
|||
|
||||
(lower, upper)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.n > 0 {
|
||||
// nth(n) skips n+1
|
||||
if self.iter.nth(self.n - 1).is_none() {
|
||||
return init;
|
||||
}
|
||||
}
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1934,6 +2101,16 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.frontiter.into_iter()
|
||||
.chain(self.iter.map(self.f).map(U::into_iter))
|
||||
.chain(self.backiter)
|
||||
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -2011,6 +2188,17 @@ impl<I> Iterator for Fuse<I> where I: Iterator {
|
|||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.done {
|
||||
init
|
||||
} else {
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2025,6 +2213,17 @@ impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
|
|||
next
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
if self.done {
|
||||
init
|
||||
} else {
|
||||
self.iter.rfold(init, fold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<I> TrustedRandomAccess for Fuse<I>
|
||||
|
|
@ -2065,6 +2264,13 @@ impl<I> Iterator for Fuse<I> where I: FusedIterator {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.fold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
|
||||
|
|
@ -2075,6 +2281,13 @@ impl<I> DoubleEndedIterator for Fuse<I>
|
|||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.rfold(init, fold)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2139,6 +2352,14 @@ impl<I: Iterator, F> Iterator for Inspect<I, F> where F: FnMut(&I::Item) {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2150,6 +2371,14 @@ impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
|
|||
let next = self.iter.next_back();
|
||||
self.do_inspect(next)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ macro_rules! step_impl_unsigned {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$t>::try_from(n) {
|
||||
Ok(n_as_t) => self.checked_add(n_as_t),
|
||||
|
|
@ -120,6 +121,7 @@ macro_rules! step_impl_signed {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$unsigned>::try_from(n) {
|
||||
Ok(n_as_unsigned) => {
|
||||
|
|
|
|||
|
|
@ -415,6 +415,70 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn next_back(&mut self) -> Option<Self::Item>;
|
||||
|
||||
/// An iterator method that reduces the iterator's elements to a single,
|
||||
/// final value, starting from the back.
|
||||
///
|
||||
/// This is the reverse version of [`fold()`]: it takes elements starting from
|
||||
/// the back of the iterator.
|
||||
///
|
||||
/// `rfold()` takes two arguments: an initial value, and a closure with two
|
||||
/// arguments: an 'accumulator', and an element. The closure returns the value that
|
||||
/// the accumulator should have for the next iteration.
|
||||
///
|
||||
/// The initial value is the value the accumulator will have on the first
|
||||
/// call.
|
||||
///
|
||||
/// After applying this closure to every element of the iterator, `rfold()`
|
||||
/// returns the accumulator.
|
||||
///
|
||||
/// This operation is sometimes called 'reduce' or 'inject'.
|
||||
///
|
||||
/// Folding is useful whenever you have a collection of something, and want
|
||||
/// to produce a single value from it.
|
||||
///
|
||||
/// [`fold()`]: trait.Iterator.html#method.fold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_rfold)]
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// // the sum of all of the elements of a
|
||||
/// let sum = a.iter()
|
||||
/// .rfold(0, |acc, &x| acc + x);
|
||||
///
|
||||
/// assert_eq!(sum, 6);
|
||||
/// ```
|
||||
///
|
||||
/// This example builds a string, starting with an initial value
|
||||
/// and continuing with each element from the back until the front:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_rfold)]
|
||||
/// let numbers = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let zero = "0".to_string();
|
||||
///
|
||||
/// let result = numbers.iter().rfold(zero, |acc, &x| {
|
||||
/// format!("({} + {})", x, acc)
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_rfold", issue = "44705")]
|
||||
fn rfold<B, F>(mut self, mut accum: B, mut f: F) -> B where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
while let Some(x) = self.next_back() {
|
||||
accum = f(accum, x);
|
||||
}
|
||||
accum
|
||||
}
|
||||
|
||||
/// Searches for an element of an iterator from the right that satisfies a predicate.
|
||||
///
|
||||
/// `rfind()` takes a closure that returns `true` or `false`. It applies
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub trait Sized {
|
|||
/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
/// [nomicon-coerce]: ../../nomicon/coercions.html
|
||||
#[unstable(feature = "unsize", issue = "27732")]
|
||||
#[lang="unsize"]
|
||||
#[lang = "unsize"]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
// Empty.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,15 +177,59 @@ pub fn forget<T>(t: T) {
|
|||
|
||||
/// Returns the size of a type in bytes.
|
||||
///
|
||||
/// More specifically, this is the offset in bytes between successive
|
||||
/// items of the same type, including alignment padding.
|
||||
/// More specifically, this is the offset in bytes between successive elements
|
||||
/// in an array with that item type including alignment padding. Thus, for any
|
||||
/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::<T>()`.
|
||||
///
|
||||
/// In general, the size of a type is not stable across compilations, but
|
||||
/// specific types such as primitives are.
|
||||
///
|
||||
/// The following table gives the size for primitives.
|
||||
///
|
||||
/// Type | size_of::\<Type>()
|
||||
/// ---- | ---------------
|
||||
/// () | 0
|
||||
/// u8 | 1
|
||||
/// u16 | 2
|
||||
/// u32 | 4
|
||||
/// u64 | 8
|
||||
/// i8 | 1
|
||||
/// i16 | 2
|
||||
/// i32 | 4
|
||||
/// i64 | 8
|
||||
/// f32 | 4
|
||||
/// f64 | 8
|
||||
/// char | 4
|
||||
///
|
||||
/// Furthermore, `usize` and `isize` have the same size.
|
||||
///
|
||||
/// The types `*const T`, `&T`, `Box<T>`, `Option<&T>`, and `Option<Box<T>>` all have
|
||||
/// the same size. If `T` is Sized, all of those types have the same size as `usize`.
|
||||
///
|
||||
/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T`
|
||||
/// have the same size. Likewise for `*const T` and `*mut T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// // Some primitives
|
||||
/// assert_eq!(4, mem::size_of::<i32>());
|
||||
/// assert_eq!(8, mem::size_of::<f64>());
|
||||
/// assert_eq!(0, mem::size_of::<()>());
|
||||
///
|
||||
/// // Some arrays
|
||||
/// assert_eq!(8, mem::size_of::<[i32; 2]>());
|
||||
/// assert_eq!(12, mem::size_of::<[i32; 3]>());
|
||||
/// assert_eq!(0, mem::size_of::<[i32; 0]>());
|
||||
///
|
||||
///
|
||||
/// // Pointer size equality
|
||||
/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>());
|
||||
/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Box<i32>>());
|
||||
/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Option<&i32>>());
|
||||
/// assert_eq!(mem::size_of::<Box<i32>>(), mem::size_of::<Option<Box<i32>>>());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -358,7 +402,7 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "needs_drop", since = "1.22.0")]
|
||||
#[stable(feature = "needs_drop", since = "1.21.0")]
|
||||
pub fn needs_drop<T>() -> bool {
|
||||
unsafe { intrinsics::needs_drop::<T>() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use str::FromStr;
|
||||
|
|
@ -2507,16 +2507,24 @@ impl fmt::Display for TryFromIntError {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl From<Infallible> for TryFromIntError {
|
||||
fn from(infallible: Infallible) -> TryFromIntError {
|
||||
match infallible {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no possible bounds violation
|
||||
macro_rules! try_from_unbounded {
|
||||
($source:ty, $($target:ty),*) => {$(
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl TryFrom<$source> for $target {
|
||||
type Error = TryFromIntError;
|
||||
type Error = Infallible;
|
||||
|
||||
#[inline]
|
||||
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
|
||||
Ok(u as $target)
|
||||
fn try_from(value: $source) -> Result<Self, Self::Error> {
|
||||
Ok(value as $target)
|
||||
}
|
||||
}
|
||||
)*}
|
||||
|
|
@ -2588,31 +2596,17 @@ macro_rules! rev {
|
|||
}
|
||||
|
||||
/// intra-sign conversions
|
||||
try_from_unbounded!(u8, u8, u16, u32, u64, u128);
|
||||
try_from_unbounded!(u16, u16, u32, u64, u128);
|
||||
try_from_unbounded!(u32, u32, u64, u128);
|
||||
try_from_unbounded!(u64, u64, u128);
|
||||
try_from_unbounded!(u128, u128);
|
||||
try_from_upper_bounded!(u16, u8);
|
||||
try_from_upper_bounded!(u32, u16, u8);
|
||||
try_from_upper_bounded!(u64, u32, u16, u8);
|
||||
try_from_upper_bounded!(u128, u64, u32, u16, u8);
|
||||
|
||||
try_from_unbounded!(i8, i8, i16, i32, i64, i128);
|
||||
try_from_unbounded!(i16, i16, i32, i64, i128);
|
||||
try_from_unbounded!(i32, i32, i64, i128);
|
||||
try_from_unbounded!(i64, i64, i128);
|
||||
try_from_unbounded!(i128, i128);
|
||||
try_from_both_bounded!(i16, i8);
|
||||
try_from_both_bounded!(i32, i16, i8);
|
||||
try_from_both_bounded!(i64, i32, i16, i8);
|
||||
try_from_both_bounded!(i128, i64, i32, i16, i8);
|
||||
|
||||
// unsigned-to-signed
|
||||
try_from_unbounded!(u8, i16, i32, i64, i128);
|
||||
try_from_unbounded!(u16, i32, i64, i128);
|
||||
try_from_unbounded!(u32, i64, i128);
|
||||
try_from_unbounded!(u64, i128);
|
||||
try_from_upper_bounded!(u8, i8);
|
||||
try_from_upper_bounded!(u16, i8, i16);
|
||||
try_from_upper_bounded!(u32, i8, i16, i32);
|
||||
|
|
@ -2631,15 +2625,13 @@ try_from_both_bounded!(i64, u32, u16, u8);
|
|||
try_from_both_bounded!(i128, u64, u32, u16, u8);
|
||||
|
||||
// usize/isize
|
||||
try_from_unbounded!(usize, usize);
|
||||
try_from_upper_bounded!(usize, isize);
|
||||
try_from_lower_bounded!(isize, usize);
|
||||
try_from_unbounded!(isize, isize);
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8);
|
||||
try_from_unbounded!(usize, u16, u32, u64, u128);
|
||||
|
|
@ -2651,21 +2643,21 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8);
|
||||
try_from_unbounded!(isize, i16, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16);
|
||||
rev!(try_from_unbounded, usize, u16);
|
||||
rev!(try_from_upper_bounded, usize, u32, u64, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16);
|
||||
rev!(try_from_both_bounded, usize, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8);
|
||||
rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16);
|
||||
rev!(try_from_unbounded, isize, i16);
|
||||
rev!(try_from_both_bounded, isize, i32, i64, i128);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8, u16);
|
||||
try_from_unbounded!(usize, u32, u64, u128);
|
||||
|
|
@ -2677,21 +2669,21 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8, i16);
|
||||
try_from_unbounded!(isize, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16, u32);
|
||||
rev!(try_from_unbounded, usize, u16, u32);
|
||||
rev!(try_from_upper_bounded, usize, u64, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16, i32);
|
||||
rev!(try_from_both_bounded, usize, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8, u16);
|
||||
rev!(try_from_upper_bounded, isize, u32, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16, i32);
|
||||
rev!(try_from_unbounded, isize, i16, i32);
|
||||
rev!(try_from_both_bounded, isize, i64, i128);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8, u16, u32);
|
||||
try_from_unbounded!(usize, u64, u128);
|
||||
|
|
@ -2703,14 +2695,14 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8, i16, i32);
|
||||
try_from_unbounded!(isize, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16, u32, u64);
|
||||
rev!(try_from_unbounded, usize, u16, u32, u64);
|
||||
rev!(try_from_upper_bounded, usize, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
|
||||
rev!(try_from_both_bounded, usize, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8, u16, u32);
|
||||
rev!(try_from_upper_bounded, isize, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16, i32, i64);
|
||||
rev!(try_from_unbounded, isize, i16, i32, i64);
|
||||
rev!(try_from_both_bounded, isize, i128);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ macro_rules! sh_impl_signed {
|
|||
*self = *self << other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Shr<$f> for Wrapping<$t> {
|
||||
|
|
@ -58,6 +59,7 @@ macro_rules! sh_impl_signed {
|
|||
*self = *self >> other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ macro_rules! sh_impl_unsigned {
|
|||
*self = *self << other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Shr<$f> for Wrapping<$t> {
|
||||
|
|
@ -98,6 +101,7 @@ macro_rules! sh_impl_unsigned {
|
|||
*self = *self >> other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +146,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Sub for Wrapping<$t> {
|
||||
|
|
@ -162,6 +167,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Mul for Wrapping<$t> {
|
||||
|
|
@ -182,6 +188,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self * other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "wrapping_div", since = "1.3.0")]
|
||||
impl Div for Wrapping<$t> {
|
||||
|
|
@ -202,6 +209,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self / other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "wrapping_impls", since = "1.7.0")]
|
||||
impl Rem for Wrapping<$t> {
|
||||
|
|
@ -222,6 +230,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self % other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Not for Wrapping<$t> {
|
||||
|
|
@ -254,6 +263,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self ^ other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl BitOr for Wrapping<$t> {
|
||||
|
|
@ -274,6 +284,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self | other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl BitAnd for Wrapping<$t> {
|
||||
|
|
@ -294,6 +305,7 @@ macro_rules! wrapping_impl {
|
|||
*self = *self & other;
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
|
||||
|
||||
#[stable(feature = "wrapping_neg", since = "1.10.0")]
|
||||
impl Neg for Wrapping<$t> {
|
||||
|
|
|
|||
|
|
@ -662,6 +662,8 @@ macro_rules! add_assign_impl {
|
|||
#[rustc_inherit_overflow_checks]
|
||||
fn add_assign(&mut self, other: $t) { *self += other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -713,6 +715,8 @@ macro_rules! sub_assign_impl {
|
|||
#[rustc_inherit_overflow_checks]
|
||||
fn sub_assign(&mut self, other: $t) { *self -= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -755,6 +759,8 @@ macro_rules! mul_assign_impl {
|
|||
#[rustc_inherit_overflow_checks]
|
||||
fn mul_assign(&mut self, other: $t) { *self *= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -796,6 +802,8 @@ macro_rules! div_assign_impl {
|
|||
#[inline]
|
||||
fn div_assign(&mut self, other: $t) { *self /= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -841,6 +849,8 @@ macro_rules! rem_assign_impl {
|
|||
#[inline]
|
||||
fn rem_assign(&mut self, other: $t) { *self %= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -593,6 +593,8 @@ macro_rules! bitand_assign_impl {
|
|||
#[inline]
|
||||
fn bitand_assign(&mut self, other: $t) { *self &= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -638,6 +640,8 @@ macro_rules! bitor_assign_impl {
|
|||
#[inline]
|
||||
fn bitor_assign(&mut self, other: $t) { *self |= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -683,6 +687,8 @@ macro_rules! bitxor_assign_impl {
|
|||
#[inline]
|
||||
fn bitxor_assign(&mut self, other: $t) { *self ^= other }
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
|
||||
)+)
|
||||
}
|
||||
|
||||
|
|
@ -729,6 +735,8 @@ macro_rules! shl_assign_impl {
|
|||
*self <<= other
|
||||
}
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -793,6 +801,8 @@ macro_rules! shr_assign_impl {
|
|||
*self >>= other
|
||||
}
|
||||
}
|
||||
|
||||
forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -241,9 +241,9 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An range bounded inclusively below and above (`start...end`).
|
||||
/// An range bounded inclusively below and above (`start..=end`).
|
||||
///
|
||||
/// The `RangeInclusive` `start...end` contains all values with `x >= start`
|
||||
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
|
||||
/// and `x <= end`.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -251,12 +251,12 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
|||
/// ```
|
||||
/// #![feature(inclusive_range,inclusive_range_syntax)]
|
||||
///
|
||||
/// assert_eq!((3...5), std::ops::RangeInclusive { start: 3, end: 5 });
|
||||
/// assert_eq!(3 + 4 + 5, (3...5).sum());
|
||||
/// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 });
|
||||
/// assert_eq!(3 + 4 + 5, (3..=5).sum());
|
||||
///
|
||||
/// let arr = [0, 1, 2, 3];
|
||||
/// assert_eq!(arr[ ...2], [0,1,2 ]);
|
||||
/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive
|
||||
/// assert_eq!(arr[ ..=2], [0,1,2 ]);
|
||||
/// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
|
|
@ -276,7 +276,7 @@ pub struct RangeInclusive<Idx> {
|
|||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{:?}...{:?}", self.start, self.end)
|
||||
write!(fmt, "{:?}..={:?}", self.start, self.end)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,32 +289,32 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
|||
/// ```
|
||||
/// #![feature(range_contains,inclusive_range_syntax)]
|
||||
///
|
||||
/// assert!(!(3...5).contains(2));
|
||||
/// assert!( (3...5).contains(3));
|
||||
/// assert!( (3...5).contains(4));
|
||||
/// assert!( (3...5).contains(5));
|
||||
/// assert!(!(3...5).contains(6));
|
||||
/// assert!(!(3..=5).contains(2));
|
||||
/// assert!( (3..=5).contains(3));
|
||||
/// assert!( (3..=5).contains(4));
|
||||
/// assert!( (3..=5).contains(5));
|
||||
/// assert!(!(3..=5).contains(6));
|
||||
///
|
||||
/// assert!( (3...3).contains(3));
|
||||
/// assert!(!(3...2).contains(3));
|
||||
/// assert!( (3..=3).contains(3));
|
||||
/// assert!(!(3..=2).contains(3));
|
||||
/// ```
|
||||
pub fn contains(&self, item: Idx) -> bool {
|
||||
self.start <= item && item <= self.end
|
||||
}
|
||||
}
|
||||
|
||||
/// A range only bounded inclusively above (`...end`).
|
||||
/// A range only bounded inclusively above (`..=end`).
|
||||
///
|
||||
/// The `RangeToInclusive` `...end` contains all values with `x <= end`.
|
||||
/// The `RangeToInclusive` `..=end` contains all values with `x <= end`.
|
||||
/// It cannot serve as an [`Iterator`] because it doesn't have a starting point.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `...end` syntax is a `RangeToInclusive`:
|
||||
/// The `..=end` syntax is a `RangeToInclusive`:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(inclusive_range,inclusive_range_syntax)]
|
||||
/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 });
|
||||
/// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 });
|
||||
/// ```
|
||||
///
|
||||
/// It does not have an [`IntoIterator`] implementation, so you can't use it in a
|
||||
|
|
@ -325,7 +325,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
|||
///
|
||||
/// // error[E0277]: the trait bound `std::ops::RangeToInclusive<{integer}>:
|
||||
/// // std::iter::Iterator` is not satisfied
|
||||
/// for i in ...5 {
|
||||
/// for i in ..=5 {
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
|
|
@ -337,8 +337,8 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
|||
/// #![feature(inclusive_range_syntax)]
|
||||
///
|
||||
/// let arr = [0, 1, 2, 3];
|
||||
/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive
|
||||
/// assert_eq!(arr[1...2], [ 1,2 ]);
|
||||
/// assert_eq!(arr[ ..=2], [0,1,2 ]); // RangeToInclusive
|
||||
/// assert_eq!(arr[1..=2], [ 1,2 ]);
|
||||
/// ```
|
||||
///
|
||||
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
||||
|
|
@ -357,7 +357,7 @@ pub struct RangeToInclusive<Idx> {
|
|||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "...{:?}", self.end)
|
||||
write!(fmt, "..={:?}", self.end)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,9 +370,9 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
|
|||
/// ```
|
||||
/// #![feature(range_contains,inclusive_range_syntax)]
|
||||
///
|
||||
/// assert!( (...5).contains(-1_000_000_000));
|
||||
/// assert!( (...5).contains(5));
|
||||
/// assert!(!(...5).contains(6));
|
||||
/// assert!( (..=5).contains(-1_000_000_000));
|
||||
/// assert!( (..=5).contains(5));
|
||||
/// assert!(!(..=5).contains(6));
|
||||
/// ```
|
||||
pub fn contains(&self, item: Idx) -> bool {
|
||||
(item <= self.end)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ use marker::Unsize;
|
|||
/// [unsize]: ../marker/trait.Unsize.html
|
||||
/// [nomicon-coerce]: ../../nomicon/coercions.html
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
#[lang="coerce_unsized"]
|
||||
#[lang = "coerce_unsized"]
|
||||
pub trait CoerceUnsized<T> {
|
||||
// Empty.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@
|
|||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use iter::{FromIterator, FusedIterator, TrustedLen};
|
||||
use mem;
|
||||
use {mem, ops};
|
||||
|
||||
// Note that this is not a lang item per se, but it has a hidden dependency on
|
||||
// `Iterator`, which is one. The compiler assumes that the `next` method of
|
||||
|
|
@ -1123,3 +1123,29 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type that results from applying the try operator (`?`) to a `None` value. If you wish
|
||||
/// to allow `x?` (where `x` is an `Option<T>`) to be converted into your error type, you can
|
||||
/// implement `impl From<NoneError>` for `YourErrorType`. In that case, `x?` within a function that
|
||||
/// returns `Result<_, YourErrorType>` will translate a `None` value into an `Err` result.
|
||||
#[unstable(feature = "try_trait", issue = "42327")]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||
pub struct NoneError;
|
||||
|
||||
#[unstable(feature = "try_trait", issue = "42327")]
|
||||
impl<T> ops::Try for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
|
||||
fn from_ok(v: T) -> Self {
|
||||
Some(v)
|
||||
}
|
||||
|
||||
fn from_error(_: NoneError) -> Self {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub use intrinsics::write_bytes;
|
|||
/// This has all the same safety problems as `ptr::read` with respect to
|
||||
/// invalid pointers, types, and double drops.
|
||||
#[stable(feature = "drop_in_place", since = "1.8.0")]
|
||||
#[lang="drop_in_place"]
|
||||
#[lang = "drop_in_place"]
|
||||
#[allow(unconditional_recursion)]
|
||||
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
// Code here does not matter - this is replaced by the
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
// FIXME: after next stage0, change RangeInclusive { ... } back to ..=
|
||||
use ops::RangeInclusive;
|
||||
|
||||
// How this module is organized.
|
||||
//
|
||||
// The library infrastructure for slices is fairly messy. There's
|
||||
|
|
@ -1044,32 +1047,32 @@ impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
|||
|
||||
#[inline]
|
||||
fn get(self, slice: &[T]) -> Option<&[T]> {
|
||||
(0...self.end).get(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).get(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
|
||||
(0...self.end).get_mut(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).get_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
|
||||
(0...self.end).get_unchecked(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).get_unchecked(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
(0...self.end).get_unchecked_mut(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).get_unchecked_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self, slice: &[T]) -> &[T] {
|
||||
(0...self.end).index(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).index(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
(0...self.end).index_mut(slice)
|
||||
(RangeInclusive { start: 0, end: self.end }).index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ use self::pattern::Pattern;
|
|||
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
|
||||
|
||||
use char;
|
||||
use convert::TryFrom;
|
||||
use fmt;
|
||||
use iter::{Map, Cloned, FusedIterator};
|
||||
use iter::{Map, Cloned, FusedIterator, TrustedLen};
|
||||
use iter_private::TrustedRandomAccess;
|
||||
use slice::{self, SliceIndex};
|
||||
use mem;
|
||||
|
||||
|
|
@ -818,6 +818,17 @@ impl<'a> ExactSizeIterator for Bytes<'a> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a> FusedIterator for Bytes<'a> {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<'a> TrustedLen for Bytes<'a> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a> TrustedRandomAccess for Bytes<'a> {
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> u8 {
|
||||
self.0.get_unchecked(i)
|
||||
}
|
||||
fn may_have_side_effect() -> bool { false }
|
||||
}
|
||||
|
||||
/// This macro generates a Clone impl for string pattern API
|
||||
/// wrapper types of the form X<'a, P>
|
||||
macro_rules! derive_pattern_clone {
|
||||
|
|
@ -1399,9 +1410,6 @@ Section: Comparing strings
|
|||
*/
|
||||
|
||||
/// Bytewise slice equality
|
||||
/// NOTE: This function is (ab)used in rustc::middle::trans::_match
|
||||
/// to compare &[u8] byte slices that are not necessarily valid UTF-8.
|
||||
#[lang = "str_eq"]
|
||||
#[inline]
|
||||
fn eq_slice(a: &str, b: &str) -> bool {
|
||||
a.as_bytes() == b.as_bytes()
|
||||
|
|
@ -2189,7 +2197,7 @@ pub trait StrExt {
|
|||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn is_empty(&self) -> bool;
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn parse<'a, T: TryFrom<&'a str>>(&'a self) -> Result<T, T::Error>;
|
||||
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
|
||||
}
|
||||
|
||||
// truncate `&str` to length at most equal to `max`
|
||||
|
|
@ -2509,9 +2517,7 @@ impl StrExt for str {
|
|||
fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
#[inline]
|
||||
fn parse<'a, T>(&'a self) -> Result<T, T::Error> where T: TryFrom<&'a str> {
|
||||
T::try_from(self)
|
||||
}
|
||||
fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -926,10 +926,24 @@ macro_rules! atomic_int {
|
|||
$stable_cxchg:meta,
|
||||
$stable_debug:meta,
|
||||
$stable_access:meta,
|
||||
$s_int_type:expr, $int_ref:expr,
|
||||
$int_type:ident $atomic_type:ident $atomic_init:ident) => {
|
||||
/// An integer type which can be safely shared between threads.
|
||||
///
|
||||
/// This type has the same in-memory representation as the underlying integer type.
|
||||
/// This type has the same in-memory representation as the underlying
|
||||
/// integer type, [`
|
||||
#[doc = $s_int_type]
|
||||
/// `](
|
||||
#[doc = $int_ref]
|
||||
/// ). For more about the differences between atomic types and
|
||||
/// non-atomic types, please see the [module-level documentation].
|
||||
///
|
||||
/// Please note that examples are shared between atomic variants of
|
||||
/// primitive integer types, so it's normal that they are all
|
||||
/// demonstrating [`AtomicIsize`].
|
||||
///
|
||||
/// [module-level documentation]: index.html
|
||||
/// [`AtomicIsize`]: struct.AtomicIsize.html
|
||||
#[$stable]
|
||||
pub struct $atomic_type {
|
||||
v: UnsafeCell<$int_type>,
|
||||
|
|
@ -1339,6 +1353,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"i8", "../../../std/primitive.i8.html",
|
||||
i8 AtomicI8 ATOMIC_I8_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
|
|
@ -1348,6 +1363,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"u8", "../../../std/primitive.u8.html",
|
||||
u8 AtomicU8 ATOMIC_U8_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
|
|
@ -1357,6 +1373,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"i16", "../../../std/primitive.i16.html",
|
||||
i16 AtomicI16 ATOMIC_I16_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
|
|
@ -1366,6 +1383,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"u16", "../../../std/primitive.u16.html",
|
||||
u16 AtomicU16 ATOMIC_U16_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
|
|
@ -1375,6 +1393,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"i32", "../../../std/primitive.i32.html",
|
||||
i32 AtomicI32 ATOMIC_I32_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
|
|
@ -1384,6 +1403,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"u32", "../../../std/primitive.u32.html",
|
||||
u32 AtomicU32 ATOMIC_U32_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
|
|
@ -1393,6 +1413,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"i64", "../../../std/primitive.i64.html",
|
||||
i64 AtomicI64 ATOMIC_I64_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
|
|
@ -1402,6 +1423,7 @@ atomic_int! {
|
|||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
unstable(feature = "integer_atomics", issue = "32976"),
|
||||
"u64", "../../../std/primitive.u64.html",
|
||||
u64 AtomicU64 ATOMIC_U64_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
|
|
@ -1411,6 +1433,7 @@ atomic_int!{
|
|||
stable(feature = "extended_compare_and_swap", since = "1.10.0"),
|
||||
stable(feature = "atomic_debug", since = "1.3.0"),
|
||||
stable(feature = "atomic_access", since = "1.15.0"),
|
||||
"isize", "../../../std/primitive.isize.html",
|
||||
isize AtomicIsize ATOMIC_ISIZE_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
|
|
@ -1420,6 +1443,7 @@ atomic_int!{
|
|||
stable(feature = "extended_compare_and_swap", since = "1.10.0"),
|
||||
stable(feature = "atomic_debug", since = "1.3.0"),
|
||||
stable(feature = "atomic_access", since = "1.15.0"),
|
||||
"usize", "../../../std/primitive.usize.html",
|
||||
usize AtomicUsize ATOMIC_USIZE_INIT
|
||||
}
|
||||
|
||||
|
|
@ -1752,7 +1776,7 @@ pub fn fence(order: Ordering) {
|
|||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt
|
||||
#[inline]
|
||||
#[stable(feature = "compiler_fences", since = "1.22.0")]
|
||||
#[stable(feature = "compiler_fences", since = "1.21.0")]
|
||||
pub fn compiler_fence(order: Ordering) {
|
||||
unsafe {
|
||||
match order {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ fn test_convert() {
|
|||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(char::from_str("a").unwrap(), 'a');
|
||||
assert_eq!(char::try_from("a").unwrap(), 'a');
|
||||
assert_eq!(char::from_str("\0").unwrap(), '\0');
|
||||
assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}');
|
||||
assert!(char::from_str("").is_err());
|
||||
|
|
|
|||
|
|
@ -248,6 +248,25 @@ fn test_filter_map() {
|
|||
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filter_map_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let ys = [0*0, 2*2, 4*4, 6*6, 8*8];
|
||||
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
|
||||
let i = it.fold(0, |i, x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
|
||||
let i = it.rfold(ys.len(), |i, x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
|
|
@ -282,7 +301,31 @@ fn test_iterator_enumerate_nth() {
|
|||
#[test]
|
||||
fn test_iterator_enumerate_count() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
assert_eq!(xs.iter().count(), 6);
|
||||
assert_eq!(xs.iter().enumerate().count(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().enumerate();
|
||||
// steal a couple to get an interesting offset
|
||||
assert_eq!(it.next(), Some((0, &0)));
|
||||
assert_eq!(it.next(), Some((1, &1)));
|
||||
let i = it.fold(2, |i, (j, &x)| {
|
||||
assert_eq!(i, j);
|
||||
assert_eq!(x, xs[j]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
|
||||
let mut it = xs.iter().enumerate();
|
||||
assert_eq!(it.next(), Some((0, &0)));
|
||||
let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
|
||||
assert_eq!(i, j);
|
||||
assert_eq!(x, xs[j]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -291,6 +334,25 @@ fn test_iterator_filter_count() {
|
|||
assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_filter_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let ys = [0, 2, 4, 6, 8];
|
||||
let it = xs.iter().filter(|&&x| x % 2 == 0);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let it = xs.iter().filter(|&&x| x % 2 == 0);
|
||||
let i = it.rfold(ys.len(), |i, &x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_peekable() {
|
||||
let xs = vec![0, 1, 2, 3, 4, 5];
|
||||
|
|
@ -381,6 +443,18 @@ fn test_iterator_peekable_last() {
|
|||
assert_eq!(it.last(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_peekable_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().peekable();
|
||||
assert_eq!(it.peek(), Some(&&0));
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
|
||||
/// This is an iterator that follows the Iterator contract,
|
||||
/// but it is not fused. After having returned None once, it will start
|
||||
/// producing elements if .next() is called again.
|
||||
|
|
@ -470,6 +544,26 @@ fn test_iterator_skip_while() {
|
|||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip_while_fold() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
let ys = [15, 16, 17, 19];
|
||||
let it = xs.iter().skip_while(|&x| *x < 15);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().skip_while(|&x| *x < 15);
|
||||
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
|
||||
let i = it.fold(1, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
|
||||
|
|
@ -566,6 +660,26 @@ fn test_iterator_skip_last() {
|
|||
assert_eq!(it.last(), Some(&30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_skip_fold() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
|
||||
let ys = [13, 15, 16, 17, 19, 20, 30];
|
||||
let it = xs.iter().skip(5);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().skip(5);
|
||||
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
|
||||
let i = it.fold(1, |i, &x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_take() {
|
||||
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
|
|
@ -661,13 +775,22 @@ fn test_iterator_flat_map_fold() {
|
|||
let xs = [0, 3, 6];
|
||||
let ys = [1, 2, 3, 4, 5, 6, 7];
|
||||
let mut it = xs.iter().flat_map(|&x| x..x+3);
|
||||
it.next();
|
||||
it.next_back();
|
||||
assert_eq!(it.next(), Some(0));
|
||||
assert_eq!(it.next_back(), Some(8));
|
||||
let i = it.fold(0, |i, x| {
|
||||
assert_eq!(x, ys[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, ys.len());
|
||||
|
||||
let mut it = xs.iter().flat_map(|&x| x..x+3);
|
||||
assert_eq!(it.next(), Some(0));
|
||||
assert_eq!(it.next_back(), Some(8));
|
||||
let i = it.rfold(ys.len(), |i, x| {
|
||||
assert_eq!(x, ys[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -684,6 +807,32 @@ fn test_inspect() {
|
|||
assert_eq!(&xs[..], &ys[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inspect_fold() {
|
||||
let xs = [1, 2, 3, 4];
|
||||
let mut n = 0;
|
||||
{
|
||||
let it = xs.iter().inspect(|_| n += 1);
|
||||
let i = it.fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
assert_eq!(n, xs.len());
|
||||
|
||||
let mut n = 0;
|
||||
{
|
||||
let it = xs.iter().inspect(|_| n += 1);
|
||||
let i = it.rfold(xs.len(), |i, &x| {
|
||||
assert_eq!(x, xs[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
}
|
||||
assert_eq!(n, xs.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cycle() {
|
||||
let cycle_len = 3;
|
||||
|
|
@ -1094,21 +1243,21 @@ fn test_range() {
|
|||
|
||||
#[test]
|
||||
fn test_range_inclusive_exhaustion() {
|
||||
let mut r = 10...10;
|
||||
let mut r = 10..=10;
|
||||
assert_eq!(r.next(), Some(10));
|
||||
assert_eq!(r, 1...0);
|
||||
assert_eq!(r, 1..=0);
|
||||
|
||||
let mut r = 10...10;
|
||||
let mut r = 10..=10;
|
||||
assert_eq!(r.next_back(), Some(10));
|
||||
assert_eq!(r, 1...0);
|
||||
assert_eq!(r, 1..=0);
|
||||
|
||||
let mut r = 10...12;
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.nth(2), Some(12));
|
||||
assert_eq!(r, 1...0);
|
||||
assert_eq!(r, 1..=0);
|
||||
|
||||
let mut r = 10...12;
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.nth(5), None);
|
||||
assert_eq!(r, 1...0);
|
||||
assert_eq!(r, 1..=0);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1145,20 +1294,20 @@ fn test_range_from_nth() {
|
|||
|
||||
#[test]
|
||||
fn test_range_inclusive_nth() {
|
||||
assert_eq!((10...15).nth(0), Some(10));
|
||||
assert_eq!((10...15).nth(1), Some(11));
|
||||
assert_eq!((10...15).nth(5), Some(15));
|
||||
assert_eq!((10...15).nth(6), None);
|
||||
assert_eq!((10..=15).nth(0), Some(10));
|
||||
assert_eq!((10..=15).nth(1), Some(11));
|
||||
assert_eq!((10..=15).nth(5), Some(15));
|
||||
assert_eq!((10..=15).nth(6), None);
|
||||
|
||||
let mut r = 10_u8...20;
|
||||
let mut r = 10_u8..=20;
|
||||
assert_eq!(r.nth(2), Some(12));
|
||||
assert_eq!(r, 13...20);
|
||||
assert_eq!(r, 13..=20);
|
||||
assert_eq!(r.nth(2), Some(15));
|
||||
assert_eq!(r, 16...20);
|
||||
assert_eq!(r, 16..=20);
|
||||
assert_eq!(r.is_empty(), 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!(r, 1..=0); // We may not want to document/promise this detail
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1241,6 +1390,31 @@ fn test_fuse_count() {
|
|||
// Can't check len now because count consumes.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fuse_fold() {
|
||||
let xs = [0, 1, 2];
|
||||
let it = xs.iter(); // `FusedIterator`
|
||||
let i = it.fuse().fold(0, |i, &x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
|
||||
let it = xs.iter(); // `FusedIterator`
|
||||
let i = it.fuse().rfold(xs.len(), |i, &x| {
|
||||
assert_eq!(x, xs[i - 1]);
|
||||
i - 1
|
||||
});
|
||||
assert_eq!(i, 0);
|
||||
|
||||
let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
|
||||
let i = it.fuse().fold(0, |i, x| {
|
||||
assert_eq!(x, xs[i]);
|
||||
i + 1
|
||||
});
|
||||
assert_eq!(i, xs.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_once() {
|
||||
let mut it = once(42);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#![feature(inclusive_range)]
|
||||
#![feature(inclusive_range_syntax)]
|
||||
#![feature(iter_rfind)]
|
||||
#![feature(iter_rfold)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(rand)]
|
||||
#![feature(raw)]
|
||||
|
|
@ -38,6 +39,7 @@
|
|||
#![feature(test)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_from)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(unique)]
|
||||
|
||||
#![feature(const_atomic_bool_new)]
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::cmp::PartialEq;
|
||||
use core::fmt::Debug;
|
||||
use core::marker::Copy;
|
||||
use core::num::TryFromIntError;
|
||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
|
|
@ -134,6 +135,13 @@ fn test_empty() {
|
|||
assert_eq!("".parse::<u8>().ok(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_infallible_try_from_int_error() {
|
||||
let func = |x: i8| -> Result<i32, TryFromIntError> { Ok(x.try_into()?) };
|
||||
|
||||
assert!(func(0).is_ok());
|
||||
}
|
||||
|
||||
macro_rules! test_impl_from {
|
||||
($fn_name: ident, $Small: ty, $Large: ty) => {
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -270,3 +270,30 @@ fn test_cloned() {
|
|||
assert_eq!(opt_ref_ref.clone().cloned(), Some(&val));
|
||||
assert_eq!(opt_ref_ref.cloned().cloned(), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try() {
|
||||
fn try_option_some() -> Option<u8> {
|
||||
let val = Some(1)?;
|
||||
Some(val)
|
||||
}
|
||||
assert_eq!(try_option_some(), Some(1));
|
||||
|
||||
fn try_option_none() -> Option<u8> {
|
||||
let val = None?;
|
||||
Some(val)
|
||||
}
|
||||
assert_eq!(try_option_none(), None);
|
||||
|
||||
fn try_option_ok() -> Result<u8, NoneError> {
|
||||
let val = Some(1)?;
|
||||
Ok(val)
|
||||
}
|
||||
assert_eq!(try_option_ok(), Ok(1));
|
||||
|
||||
fn try_option_err() -> Result<u8, NoneError> {
|
||||
let val = None?;
|
||||
Ok(val)
|
||||
}
|
||||
assert_eq!(try_option_err(), Err(NoneError));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::option::*;
|
||||
|
||||
fn op1() -> Result<isize, &'static str> { Ok(666) }
|
||||
fn op2() -> Result<isize, &'static str> { Err("sadface") }
|
||||
|
||||
|
|
@ -202,3 +204,30 @@ pub fn test_unwrap_or_default() {
|
|||
assert_eq!(op1().unwrap_or_default(), 666);
|
||||
assert_eq!(op2().unwrap_or_default(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try() {
|
||||
fn try_result_some() -> Option<u8> {
|
||||
let val = Ok(1)?;
|
||||
Some(val)
|
||||
}
|
||||
assert_eq!(try_result_some(), Some(1));
|
||||
|
||||
fn try_result_none() -> Option<u8> {
|
||||
let val = Err(NoneError)?;
|
||||
Some(val)
|
||||
}
|
||||
assert_eq!(try_result_none(), None);
|
||||
|
||||
fn try_result_ok() -> Result<u8, u8> {
|
||||
let val = Ok(1)?;
|
||||
Ok(val)
|
||||
}
|
||||
assert_eq!(try_result_ok(), Ok(1));
|
||||
|
||||
fn try_result_err() -> Result<u8, u8> {
|
||||
let val = Err(1)?;
|
||||
Ok(val)
|
||||
}
|
||||
assert_eq!(try_result_err(), Err(1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 95848f9622deccc9cbadcd5d3a4faef01a90ead4
|
||||
Subproject commit 44e4018e1a37716286ec98cb5b7dd7d33ecaf940
|
||||
|
|
@ -509,6 +509,7 @@ impl TokenTree {
|
|||
Dot => op!('.'),
|
||||
DotDot => joint!('.', Dot),
|
||||
DotDotDot => joint!('.', DotDot),
|
||||
DotDotEq => joint!('.', DotEq),
|
||||
Comma => op!(','),
|
||||
Semi => op!(';'),
|
||||
Colon => op!(':'),
|
||||
|
|
@ -531,6 +532,7 @@ impl TokenTree {
|
|||
})
|
||||
}
|
||||
|
||||
DotEq => unreachable!(),
|
||||
OpenDelim(..) | CloseDelim(..) => unreachable!(),
|
||||
Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -202,8 +202,8 @@ impl Quote for Token {
|
|||
|
||||
gen_match! {
|
||||
Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot,
|
||||
Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question,
|
||||
Underscore;
|
||||
DotDotEq, Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar,
|
||||
Question, Underscore;
|
||||
|
||||
Token::OpenDelim(delim) => quote!(rt::token::OpenDelim((quote delim))),
|
||||
Token::CloseDelim(delim) => quote!(rt::token::CloseDelim((quote delim))),
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ doc = false
|
|||
core = { path = "../libcore" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3.50"
|
||||
cc = "1.0"
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
//!
|
||||
//! See the build.rs for libcompiler_builtins crate for details.
|
||||
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").expect("TARGET was not set");
|
||||
let cfg = &mut gcc::Build::new();
|
||||
let cfg = &mut cc::Build::new();
|
||||
|
||||
let mut profile_sources = vec!["GCDAProfiling.c",
|
||||
"InstrProfiling.c",
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ incremental improves that may change.)
|
|||
|
||||
The dependency structure of these crates is roughly a diamond:
|
||||
|
||||
````
|
||||
```
|
||||
rustc_driver
|
||||
/ | \
|
||||
/ | \
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
//! user of the `DepNode` API of having to know how to compute the expected
|
||||
//! fingerprint for a given set of node parameters.
|
||||
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
use hir::map::DefPathHash;
|
||||
use hir::{HirId, ItemLocalId};
|
||||
|
||||
|
|
@ -80,14 +80,28 @@ macro_rules! erase {
|
|||
($x:tt) => ({})
|
||||
}
|
||||
|
||||
macro_rules! anon_attr_to_bool {
|
||||
(anon) => (true)
|
||||
macro_rules! is_anon_attr {
|
||||
(anon) => (true);
|
||||
($attr:ident) => (false);
|
||||
}
|
||||
|
||||
macro_rules! is_input_attr {
|
||||
(input) => (true);
|
||||
($attr:ident) => (false);
|
||||
}
|
||||
|
||||
macro_rules! contains_anon_attr {
|
||||
($($attr:ident),*) => ({$(is_anon_attr!($attr) | )* false});
|
||||
}
|
||||
|
||||
macro_rules! contains_input_attr {
|
||||
($($attr:ident),*) => ({$(is_input_attr!($attr) | )* false});
|
||||
}
|
||||
|
||||
macro_rules! define_dep_nodes {
|
||||
(<$tcx:tt>
|
||||
$(
|
||||
[$($anon:ident)*]
|
||||
[$($attr:ident),* ]
|
||||
$variant:ident $(( $($tuple_arg:tt),* ))*
|
||||
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
|
||||
,)*
|
||||
|
|
@ -105,7 +119,9 @@ macro_rules! define_dep_nodes {
|
|||
match *self {
|
||||
$(
|
||||
DepKind :: $variant => {
|
||||
$(return !anon_attr_to_bool!($anon);)*
|
||||
if contains_anon_attr!($($attr),*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// tuple args
|
||||
$({
|
||||
|
|
@ -126,15 +142,20 @@ macro_rules! define_dep_nodes {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
#[inline]
|
||||
pub fn is_anon<$tcx>(&self) -> bool {
|
||||
pub fn is_anon(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
DepKind :: $variant => {
|
||||
$(return anon_attr_to_bool!($anon);)*
|
||||
false
|
||||
}
|
||||
DepKind :: $variant => { contains_anon_attr!($($attr),*) }
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_input(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
DepKind :: $variant => { contains_input_attr!($($attr),*) }
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
|
@ -366,6 +387,17 @@ impl DefId {
|
|||
}
|
||||
}
|
||||
|
||||
impl DepKind {
|
||||
#[inline]
|
||||
pub fn fingerprint_needed_for_crate_hash(self) -> bool {
|
||||
match self {
|
||||
DepKind::HirBody |
|
||||
DepKind::Krate => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_dep_nodes!( <'tcx>
|
||||
// Represents the `Krate` as a whole (the `hir::Krate` value) (as
|
||||
// distinct from the krate module). This is basically a hash of
|
||||
|
|
@ -378,18 +410,17 @@ define_dep_nodes!( <'tcx>
|
|||
// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
|
||||
// access to the krate, but you must remember to add suitable
|
||||
// edges yourself for the individual items that you read.
|
||||
[] Krate,
|
||||
|
||||
// Represents the HIR node with the given node-id
|
||||
[] Hir(DefId),
|
||||
[input] Krate,
|
||||
|
||||
// Represents the body of a function or method. The def-id is that of the
|
||||
// function/method.
|
||||
[] HirBody(DefId),
|
||||
[input] HirBody(DefId),
|
||||
|
||||
// Represents the metadata for a given HIR node, typically found
|
||||
// in an extern crate.
|
||||
[] MetaData(DefId),
|
||||
// Represents the HIR node with the given node-id
|
||||
[input] Hir(DefId),
|
||||
|
||||
// Represents metadata from an extern crate.
|
||||
[input] CrateMetadata(CrateNum),
|
||||
|
||||
// Represents some artifact that we save to disk. Note that these
|
||||
// do not have a def-id as part of their identifier.
|
||||
|
|
@ -414,6 +445,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] BorrowCheckKrate,
|
||||
[] BorrowCheck(DefId),
|
||||
[] MirBorrowCheck(DefId),
|
||||
[] UnsafetyViolations(DefId),
|
||||
|
||||
[] RvalueCheck(DefId),
|
||||
[] Reachability,
|
||||
|
|
@ -529,7 +561,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] ExternCrate(DefId),
|
||||
[] LintLevels,
|
||||
[] Specializes { impl1: DefId, impl2: DefId },
|
||||
[] InScopeTraits(DefIndex),
|
||||
[input] InScopeTraits(DefIndex),
|
||||
[] ModuleExports(DefId),
|
||||
[] IsSanitizerRuntime(CrateNum),
|
||||
[] IsProfilerRuntime(CrateNum),
|
||||
|
|
@ -647,6 +679,22 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefIndex,
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (CrateNum,) {
|
||||
const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
|
||||
|
||||
fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
|
||||
let def_id = DefId {
|
||||
krate: self.0,
|
||||
index: CRATE_DEF_INDEX,
|
||||
};
|
||||
tcx.def_path_hash(def_id).0
|
||||
}
|
||||
|
||||
fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
|
||||
tcx.crate_name(self.0).as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, DefId) {
|
||||
const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use std::mem;
|
|||
use super::{DepGraphQuery, DepKind, DepNode};
|
||||
use super::debug::EdgeFilter;
|
||||
|
||||
pub struct DepGraphEdges {
|
||||
pub(super) struct DepGraphEdges {
|
||||
nodes: Vec<DepNode>,
|
||||
indices: FxHashMap<DepNode, DepNodeIndex>,
|
||||
edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
|
||||
|
|
@ -31,8 +31,8 @@ pub struct DepGraphEdges {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DepNodeIndex {
|
||||
index: u32
|
||||
pub(super) struct DepNodeIndex {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl DepNodeIndex {
|
||||
|
|
@ -123,6 +123,7 @@ impl DepGraphEdges {
|
|||
reads
|
||||
} = popped_node {
|
||||
debug_assert_eq!(node, key);
|
||||
debug_assert!(!node.kind.is_input() || reads.is_empty());
|
||||
|
||||
let target_id = self.get_or_create_node(node);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
StableHashingContextProvider};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use session::config::OutputType;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
use util::common::{ProfileQueriesMsg, profq_msg};
|
||||
|
||||
|
|
@ -22,17 +24,56 @@ use super::dep_node::{DepNode, DepKind, WorkProductId};
|
|||
use super::query::DepGraphQuery;
|
||||
use super::raii;
|
||||
use super::safe::DepGraphSafe;
|
||||
use super::edges::{DepGraphEdges, DepNodeIndex};
|
||||
use super::edges::{self, DepGraphEdges};
|
||||
use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
|
||||
use super::prev::PreviousDepGraph;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DepGraph {
|
||||
data: Option<Rc<DepGraphData>>
|
||||
data: Option<Rc<DepGraphData>>,
|
||||
|
||||
// At the moment we are using DepNode as key here. In the future it might
|
||||
// be possible to use an IndexVec<DepNodeIndex, _> here. At the moment there
|
||||
// are a few problems with that:
|
||||
// - Some fingerprints are needed even if incr. comp. is disabled -- yet
|
||||
// we need to have a dep-graph to generate DepNodeIndices.
|
||||
// - The architecture is still in flux and it's not clear what how to best
|
||||
// implement things.
|
||||
fingerprints: Rc<RefCell<FxHashMap<DepNode, Fingerprint>>>
|
||||
}
|
||||
|
||||
/// As a temporary measure, while transitioning to the new DepGraph
|
||||
/// implementation, we maintain the old and the new dep-graph encoding in
|
||||
/// parallel, so a DepNodeIndex actually contains two indices, one for each
|
||||
/// version.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DepNodeIndex {
|
||||
legacy: edges::DepNodeIndex,
|
||||
new: DepNodeIndexNew,
|
||||
}
|
||||
|
||||
impl DepNodeIndex {
|
||||
pub const INVALID: DepNodeIndex = DepNodeIndex {
|
||||
legacy: edges::DepNodeIndex::INVALID,
|
||||
new: DepNodeIndexNew::INVALID,
|
||||
};
|
||||
}
|
||||
|
||||
struct DepGraphData {
|
||||
/// The actual graph data.
|
||||
/// The old, initial encoding of the dependency graph. This will soon go
|
||||
/// away.
|
||||
edges: RefCell<DepGraphEdges>,
|
||||
|
||||
/// The new encoding of the dependency graph, optimized for red/green
|
||||
/// tracking. The `current` field is the dependency graph of only the
|
||||
/// current compilation session: We don't merge the previous dep-graph into
|
||||
/// current one anymore.
|
||||
current: RefCell<CurrentDepGraph>,
|
||||
|
||||
/// The dep-graph from the previous compilation session. It contains all
|
||||
/// nodes and edges as well as all fingerprints of nodes that have them.
|
||||
previous: PreviousDepGraph,
|
||||
|
||||
/// When we load, there may be `.o` files, cached mir, or other such
|
||||
/// things available to us. If we find that they are not dirty, we
|
||||
/// load the path to the file storing those work-products here into
|
||||
|
|
@ -46,18 +87,25 @@ struct DepGraphData {
|
|||
}
|
||||
|
||||
impl DepGraph {
|
||||
pub fn new(enabled: bool) -> DepGraph {
|
||||
|
||||
pub fn new(prev_graph: PreviousDepGraph) -> DepGraph {
|
||||
DepGraph {
|
||||
data: if enabled {
|
||||
Some(Rc::new(DepGraphData {
|
||||
previous_work_products: RefCell::new(FxHashMap()),
|
||||
work_products: RefCell::new(FxHashMap()),
|
||||
edges: RefCell::new(DepGraphEdges::new()),
|
||||
dep_node_debug: RefCell::new(FxHashMap()),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
data: Some(Rc::new(DepGraphData {
|
||||
previous_work_products: RefCell::new(FxHashMap()),
|
||||
work_products: RefCell::new(FxHashMap()),
|
||||
edges: RefCell::new(DepGraphEdges::new()),
|
||||
dep_node_debug: RefCell::new(FxHashMap()),
|
||||
current: RefCell::new(CurrentDepGraph::new()),
|
||||
previous: prev_graph,
|
||||
})),
|
||||
fingerprints: Rc::new(RefCell::new(FxHashMap())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_disabled() -> DepGraph {
|
||||
DepGraph {
|
||||
data: None,
|
||||
fingerprints: Rc::new(RefCell::new(FxHashMap())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +120,8 @@ impl DepGraph {
|
|||
}
|
||||
|
||||
pub fn in_ignore<'graph>(&'graph self) -> Option<raii::IgnoreTask<'graph>> {
|
||||
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges))
|
||||
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges,
|
||||
&data.current))
|
||||
}
|
||||
|
||||
pub fn with_ignore<OP,R>(&self, op: OP) -> R
|
||||
|
|
@ -120,6 +169,7 @@ impl DepGraph {
|
|||
{
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().push_task(key);
|
||||
data.current.borrow_mut().push_task(key);
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(ProfileQueriesMsg::TaskBegin(key.clone()))
|
||||
};
|
||||
|
|
@ -135,15 +185,36 @@ impl DepGraph {
|
|||
if cfg!(debug_assertions) {
|
||||
profq_msg(ProfileQueriesMsg::TaskEnd)
|
||||
};
|
||||
let dep_node_index = data.edges.borrow_mut().pop_task(key);
|
||||
|
||||
let dep_node_index_legacy = data.edges.borrow_mut().pop_task(key);
|
||||
let dep_node_index_new = data.current.borrow_mut().pop_task(key);
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
result.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
let _: Fingerprint = stable_hasher.finish();
|
||||
|
||||
(result, dep_node_index)
|
||||
assert!(self.fingerprints
|
||||
.borrow_mut()
|
||||
.insert(key, stable_hasher.finish())
|
||||
.is_none());
|
||||
|
||||
(result, DepNodeIndex {
|
||||
legacy: dep_node_index_legacy,
|
||||
new: dep_node_index_new,
|
||||
})
|
||||
} else {
|
||||
(task(cx, arg), DepNodeIndex::INVALID)
|
||||
if key.kind.fingerprint_needed_for_crate_hash() {
|
||||
let mut hcx = cx.create_stable_hashing_context();
|
||||
let result = task(cx, arg);
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
result.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
assert!(self.fingerprints
|
||||
.borrow_mut()
|
||||
.insert(key, stable_hasher.finish())
|
||||
.is_none());
|
||||
(result, DepNodeIndex::INVALID)
|
||||
} else {
|
||||
(task(cx, arg), DepNodeIndex::INVALID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,9 +225,14 @@ impl DepGraph {
|
|||
{
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().push_anon_task();
|
||||
data.current.borrow_mut().push_anon_task();
|
||||
let result = op();
|
||||
let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind);
|
||||
(result, dep_node)
|
||||
let dep_node_index_legacy = data.edges.borrow_mut().pop_anon_task(dep_kind);
|
||||
let dep_node_index_new = data.current.borrow_mut().pop_anon_task(dep_kind);
|
||||
(result, DepNodeIndex {
|
||||
legacy: dep_node_index_legacy,
|
||||
new: dep_node_index_new,
|
||||
})
|
||||
} else {
|
||||
(op(), DepNodeIndex::INVALID)
|
||||
}
|
||||
|
|
@ -166,13 +242,21 @@ impl DepGraph {
|
|||
pub fn read(&self, v: DepNode) {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().read(v);
|
||||
|
||||
let mut current = data.current.borrow_mut();
|
||||
if let Some(&dep_node_index_new) = current.node_to_node_index.get(&v) {
|
||||
current.read_index(dep_node_index_new);
|
||||
} else {
|
||||
bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_index(&self, v: DepNodeIndex) {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().read_index(v);
|
||||
data.edges.borrow_mut().read_index(v.legacy);
|
||||
data.current.borrow_mut().read_index(v.new);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,12 +271,12 @@ impl DepGraph {
|
|||
self.data.as_ref().unwrap().edges.borrow_mut().add_node(node);
|
||||
}
|
||||
|
||||
pub fn alloc_input_node(&self, node: DepNode) -> DepNodeIndex {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().add_node(node)
|
||||
} else {
|
||||
DepNodeIndex::INVALID
|
||||
}
|
||||
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint {
|
||||
self.fingerprints.borrow()[dep_node]
|
||||
}
|
||||
|
||||
pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint {
|
||||
self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
|
||||
}
|
||||
|
||||
/// Indicates that a previous work product exists for `v`. This is
|
||||
|
|
@ -261,6 +345,44 @@ impl DepGraph {
|
|||
pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> {
|
||||
self.data.as_ref().and_then(|t| t.dep_node_debug.borrow().get(&dep_node).cloned())
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> SerializedDepGraph {
|
||||
let fingerprints = self.fingerprints.borrow();
|
||||
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
|
||||
|
||||
let nodes: IndexVec<_, _> = current_dep_graph.nodes.iter().map(|dep_node| {
|
||||
let fingerprint = fingerprints.get(dep_node)
|
||||
.cloned()
|
||||
.unwrap_or(Fingerprint::zero());
|
||||
(*dep_node, fingerprint)
|
||||
}).collect();
|
||||
|
||||
let total_edge_count: usize = current_dep_graph.edges.iter()
|
||||
.map(|v| v.len())
|
||||
.sum();
|
||||
|
||||
let mut edge_list_indices = IndexVec::with_capacity(nodes.len());
|
||||
let mut edge_list_data = Vec::with_capacity(total_edge_count);
|
||||
|
||||
for (current_dep_node_index, edges) in current_dep_graph.edges.iter_enumerated() {
|
||||
let start = edge_list_data.len() as u32;
|
||||
// This should really just be a memcpy :/
|
||||
edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex(i.index)));
|
||||
let end = edge_list_data.len() as u32;
|
||||
|
||||
debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len());
|
||||
edge_list_indices.push((start, end));
|
||||
}
|
||||
|
||||
debug_assert!(edge_list_data.len() <= ::std::u32::MAX as usize);
|
||||
debug_assert_eq!(edge_list_data.len(), total_edge_count);
|
||||
|
||||
SerializedDepGraph {
|
||||
nodes,
|
||||
edge_list_indices,
|
||||
edge_list_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A "work product" is an intermediate result that we save into the
|
||||
|
|
@ -305,3 +427,174 @@ pub struct WorkProduct {
|
|||
/// Saved files associated with this CGU
|
||||
pub saved_files: Vec<(OutputType, String)>,
|
||||
}
|
||||
|
||||
pub(super) struct CurrentDepGraph {
|
||||
nodes: IndexVec<DepNodeIndexNew, DepNode>,
|
||||
edges: IndexVec<DepNodeIndexNew, Vec<DepNodeIndexNew>>,
|
||||
node_to_node_index: FxHashMap<DepNode, DepNodeIndexNew>,
|
||||
|
||||
task_stack: Vec<OpenTask>,
|
||||
}
|
||||
|
||||
impl CurrentDepGraph {
|
||||
fn new() -> CurrentDepGraph {
|
||||
CurrentDepGraph {
|
||||
nodes: IndexVec::new(),
|
||||
edges: IndexVec::new(),
|
||||
node_to_node_index: FxHashMap(),
|
||||
task_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn push_ignore(&mut self) {
|
||||
self.task_stack.push(OpenTask::Ignore);
|
||||
}
|
||||
|
||||
pub(super) fn pop_ignore(&mut self) {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
debug_assert_eq!(popped_node, OpenTask::Ignore);
|
||||
}
|
||||
|
||||
pub(super) fn push_task(&mut self, key: DepNode) {
|
||||
self.task_stack.push(OpenTask::Regular {
|
||||
node: key,
|
||||
reads: Vec::new(),
|
||||
read_set: FxHashSet(),
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndexNew {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
|
||||
if let OpenTask::Regular {
|
||||
node,
|
||||
read_set: _,
|
||||
reads
|
||||
} = popped_node {
|
||||
debug_assert_eq!(node, key);
|
||||
self.alloc_node(node, reads)
|
||||
} else {
|
||||
bug!("pop_task() - Expected regular task to be popped")
|
||||
}
|
||||
}
|
||||
|
||||
fn push_anon_task(&mut self) {
|
||||
self.task_stack.push(OpenTask::Anon {
|
||||
reads: Vec::new(),
|
||||
read_set: FxHashSet(),
|
||||
});
|
||||
}
|
||||
|
||||
fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndexNew {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
|
||||
if let OpenTask::Anon {
|
||||
read_set: _,
|
||||
reads
|
||||
} = popped_node {
|
||||
let mut fingerprint = Fingerprint::zero();
|
||||
let mut hasher = StableHasher::new();
|
||||
|
||||
for &read in reads.iter() {
|
||||
let read_dep_node = self.nodes[read];
|
||||
|
||||
::std::mem::discriminant(&read_dep_node.kind).hash(&mut hasher);
|
||||
|
||||
// Fingerprint::combine() is faster than sending Fingerprint
|
||||
// through the StableHasher (at least as long as StableHasher
|
||||
// is so slow).
|
||||
fingerprint = fingerprint.combine(read_dep_node.hash);
|
||||
}
|
||||
|
||||
fingerprint = fingerprint.combine(hasher.finish());
|
||||
|
||||
let target_dep_node = DepNode {
|
||||
kind,
|
||||
hash: fingerprint,
|
||||
};
|
||||
|
||||
if let Some(&index) = self.node_to_node_index.get(&target_dep_node) {
|
||||
return index;
|
||||
}
|
||||
|
||||
self.alloc_node(target_dep_node, reads)
|
||||
} else {
|
||||
bug!("pop_anon_task() - Expected anonymous task to be popped")
|
||||
}
|
||||
}
|
||||
|
||||
fn read_index(&mut self, source: DepNodeIndexNew) {
|
||||
match self.task_stack.last_mut() {
|
||||
Some(&mut OpenTask::Regular {
|
||||
ref mut reads,
|
||||
ref mut read_set,
|
||||
node: _,
|
||||
}) => {
|
||||
if read_set.insert(source) {
|
||||
reads.push(source);
|
||||
}
|
||||
}
|
||||
Some(&mut OpenTask::Anon {
|
||||
ref mut reads,
|
||||
ref mut read_set,
|
||||
}) => {
|
||||
if read_set.insert(source) {
|
||||
reads.push(source);
|
||||
}
|
||||
}
|
||||
Some(&mut OpenTask::Ignore) | None => {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_node(&mut self,
|
||||
dep_node: DepNode,
|
||||
edges: Vec<DepNodeIndexNew>)
|
||||
-> DepNodeIndexNew {
|
||||
debug_assert_eq!(self.edges.len(), self.nodes.len());
|
||||
debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
|
||||
debug_assert!(!self.node_to_node_index.contains_key(&dep_node));
|
||||
let dep_node_index = DepNodeIndexNew::new(self.nodes.len());
|
||||
self.nodes.push(dep_node);
|
||||
self.node_to_node_index.insert(dep_node, dep_node_index);
|
||||
self.edges.push(edges);
|
||||
dep_node_index
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(super) struct DepNodeIndexNew {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl Idx for DepNodeIndexNew {
|
||||
fn new(v: usize) -> DepNodeIndexNew {
|
||||
assert!((v & 0xFFFF_FFFF) == v);
|
||||
DepNodeIndexNew { index: v as u32 }
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.index as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl DepNodeIndexNew {
|
||||
const INVALID: DepNodeIndexNew = DepNodeIndexNew {
|
||||
index: ::std::u32::MAX,
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum OpenTask {
|
||||
Regular {
|
||||
node: DepNode,
|
||||
reads: Vec<DepNodeIndexNew>,
|
||||
read_set: FxHashSet<DepNodeIndexNew>,
|
||||
},
|
||||
Anon {
|
||||
reads: Vec<DepNodeIndexNew>,
|
||||
read_set: FxHashSet<DepNodeIndexNew>,
|
||||
},
|
||||
Ignore,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,19 +13,17 @@ mod dep_node;
|
|||
mod dep_tracking_map;
|
||||
mod edges;
|
||||
mod graph;
|
||||
mod prev;
|
||||
mod query;
|
||||
mod raii;
|
||||
mod safe;
|
||||
mod serialized;
|
||||
|
||||
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
|
||||
pub use self::dep_node::DepNode;
|
||||
pub use self::dep_node::WorkProductId;
|
||||
pub use self::graph::DepGraph;
|
||||
pub use self::graph::WorkProduct;
|
||||
pub use self::edges::DepNodeIndex;
|
||||
pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId};
|
||||
pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex};
|
||||
pub use self::prev::PreviousDepGraph;
|
||||
pub use self::query::DepGraphQuery;
|
||||
pub use self::safe::AssertDepGraphSafe;
|
||||
pub use self::safe::DepGraphSafe;
|
||||
pub use self::raii::DepTask;
|
||||
|
||||
pub use self::dep_node::{DepKind, DepConstructor};
|
||||
pub use self::serialized::SerializedDepGraph;
|
||||
|
|
|
|||
46
src/librustc/dep_graph/prev.rs
Normal file
46
src/librustc/dep_graph/prev.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// 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.
|
||||
|
||||
use ich::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use super::dep_node::DepNode;
|
||||
use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
|
||||
|
||||
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct PreviousDepGraph {
|
||||
data: SerializedDepGraph,
|
||||
index: FxHashMap<DepNode, SerializedDepNodeIndex>,
|
||||
}
|
||||
|
||||
impl PreviousDepGraph {
|
||||
pub fn new(data: SerializedDepGraph) -> PreviousDepGraph {
|
||||
let index: FxHashMap<_, _> = data.nodes
|
||||
.iter_enumerated()
|
||||
.map(|(idx, &(dep_node, _))| (dep_node, idx))
|
||||
.collect();
|
||||
PreviousDepGraph { data, index }
|
||||
}
|
||||
|
||||
pub fn with_edges_from<F>(&self, dep_node: &DepNode, mut f: F)
|
||||
where
|
||||
F: FnMut(&(DepNode, Fingerprint)),
|
||||
{
|
||||
let node_index = self.index[dep_node];
|
||||
self.data
|
||||
.edge_targets_from(node_index)
|
||||
.into_iter()
|
||||
.for_each(|&index| f(&self.data.nodes[index]));
|
||||
}
|
||||
|
||||
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint {
|
||||
let node_index = self.index[dep_node];
|
||||
self.data.nodes[node_index].1
|
||||
}
|
||||
}
|
||||
|
|
@ -8,50 +8,33 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::DepNode;
|
||||
use super::edges::DepGraphEdges;
|
||||
use super::graph::CurrentDepGraph;
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct DepTask<'graph> {
|
||||
graph: &'graph RefCell<DepGraphEdges>,
|
||||
key: DepNode,
|
||||
}
|
||||
|
||||
impl<'graph> DepTask<'graph> {
|
||||
pub fn new(graph: &'graph RefCell<DepGraphEdges>,
|
||||
key: DepNode)
|
||||
-> DepTask<'graph> {
|
||||
graph.borrow_mut().push_task(key);
|
||||
DepTask {
|
||||
graph,
|
||||
key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> Drop for DepTask<'graph> {
|
||||
fn drop(&mut self) {
|
||||
self.graph.borrow_mut().pop_task(self.key);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IgnoreTask<'graph> {
|
||||
graph: &'graph RefCell<DepGraphEdges>,
|
||||
legacy_graph: &'graph RefCell<DepGraphEdges>,
|
||||
new_graph: &'graph RefCell<CurrentDepGraph>,
|
||||
}
|
||||
|
||||
impl<'graph> IgnoreTask<'graph> {
|
||||
pub fn new(graph: &'graph RefCell<DepGraphEdges>) -> IgnoreTask<'graph> {
|
||||
graph.borrow_mut().push_ignore();
|
||||
pub(super) fn new(legacy_graph: &'graph RefCell<DepGraphEdges>,
|
||||
new_graph: &'graph RefCell<CurrentDepGraph>)
|
||||
-> IgnoreTask<'graph> {
|
||||
legacy_graph.borrow_mut().push_ignore();
|
||||
new_graph.borrow_mut().push_ignore();
|
||||
IgnoreTask {
|
||||
graph
|
||||
legacy_graph,
|
||||
new_graph,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> Drop for IgnoreTask<'graph> {
|
||||
fn drop(&mut self) {
|
||||
self.graph.borrow_mut().pop_ignore();
|
||||
self.legacy_graph.borrow_mut().pop_ignore();
|
||||
self.new_graph.borrow_mut().pop_ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
63
src/librustc/dep_graph/serialized.rs
Normal file
63
src/librustc/dep_graph/serialized.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// 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.
|
||||
|
||||
//! The data that we will serialize and deserialize.
|
||||
|
||||
use dep_graph::DepNode;
|
||||
use ich::Fingerprint;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
|
||||
/// The index of a DepNode in the SerializedDepGraph::nodes array.
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug,
|
||||
RustcEncodable, RustcDecodable)]
|
||||
pub struct SerializedDepNodeIndex(pub u32);
|
||||
|
||||
impl Idx for SerializedDepNodeIndex {
|
||||
#[inline]
|
||||
fn new(idx: usize) -> Self {
|
||||
assert!(idx <= ::std::u32::MAX as usize);
|
||||
SerializedDepNodeIndex(idx as u32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Data for use when recompiling the **current crate**.
|
||||
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct SerializedDepGraph {
|
||||
/// The set of all DepNodes in the graph
|
||||
pub nodes: IndexVec<SerializedDepNodeIndex, (DepNode, Fingerprint)>,
|
||||
/// For each DepNode, stores the list of edges originating from that
|
||||
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
|
||||
/// which holds the actual DepNodeIndices of the target nodes.
|
||||
pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
|
||||
/// A flattened list of all edge targets in the graph. Edge sources are
|
||||
/// implicit in edge_list_indices.
|
||||
pub edge_list_data: Vec<SerializedDepNodeIndex>,
|
||||
}
|
||||
|
||||
impl SerializedDepGraph {
|
||||
|
||||
pub fn new() -> SerializedDepGraph {
|
||||
SerializedDepGraph {
|
||||
nodes: IndexVec::new(),
|
||||
edge_list_indices: IndexVec::new(),
|
||||
edge_list_data: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] {
|
||||
let targets = self.edge_list_indices[source];
|
||||
&self.edge_list_data[targets.0 as usize..targets.1 as usize]
|
||||
}
|
||||
}
|
||||
|
|
@ -479,40 +479,6 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0133: r##"
|
||||
Unsafe code was used outside of an unsafe function or block.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0133
|
||||
unsafe fn f() { return; } // This is the unsafe code
|
||||
|
||||
fn main() {
|
||||
f(); // error: call to unsafe function requires unsafe function or block
|
||||
}
|
||||
```
|
||||
|
||||
Using unsafe functionality is potentially dangerous and disallowed by safety
|
||||
checks. Examples:
|
||||
|
||||
* Dereferencing raw pointers
|
||||
* Calling functions via FFI
|
||||
* Calling functions marked unsafe
|
||||
|
||||
These safety checks can be relaxed for a section of the code by wrapping the
|
||||
unsafe instructions with an `unsafe` block. For instance:
|
||||
|
||||
```
|
||||
unsafe fn f() { return; }
|
||||
|
||||
fn main() {
|
||||
unsafe { f(); } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
See also https://doc.rust-lang.org/book/first-edition/unsafe.html
|
||||
"##,
|
||||
|
||||
// This shouldn't really ever trigger since the repeated value error comes first
|
||||
E0136: r##"
|
||||
A binary can only have one entry point, and by default that entry point is the
|
||||
|
|
@ -1139,11 +1105,13 @@ already specify all requirements that will be used for every type parameter.
|
|||
"##,
|
||||
|
||||
E0281: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
You tried to supply a type which doesn't implement some trait in a location
|
||||
which expected that trait. This error typically occurs when working with
|
||||
`Fn`-based types. Erroneous code example:
|
||||
|
||||
```compile_fail,E0281
|
||||
```compile-fail
|
||||
fn foo<F: Fn(usize)>(x: F) { }
|
||||
|
||||
fn main() {
|
||||
|
|
@ -1383,74 +1351,6 @@ struct Foo<T: 'static> {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0312: r##"
|
||||
A lifetime of reference outlives lifetime of borrowed content.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0312
|
||||
fn make_child<'tree, 'human>(
|
||||
x: &'human i32,
|
||||
y: &'tree i32
|
||||
) -> &'human i32 {
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y }
|
||||
// error: lifetime of reference outlives lifetime of borrowed content
|
||||
}
|
||||
```
|
||||
|
||||
The function declares that it returns a reference with the `'human`
|
||||
lifetime, but it may return data with the `'tree` lifetime. As neither
|
||||
lifetime is declared longer than the other, this results in an
|
||||
error. Sometimes, this error is because the function *body* is
|
||||
incorrect -- that is, maybe you did not *mean* to return data from
|
||||
`y`. In that case, you should fix the function body.
|
||||
|
||||
Often, however, the body is correct. In that case, the function
|
||||
signature needs to be altered to match the body, so that the caller
|
||||
understands that data from either `x` or `y` may be returned. The
|
||||
simplest way to do this is to give both function parameters the *same*
|
||||
named lifetime:
|
||||
|
||||
```
|
||||
fn make_child<'human>(
|
||||
x: &'human i32,
|
||||
y: &'human i32
|
||||
) -> &'human i32 {
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
However, in some cases, you may prefer to explicitly declare that one lifetime
|
||||
outlives another using a `where` clause:
|
||||
|
||||
```
|
||||
fn make_child<'tree, 'human>(
|
||||
x: &'human i32,
|
||||
y: &'tree i32
|
||||
) -> &'human i32
|
||||
where
|
||||
'tree: 'human
|
||||
{
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
Here, the where clause `'tree: 'human` can be read as "the lifetime
|
||||
'tree outlives the lifetime 'human" -- meaning, references with the
|
||||
`'tree` lifetime live *at least as long as* references with the
|
||||
`'human` lifetime. Therefore, it is safe to return data with lifetime
|
||||
`'tree` when data with the lifetime `'human` is needed.
|
||||
"##,
|
||||
|
||||
E0317: r##"
|
||||
This error occurs when an `if` expression without an `else` block is used in a
|
||||
context where a type other than `()` is expected, for example a `let`
|
||||
|
|
@ -2060,6 +1960,7 @@ register_diagnostics! {
|
|||
// E0304, // expected signed integer constant
|
||||
// E0305, // expected constant
|
||||
E0311, // thing may not live long enough
|
||||
E0312, // lifetime of reference outlives lifetime of borrowed content
|
||||
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
|
||||
E0314, // closure outlives stack frame
|
||||
E0315, // cannot invoke closure outside of its lifetime
|
||||
|
|
@ -2086,4 +1987,6 @@ register_diagnostics! {
|
|||
E0566, // conflicting representation hints
|
||||
E0623, // lifetime mismatch where both parameters are anonymous regions
|
||||
E0628, // generators cannot have explicit arguments
|
||||
E0631, // type mismatch in closure arguments
|
||||
E0637, // "'_" is not a valid lifetime bound
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,17 @@ impl serialize::UseSpecializedDecodable for CrateNum {
|
|||
RustcDecodable, Hash, Copy)]
|
||||
pub struct DefIndex(u32);
|
||||
|
||||
impl Idx for DefIndex {
|
||||
fn new(value: usize) -> Self {
|
||||
assert!(value < (u32::MAX) as usize);
|
||||
DefIndex(value as u32)
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DefIndex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
|
|
|
|||
|
|
@ -422,7 +422,12 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
|
|||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
|
||||
visitor.visit_id(lifetime.id);
|
||||
visitor.visit_name(lifetime.span, lifetime.name);
|
||||
match lifetime.name {
|
||||
LifetimeName::Name(name) => {
|
||||
visitor.visit_name(lifetime.span, name);
|
||||
}
|
||||
LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
|
||||
|
|
@ -622,7 +627,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
path_span: Span,
|
||||
segment: &'v PathSegment) {
|
||||
visitor.visit_name(path_span, segment.name);
|
||||
visitor.visit_path_parameters(path_span, &segment.parameters);
|
||||
if let Some(ref parameters) = segment.parameters {
|
||||
visitor.visit_path_parameters(path_span, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ use syntax::codemap::{self, respan, Spanned, CompilerDesugaringKind};
|
|||
use syntax::std_inject;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree, Delimited};
|
||||
use syntax::parse::token::{Token, DelimToken};
|
||||
use syntax::parse::token::Token;
|
||||
use syntax::util::small_vector::SmallVector;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -606,10 +606,12 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
|
||||
tokens.into_trees().map(|tree| self.lower_token_tree(tree)).collect()
|
||||
tokens.into_trees()
|
||||
.flat_map(|tree| self.lower_token_tree(tree).into_trees())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn lower_token_tree(&mut self, tree: TokenTree) -> TokenTree {
|
||||
fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
|
||||
match tree {
|
||||
TokenTree::Token(span, token) => {
|
||||
self.lower_token(token, span)
|
||||
|
|
@ -618,23 +620,19 @@ impl<'a> LoweringContext<'a> {
|
|||
TokenTree::Delimited(span, Delimited {
|
||||
delim: delimited.delim,
|
||||
tts: self.lower_token_stream(delimited.tts.into()).into(),
|
||||
})
|
||||
}).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_token(&mut self, token: Token, span: Span) -> TokenTree {
|
||||
fn lower_token(&mut self, token: Token, span: Span) -> TokenStream {
|
||||
match token {
|
||||
Token::Interpolated(_) => {}
|
||||
other => return TokenTree::Token(span, other),
|
||||
other => return TokenTree::Token(span, other).into(),
|
||||
}
|
||||
|
||||
let tts = token.interpolated_to_tokenstream(&self.sess.parse_sess, span);
|
||||
let tts = self.lower_token_stream(tts);
|
||||
TokenTree::Delimited(span, Delimited {
|
||||
delim: DelimToken::NoDelim,
|
||||
tts: tts.into(),
|
||||
})
|
||||
self.lower_token_stream(tts)
|
||||
}
|
||||
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
|
||||
|
|
@ -685,17 +683,16 @@ impl<'a> LoweringContext<'a> {
|
|||
return self.lower_ty(ty);
|
||||
}
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
let id = self.lower_node_id(t.id).node_id;
|
||||
let id = self.lower_node_id(t.id);
|
||||
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit);
|
||||
return self.ty_path(id, t.span, qpath);
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
|
||||
def: self.expect_full_def(t.id),
|
||||
segments: hir_vec![hir::PathSegment {
|
||||
name: keywords::SelfType.name(),
|
||||
parameters: hir::PathParameters::none()
|
||||
}],
|
||||
segments: hir_vec![
|
||||
hir::PathSegment::from_name(keywords::SelfType.name())
|
||||
],
|
||||
span: t.span,
|
||||
})))
|
||||
}
|
||||
|
|
@ -734,10 +731,12 @@ impl<'a> LoweringContext<'a> {
|
|||
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
|
||||
};
|
||||
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(t.id);
|
||||
P(hir::Ty {
|
||||
id: self.lower_node_id(t.id).node_id,
|
||||
id: node_id,
|
||||
node: kind,
|
||||
span: t.span,
|
||||
hir_id,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -863,7 +862,7 @@ impl<'a> LoweringContext<'a> {
|
|||
// Otherwise, the base path is an implicit `Self` type path,
|
||||
// e.g. `Vec` in `Vec::new` or `<I as Iterator>::Item` in
|
||||
// `<I as Iterator>::Item::default`.
|
||||
let new_id = self.next_id().node_id;
|
||||
let new_id = self.next_id();
|
||||
self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path))
|
||||
};
|
||||
|
||||
|
|
@ -888,7 +887,7 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
// Wrap the associated extension in another type node.
|
||||
let new_id = self.next_id().node_id;
|
||||
let new_id = self.next_id();
|
||||
ty = self.ty_path(new_id, p.span, qpath);
|
||||
}
|
||||
|
||||
|
|
@ -914,12 +913,8 @@ impl<'a> LoweringContext<'a> {
|
|||
segments: segments.map(|segment| {
|
||||
self.lower_path_segment(p.span, segment, param_mode, 0,
|
||||
ParenthesizedGenericArgs::Err)
|
||||
}).chain(name.map(|name| {
|
||||
hir::PathSegment {
|
||||
name,
|
||||
parameters: hir::PathParameters::none()
|
||||
}
|
||||
})).collect(),
|
||||
}).chain(name.map(|name| hir::PathSegment::from_name(name)))
|
||||
.collect(),
|
||||
span: p.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -940,7 +935,7 @@ impl<'a> LoweringContext<'a> {
|
|||
expected_lifetimes: usize,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs)
|
||||
-> hir::PathSegment {
|
||||
let mut parameters = if let Some(ref parameters) = segment.parameters {
|
||||
let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
|
||||
let msg = "parenthesized parameters may only be used with a trait";
|
||||
match **parameters {
|
||||
PathParameters::AngleBracketed(ref data) => {
|
||||
|
|
@ -951,12 +946,12 @@ impl<'a> LoweringContext<'a> {
|
|||
ParenthesizedGenericArgs::Warn => {
|
||||
self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
|
||||
CRATE_NODE_ID, data.span, msg.into());
|
||||
hir::PathParameters::none()
|
||||
(hir::PathParameters::none(), true)
|
||||
}
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
|
||||
.span_label(data.span, "only traits may use parentheses").emit();
|
||||
hir::PathParameters::none()
|
||||
(hir::PathParameters::none(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -970,39 +965,39 @@ impl<'a> LoweringContext<'a> {
|
|||
}).collect();
|
||||
}
|
||||
|
||||
hir::PathSegment {
|
||||
name: self.lower_ident(segment.identifier),
|
||||
hir::PathSegment::new(
|
||||
self.lower_ident(segment.identifier),
|
||||
parameters,
|
||||
}
|
||||
infer_types
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_angle_bracketed_parameter_data(&mut self,
|
||||
data: &AngleBracketedParameterData,
|
||||
param_mode: ParamMode)
|
||||
-> hir::PathParameters {
|
||||
-> (hir::PathParameters, bool) {
|
||||
let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data;
|
||||
hir::PathParameters {
|
||||
(hir::PathParameters {
|
||||
lifetimes: self.lower_lifetimes(lifetimes),
|
||||
types: types.iter().map(|ty| self.lower_ty(ty)).collect(),
|
||||
infer_types: types.is_empty() && param_mode == ParamMode::Optional,
|
||||
bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(),
|
||||
parenthesized: false,
|
||||
}
|
||||
}, types.is_empty() && param_mode == ParamMode::Optional)
|
||||
}
|
||||
|
||||
fn lower_parenthesized_parameter_data(&mut self,
|
||||
data: &ParenthesizedParameterData)
|
||||
-> hir::PathParameters {
|
||||
-> (hir::PathParameters, bool) {
|
||||
let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
|
||||
let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect();
|
||||
let mk_tup = |this: &mut Self, tys, span| {
|
||||
P(hir::Ty { node: hir::TyTup(tys), id: this.next_id().node_id, span })
|
||||
let LoweredNodeId { node_id, hir_id } = this.next_id();
|
||||
P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
|
||||
};
|
||||
|
||||
hir::PathParameters {
|
||||
(hir::PathParameters {
|
||||
lifetimes: hir::HirVec::new(),
|
||||
types: hir_vec![mk_tup(self, inputs, span)],
|
||||
infer_types: false,
|
||||
bindings: hir_vec![hir::TypeBinding {
|
||||
id: self.next_id().node_id,
|
||||
name: Symbol::intern(FN_OUTPUT_NAME),
|
||||
|
|
@ -1011,7 +1006,7 @@ impl<'a> LoweringContext<'a> {
|
|||
span: output.as_ref().map_or(span, |ty| ty.span),
|
||||
}],
|
||||
parenthesized: true,
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
|
||||
|
|
@ -1108,6 +1103,10 @@ impl<'a> LoweringContext<'a> {
|
|||
default: tp.default.as_ref().map(|x| self.lower_ty(x)),
|
||||
span: tp.span,
|
||||
pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
|
||||
synthetic: tp.attrs.iter()
|
||||
.filter(|attr| attr.check_name("rustc_synthetic"))
|
||||
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
|
||||
.nth(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1121,7 +1120,11 @@ impl<'a> LoweringContext<'a> {
|
|||
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
id: self.lower_node_id(l.id).node_id,
|
||||
name: self.lower_ident(l.ident),
|
||||
name: match self.lower_ident(l.ident) {
|
||||
x if x == "'_" => hir::LifetimeName::Underscore,
|
||||
x if x == "'static" => hir::LifetimeName::Static,
|
||||
name => hir::LifetimeName::Name(name),
|
||||
},
|
||||
span: l.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -1865,7 +1868,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
|
||||
match *e {
|
||||
RangeEnd::Included => hir::RangeEnd::Included,
|
||||
RangeEnd::Included(_) => hir::RangeEnd::Included,
|
||||
RangeEnd::Excluded => hir::RangeEnd::Excluded,
|
||||
}
|
||||
}
|
||||
|
|
@ -2972,7 +2975,7 @@ impl<'a> LoweringContext<'a> {
|
|||
self.expr_block(block, attrs)
|
||||
}
|
||||
|
||||
fn ty_path(&mut self, id: NodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
|
||||
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
|
||||
let mut id = id;
|
||||
let node = match qpath {
|
||||
hir::QPath::Resolved(None, path) => {
|
||||
|
|
@ -2982,14 +2985,14 @@ impl<'a> LoweringContext<'a> {
|
|||
bound_lifetimes: hir_vec![],
|
||||
trait_ref: hir::TraitRef {
|
||||
path: path.and_then(|path| path),
|
||||
ref_id: id,
|
||||
ref_id: id.node_id,
|
||||
},
|
||||
span,
|
||||
};
|
||||
|
||||
// The original ID is taken by the `PolyTraitRef`,
|
||||
// so the `Ty` itself needs a different one.
|
||||
id = self.next_id().node_id;
|
||||
id = self.next_id();
|
||||
|
||||
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
|
||||
} else {
|
||||
|
|
@ -2998,14 +3001,14 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
_ => hir::TyPath(qpath)
|
||||
};
|
||||
P(hir::Ty { id, node, span })
|
||||
P(hir::Ty { id: id.node_id, hir_id: id.hir_id, node, span })
|
||||
}
|
||||
|
||||
fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
id: self.next_id().node_id,
|
||||
span,
|
||||
name: keywords::Invalid.name()
|
||||
name: hir::LifetimeName::Implicit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ use std::iter::repeat;
|
|||
use syntax::ast::{NodeId, CRATE_NODE_ID};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use ich::StableHashingContext;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
|
||||
|
||||
/// A Visitor that walks over the HIR and collects Nodes into a HIR map
|
||||
pub(super) struct NodeCollector<'a, 'hir> {
|
||||
/// The crate
|
||||
|
|
@ -25,37 +28,113 @@ pub(super) struct NodeCollector<'a, 'hir> {
|
|||
/// The parent of this node
|
||||
parent_node: NodeId,
|
||||
|
||||
// These fields keep track of the currently relevant DepNodes during
|
||||
// the visitor's traversal.
|
||||
current_dep_node_owner: DefIndex,
|
||||
current_dep_node_index: DepNodeIndex,
|
||||
current_signature_dep_index: DepNodeIndex,
|
||||
current_full_dep_index: DepNodeIndex,
|
||||
currently_in_body: bool,
|
||||
|
||||
dep_graph: &'a DepGraph,
|
||||
definitions: &'a definitions::Definitions,
|
||||
|
||||
hcx: StableHashingContext<'a>,
|
||||
|
||||
// We are collecting DepNode::HirBody hashes here so we can compute the
|
||||
// crate hash from then later on.
|
||||
hir_body_nodes: Vec<DefPathHash>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
pub(super) fn root(krate: &'hir Crate,
|
||||
dep_graph: &'a DepGraph,
|
||||
definitions: &'a definitions::Definitions)
|
||||
dep_graph: &'a DepGraph,
|
||||
definitions: &'a definitions::Definitions,
|
||||
hcx: StableHashingContext<'a>)
|
||||
-> NodeCollector<'a, 'hir> {
|
||||
let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX);
|
||||
let root_mod_dep_node = root_mod_def_path_hash.to_dep_node(DepKind::Hir);
|
||||
let root_mod_dep_node_index = dep_graph.alloc_input_node(root_mod_dep_node);
|
||||
|
||||
// Allocate DepNodes for the root module
|
||||
let (root_mod_sig_dep_index, root_mod_full_dep_index);
|
||||
{
|
||||
let Crate {
|
||||
ref module,
|
||||
// Crate attributes are not copied over to the root `Mod`, so hash
|
||||
// them explicitly here.
|
||||
ref attrs,
|
||||
span,
|
||||
|
||||
// These fields are handled separately:
|
||||
exported_macros: _,
|
||||
items: _,
|
||||
trait_items: _,
|
||||
impl_items: _,
|
||||
bodies: _,
|
||||
trait_impls: _,
|
||||
trait_default_impl: _,
|
||||
body_ids: _,
|
||||
} = *krate;
|
||||
|
||||
root_mod_sig_dep_index = dep_graph.with_task(
|
||||
root_mod_def_path_hash.to_dep_node(DepKind::Hir),
|
||||
&hcx,
|
||||
HirItemLike { item_like: (module, attrs, span), hash_bodies: false },
|
||||
identity_fn
|
||||
).1;
|
||||
root_mod_full_dep_index = dep_graph.with_task(
|
||||
root_mod_def_path_hash.to_dep_node(DepKind::HirBody),
|
||||
&hcx,
|
||||
HirItemLike { item_like: (module, attrs, span), hash_bodies: true },
|
||||
identity_fn
|
||||
).1;
|
||||
}
|
||||
|
||||
{
|
||||
dep_graph.with_task(
|
||||
DepNode::new_no_params(DepKind::AllLocalTraitImpls),
|
||||
&hcx,
|
||||
&krate.trait_impls,
|
||||
identity_fn
|
||||
);
|
||||
}
|
||||
|
||||
let hir_body_nodes = vec![root_mod_def_path_hash];
|
||||
|
||||
let mut collector = NodeCollector {
|
||||
krate,
|
||||
map: vec![],
|
||||
parent_node: CRATE_NODE_ID,
|
||||
current_dep_node_index: root_mod_dep_node_index,
|
||||
current_signature_dep_index: root_mod_sig_dep_index,
|
||||
current_full_dep_index: root_mod_full_dep_index,
|
||||
current_dep_node_owner: CRATE_DEF_INDEX,
|
||||
currently_in_body: false,
|
||||
dep_graph,
|
||||
definitions,
|
||||
hcx,
|
||||
hir_body_nodes,
|
||||
};
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_dep_node_index));
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_sig_dep_index));
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub(super) fn into_map(self) -> Vec<MapEntry<'hir>> {
|
||||
pub(super) fn finalize_and_compute_crate_hash(self,
|
||||
crate_disambiguator: &str)
|
||||
-> Vec<MapEntry<'hir>> {
|
||||
let mut node_hashes: Vec<_> = self
|
||||
.hir_body_nodes
|
||||
.iter()
|
||||
.map(|&def_path_hash| {
|
||||
let dep_node = def_path_hash.to_dep_node(DepKind::HirBody);
|
||||
(def_path_hash, self.dep_graph.fingerprint_of(&dep_node))
|
||||
})
|
||||
.collect();
|
||||
|
||||
node_hashes.sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2));
|
||||
|
||||
self.dep_graph.with_task(DepNode::new_no_params(DepKind::Krate),
|
||||
&self.hcx,
|
||||
(node_hashes, crate_disambiguator),
|
||||
identity_fn);
|
||||
self.map
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +149,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
|
||||
fn insert(&mut self, id: NodeId, node: Node<'hir>) {
|
||||
let parent = self.parent_node;
|
||||
let dep_node_index = self.current_dep_node_index;
|
||||
let dep_node_index = if self.currently_in_body {
|
||||
self.current_full_dep_index
|
||||
} else {
|
||||
self.current_signature_dep_index
|
||||
};
|
||||
|
||||
let entry = match node {
|
||||
NodeItem(n) => EntryItem(parent, dep_node_index, n),
|
||||
|
|
@ -91,6 +174,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
NodeTyParam(n) => EntryTyParam(parent, dep_node_index, n),
|
||||
NodeVisibility(n) => EntryVisibility(parent, dep_node_index, n),
|
||||
NodeLocal(n) => EntryLocal(parent, dep_node_index, n),
|
||||
NodeMacroDef(n) => EntryMacroDef(dep_node_index, n),
|
||||
};
|
||||
|
||||
// Make sure that the DepNode of some node coincides with the HirId
|
||||
|
|
@ -127,22 +211,41 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
self.parent_node = parent_node;
|
||||
}
|
||||
|
||||
fn with_dep_node_owner<F: FnOnce(&mut Self)>(&mut self,
|
||||
fn with_dep_node_owner<T: HashStable<StableHashingContext<'a>>,
|
||||
F: FnOnce(&mut Self)>(&mut self,
|
||||
dep_node_owner: DefIndex,
|
||||
item_like: &T,
|
||||
f: F) {
|
||||
let prev_owner = self.current_dep_node_owner;
|
||||
let prev_index = self.current_dep_node_index;
|
||||
let prev_signature_dep_index = self.current_signature_dep_index;
|
||||
let prev_full_dep_index = self.current_signature_dep_index;
|
||||
let prev_in_body = self.currently_in_body;
|
||||
|
||||
let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
|
||||
|
||||
self.current_signature_dep_index = self.dep_graph.with_task(
|
||||
def_path_hash.to_dep_node(DepKind::Hir),
|
||||
&self.hcx,
|
||||
HirItemLike { item_like, hash_bodies: false },
|
||||
identity_fn
|
||||
).1;
|
||||
|
||||
self.current_full_dep_index = self.dep_graph.with_task(
|
||||
def_path_hash.to_dep_node(DepKind::HirBody),
|
||||
&self.hcx,
|
||||
HirItemLike { item_like, hash_bodies: true },
|
||||
identity_fn
|
||||
).1;
|
||||
|
||||
self.hir_body_nodes.push(def_path_hash);
|
||||
|
||||
// When we enter a new owner (item, impl item, or trait item), we always
|
||||
// start out again with DepKind::Hir.
|
||||
let new_dep_node = self.definitions
|
||||
.def_path_hash(dep_node_owner)
|
||||
.to_dep_node(DepKind::Hir);
|
||||
self.current_dep_node_index = self.dep_graph.alloc_input_node(new_dep_node);
|
||||
self.current_dep_node_owner = dep_node_owner;
|
||||
self.currently_in_body = false;
|
||||
f(self);
|
||||
self.current_dep_node_index = prev_index;
|
||||
self.currently_in_body = prev_in_body;
|
||||
self.current_dep_node_owner = prev_owner;
|
||||
self.current_full_dep_index = prev_full_dep_index;
|
||||
self.current_signature_dep_index = prev_signature_dep_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,24 +272,17 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_nested_body(&mut self, id: BodyId) {
|
||||
// When we enter a body, we switch to DepKind::HirBody.
|
||||
// Note that current_dep_node_index might already be DepKind::HirBody,
|
||||
// e.g. when entering the body of a closure that is already part of a
|
||||
// surrounding body. That's expected and not a problem.
|
||||
let prev_index = self.current_dep_node_index;
|
||||
let new_dep_node = self.definitions
|
||||
.def_path_hash(self.current_dep_node_owner)
|
||||
.to_dep_node(DepKind::HirBody);
|
||||
self.current_dep_node_index = self.dep_graph.alloc_input_node(new_dep_node);
|
||||
let prev_in_body = self.currently_in_body;
|
||||
self.currently_in_body = true;
|
||||
self.visit_body(self.krate.body(id));
|
||||
self.current_dep_node_index = prev_index;
|
||||
self.currently_in_body = prev_in_body;
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'hir Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
debug_assert_eq!(i.hir_id.owner,
|
||||
self.definitions.opt_def_index(i.id).unwrap());
|
||||
self.with_dep_node_owner(i.hir_id.owner, |this| {
|
||||
self.with_dep_node_owner(i.hir_id.owner, i, |this| {
|
||||
this.insert(i.id, NodeItem(i));
|
||||
this.with_parent(i.id, |this| {
|
||||
match i.node {
|
||||
|
|
@ -222,7 +318,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
fn visit_trait_item(&mut self, ti: &'hir TraitItem) {
|
||||
debug_assert_eq!(ti.hir_id.owner,
|
||||
self.definitions.opt_def_index(ti.id).unwrap());
|
||||
self.with_dep_node_owner(ti.hir_id.owner, |this| {
|
||||
self.with_dep_node_owner(ti.hir_id.owner, ti, |this| {
|
||||
this.insert(ti.id, NodeTraitItem(ti));
|
||||
|
||||
this.with_parent(ti.id, |this| {
|
||||
|
|
@ -234,7 +330,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
fn visit_impl_item(&mut self, ii: &'hir ImplItem) {
|
||||
debug_assert_eq!(ii.hir_id.owner,
|
||||
self.definitions.opt_def_index(ii.id).unwrap());
|
||||
self.with_dep_node_owner(ii.hir_id.owner, |this| {
|
||||
self.with_dep_node_owner(ii.hir_id.owner, ii, |this| {
|
||||
this.insert(ii.id, NodeImplItem(ii));
|
||||
|
||||
this.with_parent(ii.id, |this| {
|
||||
|
|
@ -328,7 +424,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'hir MacroDef) {
|
||||
self.insert_entry(macro_def.id, NotPresent);
|
||||
let def_index = self.definitions.opt_def_index(macro_def.id).unwrap();
|
||||
|
||||
self.with_dep_node_owner(def_index, macro_def, |this| {
|
||||
this.insert(macro_def.id, NodeMacroDef(macro_def));
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: NodeId) {
|
||||
|
|
@ -375,3 +475,28 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
self.visit_nested_impl_item(id);
|
||||
}
|
||||
}
|
||||
|
||||
// We use this with DepGraph::with_task(). Since we are handling only input
|
||||
// values here, the "task" computing them just passes them through.
|
||||
fn identity_fn<T>(_: &StableHashingContext, item_like: T) -> T {
|
||||
item_like
|
||||
}
|
||||
|
||||
// This is a wrapper structure that allows determining if span values within
|
||||
// the wrapped item should be hashed or not.
|
||||
struct HirItemLike<T> {
|
||||
item_like: T,
|
||||
hash_bodies: bool,
|
||||
}
|
||||
|
||||
impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
|
||||
where T: HashStable<StableHashingContext<'hir>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'hir>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| {
|
||||
self.item_like.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ pub enum Node<'hir> {
|
|||
NodePat(&'hir Pat),
|
||||
NodeBlock(&'hir Block),
|
||||
NodeLocal(&'hir Local),
|
||||
NodeMacroDef(&'hir MacroDef),
|
||||
|
||||
/// NodeStructCtor represents a tuple struct.
|
||||
NodeStructCtor(&'hir VariantData),
|
||||
|
|
@ -93,6 +94,8 @@ enum MapEntry<'hir> {
|
|||
EntryVisibility(NodeId, DepNodeIndex, &'hir Visibility),
|
||||
EntryLocal(NodeId, DepNodeIndex, &'hir Local),
|
||||
|
||||
EntryMacroDef(DepNodeIndex, &'hir MacroDef),
|
||||
|
||||
/// Roots for node trees. The DepNodeIndex is the dependency node of the
|
||||
/// crate's root module.
|
||||
RootCrate(DepNodeIndex),
|
||||
|
|
@ -127,6 +130,7 @@ impl<'hir> MapEntry<'hir> {
|
|||
EntryLocal(id, _, _) => id,
|
||||
|
||||
NotPresent |
|
||||
EntryMacroDef(..) |
|
||||
RootCrate(_) => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -151,6 +155,7 @@ impl<'hir> MapEntry<'hir> {
|
|||
EntryTyParam(_, _, n) => NodeTyParam(n),
|
||||
EntryVisibility(_, _, n) => NodeVisibility(n),
|
||||
EntryLocal(_, _, n) => NodeLocal(n),
|
||||
EntryMacroDef(_, n) => NodeMacroDef(n),
|
||||
|
||||
NotPresent |
|
||||
RootCrate(_) => return None
|
||||
|
|
@ -285,20 +290,12 @@ impl<'hir> Map<'hir> {
|
|||
EntryVisibility(_, dep_node_index, _) |
|
||||
EntryExpr(_, dep_node_index, _) |
|
||||
EntryLocal(_, dep_node_index, _) |
|
||||
EntryMacroDef(dep_node_index, _) |
|
||||
RootCrate(dep_node_index) => {
|
||||
self.dep_graph.read_index(dep_node_index);
|
||||
}
|
||||
NotPresent => {
|
||||
// Some nodes, notably macro definitions, are not
|
||||
// present in the map for whatever reason, but
|
||||
// they *do* have def-ids. So if we encounter an
|
||||
// empty hole, check for that case.
|
||||
if let Some(def_index) = self.definitions.opt_def_index(id) {
|
||||
let def_path_hash = self.definitions.def_path_hash(def_index);
|
||||
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
|
||||
} else {
|
||||
bug!("called HirMap::read() with invalid NodeId")
|
||||
}
|
||||
bug!("called HirMap::read() with invalid NodeId")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -805,7 +802,7 @@ impl<'hir> Map<'hir> {
|
|||
NodeTraitItem(ti) => ti.name,
|
||||
NodeVariant(v) => v.node.name,
|
||||
NodeField(f) => f.name,
|
||||
NodeLifetime(lt) => lt.name,
|
||||
NodeLifetime(lt) => lt.name.name(),
|
||||
NodeTyParam(tp) => tp.name,
|
||||
NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node,
|
||||
NodeStructCtor(_) => self.name(self.get_parent(id)),
|
||||
|
|
@ -875,20 +872,11 @@ impl<'hir> Map<'hir> {
|
|||
Some(EntryVisibility(_, _, &Visibility::Restricted { ref path, .. })) => path.span,
|
||||
Some(EntryVisibility(_, _, v)) => bug!("unexpected Visibility {:?}", v),
|
||||
Some(EntryLocal(_, _, local)) => local.span,
|
||||
Some(EntryMacroDef(_, macro_def)) => macro_def.span,
|
||||
|
||||
Some(RootCrate(_)) => self.forest.krate.span,
|
||||
Some(NotPresent) | None => {
|
||||
// Some nodes, notably macro definitions, are not
|
||||
// present in the map for whatever reason, but
|
||||
// they *do* have def-ids. So if we encounter an
|
||||
// empty hole, check for that case.
|
||||
if let Some(def_index) = self.definitions.opt_def_index(id) {
|
||||
let def_path_hash = self.definitions.def_path_hash(def_index);
|
||||
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
|
||||
DUMMY_SP
|
||||
} else {
|
||||
bug!("hir::map::Map::span: id not in map: {:?}", id)
|
||||
}
|
||||
bug!("hir::map::Map::span: id not in map: {:?}", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1012,15 +1000,22 @@ impl Named for StructField { fn name(&self) -> Name { self.name } }
|
|||
impl Named for TraitItem { fn name(&self) -> Name { self.name } }
|
||||
impl Named for ImplItem { fn name(&self) -> Name { self.name } }
|
||||
|
||||
pub fn map_crate<'hir>(forest: &'hir mut Forest,
|
||||
pub fn map_crate<'hir>(sess: &::session::Session,
|
||||
cstore: &::middle::cstore::CrateStore,
|
||||
forest: &'hir mut Forest,
|
||||
definitions: &'hir Definitions)
|
||||
-> Map<'hir> {
|
||||
let map = {
|
||||
let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore);
|
||||
|
||||
let mut collector = NodeCollector::root(&forest.krate,
|
||||
&forest.dep_graph,
|
||||
&definitions);
|
||||
&definitions,
|
||||
hcx);
|
||||
intravisit::walk_crate(&mut collector, &forest.krate);
|
||||
collector.into_map()
|
||||
|
||||
let crate_disambiguator = sess.local_crate_disambiguator().as_str();
|
||||
collector.finalize_and_compute_crate_hash(&crate_disambiguator)
|
||||
};
|
||||
|
||||
if log_enabled!(::log::LogLevel::Debug) {
|
||||
|
|
@ -1103,6 +1098,7 @@ impl<'a> print::State<'a> {
|
|||
// printing.
|
||||
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
|
||||
NodeLocal(a) => self.print_local_decl(&a),
|
||||
NodeMacroDef(_) => bug!("cannot print MacroDef"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1219,6 +1215,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
|||
Some(NodeVisibility(ref vis)) => {
|
||||
format!("visibility {:?}{}", vis, id_str)
|
||||
}
|
||||
Some(NodeMacroDef(_)) => {
|
||||
format!("macro {}{}", path_str(), id_str)
|
||||
}
|
||||
None => {
|
||||
format!("unknown node{}", id_str)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,27 @@ pub struct Lifetime {
|
|||
/// HIR lowering inserts these placeholders in type paths that
|
||||
/// refer to type definitions needing lifetime parameters,
|
||||
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
|
||||
pub name: Name,
|
||||
pub name: LifetimeName,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
||||
pub enum LifetimeName {
|
||||
Implicit,
|
||||
Underscore,
|
||||
Static,
|
||||
Name(Name),
|
||||
}
|
||||
|
||||
impl LifetimeName {
|
||||
pub fn name(&self) -> Name {
|
||||
use self::LifetimeName::*;
|
||||
match *self {
|
||||
Implicit => keywords::Invalid.name(),
|
||||
Underscore => Symbol::intern("'_"),
|
||||
Static => keywords::StaticLifetime.name(),
|
||||
Name(name) => name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Lifetime {
|
||||
|
|
@ -159,11 +179,15 @@ impl fmt::Debug for Lifetime {
|
|||
|
||||
impl Lifetime {
|
||||
pub fn is_elided(&self) -> bool {
|
||||
self.name == keywords::Invalid.name()
|
||||
use self::LifetimeName::*;
|
||||
match self.name {
|
||||
Implicit | Underscore => true,
|
||||
Static | Name(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_static(&self) -> bool {
|
||||
self.name == "'static"
|
||||
self.name == LifetimeName::Static
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +236,13 @@ pub struct PathSegment {
|
|||
/// this is more than just simple syntactic sugar; the use of
|
||||
/// parens affects the region binding rules, so we preserve the
|
||||
/// distinction.
|
||||
pub parameters: PathParameters,
|
||||
pub parameters: Option<P<PathParameters>>,
|
||||
|
||||
/// Whether to infer remaining type parameters, if any.
|
||||
/// This only applies to expression and pattern paths, and
|
||||
/// out of those only the segments with no type parameters
|
||||
/// to begin with, e.g. `Vec::new` is `<Vec<..>>::new::<..>`.
|
||||
pub infer_types: bool,
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
|
|
@ -220,9 +250,35 @@ impl PathSegment {
|
|||
pub fn from_name(name: Name) -> PathSegment {
|
||||
PathSegment {
|
||||
name,
|
||||
parameters: PathParameters::none()
|
||||
infer_types: true,
|
||||
parameters: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(name: Name, parameters: PathParameters, infer_types: bool) -> Self {
|
||||
PathSegment {
|
||||
name,
|
||||
infer_types,
|
||||
parameters: if parameters.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(P(parameters))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: hack required because you can't create a static
|
||||
// PathParameters, so you can't just return a &PathParameters.
|
||||
pub fn with_parameters<F, R>(&self, f: F) -> R
|
||||
where F: FnOnce(&PathParameters) -> R
|
||||
{
|
||||
let dummy = PathParameters::none();
|
||||
f(if let Some(ref params) = self.parameters {
|
||||
¶ms
|
||||
} else {
|
||||
&dummy
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
|
|
@ -231,11 +287,6 @@ pub struct PathParameters {
|
|||
pub lifetimes: HirVec<Lifetime>,
|
||||
/// The type parameters for this path segment, if present.
|
||||
pub types: HirVec<P<Ty>>,
|
||||
/// Whether to infer remaining type parameters, if any.
|
||||
/// This only applies to expression and pattern paths, and
|
||||
/// out of those only the segments with no type parameters
|
||||
/// to begin with, e.g. `Vec::new` is `<Vec<..>>::new::<..>`.
|
||||
pub infer_types: bool,
|
||||
/// Bindings (equality constraints) on associated types, if present.
|
||||
/// E.g., `Foo<A=Bar>`.
|
||||
pub bindings: HirVec<TypeBinding>,
|
||||
|
|
@ -250,12 +301,16 @@ impl PathParameters {
|
|||
Self {
|
||||
lifetimes: HirVec::new(),
|
||||
types: HirVec::new(),
|
||||
infer_types: true,
|
||||
bindings: HirVec::new(),
|
||||
parenthesized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.lifetimes.is_empty() && self.types.is_empty() &&
|
||||
self.bindings.is_empty() && !self.parenthesized
|
||||
}
|
||||
|
||||
pub fn inputs(&self) -> &[P<Ty>] {
|
||||
if self.parenthesized {
|
||||
if let Some(ref ty) = self.types.get(0) {
|
||||
|
|
@ -296,6 +351,7 @@ pub struct TyParam {
|
|||
pub default: Option<P<Ty>>,
|
||||
pub span: Span,
|
||||
pub pure_wrt_drop: bool,
|
||||
pub synthetic: Option<SyntheticTyParamKind>,
|
||||
}
|
||||
|
||||
/// Represents lifetimes and type parameters attached to a declaration
|
||||
|
|
@ -364,6 +420,13 @@ impl Generics {
|
|||
}
|
||||
}
|
||||
|
||||
/// Synthetic Type Parameters are converted to an other form during lowering, this allows
|
||||
/// to track the original form they had. Usefull for error messages.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum SyntheticTyParamKind {
|
||||
ImplTrait
|
||||
}
|
||||
|
||||
/// A `where` clause in a definition
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct WhereClause {
|
||||
|
|
@ -1330,6 +1393,7 @@ pub struct Ty {
|
|||
pub id: NodeId,
|
||||
pub node: Ty_,
|
||||
pub span: Span,
|
||||
pub hir_id: HirId,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Ty {
|
||||
|
|
|
|||
|
|
@ -1213,11 +1213,17 @@ impl<'a> State<'a> {
|
|||
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX)?;
|
||||
self.s.word(".")?;
|
||||
self.print_name(segment.name)?;
|
||||
if !segment.parameters.lifetimes.is_empty() ||
|
||||
!segment.parameters.types.is_empty() ||
|
||||
!segment.parameters.bindings.is_empty() {
|
||||
self.print_path_parameters(&segment.parameters, true)?;
|
||||
}
|
||||
|
||||
segment.with_parameters(|parameters| {
|
||||
if !parameters.lifetimes.is_empty() ||
|
||||
!parameters.types.is_empty() ||
|
||||
!parameters.bindings.is_empty()
|
||||
{
|
||||
self.print_path_parameters(¶meters, segment.infer_types, true)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
self.print_call_post(base_args)
|
||||
}
|
||||
|
||||
|
|
@ -1564,8 +1570,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
if segment.name != keywords::CrateRoot.name() &&
|
||||
segment.name != keywords::DollarCrate.name() {
|
||||
self.print_name(segment.name)?;
|
||||
self.print_path_parameters(&segment.parameters, colons_before_params)?;
|
||||
self.print_name(segment.name)?;
|
||||
segment.with_parameters(|parameters| {
|
||||
self.print_path_parameters(parameters,
|
||||
segment.infer_types,
|
||||
colons_before_params)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1593,7 +1603,11 @@ impl<'a> State<'a> {
|
|||
if segment.name != keywords::CrateRoot.name() &&
|
||||
segment.name != keywords::DollarCrate.name() {
|
||||
self.print_name(segment.name)?;
|
||||
self.print_path_parameters(&segment.parameters, colons_before_params)?;
|
||||
segment.with_parameters(|parameters| {
|
||||
self.print_path_parameters(parameters,
|
||||
segment.infer_types,
|
||||
colons_before_params)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1601,7 +1615,11 @@ impl<'a> State<'a> {
|
|||
self.s.word("::")?;
|
||||
let item_segment = path.segments.last().unwrap();
|
||||
self.print_name(item_segment.name)?;
|
||||
self.print_path_parameters(&item_segment.parameters, colons_before_params)
|
||||
item_segment.with_parameters(|parameters| {
|
||||
self.print_path_parameters(parameters,
|
||||
item_segment.infer_types,
|
||||
colons_before_params)
|
||||
})
|
||||
}
|
||||
hir::QPath::TypeRelative(ref qself, ref item_segment) => {
|
||||
self.s.word("<")?;
|
||||
|
|
@ -1609,13 +1627,18 @@ impl<'a> State<'a> {
|
|||
self.s.word(">")?;
|
||||
self.s.word("::")?;
|
||||
self.print_name(item_segment.name)?;
|
||||
self.print_path_parameters(&item_segment.parameters, colons_before_params)
|
||||
item_segment.with_parameters(|parameters| {
|
||||
self.print_path_parameters(parameters,
|
||||
item_segment.infer_types,
|
||||
colons_before_params)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_path_parameters(&mut self,
|
||||
parameters: &hir::PathParameters,
|
||||
infer_types: bool,
|
||||
colons_before_params: bool)
|
||||
-> io::Result<()> {
|
||||
if parameters.parenthesized {
|
||||
|
|
@ -1652,7 +1675,7 @@ impl<'a> State<'a> {
|
|||
|
||||
// FIXME(eddyb) This would leak into error messages, e.g.:
|
||||
// "non-exhaustive patterns: `Some::<..>(_)` not covered".
|
||||
if parameters.infer_types && false {
|
||||
if infer_types && false {
|
||||
start_or_comma(self)?;
|
||||
self.s.word("..")?;
|
||||
}
|
||||
|
|
@ -1975,7 +1998,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
|
||||
self.print_name(lifetime.name)
|
||||
self.print_name(lifetime.name.name())
|
||||
}
|
||||
|
||||
pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ struct CacheEntry {
|
|||
file_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CachingCodemapView<'cm> {
|
||||
codemap: &'cm CodeMap,
|
||||
line_cache: [CacheEntry; 3],
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ thread_local!(static IGNORED_ATTR_NAMES: RefCell<FxHashSet<Symbol>> =
|
|||
/// enough information to transform DefIds and HirIds into stable DefPaths (i.e.
|
||||
/// a reference to the TyCtxt) and it holds a few caches for speeding up various
|
||||
/// things (e.g. each DefId/DefPath is only hashed once).
|
||||
#[derive(Clone)]
|
||||
pub struct StableHashingContext<'gcx> {
|
||||
sess: &'gcx Session,
|
||||
definitions: &'gcx Definitions,
|
||||
|
|
@ -168,6 +169,11 @@ impl<'gcx> StableHashingContext<'gcx> {
|
|||
self.definitions.def_path_hash(def_index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
|
||||
self.definitions.node_to_hir_id(node_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hash_spans(&self) -> bool {
|
||||
self.hash_spans
|
||||
|
|
@ -259,6 +265,18 @@ impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> {
|
||||
type ContextType = StableHashingContext<'gcx>;
|
||||
fn create_stable_hashing_context(&self) -> Self::ContextType {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'gcx> {
|
||||
}
|
||||
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
|
|
|
|||
|
|
@ -123,6 +123,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItemId {
|
|||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum hir::LifetimeName {
|
||||
Implicit,
|
||||
Underscore,
|
||||
Static,
|
||||
Name(name)
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::Lifetime {
|
||||
id,
|
||||
span,
|
||||
|
|
@ -143,13 +150,13 @@ impl_stable_hash_for!(struct hir::Path {
|
|||
|
||||
impl_stable_hash_for!(struct hir::PathSegment {
|
||||
name,
|
||||
infer_types,
|
||||
parameters
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::PathParameters {
|
||||
lifetimes,
|
||||
types,
|
||||
infer_types,
|
||||
bindings,
|
||||
parenthesized
|
||||
});
|
||||
|
|
@ -170,7 +177,8 @@ impl_stable_hash_for!(struct hir::TyParam {
|
|||
bounds,
|
||||
default,
|
||||
span,
|
||||
pure_wrt_drop
|
||||
pure_wrt_drop,
|
||||
synthetic
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::Generics {
|
||||
|
|
@ -180,6 +188,10 @@ impl_stable_hash_for!(struct hir::Generics {
|
|||
span
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::SyntheticTyParamKind {
|
||||
ImplTrait
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::WhereClause {
|
||||
id,
|
||||
predicates
|
||||
|
|
@ -238,6 +250,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Ty {
|
|||
hcx.while_hashing_hir_bodies(true, |hcx| {
|
||||
let hir::Ty {
|
||||
id: _,
|
||||
hir_id: _,
|
||||
ref node,
|
||||
ref span,
|
||||
} = *self;
|
||||
|
|
@ -691,7 +704,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem {
|
|||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::TraitItem {
|
||||
id,
|
||||
id: _,
|
||||
hir_id: _,
|
||||
name,
|
||||
ref attrs,
|
||||
|
|
@ -700,7 +713,6 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem {
|
|||
} = *self;
|
||||
|
||||
hcx.hash_hir_item_like(attrs, |hcx| {
|
||||
id.hash_stable(hcx, hasher);
|
||||
name.hash_stable(hcx, hasher);
|
||||
attrs.hash_stable(hcx, hasher);
|
||||
node.hash_stable(hcx, hasher);
|
||||
|
|
@ -725,7 +737,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem {
|
|||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::ImplItem {
|
||||
id,
|
||||
id: _,
|
||||
hir_id: _,
|
||||
name,
|
||||
ref vis,
|
||||
|
|
@ -736,7 +748,6 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem {
|
|||
} = *self;
|
||||
|
||||
hcx.hash_hir_item_like(attrs, |hcx| {
|
||||
id.hash_stable(hcx, hasher);
|
||||
name.hash_stable(hcx, hasher);
|
||||
vis.hash_stable(hcx, hasher);
|
||||
defaultness.hash_stable(hcx, hasher);
|
||||
|
|
@ -1160,6 +1171,25 @@ for hir::TraitCandidate {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::TraitCandidate {
|
||||
type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>);
|
||||
|
||||
fn to_stable_hash_key(&self,
|
||||
hcx: &StableHashingContext<'gcx>)
|
||||
-> Self::KeyType {
|
||||
let hir::TraitCandidate {
|
||||
def_id,
|
||||
import_id,
|
||||
} = *self;
|
||||
|
||||
let import_id = import_id.map(|node_id| hcx.node_to_hir_id(node_id))
|
||||
.map(|hir_id| (hcx.local_def_path_hash(hir_id.owner),
|
||||
hir_id.local_id));
|
||||
(hcx.def_path_hash(def_id), import_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl_stable_hash_for!(struct hir::Freevar {
|
||||
def,
|
||||
span
|
||||
|
|
|
|||
|
|
@ -28,10 +28,12 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
|
|||
name,
|
||||
source_info,
|
||||
internal,
|
||||
lexical_scope,
|
||||
is_user_variable
|
||||
});
|
||||
impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
|
||||
impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
|
||||
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, lint_node_id });
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
for mir::Terminator<'gcx> {
|
||||
|
|
@ -75,6 +77,22 @@ for mir::Terminator<'gcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearOnDecode<T>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
mir::ClearOnDecode::Clear => {}
|
||||
mir::ClearOnDecode::Set(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Local {
|
||||
#[inline]
|
||||
|
|
@ -347,6 +365,26 @@ for mir::ProjectionElem<'gcx, V, T>
|
|||
}
|
||||
|
||||
impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
|
||||
impl_stable_hash_for!(struct mir::VisibilityScopeInfo {
|
||||
lint_root, safety
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Safety {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
mir::Safety::Safe |
|
||||
mir::Safety::BuiltinUnsafe |
|
||||
mir::Safety::FnUnsafe => {}
|
||||
mir::Safety::ExplicitUnsafe(node_id) => {
|
||||
node_id.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
|
|
|
|||
|
|
@ -272,6 +272,8 @@ fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token,
|
|||
token::Token::Dot |
|
||||
token::Token::DotDot |
|
||||
token::Token::DotDotDot |
|
||||
token::Token::DotDotEq |
|
||||
token::Token::DotEq |
|
||||
token::Token::Comma |
|
||||
token::Token::Semi |
|
||||
token::Token::Colon |
|
||||
|
|
|
|||
|
|
@ -463,7 +463,8 @@ impl_stable_hash_for!(struct ty::TypeParameterDef {
|
|||
index,
|
||||
has_default,
|
||||
object_lifetime_default,
|
||||
pure_wrt_drop
|
||||
pure_wrt_drop,
|
||||
synthetic
|
||||
});
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
|
||||
|
|
@ -514,13 +515,8 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
|
|||
FnPtrAddrCast
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum ::middle::region::Scope {
|
||||
Node(local_id),
|
||||
Destruction(local_id),
|
||||
CallSite(local_id),
|
||||
Arguments(local_id),
|
||||
Remainder(block_remainder)
|
||||
});
|
||||
impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { idx });
|
||||
impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
|
||||
|
||||
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for region::Scope {
|
||||
type KeyType = region::Scope;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use infer::region_inference::RegionResolutionError;
|
|||
use hir::map as hir_map;
|
||||
use middle::resolve_lifetime as rl;
|
||||
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use infer::error_reporting::util::AnonymousArgInfo;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// This method prints the error message for lifetime errors when both the concerned regions
|
||||
|
|
@ -57,6 +58,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
|
||||
|
||||
let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
|
||||
|
||||
debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
|
||||
ty_sub,
|
||||
sup,
|
||||
|
|
@ -66,56 +68,70 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
sub,
|
||||
bregion_sub);
|
||||
|
||||
let (main_label, label1, label2) = if let (Some(sup_arg), Some(sub_arg)) =
|
||||
(self.find_arg_with_region(sup, sup), self.find_arg_with_region(sub, sub)) {
|
||||
let (ty_sup, ty_fndecl_sup) = ty_sup;
|
||||
let (ty_sub, ty_fndecl_sub) = ty_sub;
|
||||
|
||||
let (anon_arg_sup, is_first_sup, anon_arg_sub, is_first_sub) =
|
||||
(sup_arg.arg, sup_arg.is_first, sub_arg.arg, sub_arg.is_first);
|
||||
if self.is_self_anon(is_first_sup, scope_def_id_sup) ||
|
||||
self.is_self_anon(is_first_sub, scope_def_id_sub) {
|
||||
return false;
|
||||
}
|
||||
let AnonymousArgInfo { arg: anon_arg_sup, .. } =
|
||||
or_false!(self.find_arg_with_region(sup, sup));
|
||||
let AnonymousArgInfo { arg: anon_arg_sub, .. } =
|
||||
or_false!(self.find_arg_with_region(sub, sub));
|
||||
|
||||
if self.is_return_type_anon(scope_def_id_sup, bregion_sup) ||
|
||||
self.is_return_type_anon(scope_def_id_sub, bregion_sub) {
|
||||
return false;
|
||||
}
|
||||
let sup_is_ret_type =
|
||||
self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
|
||||
let sub_is_ret_type =
|
||||
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
|
||||
|
||||
if anon_arg_sup == anon_arg_sub {
|
||||
(format!("this type was declared with multiple lifetimes..."),
|
||||
format!(" with one lifetime"),
|
||||
format!(" into the other"))
|
||||
} else {
|
||||
let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
|
||||
format!(" from `{}`", simple_name)
|
||||
} else {
|
||||
format!("")
|
||||
};
|
||||
|
||||
let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
|
||||
format!(" into `{}`", simple_name)
|
||||
} else {
|
||||
format!("")
|
||||
};
|
||||
|
||||
let span_label =
|
||||
format!("these two types are declared with different lifetimes...",);
|
||||
|
||||
(span_label, span_label_var1, span_label_var2)
|
||||
}
|
||||
let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
|
||||
format!(" from `{}`", simple_name)
|
||||
} else {
|
||||
debug!("no arg with anon region found");
|
||||
debug!("try_report_anon_anon_conflict: is_suitable(sub) = {:?}",
|
||||
self.is_suitable_region(sub));
|
||||
debug!("try_report_anon_anon_conflict: is_suitable(sup) = {:?}",
|
||||
self.is_suitable_region(sup));
|
||||
return false;
|
||||
format!("")
|
||||
};
|
||||
|
||||
let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
|
||||
format!(" into `{}`", simple_name)
|
||||
} else {
|
||||
format!("")
|
||||
};
|
||||
|
||||
|
||||
let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
|
||||
(None, None) => {
|
||||
let (main_label_1, span_label_1) = if ty_sup == ty_sub {
|
||||
|
||||
(format!("this type is declared with multiple lifetimes..."),
|
||||
format!("...but data{} flows{} here",
|
||||
format!(" with one lifetime"),
|
||||
format!(" into the other")))
|
||||
} else {
|
||||
(format!("these two types are declared with different lifetimes..."),
|
||||
format!("...but data{} flows{} here",
|
||||
span_label_var1,
|
||||
span_label_var2))
|
||||
};
|
||||
(ty_sup.span, ty_sub.span, main_label_1, span_label_1)
|
||||
}
|
||||
|
||||
(Some(ret_span), _) => {
|
||||
(ty_sub.span,
|
||||
ret_span,
|
||||
format!("this parameter and the return type are declared \
|
||||
with different lifetimes...",),
|
||||
format!("...but data{} is returned here", span_label_var1))
|
||||
}
|
||||
(_, Some(ret_span)) => {
|
||||
(ty_sup.span,
|
||||
ret_span,
|
||||
format!("this parameter and the return type are declared \
|
||||
with different lifetimes...",),
|
||||
format!("...but data{} is returned here", span_label_var1))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
|
||||
.span_label(ty_sup.span, main_label)
|
||||
.span_label(ty_sub.span, format!(""))
|
||||
.span_label(span, format!("...but data{} flows{} here", label1, label2))
|
||||
.span_label(span_1, main_label)
|
||||
.span_label(span_2, format!(""))
|
||||
.span_label(span, span_label)
|
||||
.emit();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -135,28 +151,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
/// ```
|
||||
/// The function returns the nested type corresponding to the anonymous region
|
||||
/// for e.g. `&u8` and Vec<`&u8`.
|
||||
pub fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
|
||||
pub fn find_anon_type(&self,
|
||||
region: Region<'tcx>,
|
||||
br: &ty::BoundRegion)
|
||||
-> Option<(&hir::Ty, &hir::FnDecl)> {
|
||||
if let Some(anon_reg) = self.is_suitable_region(region) {
|
||||
let def_id = anon_reg.def_id;
|
||||
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
let inputs: &[_] = match self.tcx.hir.get(node_id) {
|
||||
let fndecl = match self.tcx.hir.get(node_id) {
|
||||
hir_map::NodeItem(&hir::Item { node: hir::ItemFn(ref fndecl, ..), .. }) => {
|
||||
&fndecl.inputs
|
||||
&fndecl
|
||||
}
|
||||
hir_map::NodeTraitItem(&hir::TraitItem {
|
||||
node: hir::TraitItemKind::Method(ref fndecl, ..), ..
|
||||
}) => &fndecl.decl.inputs,
|
||||
node: hir::TraitItemKind::Method(ref m, ..), ..
|
||||
}) |
|
||||
hir_map::NodeImplItem(&hir::ImplItem {
|
||||
node: hir::ImplItemKind::Method(ref fndecl, ..), ..
|
||||
}) => &fndecl.decl.inputs,
|
||||
|
||||
_ => &[],
|
||||
node: hir::ImplItemKind::Method(ref m, ..), ..
|
||||
}) => &m.decl,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
return inputs
|
||||
return fndecl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|arg| self.find_component_for_bound_region(&**arg, br))
|
||||
.next();
|
||||
.filter_map(|arg| self.find_component_for_bound_region(arg, br))
|
||||
.next()
|
||||
.map(|ty| (ty, &**fndecl));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ use syntax::ast::DUMMY_NODE_ID;
|
|||
use syntax_pos::{Pos, Span};
|
||||
use errors::{DiagnosticBuilder, DiagnosticStyledString};
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
mod note;
|
||||
|
||||
mod need_type_info;
|
||||
|
|
@ -152,21 +154,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let scope_decorated_tag = match scope {
|
||||
region::Scope::Node(_) => tag,
|
||||
region::Scope::CallSite(_) => {
|
||||
let scope_decorated_tag = match scope.data() {
|
||||
region::ScopeData::Node(_) => tag,
|
||||
region::ScopeData::CallSite(_) => {
|
||||
"scope of call-site for function"
|
||||
}
|
||||
region::Scope::Arguments(_) => {
|
||||
region::ScopeData::Arguments(_) => {
|
||||
"scope of function body"
|
||||
}
|
||||
region::Scope::Destruction(_) => {
|
||||
region::ScopeData::Destruction(_) => {
|
||||
new_string = format!("destruction scope surrounding {}", tag);
|
||||
&new_string[..]
|
||||
}
|
||||
region::Scope::Remainder(r) => {
|
||||
region::ScopeData::Remainder(r) => {
|
||||
new_string = format!("block suffix following statement {}",
|
||||
r.first_statement_index);
|
||||
r.first_statement_index.index());
|
||||
&new_string[..]
|
||||
}
|
||||
};
|
||||
|
|
@ -333,11 +335,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
GenericBoundFailure(..) => true,
|
||||
};
|
||||
|
||||
if errors.iter().all(|e| is_bound_failure(e)) {
|
||||
|
||||
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
|
||||
errors.clone()
|
||||
} else {
|
||||
errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
|
||||
}
|
||||
};
|
||||
|
||||
// sort the errors by span, for better error message stability.
|
||||
errors.sort_by_key(|u| match *u {
|
||||
ConcreteFailure(ref sro, _, _) => sro.span(),
|
||||
GenericBoundFailure(ref sro, _, _) => sro.span(),
|
||||
SubSupConflict(ref rvo, _, _, _, _) => rvo.span(),
|
||||
});
|
||||
errors
|
||||
}
|
||||
|
||||
/// Adds a note if the types come from similarly named crates
|
||||
|
|
@ -774,10 +785,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>)
|
||||
{
|
||||
// FIXME: it would be better to report the first error message
|
||||
// with the span of the parameter itself, rather than the span
|
||||
// where the error was detected. But that span is not readily
|
||||
// accessible.
|
||||
// Attempt to obtain the span of the parameter so we can
|
||||
// suggest adding an explicit lifetime bound to it.
|
||||
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
||||
(Some(ref table), GenericKind::Param(ref param)) => {
|
||||
let table = table.borrow();
|
||||
table.local_id_root.and_then(|did| {
|
||||
let generics = self.tcx.generics_of(did);
|
||||
// Account for the case where `did` corresponds to `Self`, which doesn't have
|
||||
// the expected type argument.
|
||||
if generics.types.len() > 0 {
|
||||
let type_param = generics.type_param(param);
|
||||
let hir = &self.tcx.hir;
|
||||
hir.as_local_node_id(type_param.def_id).map(|id| {
|
||||
// Get the `hir::TyParam` to verify wether it already has any bounds.
|
||||
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
|
||||
// instead we suggest `T: 'a + 'b` in that case.
|
||||
let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) {
|
||||
p.bounds.len() > 0
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let sp = hir.span(id);
|
||||
// `sp` only covers `T`, change it so that it covers
|
||||
// `T:` when appropriate
|
||||
let sp = if has_lifetimes {
|
||||
sp.to(sp.next_point().next_point())
|
||||
} else {
|
||||
sp
|
||||
};
|
||||
(sp, has_lifetimes)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let labeled_user_string = match bound_kind {
|
||||
GenericKind::Param(ref p) =>
|
||||
|
|
@ -799,6 +844,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>,
|
||||
type_param_span: Option<(Span, bool)>,
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: S) {
|
||||
let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...",
|
||||
bound_kind,
|
||||
sub);
|
||||
if let Some((sp, has_lifetimes)) = type_param_span {
|
||||
let tail = if has_lifetimes {
|
||||
" + "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
|
||||
err.span_suggestion_short(sp, consider, suggestion);
|
||||
} else {
|
||||
err.help(consider);
|
||||
}
|
||||
}
|
||||
|
||||
let mut err = match *sub {
|
||||
ty::ReEarlyBound(_) |
|
||||
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
||||
|
|
@ -808,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
E0309,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
|
||||
bound_kind,
|
||||
sub));
|
||||
binding_suggestion(&mut err, type_param_span, bound_kind, sub);
|
||||
err
|
||||
}
|
||||
|
||||
|
|
@ -821,9 +884,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
E0310,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
err.help(&format!("consider adding an explicit lifetime \
|
||||
bound `{}: 'static`...",
|
||||
bound_kind));
|
||||
binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
|
||||
err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,15 +35,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// only introduced anonymous regions in parameters) as well as a
|
||||
// version new_ty of its type where the anonymous region is replaced
|
||||
// with the named one.//scope_def_id
|
||||
let (named, anon_arg_info, region_info) =
|
||||
let (named, anon, anon_arg_info, region_info) =
|
||||
if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
|
||||
self.find_arg_with_region(sup, sub).is_some() {
|
||||
(sub,
|
||||
sup,
|
||||
self.find_arg_with_region(sup, sub).unwrap(),
|
||||
self.is_suitable_region(sup).unwrap())
|
||||
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
|
||||
self.find_arg_with_region(sub, sup).is_some() {
|
||||
(sup,
|
||||
sub,
|
||||
self.find_arg_with_region(sub, sup).unwrap(),
|
||||
self.is_suitable_region(sub).unwrap())
|
||||
} else {
|
||||
|
|
@ -76,33 +78,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if self.is_return_type_anon(scope_def_id, br) {
|
||||
debug!("try_report_named_anon_conflict: is_return_type_anon({:?}, {:?}) = true",
|
||||
scope_def_id,
|
||||
br);
|
||||
return false;
|
||||
} else if self.is_self_anon(is_first, scope_def_id) {
|
||||
debug!("try_report_named_anon_conflict: is_self_anon({:?}, {:?}) = true",
|
||||
is_first,
|
||||
scope_def_id);
|
||||
return false;
|
||||
} else {
|
||||
let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
|
||||
(format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
|
||||
} else {
|
||||
("parameter type".to_owned(), "type".to_owned())
|
||||
};
|
||||
|
||||
struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0621,
|
||||
"explicit lifetime required in {}",
|
||||
error_var)
|
||||
.span_label(arg.pat.span,
|
||||
format!("consider changing {} to `{}`", span_label_var, new_ty))
|
||||
.span_label(span, format!("lifetime `{}` required", named))
|
||||
.emit();
|
||||
return true;
|
||||
if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
|
||||
if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
|
||||
self.is_self_anon(is_first, scope_def_id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
|
||||
(format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
|
||||
} else {
|
||||
("parameter type".to_owned(), "type".to_owned())
|
||||
};
|
||||
|
||||
struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0621,
|
||||
"explicit lifetime required in {}",
|
||||
error_var)
|
||||
.span_label(arg.pat.span,
|
||||
format!("consider changing {} to `{}`", span_label_var, new_ty))
|
||||
.span_label(span, format!("lifetime `{}` required", named))
|
||||
.emit();
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use infer::InferCtxt;
|
|||
use ty::{self, Region, Ty};
|
||||
use hir::def_id::DefId;
|
||||
use hir::map as hir_map;
|
||||
use syntax_pos::Span;
|
||||
|
||||
macro_rules! or_false {
|
||||
($v:expr) => {
|
||||
|
|
@ -163,7 +164,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// Here, we check for the case where the anonymous region
|
||||
// is in the return type.
|
||||
// FIXME(#42703) - Need to handle certain cases here.
|
||||
pub fn is_return_type_anon(&self, scope_def_id: DefId, br: ty::BoundRegion) -> bool {
|
||||
pub fn is_return_type_anon(&self,
|
||||
scope_def_id: DefId,
|
||||
br: ty::BoundRegion,
|
||||
decl: &hir::FnDecl)
|
||||
-> Option<Span> {
|
||||
let ret_ty = self.tcx.type_of(scope_def_id);
|
||||
match ret_ty.sty {
|
||||
ty::TyFnDef(_, _) => {
|
||||
|
|
@ -171,12 +176,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let late_bound_regions = self.tcx
|
||||
.collect_referenced_late_bound_regions(&sig.output());
|
||||
if late_bound_regions.iter().any(|r| *r == br) {
|
||||
return true;
|
||||
return Some(decl.output.span());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
None
|
||||
}
|
||||
// Here we check for the case where anonymous region
|
||||
// corresponds to self and if yes, we display E0312.
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ pub mod middle {
|
|||
pub mod dataflow;
|
||||
pub mod dead;
|
||||
pub mod dependency_format;
|
||||
pub mod effect;
|
||||
pub mod entry;
|
||||
pub mod exported_symbols;
|
||||
pub mod free_region;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ declare_lint! {
|
|||
|
||||
declare_lint! {
|
||||
pub UNUSED_EXTERN_CRATES,
|
||||
Warn,
|
||||
Allow,
|
||||
"extern crates that are never used"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,11 @@ impl LintLevelMap {
|
|||
self.sets.get_lint_level(lint, *idx, None)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns if this `id` has lint level information.
|
||||
pub fn lint_level_set(&self, id: HirId) -> Option<u32> {
|
||||
self.id_to_set.get(&id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LintLevelMap {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue