Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Nikolai Vazquez 2017-09-30 10:08:33 -04:00
commit 4c853adce9
362 changed files with 7972 additions and 4180 deletions

3
.gitignore vendored
View file

@ -103,3 +103,6 @@ version.texi
.cargo
!src/vendor/**
/src/target/
no_llvm_build

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -46,4 +46,6 @@ impl Default for ToolState {
pub struct ToolStates {
pub miri: ToolState,
pub clippy: ToolState,
pub rls: ToolState,
pub rustfmt: ToolState,
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 = []

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,4 +15,4 @@ doc = false
core = { path = "../libcore" }
[build-dependencies]
gcc = "0.3.50"
cc = "1.0"

View file

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

View file

@ -37,7 +37,7 @@ incremental improves that may change.)
The dependency structure of these crates is roughly a diamond:
````
```
rustc_driver
/ | \
/ | \

View file

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

View file

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

View file

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

View file

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

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

View file

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

View 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]
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 {
&params
} 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 {

View file

@ -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(&parameters, 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<()> {

View file

@ -22,6 +22,7 @@ struct CacheEntry {
file_index: usize,
}
#[derive(Clone)]
pub struct CachingCodemapView<'cm> {
codemap: &'cm CodeMap,
line_cache: [CacheEntry; 3],

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,7 +30,7 @@ declare_lint! {
declare_lint! {
pub UNUSED_EXTERN_CRATES,
Warn,
Allow,
"extern crates that are never used"
}

View file

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