Merge remote-tracking branch 'origin/master' into gen

This commit is contained in:
Alex Crichton 2017-08-07 22:30:39 -07:00
commit c25ddf21f1
280 changed files with 17756 additions and 2240 deletions

1
configure vendored
View File

@ -437,7 +437,6 @@ opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)"
opt llvm-clean-rebuild 0 "delete LLVM build directory on rebuild"
opt rpath 1 "build rpaths into rustc itself"
opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
# This is used by the automation to produce single-target nightlies

42
src/Cargo.lock generated
View File

@ -187,7 +187,7 @@ dependencies = [
"curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -323,7 +323,7 @@ name = "crates-io"
version = "0.11.0"
dependencies = [
"curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -436,6 +436,14 @@ dependencies = [
"backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.11.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error_index_generator"
version = "0.0.0"
@ -1132,8 +1140,8 @@ dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfmt-nightly 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1147,23 +1155,25 @@ dependencies = [
[[package]]
name = "rls-analysis"
version = "0.4.5"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rls-data"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1242,6 +1252,13 @@ dependencies = [
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_apfloat"
version = "0.0.0"
dependencies = [
"rustc_bitflags 0.0.0",
]
[[package]]
name = "rustc_asan"
version = "0.0.0"
@ -1299,6 +1316,7 @@ dependencies = [
name = "rustc_const_math"
version = "0.0.0"
dependencies = [
"rustc_apfloat 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
]
@ -1496,10 +1514,11 @@ name = "rustc_save_analysis"
version = "0.0.0"
dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_typeck 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
@ -1509,11 +1528,11 @@ dependencies = [
name = "rustc_trans"
version = "0.0.0"
dependencies = [
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2145,6 +2164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38d3a55d9a7a456748f2a3912c0941a5d9a68006eb15b3c3c9836b8420dc102d"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
@ -2209,8 +2229,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
"checksum rls-analysis 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0127cfae9c726461facbbbc8327e782adf8afd61f7fcc6adf8ea9ad8fc428ed0"
"checksum rls-data 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f274ec7f966337dc2601fe9bde060b551d1293c277af782dc65cd7200ca070c0"
"checksum rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cb40c0371765897ae428b5706bb17135705ad4f6d1b8b6afbaabcf8c9b5cff"
"checksum rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11d339f1888e33e74d8032de0f83c40b2bdaaaf04a8cfc03b32186c3481fb534"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"

View File

@ -188,7 +188,7 @@ fn main() {
cmd.arg("-Zsave-analysis");
cmd.env("RUST_SAVE_ANALYSIS_CONFIG",
"{\"output_file\": null,\"full_docs\": false,\"pub_only\": true,\
\"signatures\": false,\"borrow_data\": false}");
\"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}");
}
// Dealing with rpath here is a little special, so let's go into some

View File

@ -28,6 +28,7 @@ use check;
use flags::Subcommand;
use doc;
use tool;
use native;
pub use Compiler;
@ -256,7 +257,8 @@ impl<'a> Builder<'a> {
compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex,
tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc),
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc,
native::Llvm),
Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Linkcheck,
check::Cargotest, check::Cargo, check::Rls, check::Docs, check::ErrorIndex,

View File

@ -1050,11 +1050,8 @@ impl Step for Crate {
dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
if target.contains("emscripten") || build.remote_tested(target) {
cargo.arg("--no-run");
}
cargo.arg("--");
cargo.args(&build.flags.cmd.test_args());
if build.config.quiet_tests {
cargo.arg("--quiet");
@ -1063,75 +1060,24 @@ impl Step for Crate {
let _time = util::timeit();
if target.contains("emscripten") {
build.run(&mut cargo);
krate_emscripten(build, compiler, target, mode);
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
build.config.nodejs.as_ref().expect("nodejs not configured"));
} else if build.remote_tested(target) {
build.run(&mut cargo);
krate_remote(builder, compiler, target, mode);
} else {
cargo.args(&build.flags.cmd.test_args());
try_run(build, &mut cargo);
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
format!("{} run",
builder.tool_exe(Tool::RemoteTestClient).display()));
}
try_run(build, &mut cargo);
}
}
fn krate_emscripten(build: &Build,
compiler: Compiler,
target: Interned<String>,
mode: Mode) {
let out_dir = build.cargo_out(compiler, mode, target);
let tests = find_tests(&out_dir.join("deps"), target);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
for test in tests {
println!("running {}", test.display());
let mut cmd = Command::new(nodejs);
cmd.arg(&test);
if build.config.quiet_tests {
cmd.arg("--quiet");
fn envify(s: &str) -> String {
s.chars().map(|c| {
match c {
'-' => '_',
c => c,
}
try_run(build, &mut cmd);
}
}
fn krate_remote(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
mode: Mode) {
let build = builder.build;
let out_dir = build.cargo_out(compiler, mode, target);
let tests = find_tests(&out_dir.join("deps"), target);
let tool = builder.tool_exe(Tool::RemoteTestClient);
for test in tests {
let mut cmd = Command::new(&tool);
cmd.arg("run")
.arg(&test);
if build.config.quiet_tests {
cmd.arg("--quiet");
}
cmd.args(&build.flags.cmd.test_args());
try_run(build, &mut cmd);
}
}
fn find_tests(dir: &Path, target: Interned<String>) -> Vec<PathBuf> {
let mut dst = Vec::new();
for e in t!(dir.read_dir()).map(|e| t!(e)) {
let file_type = t!(e.file_type());
if !file_type.is_file() {
continue
}
let filename = e.file_name().into_string().unwrap();
if (target.contains("windows") && filename.ends_with(".exe")) ||
(!target.contains("windows") && !filename.contains(".")) ||
(target.contains("emscripten") &&
filename.ends_with(".js") &&
!filename.ends_with(".asm.js")) {
dst.push(e.path());
}
}
dst
}).flat_map(|c| c.to_uppercase()).collect()
}
/// Some test suites are run inside emulators or on remote devices, and most

View File

@ -62,7 +62,6 @@ pub struct Config {
pub llvm_targets: Option<String>,
pub llvm_experimental_targets: Option<String>,
pub llvm_link_jobs: Option<u32>,
pub llvm_clean_rebuild: bool,
// rust codegen options
pub rust_optimize: bool,
@ -203,7 +202,6 @@ struct Llvm {
targets: Option<String>,
experimental_targets: Option<String>,
link_jobs: Option<u32>,
clean_rebuild: Option<bool>,
}
#[derive(Deserialize, Default, Clone)]
@ -352,7 +350,6 @@ impl Config {
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
set(&mut config.llvm_version_check, llvm.version_check);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
set(&mut config.llvm_clean_rebuild, llvm.clean_rebuild);
config.llvm_targets = llvm.targets.clone();
config.llvm_experimental_targets = llvm.experimental_targets.clone();
config.llvm_link_jobs = llvm.link_jobs;
@ -477,7 +474,6 @@ impl Config {
("LLVM_VERSION_CHECK", self.llvm_version_check),
("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp),
("LLVM_LINK_SHARED", self.llvm_link_shared),
("LLVM_CLEAN_REBUILD", self.llvm_clean_rebuild),
("OPTIMIZE", self.rust_optimize),
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
("DEBUGINFO", self.rust_debuginfo),

View File

@ -69,11 +69,6 @@
# controlled by rustbuild's -j parameter.
#link-jobs = 0
# Delete LLVM build directory on LLVM rebuild.
# This option defaults to `false` for local development, but CI may want to
# always perform clean full builds (possibly accelerated by (s)ccache).
#clean-rebuild = false
# =============================================================================
# General build configuration options
# =============================================================================
@ -208,7 +203,7 @@
#codegen-units = 1
# Whether or not debug assertions are enabled for the compiler and standard
# library
# library. Also enables compilation of debug! and trace! logging macros.
#debug-assertions = false
# Whether or not debuginfo is emitted

View File

@ -48,6 +48,10 @@ impl Step for Llvm {
run.path("src/llvm")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Llvm { target: run.target })
}
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) {
let build = builder.build;
@ -76,9 +80,6 @@ impl Step for Llvm {
return
}
}
if build.config.llvm_clean_rebuild {
drop(fs::remove_dir_all(&out_dir));
}
let _folder = build.fold_output(|| "llvm");
println!("Building LLVM for {}", target);
@ -128,6 +129,15 @@ impl Step for Llvm {
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
// This setting makes the LLVM tools link to the dynamic LLVM library,
// which saves both memory during parallel links and overall disk space
// for the tools. We don't distribute any of those tools, so this is
// just a local concern. However, it doesn't work well everywhere.
if target.contains("linux-gnu") || target.contains("apple-darwin") {
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
}
if target.contains("msvc") {
cfg.define("LLVM_USE_CRT_DEBUG", "MT");
cfg.define("LLVM_USE_CRT_RELEASE", "MT");
@ -154,6 +164,14 @@ impl Step for Llvm {
let host = build.llvm_out(build.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TABLEGEN", &host);
if target.contains("netbsd") {
cfg.define("CMAKE_SYSTEM_NAME", "NetBSD");
} else if target.contains("freebsd") {
cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
}
cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build"));
}
let sanitize_cc = |cc: &Path| {

View File

@ -13,7 +13,6 @@
extern crate filetime;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};
@ -211,7 +210,7 @@ pub fn native_lib_boilerplate(src_name: &str,
let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
let out_dir = PathBuf::from(out_dir).join(out_name);
t!(create_dir_racy(&out_dir));
t!(fs::create_dir_all(&out_dir));
if link_name.contains('=') {
println!("cargo:rustc-link-lib={}", link_name);
} else {
@ -260,21 +259,3 @@ fn fail(s: &str) -> ! {
println!("\n\n{}\n\n", s);
std::process::exit(1);
}
fn create_dir_racy(path: &Path) -> io::Result<()> {
match fs::create_dir(path) {
Ok(()) => return Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
Err(e) => return Err(e),
}
match path.parent() {
Some(p) => try!(create_dir_racy(p)),
None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
}
match fs::create_dir(path) {
Ok(()) => Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
Err(e) => Err(e),
}
}

View File

@ -13,7 +13,7 @@ set -ex
ARCH=$1
BINUTILS=2.25.1
GCC=5.3.0
GCC=6.4.0
hide_output() {
set +x
@ -86,7 +86,7 @@ rm -rf freebsd
# Finally, download and build gcc to target FreeBSD
mkdir gcc
cd gcc
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.gz | tar xzf -
cd gcc-$GCC
./contrib/download_prerequisites

View File

@ -13,7 +13,7 @@ set -ex
ARCH=$1
BINUTILS=2.25.1
GCC=5.3.0
GCC=6.4.0
hide_output() {
set +x
@ -86,7 +86,7 @@ rm -rf freebsd
# Finally, download and build gcc to target FreeBSD
mkdir gcc
cd gcc
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.gz | tar xzf -
cd gcc-$GCC
./contrib/download_prerequisites

View File

@ -67,6 +67,13 @@ else
args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
fi
# Run containers as privileged as it should give them access to some more
# syscalls such as ptrace and whatnot. In the upgrade to LLVM 5.0 it was
# discovered that the leak sanitizer apparently needs these syscalls nowadays so
# we'll need `--privileged` for at least the `x86_64-gnu` builder, so this just
# goes ahead and sets it for all builders.
args="$args --privileged"
exec docker \
run \
--volume "$root_dir:/checkout:ro" \

View File

@ -31,7 +31,6 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-clean-rebuild"
if [ "$DIST_SRC" = "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"

@ -1 +1 @@
Subproject commit 4ee596df22f8ecaa9a0b2ddc0624b0104540dbf7
Subproject commit 6f1a03dae6bcea44976918186f2d554186b3499c

@ -1 +1 @@
Subproject commit f8fd6710399a1a557155cb5be4922fe6a6f694c0
Subproject commit f570bcb681771d691aa4fdb8dfcfad1939844bf5

View File

@ -3,8 +3,15 @@
"intrinsic_prefix": "_vec_",
"llvm_prefix": "llvm.ppc.altivec.",
"number_info": {
"unsigned": {},
"signed": {}
"unsigned": {
"kind" : "u",
"data_type_short": { "8": "b", "16": "h", "32": "w", "64": "d" }
},
"signed": {
"kind" : "s",
"data_type_short": { "8": "b", "16": "h", "32": "w", "64": "d" }
},
"float": {}
},
"width_info": {
"128": { "width": "" }
@ -16,6 +23,55 @@
"llvm": "vperm",
"ret": "s32",
"args": ["0", "0", "s8"]
},
{
"intrinsic": "mradds",
"width": [128],
"llvm": "vmhraddshs",
"ret": "s16",
"args": ["0", "0", "0"]
},
{
"intrinsic": "cmpb",
"width": [128],
"llvm": "vcmpbfp",
"ret": "s32",
"args": ["f32", "f32"]
},
{
"intrinsic": "cmpeq{0.data_type_short}",
"width": [128],
"llvm": "vcmpequ{0.data_type_short}",
"ret": "s(8-32)",
"args": ["0", "0"]
},
{
"intrinsic": "cmpgt{1.kind}{1.data_type_short}",
"width": [128],
"llvm": "vcmpgt{1.kind}{1.data_type_short}",
"ret": "s(8-32)",
"args": ["0u", "1"]
},
{
"intrinsic": "cmpgt{1.kind}{1.data_type_short}",
"width": [128],
"llvm": "vcmpgt{1.kind}{1.data_type_short}",
"ret": "s(8-32)",
"args": ["0", "1"]
},
{
"intrinsic": "max{0.kind}{0.data_type_short}",
"width": [128],
"llvm": "vmax{0.kind}{0.data_type_short}",
"ret": "i(8-32)",
"args": ["0", "0"]
},
{
"intrinsic": "min{0.kind}{0.data_type_short}",
"width": [128],
"llvm": "vmin{0.kind}{0.data_type_short}",
"ret": "i(8-32)",
"args": ["0", "0"]
}
]
}

View File

@ -215,6 +215,7 @@ impl Layout {
/// of each element in the array.
///
/// On arithmetic overflow, returns `None`.
#[inline]
pub fn repeat(&self, n: usize) -> Option<(Self, usize)> {
let padded_size = match self.size.checked_add(self.padding_needed_for(self.align)) {
None => return None,

View File

@ -273,7 +273,10 @@ impl str {
core_str::StrExt::is_char_boundary(self, index)
}
/// Converts a string slice to a byte slice.
/// Converts a string slice to a byte slice. To convert the byte slice back
/// into a string slice, use the [`str::from_utf8`] function.
///
/// [`str::from_utf8`]: ./str/fn.from_utf8.html
///
/// # Examples
///
@ -289,7 +292,11 @@ impl str {
core_str::StrExt::as_bytes(self)
}
/// Converts a mutable string slice to a mutable byte slice.
/// Converts a mutable string slice to a mutable byte slice. To convert the
/// mutable byte slice back into a mutable string slice, use the
/// [`str::from_utf8_mut`] function.
///
/// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
#[stable(feature = "str_mut_extras", since = "1.20.0")]
#[inline(always)]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
@ -328,11 +335,16 @@ impl str {
/// # Examples
///
/// ```
/// let v = "🗻∈🌏";
/// let mut v = String::from("🗻∈🌏");
///
/// assert_eq!(Some("🗻"), v.get(0..4));
/// assert!(v.get(1..).is_none());
/// assert!(v.get(..8).is_none());
/// assert!(v.get(..42).is_none());
///
/// // indices not on UTF-8 sequence boundaries
/// assert!(v.get_mut(1..).is_none());
/// assert!(v.get_mut(..8).is_none());
///
/// // out of bounds
/// assert!(v.get_mut(..42).is_none());
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
@ -351,9 +363,14 @@ impl str {
///
/// ```
/// let mut v = String::from("🗻∈🌏");
///
/// assert_eq!(Some("🗻"), v.get_mut(0..4).map(|v| &*v));
///
/// // indices not on UTF-8 sequence boundaries
/// assert!(v.get_mut(1..).is_none());
/// assert!(v.get_mut(..8).is_none());
///
/// // out of bounds
/// assert!(v.get_mut(..42).is_none());
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
@ -563,12 +580,16 @@ impl str {
/// Basic usage:
///
/// ```
/// use std::ascii::AsciiExt;
///
/// let mut s = "Per Martin-Löf".to_string();
///
/// let (first, last) = s.split_at_mut(3);
///
/// assert_eq!("Per", first);
/// assert_eq!(" Martin-Löf", last);
/// {
/// let (first, last) = s.split_at_mut(3);
/// first.make_ascii_uppercase();
/// assert_eq!("PER", first);
/// assert_eq!(" Martin-Löf", last);
/// }
/// assert_eq!("PER Martin-Löf", s);
/// ```
#[inline]
#[stable(feature = "str_split_at", since = "1.4.0")]

View File

@ -188,6 +188,34 @@ use ptr;
/// A mutable memory location.
///
/// # Examples
///
/// Here you can see how using `Cell<T>` allows to use mutable field inside
/// immutable struct (which is also called 'interior mutability').
///
/// ```
/// use std::cell::Cell;
///
/// struct SomeStruct {
/// regular_field: u8,
/// special_field: Cell<u8>,
/// }
///
/// let my_struct = SomeStruct {
/// regular_field: 0,
/// special_field: Cell::new(1),
/// };
///
/// let new_value = 100;
///
/// // ERROR, because my_struct is immutable
/// // my_struct.regular_field = new_value;
///
/// // WORKS, although `my_struct` is immutable, field `special_field` is mutable because it is Cell
/// my_struct.special_field.set(new_value);
/// assert_eq!(my_struct.special_field.get(), new_value);
/// ```
///
/// See the [module-level documentation](index.html) for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Cell<T> {

View File

@ -1247,7 +1247,7 @@ pub trait Iterator {
/// assert_eq!(vec![2, 4, 6], doubled);
/// ```
///
/// Because `collect()` cares about what you're collecting into, you can
/// Because `collect()` only cares about what you're collecting into, you can
/// still use a partial type hint, `_`, with the turbofish:
///
/// ```

View File

@ -147,22 +147,13 @@ pub trait FromIterator<A>: Sized {
///
/// ```
/// let v = vec![1, 2, 3];
///
/// let mut iter = v.into_iter();
///
/// let n = iter.next();
/// assert_eq!(Some(1), n);
///
/// let n = iter.next();
/// assert_eq!(Some(2), n);
///
/// let n = iter.next();
/// assert_eq!(Some(3), n);
///
/// let n = iter.next();
/// assert_eq!(None, n);
/// assert_eq!(Some(1), iter.next());
/// assert_eq!(Some(2), iter.next());
/// assert_eq!(Some(3), iter.next());
/// assert_eq!(None, iter.next());
/// ```
///
/// Implementing `IntoIterator` for your type:
///
/// ```
@ -227,20 +218,12 @@ pub trait IntoIterator {
///
/// ```
/// let v = vec![1, 2, 3];
///
/// let mut iter = v.into_iter();
///
/// let n = iter.next();
/// assert_eq!(Some(1), n);
///
/// let n = iter.next();
/// assert_eq!(Some(2), n);
///
/// let n = iter.next();
/// assert_eq!(Some(3), n);
///
/// let n = iter.next();
/// assert_eq!(None, n);
/// assert_eq!(Some(1), iter.next());
/// assert_eq!(Some(2), iter.next());
/// assert_eq!(Some(3), iter.next());
/// assert_eq!(None, iter.next());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn into_iter(self) -> Self::IntoIter;

View File

@ -131,6 +131,10 @@ macro_rules! int_impl {
///
/// Leading and trailing whitespace represent an error.
///
/// # Panics
///
/// This function panics if `radix` is not in the range from 2 to 36.
///
/// # Examples
///
/// Basic usage:

@ -1 +1 @@
Subproject commit ec1e5ab1ef8baca57f8776bbebd9343572a87082
Subproject commit 2a5b50b7f7f539a0fd201331d6c1e0534aa332f5

View File

@ -509,14 +509,49 @@ impl TokenTree {
Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)),
Interpolated(ref nt) => __internal::with_sess(|(sess, _)| {
TokenNode::Group(Delimiter::None, TokenStream(nt.1.force(|| {
// FIXME(jseyfried): Avoid this pretty-print + reparse hack
let name = "<macro expansion>".to_owned();
let source = pprust::token_to_string(&token);
parse_stream_from_source_str(name, source, sess, Some(span))
})))
}),
Interpolated(ref nt) => {
// An `Interpolated` token means that we have a `Nonterminal`
// which is often a parsed AST item. At this point we now need
// to convert the parsed AST to an actual token stream, e.g.
// un-parse it basically.
//
// Unfortunately there's not really a great way to do that in a
// guaranteed lossless fashion right now. The fallback here is
// to just stringify the AST node and reparse it, but this loses
// all span information.
//
// As a result, some AST nodes are annotated with the token
// stream they came from. Attempt to extract these lossless
// token streams before we fall back to the stringification.
let mut tokens = None;
match nt.0 {
Nonterminal::NtItem(ref item) => {
tokens = prepend_attrs(&item.attrs, item.tokens.as_ref(), span);
}
Nonterminal::NtTraitItem(ref item) => {
tokens = prepend_attrs(&item.attrs, item.tokens.as_ref(), span);
}
Nonterminal::NtImplItem(ref item) => {
tokens = prepend_attrs(&item.attrs, item.tokens.as_ref(), span);
}
_ => {}
}
tokens.map(|tokens| {
TokenNode::Group(Delimiter::None,
TokenStream(tokens.clone()))
}).unwrap_or_else(|| {
__internal::with_sess(|(sess, _)| {
TokenNode::Group(Delimiter::None, TokenStream(nt.1.force(|| {
// FIXME(jseyfried): Avoid this pretty-print + reparse hack
let name = "<macro expansion>".to_owned();
let source = pprust::token_to_string(&token);
parse_stream_from_source_str(name, source, sess, Some(span))
})))
})
})
}
OpenDelim(..) | CloseDelim(..) => unreachable!(),
Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
@ -580,6 +615,34 @@ impl TokenTree {
}
}
fn prepend_attrs(attrs: &[ast::Attribute],
tokens: Option<&tokenstream::TokenStream>,
span: syntax_pos::Span)
-> Option<tokenstream::TokenStream>
{
let tokens = match tokens {
Some(tokens) => tokens,
None => return None,
};
if attrs.len() == 0 {
return Some(tokens.clone())
}
let mut builder = tokenstream::TokenStreamBuilder::new();
for attr in attrs {
assert_eq!(attr.style, ast::AttrStyle::Outer,
"inner attributes should prevent cached tokens from existing");
let stream = __internal::with_sess(|(sess, _)| {
// FIXME: Avoid this pretty-print + reparse hack as bove
let name = "<macro expansion>".to_owned();
let source = pprust::attr_to_string(attr);
parse_stream_from_source_str(name, source, sess, Some(span))
});
builder.push(stream);
}
builder.push(tokens.clone());
Some(builder.build())
}
/// Permanently unstable internal implementation details of this crate. This
/// should not be used.
///

View File

@ -66,7 +66,6 @@ use hir::map::DefPathHash;
use ich::Fingerprint;
use ty::{TyCtxt, Instance, InstanceDef};
use ty::fast_reject::SimplifiedType;
use ty::subst::Substs;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ich::StableHashingContext;
use std::fmt;
@ -104,6 +103,8 @@ macro_rules! define_dep_nodes {
match *self {
$(
DepKind :: $variant => {
$(return !anon_attr_to_bool!($anon);)*
// tuple args
$({
return <( $($tuple_arg,)* ) as DepNodeParams>
@ -112,6 +113,7 @@ macro_rules! define_dep_nodes {
// struct args
$({
return <( $($struct_arg_ty,)* ) as DepNodeParams>
::CAN_RECONSTRUCT_QUERY_KEY;
})*
@ -394,6 +396,7 @@ define_dep_nodes!( <'tcx>
// Represents different phases in the compiler.
[] RegionMaps(DefId),
[] Coherence,
[] CoherenceInherentImplOverlapCheck,
[] Resolve,
[] CoherenceCheckTrait(DefId),
[] PrivacyAccessLevels(CrateNum),
@ -444,17 +447,17 @@ define_dep_nodes!( <'tcx>
[] TypeckBodiesKrate,
[] TypeckTables(DefId),
[] HasTypeckTables(DefId),
[] ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> },
[anon] ConstEval,
[] SymbolName(DefId),
[] InstanceSymbolName { instance: Instance<'tcx> },
[] SpecializationGraph(DefId),
[] ObjectSafety(DefId),
[anon] IsCopy(DefId),
[anon] IsSized(DefId),
[anon] IsFreeze(DefId),
[anon] NeedsDrop(DefId),
[anon] Layout(DefId),
[anon] IsCopy,
[anon] IsSized,
[anon] IsFreeze,
[anon] NeedsDrop,
[anon] Layout,
// The set of impls for a given trait.
[] TraitImpls(DefId),

View File

@ -23,6 +23,11 @@ pub struct DepGraphEdges {
edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
task_stack: Vec<OpenTask>,
forbidden_edge: Option<EdgeFilter>,
// A set to help assert that no two tasks use the same DepNode. This is a
// temporary measure. Once we load the previous dep-graph as readonly, this
// check will fall out of the graph implementation naturally.
opened_once: FxHashSet<DepNode>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@ -80,6 +85,7 @@ impl DepGraphEdges {
edges: FxHashSet(),
task_stack: Vec::new(),
forbidden_edge,
opened_once: FxHashSet(),
}
}
@ -97,6 +103,10 @@ impl DepGraphEdges {
}
pub fn push_task(&mut self, key: DepNode) {
if !self.opened_once.insert(key) {
bug!("Re-opened node {:?}", key)
}
self.task_stack.push(OpenTask::Regular {
node: key,
reads: Vec::new(),

View File

@ -2222,7 +2222,7 @@ impl<'a> LoweringContext<'a> {
let next_ident = self.str_to_ident("__next");
let next_pat = self.pat_ident_binding_mode(e.span,
next_ident,
hir::BindByValue(hir::MutMutable));
hir::BindingAnnotation::Mutable);
// `::std::option::Option::Some(val) => next = val`
let pat_arm = {
@ -2246,8 +2246,9 @@ impl<'a> LoweringContext<'a> {
};
// `mut iter`
let iter_pat = self.pat_ident_binding_mode(e.span, iter,
hir::BindByValue(hir::MutMutable));
let iter_pat = self.pat_ident_binding_mode(e.span,
iter,
hir::BindingAnnotation::Mutable);
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
@ -2534,10 +2535,13 @@ impl<'a> LoweringContext<'a> {
}
}
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingMode {
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
match *b {
BindingMode::ByRef(m) => hir::BindByRef(self.lower_mutability(m)),
BindingMode::ByValue(m) => hir::BindByValue(self.lower_mutability(m)),
BindingMode::ByValue(Mutability::Immutable) =>
hir::BindingAnnotation::Unannotated,
BindingMode::ByRef(Mutability::Immutable) => hir::BindingAnnotation::Ref,
BindingMode::ByValue(Mutability::Mutable) => hir::BindingAnnotation::Mutable,
BindingMode::ByRef(Mutability::Mutable) => hir::BindingAnnotation::RefMut,
}
}
@ -2678,7 +2682,7 @@ impl<'a> LoweringContext<'a> {
fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
-> (hir::Stmt, NodeId) {
let pat = if mutbl {
self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable))
self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable)
} else {
self.pat_ident(sp, ident)
};
@ -2734,10 +2738,10 @@ impl<'a> LoweringContext<'a> {
}
fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> {
self.pat_ident_binding_mode(span, name, hir::BindByValue(hir::MutImmutable))
self.pat_ident_binding_mode(span, name, hir::BindingAnnotation::Unannotated)
}
fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode)
fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingAnnotation)
-> P<hir::Pat> {
let id = self.next_id();
let parent_def = self.parent_def.unwrap();

View File

@ -192,6 +192,18 @@ impl<'a> FnLikeNode<'a> {
}
}
pub fn unsafety(self) -> ast::Unsafety {
match self.kind() {
FnKind::ItemFn(_, _, unsafety, ..) => {
unsafety
}
FnKind::Method(_, m, ..) => {
m.unsafety
}
_ => ast::Unsafety::Normal
}
}
pub fn kind(self) -> FnKind<'a> {
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)

View File

@ -18,7 +18,7 @@ use hir;
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace,
CRATE_DEF_INDEX};
use ich::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::stable_hasher::StableHasher;
use serialize::{Encodable, Decodable, Encoder, Decoder};
@ -153,7 +153,7 @@ pub struct Definitions {
pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>,
macro_def_scopes: FxHashMap<Mark, DefId>,
expansions: FxHashMap<DefIndex, Mark>,
keys_created: FxHashSet<DefKey>,
next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
}
// Unfortunately we have to provide a manual impl of Clone because of the
@ -170,7 +170,7 @@ impl Clone for Definitions {
node_to_hir_id: self.node_to_hir_id.clone(),
macro_def_scopes: self.macro_def_scopes.clone(),
expansions: self.expansions.clone(),
keys_created: self.keys_created.clone(),
next_disambiguator: self.next_disambiguator.clone(),
}
}
}
@ -402,7 +402,7 @@ impl Definitions {
node_to_hir_id: IndexVec::new(),
macro_def_scopes: FxHashMap(),
expansions: FxHashMap(),
keys_created: FxHashSet(),
next_disambiguator: FxHashMap(),
}
}
@ -516,20 +516,20 @@ impl Definitions {
// The root node must be created with create_root_def()
assert!(data != DefPathData::CrateRoot);
// Find a unique DefKey. This basically means incrementing the disambiguator
// until we get no match.
let mut key = DefKey {
parent: Some(parent),
disambiguated_data: DisambiguatedDefPathData {
data,
disambiguator: 0
}
// Find the next free disambiguator for this key.
let disambiguator = {
let next_disamb = self.next_disambiguator.entry((parent, data.clone())).or_insert(0);
let disambiguator = *next_disamb;
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
disambiguator
};
while self.keys_created.contains(&key) {
key.disambiguated_data.disambiguator += 1;
}
self.keys_created.insert(key.clone());
let key = DefKey {
parent: Some(parent),
disambiguated_data: DisambiguatedDefPathData {
data, disambiguator
}
};
let parent_hash = self.table.def_path_hash(parent);
let def_path_hash = key.compute_stable_hash(parent_hash);

View File

@ -555,7 +555,9 @@ impl<'hir> Map<'hir> {
}
/// Similar to get_parent, returns the parent node id or id if there is no
/// parent.
/// parent. Note that the parent may be CRATE_NODE_ID, which is not itself
/// present in the map -- so passing the return value of get_parent_node to
/// get may actually panic.
/// This function returns the immediate parent in the AST, whereas get_parent
/// returns the enclosing item. Note that this might not be the actual parent
/// node in the AST - some kinds of nodes are not in the map and these will
@ -631,7 +633,7 @@ impl<'hir> Map<'hir> {
}
/// Retrieve the NodeId for `id`'s enclosing method, unless there's a
/// `while` or `loop` before reacing it, as block tail returns are not
/// `while` or `loop` before reaching it, as block tail returns are not
/// available in them.
///
/// ```

View File

@ -10,7 +10,6 @@
// The Rust HIR.
pub use self::BindingMode::*;
pub use self::BinOp_::*;
pub use self::BlockCheckMode::*;
pub use self::CaptureClause::*;
@ -49,7 +48,7 @@ use rustc_data_structures::indexed_vec;
use std::collections::BTreeMap;
use std::fmt;
/// HIR doesn't commit to a concrete storage type and have its own alias for a vector.
/// HIR doesn't commit to a concrete storage type and has its own alias for a vector.
/// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
/// behavior. Unlike AST, HIR is mostly a static structure, so we can use an owned slice instead
/// of `Vec` to avoid keeping extra capacity.
@ -76,14 +75,14 @@ pub mod pat_util;
pub mod print;
pub mod svh;
/// A HirId uniquely identifies a node in the HIR of then current crate. It is
/// A HirId uniquely identifies a node in the HIR of the current crate. It is
/// composed of the `owner`, which is the DefIndex of the directly enclosing
/// hir::Item, hir::TraitItem, or hir::ImplItem (i.e. the closest "item-like"),
/// and the `local_id` which is unique within the given owner.
///
/// This two-level structure makes for more stable values: One can move an item
/// around within the source code, or add or remove stuff before it, without
/// the local_id part of the HirId changing, which is a very useful property
/// the local_id part of the HirId changing, which is a very useful property in
/// incremental compilation where we have to persist things through changes to
/// the code base.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
@ -628,10 +627,28 @@ pub struct FieldPat {
pub is_shorthand: bool,
}
/// Explicit binding annotations given in the HIR for a binding. Note
/// that this is not the final binding *mode* that we infer after type
/// inference.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum BindingMode {
BindByRef(Mutability),
BindByValue(Mutability),
pub enum BindingAnnotation {
/// No binding annotation given: this means that the final binding mode
/// will depend on whether we have skipped through a `&` reference
/// when matching. For example, the `x` in `Some(x)` will have binding
/// mode `None`; if you do `let Some(x) = &Some(22)`, it will
/// ultimately be inferred to be by-reference.
///
/// Note that implicit reference skipping is not implemented yet (#42640).
Unannotated,
/// Annotated with `mut x` -- could be either ref or not, similar to `None`.
Mutable,
/// Annotated as `ref`, like `ref x`
Ref,
/// Annotated as `ref mut x`.
RefMut,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@ -647,7 +664,7 @@ pub enum PatKind {
/// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
/// The `DefId` is for the definition of the variable being bound.
Binding(BindingMode, DefId, Spanned<Name>, Option<P<Pat>>),
Binding(BindingAnnotation, DefId, Spanned<Name>, Option<P<Pat>>),
/// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
/// The `bool` is `true` in the presence of a `..`.
@ -684,6 +701,16 @@ pub enum Mutability {
MutImmutable,
}
impl Mutability {
/// Return MutMutable only if both arguments are mutable.
pub fn and(self, other: Self) -> Self {
match self {
MutMutable => other,
MutImmutable => MutImmutable,
}
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum BinOp_ {
/// The `+` operator (addition)
@ -892,6 +919,13 @@ impl Decl_ {
DeclItem(_) => &[]
}
}
pub fn is_local(&self) -> bool {
match *self {
Decl_::DeclLocal(_) => true,
_ => false,
}
}
}
/// represents one arm of a 'match'
@ -1686,7 +1720,7 @@ pub struct Item {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Item_ {
/// An`extern crate` item, with optional original crate name,
/// An `extern crate` item, with optional original crate name,
///
/// e.g. `extern crate foo` or `extern crate foo_bar as foo`
ItemExternCrate(Option<Name>),

View File

@ -87,7 +87,7 @@ impl hir::Pat {
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn each_binding<F>(&self, mut f: F)
where F: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned<ast::Name>),
{
self.walk(|p| {
if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
@ -130,12 +130,10 @@ impl hir::Pat {
pub fn simple_name(&self) -> Option<ast::Name> {
match self.node {
PatKind::Binding(hir::BindByValue(..), _, ref path1, None) => {
Some(path1.node)
}
_ => {
None
}
PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
Some(path1.node),
_ => None,
}
}
@ -163,16 +161,22 @@ impl hir::Pat {
}
/// Checks if the pattern contains any `ref` or `ref mut` bindings,
/// and if yes whether its containing mutable ones or just immutables ones.
pub fn contains_ref_binding(&self) -> Option<hir::Mutability> {
/// and if yes whether it contains mutable or just immutables ones.
///
/// FIXME(tschottdorf): this is problematic as the HIR is being scraped,
/// but ref bindings may be implicit after #42640.
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
let mut result = None;
self.each_binding(|mode, _, _, _| {
if let hir::BindingMode::BindByRef(m) = mode {
// Pick Mutable as maximum
match result {
None | Some(hir::MutImmutable) => result = Some(m),
_ => (),
self.each_binding(|annotation, _, _, _| {
match annotation {
hir::BindingAnnotation::Ref => {
match result {
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
_ => (),
}
}
hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
_ => (),
}
});
result
@ -182,9 +186,11 @@ impl hir::Pat {
impl hir::Arm {
/// Checks if the patterns for this arm contain any `ref` or `ref mut`
/// bindings, and if yes whether its containing mutable ones or just immutables ones.
pub fn contains_ref_binding(&self) -> Option<hir::Mutability> {
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
// for #42640.
self.pats.iter()
.filter_map(|pat| pat.contains_ref_binding())
.filter_map(|pat| pat.contains_explicit_ref_binding())
.max_by_key(|m| match *m {
hir::MutMutable => 1,
hir::MutImmutable => 0,

View File

@ -1655,12 +1655,16 @@ impl<'a> State<'a> {
PatKind::Wild => self.s.word("_")?,
PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
match binding_mode {
hir::BindByRef(mutbl) => {
hir::BindingAnnotation::Ref => {
self.word_nbsp("ref")?;
self.print_mutability(mutbl)?;
self.print_mutability(hir::MutImmutable)?;
}
hir::BindByValue(hir::MutImmutable) => {}
hir::BindByValue(hir::MutMutable) => {
hir::BindingAnnotation::RefMut => {
self.word_nbsp("ref")?;
self.print_mutability(hir::MutMutable)?;
}
hir::BindingAnnotation::Unannotated => {}
hir::BindingAnnotation::Mutable => {
self.word_nbsp("mut")?;
}
}

View File

@ -11,9 +11,9 @@
//! This module contains `HashStable` implementations for various data types
//! from `rustc_const_math` in no particular order.
impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
F32(val),
F64(val)
impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
ty,
bits
});
impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {

View File

@ -442,9 +442,11 @@ impl_stable_hash_for!(struct hir::FieldPat {
is_shorthand
});
impl_stable_hash_for!(enum hir::BindingMode {
BindByRef(mutability),
BindByValue(mutability)
impl_stable_hash_for!(enum hir::BindingAnnotation {
Unannotated,
Mutable,
Ref,
RefMut
});
impl_stable_hash_for!(enum hir::RangeEnd {

View File

@ -239,8 +239,12 @@ for mir::StatementKind<'tcx> {
mir::StatementKind::StorageDead(ref lvalue) => {
lvalue.hash_stable(hcx, hasher);
}
mir::StatementKind::EndRegion(ref extents) => {
extents.hash_stable(hcx, hasher);
mir::StatementKind::EndRegion(ref extent) => {
extent.hash_stable(hcx, hasher);
}
mir::StatementKind::Validate(ref op, ref lvalues) => {
op.hash_stable(hcx, hasher);
lvalues.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
@ -252,6 +256,23 @@ for mir::StatementKind<'tcx> {
}
}
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for mir::ValidationOperand<'tcx, T>
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>)
{
self.lval.hash_stable(hcx, hasher);
self.ty.hash_stable(hcx, hasher);
self.re.hash_stable(hcx, hasher);
self.mutbl.hash_stable(hcx, hasher);
}
}
impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(extent) });
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Lvalue<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
@ -271,10 +292,11 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::L
}
}
impl<'a, 'gcx, 'tcx, B, V> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for mir::Projection<'tcx, B, V>
impl<'a, 'gcx, 'tcx, B, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for mir::Projection<'tcx, B, V, T>
where B: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
@ -289,9 +311,10 @@ for mir::Projection<'tcx, B, V>
}
}
impl<'a, 'gcx, 'tcx, V> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for mir::ProjectionElem<'tcx, V>
where V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
impl<'a, 'gcx, 'tcx, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for mir::ProjectionElem<'tcx, V, T>
where V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
@ -299,7 +322,7 @@ for mir::ProjectionElem<'tcx, V>
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
mir::ProjectionElem::Deref => {}
mir::ProjectionElem::Field(field, ty) => {
mir::ProjectionElem::Field(field, ref ty) => {
field.hash_stable(hcx, hasher);
ty.hash_stable(hcx, hasher);
}

View File

@ -375,7 +375,6 @@ for ty::RegionParameterDef {
name,
def_id,
index,
issue_32330: _,
pure_wrt_drop
} = *self;
@ -630,6 +629,7 @@ for ty::TypeckTables<'tcx> {
ref node_types,
ref node_substs,
ref adjustments,
ref pat_binding_modes,
ref upvar_capture_map,
ref closure_tys,
ref closure_kinds,
@ -652,6 +652,7 @@ for ty::TypeckTables<'tcx> {
ich::hash_stable_nodemap(hcx, hasher, node_types);
ich::hash_stable_nodemap(hcx, hasher, node_substs);
ich::hash_stable_nodemap(hcx, hasher, adjustments);
ich::hash_stable_nodemap(hcx, hasher, pat_binding_modes);
ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
let ty::UpvarId {
var_id,

View File

@ -77,10 +77,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
.span_label(ty1.span,
format!("these references must have the same lifetime"))
format!("these references are not declared with the same lifetime..."))
.span_label(ty2.span, format!(""))
.span_label(span,
format!("data{}flows{}here", span_label_var1, span_label_var2))
format!("...but data{}flows{}here", span_label_var1, span_label_var2))
.emit();
} else {
return false;

View File

@ -66,8 +66,7 @@ use hir::map as hir_map;
use hir::def_id::DefId;
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, Issue32330};
use ty::{self, Region, TyCtxt, TypeFoldable};
use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span};
@ -713,35 +712,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.note_and_explain_type_err(diag, terr, span);
}
pub fn note_issue_32330(&self,
diag: &mut DiagnosticBuilder<'tcx>,
terr: &TypeError<'tcx>)
{
debug!("note_issue_32330: terr={:?}", terr);
match *terr {
TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 {
fn_def_id, region_name
})) |
TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 {
fn_def_id, region_name
})) => {
diag.note(
&format!("lifetime parameter `{0}` declared on fn `{1}` \
appears only in the return type, \
but here is required to be higher-ranked, \
which means that `{0}` must appear in both \
argument and return types",
region_name,
self.tcx.item_path_str(fn_def_id)));
diag.note(
&format!("this error is the result of a recent bug fix; \
for more information, see issue #33685 \
<https://github.com/rust-lang/rust/issues/33685>"));
}
_ => {}
}
}
pub fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>)
@ -761,7 +731,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
};
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
self.note_issue_32330(&mut diag, terr);
diag
}
@ -934,7 +903,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
format!(" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br), type_name)
}
infer::EarlyBoundRegion(_, name, _) => {
infer::EarlyBoundRegion(_, name) => {
format!(" for lifetime parameter `{}`",
name)
}

View File

@ -13,9 +13,7 @@
use super::{CombinedSnapshot,
InferCtxt,
LateBoundRegion,
HigherRankedType,
RegionVariableOrigin,
SubregionOrigin,
SkolemizationMap};
use super::combine::CombineFields;
@ -29,15 +27,6 @@ use util::nodemap::{FxHashMap, FxHashSet};
pub struct HrMatchResult<U> {
pub value: U,
/// Normally, when we do a higher-ranked match operation, we
/// expect all higher-ranked regions to be constrained as part of
/// the match operation. However, in the transition period for
/// #32330, it can happen that we sometimes have unconstrained
/// regions that get instantiated with fresh variables. In that
/// case, we collect the set of unconstrained bound regions here
/// and replace them with fresh variables.
pub unconstrained_regions: Vec<ty::BoundRegion>,
}
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
@ -108,7 +97,6 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
/// that do not appear in `T`. If that happens, those regions are
/// unconstrained, and this routine replaces them with `'static`.
pub fn higher_ranked_match<T, U>(&mut self,
span: Span,
a_pair: &Binder<(T, U)>,
b_match: &T,
a_is_expected: bool)
@ -158,28 +146,16 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// be any region from the sets above, except for other members of
// `skol_map`. There should always be a representative if things
// are properly well-formed.
let mut unconstrained_regions = vec![];
let skol_representatives: FxHashMap<_, _> =
skol_resolution_map
.iter()
.map(|(&skol, &(br, ref regions))| {
.map(|(&skol, &(_, ref regions))| {
let representative =
regions.iter()
.filter(|&&r| !skol_resolution_map.contains_key(r))
.cloned()
.next()
.unwrap_or_else(|| { // [1]
unconstrained_regions.push(br);
self.infcx.next_region_var(
LateBoundRegion(span, br, HigherRankedType))
});
// [1] There should always be a representative,
// unless the higher-ranked region did not appear
// in the values being matched. We should reject
// as ill-formed cases that can lead to this, but
// right now we sometimes issue warnings (see
// #32330).
.expect("no representative region");
(skol, representative)
})
@ -216,10 +192,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// We are now done with these skolemized variables.
self.infcx.pop_skolemized(skol_map, snapshot);
Ok(HrMatchResult {
value: a_value,
unconstrained_regions,
})
Ok(HrMatchResult { value: a_value })
});
}
@ -657,28 +630,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
skol_br,
tainted_region);
let issue_32330 = if let &ty::ReVar(vid) = tainted_region {
match self.region_vars.var_origin(vid) {
RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => {
issue_32330.map(Box::new)
}
_ => None
}
} else {
None
};
if overly_polymorphic {
return Err(if overly_polymorphic {
debug!("Overly polymorphic!");
return Err(TypeError::RegionsOverlyPolymorphic(skol_br,
tainted_region,
issue_32330));
TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
} else {
debug!("Not as polymorphic!");
return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br,
tainted_region,
issue_32330));
}
TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
})
}
}

View File

@ -299,7 +299,7 @@ pub enum RegionVariableOrigin {
Coercion(Span),
// Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name, Option<ty::Issue32330>),
EarlyBoundRegion(Span, ast::Name),
// Region variables created for bound regions
// in a function or method that is called
@ -989,7 +989,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
span: Span,
def: &ty::RegionParameterDef)
-> ty::Region<'tcx> {
self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330))
self.next_region_var(EarlyBoundRegion(span, def.name))
}
/// Create a type inference variable for the given
@ -1278,14 +1278,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
{
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
let span = cause.span;
let trace = TypeTrace {
cause,
values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b))
};
let mut combine = self.combine_fields(trace, param_env);
let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
Ok(InferOk { value: result, obligations: combine.obligations })
}

View File

@ -18,9 +18,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// the rustc crate store interface. This also includes types that
// are *mostly* used as a part of that interface, but these should
// probably get a better home if someone can find one.
//! the rustc crate store interface. This also includes types that
//! are *mostly* used as a part of that interface, but these should
//! probably get a better home if someone can find one.
use hir::def;
use hir::def_id::{CrateNum, DefId, DefIndex};
@ -50,13 +50,13 @@ pub use self::NativeLibraryKind::*;
// lonely orphan structs and enums looking for a better home
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Copy)]
pub struct LinkMeta {
pub crate_hash: Svh,
}
// Where a crate came from on the local filesystem. One of these three options
// must be non-None.
/// Where a crate came from on the local filesystem. One of these three options
/// must be non-None.
#[derive(PartialEq, Clone, Debug)]
pub struct CrateSource {
pub dylib: Option<(PathBuf, PathKind)>,
@ -120,10 +120,14 @@ pub enum LinkagePreference {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub enum NativeLibraryKind {
NativeStatic, // native static library (.a archive)
NativeStaticNobundle, // native static library, which doesn't get bundled into .rlibs
NativeFramework, // macOS-specific
NativeUnknown, // default way to specify a dynamic library
/// native static library (.a archive)
NativeStatic,
/// native static library, which doesn't get bundled into .rlibs
NativeStaticNobundle,
/// macOS-specific
NativeFramework,
/// default way to specify a dynamic library
NativeUnknown,
}
#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
@ -161,15 +165,13 @@ pub struct ExternCrate {
}
pub struct EncodedMetadata {
pub raw_data: Vec<u8>,
pub hashes: EncodedMetadataHashes,
pub raw_data: Vec<u8>
}
impl EncodedMetadata {
pub fn new() -> EncodedMetadata {
EncodedMetadata {
raw_data: Vec::new(),
hashes: EncodedMetadataHashes::new(),
}
}
}
@ -294,7 +296,7 @@ pub trait CrateStore {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &LinkMeta,
reachable: &NodeSet)
-> EncodedMetadata;
-> (EncodedMetadata, EncodedMetadataHashes);
fn metadata_encoding_version(&self) -> &[u8];
}
@ -424,7 +426,7 @@ impl CrateStore for DummyCrateStore {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &LinkMeta,
reachable: &NodeSet)
-> EncodedMetadata {
-> (EncodedMetadata, EncodedMetadataHashes) {
bug!("encode_metadata")
}
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }

View File

@ -22,6 +22,9 @@ use std::mem;
use std::usize;
use syntax::ast;
use syntax::print::pprust::PrintState;
use rustc_data_structures::graph::OUTGOING;
use util::nodemap::NodeMap;
use hir;
use hir::intravisit::{self, IdRange};
@ -523,12 +526,16 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
changed: true
};
let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry);
let mut temp = vec![0; words_per_id];
let mut num_passes = 0;
while propcx.changed {
num_passes += 1;
propcx.changed = false;
propcx.reset(&mut temp);
propcx.walk_cfg(cfg, &mut temp);
propcx.walk_cfg(cfg, &nodes_po, &mut temp);
}
debug!("finished in {} iterations", num_passes);
}
debug!("Dataflow result for {}:", self.analysis_name);
@ -543,12 +550,15 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
fn walk_cfg(&mut self,
cfg: &cfg::CFG,
nodes_po: &[CFGIndex],
in_out: &mut [usize]) {
debug!("DataFlowContext::walk_cfg(in_out={}) {}",
bits_to_string(in_out), self.dfcx.analysis_name);
assert!(self.dfcx.bits_per_id > 0);
cfg.graph.each_node(|node_index, node| {
// Iterate over nodes in reverse postorder
for &node_index in nodes_po.iter().rev() {
let node = cfg.graph.node(node_index);
debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
node_index, node.data.id(), bits_to_string(in_out));
@ -563,8 +573,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
// Propagate state on-exit from node into its successors.
self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
true // continue to next node
});
}
}
fn reset(&mut self, bits: &mut [usize]) {

View File

@ -13,7 +13,7 @@
// from live codes are live, and everything else is dead.
use hir::map as hir_map;
use hir::{self, PatKind};
use hir::{self, Item_, PatKind};
use hir::intravisit::{self, Visitor, NestedVisitorMap};
use hir::itemlikevisit::ItemLikeVisitor;
@ -189,6 +189,22 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
self.struct_has_extern_repr = had_extern_repr;
self.inherited_pub_visibility = had_inherited_pub_visibility;
}
fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec<hir::Field>) {
if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
if let Some(hir_map::NodeItem(item)) = self.tcx.hir.find(node_id) {
if let Item_::ItemUnion(ref variant, _) = item.node {
if variant.fields().len() > 1 {
for field in variant.fields() {
if fields.iter().find(|x| x.name.node == field.name).is_some() {
self.live_symbols.insert(field.id);
}
}
}
}
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
@ -231,6 +247,13 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
hir::ExprTupField(ref lhs, idx) => {
self.handle_tup_field_access(&lhs, idx.node);
}
hir::ExprStruct(_, ref fields, _) => {
if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty {
if def.is_union() {
self.mark_as_used_if_union(def.did, fields);
}
}
}
_ => ()
}
@ -561,7 +584,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
self.warn_dead_code(field.id, field.span,
field.name, "field");
}
intravisit::walk_struct_field(self, field);
}
@ -603,6 +625,9 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
let krate = tcx.hir.krate();
let live_symbols = find_live(tcx, access_levels, krate);
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
let mut visitor = DeadVisitor {
tcx: tcx,
live_symbols: live_symbols,
};
intravisit::walk_crate(&mut visitor, krate);
}

View File

@ -800,16 +800,19 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
pat);
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
match pat.node {
PatKind::Binding(hir::BindByRef(..), ..) =>
mode.lub(BorrowingMatch),
PatKind::Binding(hir::BindByValue(..), ..) => {
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
Copy => mode.lub(CopyingMatch),
Move(..) => mode.lub(MovingMatch),
if let PatKind::Binding(..) = pat.node {
let bm = *self.mc.tables.pat_binding_modes.get(&pat.id)
.expect("missing binding mode");
match bm {
ty::BindByReference(..) =>
mode.lub(BorrowingMatch),
ty::BindByValue(..) => {
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
Copy => mode.lub(CopyingMatch),
Move(..) => mode.lub(MovingMatch),
}
}
}
_ => {}
}
}));
}
@ -822,8 +825,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
if let PatKind::Binding(bmode, def_id, ..) = pat.node {
if let PatKind::Binding(_, def_id, ..) = pat.node {
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
let bm = *mc.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode");
// pat_ty: the type of the binding being produced.
let pat_ty = return_if_err!(mc.node_ty(pat.id));
@ -836,14 +840,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
// It is also a borrow or copy/move of the value being matched.
match bmode {
hir::BindByRef(m) => {
match bm {
ty::BindByReference(m) => {
if let ty::TyRef(r, _) = pat_ty.sty {
let bk = ty::BorrowKind::from_mutbl(m);
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
}
}
hir::BindByValue(..) => {
ty::BindByValue(..) => {
let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
debug!("walk_pat binding consuming pat");
delegate.consume_pat(pat, cmt_pat, mode);

View File

@ -330,11 +330,12 @@ impl MutabilityCategory {
ret
}
fn from_local(tcx: TyCtxt, id: ast::NodeId) -> MutabilityCategory {
fn from_local(tcx: TyCtxt, tables: &ty::TypeckTables, id: ast::NodeId) -> MutabilityCategory {
let ret = match tcx.hir.get(id) {
hir_map::NodeLocal(p) => match p.node {
PatKind::Binding(bind_mode, ..) => {
if bind_mode == hir::BindByValue(hir::MutMutable) {
PatKind::Binding(..) => {
let bm = *tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
if bm == ty::BindByValue(hir::MutMutable) {
McDeclared
} else {
McImmutable
@ -475,16 +476,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// *being borrowed* is. But ideally we would put in a more
// fundamental fix to this conflated use of the node id.
let ret_ty = match pat.node {
PatKind::Binding(hir::BindByRef(_), ..) => {
// a bind-by-ref means that the base_ty will be the type of the ident itself,
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false, ty::NoPreference) {
Some(t) => t.ty,
None => {
debug!("By-ref binding of non-derefable type {:?}", base_ty);
return Err(());
PatKind::Binding(..) => {
let bm = *self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode");
if let ty::BindByReference(_) = bm {
// a bind-by-ref means that the base_ty will be the type of the ident itself,
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false, ty::NoPreference) {
Some(t) => t.ty,
None => {
debug!("By-ref binding of non-derefable type {:?}", base_ty);
return Err(());
}
}
} else {
base_ty
}
}
_ => base_ty,
@ -659,7 +665,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
id,
span,
cat: Categorization::Local(vid),
mutbl: MutabilityCategory::from_local(self.tcx, vid),
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid),
ty: expr_ty,
note: NoteNone
}))
@ -717,7 +723,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let var_ty = self.node_ty(var_id)?;
// Mutability of original variable itself
let var_mutbl = MutabilityCategory::from_local(self.tcx, var_id);
let var_mutbl = MutabilityCategory::from_local(self.tcx, self.tables, var_id);
// Construct the upvar. This represents access to the field
// from the environment (perhaps we should eventually desugar

View File

@ -459,10 +459,10 @@ impl<'tcx> RegionMaps {
-> CodeExtent {
if scope_a == scope_b { return scope_a; }
/// [1] The initial values for `a_buf` and `b_buf` are not used.
/// The `ancestors_of` function will return some prefix that
/// is re-initialized with new values (or else fallback to a
/// heap-allocated vector).
// [1] The initial values for `a_buf` and `b_buf` are not used.
// The `ancestors_of` function will return some prefix that
// is re-initialized with new values (or else fallback to a
// heap-allocated vector).
let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32];
let mut a_vec: Vec<CodeExtent> = vec![];
let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32];
@ -890,8 +890,32 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
/// | ( ..., P&, ... )
/// | box P&
fn is_binding_pat(pat: &hir::Pat) -> bool {
// Note that the code below looks for *explicit* refs only, that is, it won't
// know about *implicit* refs as introduced in #42640.
//
// This is not a problem. For example, consider
//
// let (ref x, ref y) = (Foo { .. }, Bar { .. });
//
// Due to the explicit refs on the left hand side, the below code would signal
// that the temporary value on the right hand side should live until the end of
// the enclosing block (as opposed to being dropped after the let is complete).
//
// To create an implicit ref, however, you must have a borrowed value on the RHS
// already, as in this example (which won't compile before #42640):
//
// let Foo { x, .. } = &Foo { x: ..., ... };
//
// in place of
//
// let Foo { ref x, .. } = Foo { ... };
//
// In the former case (the implicit ref version), the temporary is created by the
// & expression, and its lifetime would be extended to the end of the block (due
// to a different rule, not the below code).
match pat.node {
PatKind::Binding(hir::BindByRef(_), ..) => true,
PatKind::Binding(hir::BindingAnnotation::Ref, ..) |
PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
PatKind::Struct(_, ref field_pats, _) => {
field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))

View File

@ -153,10 +153,6 @@ pub struct NamedRegionMap {
// (b) it DOES appear in the arguments.
pub late_bound: NodeSet,
// Contains the node-ids for lifetimes that were (incorrectly) categorized
// as late-bound, until #32330 was fixed.
pub issue_32330: NodeMap<ty::Issue32330>,
// For each type and trait definition, maps type parameters
// to the trait object lifetime defaults computed from them.
pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
@ -261,7 +257,6 @@ pub fn krate(sess: &Session,
let mut map = NamedRegionMap {
defs: NodeMap(),
late_bound: NodeSet(),
issue_32330: NodeMap(),
object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
};
sess.track_errors(|| {
@ -303,7 +298,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
self.visit_early_late(item.id, None, decl, generics, |this| {
self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_item(this, item);
});
}
@ -355,7 +350,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
match item.node {
hir::ForeignItemFn(ref decl, _, ref generics) => {
self.visit_early_late(item.id, None, decl, generics, |this| {
self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_foreign_item(this, item);
})
}
@ -406,7 +401,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node {
self.visit_early_late(
trait_item.id,
Some(self.hir_map.get_parent(trait_item.id)),
&sig.decl, &sig.generics,
|this| intravisit::walk_trait_item(this, trait_item))
@ -418,7 +412,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
self.visit_early_late(
impl_item.id,
Some(self.hir_map.get_parent(impl_item.id)),
&sig.decl, &sig.generics,
|this| intravisit::walk_impl_item(this, impl_item))
@ -811,18 +804,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
/// ordering is not important there.
fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
parent_id: Option<ast::NodeId>,
decl: &'tcx hir::FnDecl,
generics: &'tcx hir::Generics,
walk: F) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{
let fn_def_id = self.hir_map.local_def_id(fn_id);
insert_late_bound_lifetimes(self.map,
fn_def_id,
decl,
generics);
insert_late_bound_lifetimes(self.map, decl, generics);
// Find the start of nested early scopes, e.g. in methods.
let mut index = 0;
@ -1549,7 +1537,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
fn_def_id: DefId,
decl: &hir::FnDecl,
generics: &hir::Generics) {
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
@ -1607,22 +1594,9 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
// any `impl Trait` in the return type? early-bound.
if appears_in_output.impl_trait { continue; }
// does not appear in the inputs, but appears in the return
// type? eventually this will be early-bound, but for now we
// just mark it so we can issue warnings.
let constrained_by_input = constrained_by_input.regions.contains(&name);
let appears_in_output = appears_in_output.regions.contains(&name);
if !constrained_by_input && appears_in_output {
debug!("inserting issue_32330 entry for {:?}, {:?} on {:?}",
lifetime.lifetime.id,
name,
fn_def_id);
map.issue_32330.insert(
lifetime.lifetime.id,
ty::Issue32330 {
fn_def_id,
region_name: name,
});
// does not appear in the inputs, but appears in the return type? early-bound.
if !constrained_by_input.regions.contains(&name) &&
appears_in_output.regions.contains(&name) {
continue;
}

View File

@ -25,7 +25,7 @@ use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use util::ppaux;
use rustc_back::slice;
use hir::InlineAsm;
use hir::{self, InlineAsm};
use std::ascii;
use std::borrow::{Cow};
use std::cell::Ref;
@ -894,12 +894,18 @@ pub enum StatementKind<'tcx> {
/// End the current live range for the storage of the local.
StorageDead(Lvalue<'tcx>),
/// Execute a piece of inline Assembly.
InlineAsm {
asm: Box<InlineAsm>,
outputs: Vec<Lvalue<'tcx>>,
inputs: Vec<Operand<'tcx>>
},
/// Assert the given lvalues to be valid inhabitants of their type. These statements are
/// currently only interpreted by miri and only generated when "-Z mir-emit-validate" is passed.
/// See <https://internals.rust-lang.org/t/types-as-contracts/5562/73> for more details.
Validate(ValidationOp, Vec<ValidationOperand<'tcx, Lvalue<'tcx>>>),
/// Mark one terminating point of an extent (i.e. static region).
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(CodeExtent),
@ -908,6 +914,57 @@ pub enum StatementKind<'tcx> {
Nop,
}
/// The `ValidationOp` describes what happens with each of the operands of a
/// `Validate` statement.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq)]
pub enum ValidationOp {
/// Recursively traverse the lvalue following the type and validate that all type
/// invariants are maintained. Furthermore, acquire exclusive/read-only access to the
/// memory reachable from the lvalue.
Acquire,
/// Recursive traverse the *mutable* part of the type and relinquish all exclusive
/// access.
Release,
/// Recursive traverse the *mutable* part of the type and relinquish all exclusive
/// access *until* the given region ends. Then, access will be recovered.
Suspend(CodeExtent),
}
impl Debug for ValidationOp {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
use self::ValidationOp::*;
match *self {
Acquire => write!(fmt, "Acquire"),
Release => write!(fmt, "Release"),
// (reuse lifetime rendering policy from ppaux.)
Suspend(ref ce) => write!(fmt, "Suspend({})", ty::ReScope(*ce)),
}
}
}
// This is generic so that it can be reused by miri
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct ValidationOperand<'tcx, T> {
pub lval: T,
pub ty: Ty<'tcx>,
pub re: Option<CodeExtent>,
pub mutbl: hir::Mutability,
}
impl<'tcx, T: Debug> Debug for ValidationOperand<'tcx, T> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "{:?}: {:?}", self.lval, self.ty)?;
if let Some(ce) = self.re {
// (reuse lifetime rendering policy from ppaux.)
write!(fmt, "/{}", ty::ReScope(ce))?;
}
if let hir::MutImmutable = self.mutbl {
write!(fmt, " (imm)")?;
}
Ok(())
}
}
impl<'tcx> Debug for Statement<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
use self::StatementKind::*;
@ -915,6 +972,7 @@ impl<'tcx> Debug for Statement<'tcx> {
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
// (reuse lifetime rendering policy from ppaux.)
EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)),
Validate(ref op, ref lvalues) => write!(fmt, "Validate({:?}, {:?})", op, lvalues),
StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv),
StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv),
SetDiscriminant{lvalue: ref lv, variant_index: index} => {
@ -963,15 +1021,15 @@ impl_stable_hash_for!(struct Static<'tcx> {
/// shared between `Constant` and `Lvalue`. See the aliases
/// `LvalueProjection` etc below.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct Projection<'tcx, B, V> {
pub struct Projection<'tcx, B, V, T> {
pub base: B,
pub elem: ProjectionElem<'tcx, V>,
pub elem: ProjectionElem<'tcx, V, T>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum ProjectionElem<'tcx, V> {
pub enum ProjectionElem<'tcx, V, T> {
Deref,
Field(Field, Ty<'tcx>),
Field(Field, T),
Index(V),
/// These indices are generated by slice patterns. Easiest to explain
@ -1008,11 +1066,11 @@ pub enum ProjectionElem<'tcx, V> {
/// Alias for projections as they appear in lvalues, where the base is an lvalue
/// and the index is an operand.
pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>>;
pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>, Ty<'tcx>>;
/// Alias for projections as they appear in lvalues, where the base is an lvalue
/// and the index is an operand.
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>>;
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>, Ty<'tcx>>;
newtype_index!(Field, "field");
@ -1606,6 +1664,21 @@ impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Lvalue<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ValidationOperand {
lval: self.lval.fold_with(folder),
ty: self.ty.fold_with(folder),
re: self.re,
mutbl: self.mutbl,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.lval.visit_with(visitor) || self.ty.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use mir::StatementKind::*;
@ -1630,6 +1703,10 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
// trait with a `fn fold_extent`.
EndRegion(ref extent) => EndRegion(extent.clone()),
Validate(ref op, ref lvals) =>
Validate(op.clone(),
lvals.iter().map(|operand| operand.fold_with(folder)).collect()),
Nop => Nop,
};
Statement {
@ -1655,6 +1732,9 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
// trait with a `fn visit_extent`.
EndRegion(ref _extent) => false,
Validate(ref _op, ref lvalues) =>
lvalues.iter().any(|ty_and_lvalue| ty_and_lvalue.visit_with(visitor)),
Nop => false,
}
}
@ -1857,8 +1937,8 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
}
}
impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>
impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T>
where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>
{
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use mir::ProjectionElem::*;
@ -1866,7 +1946,7 @@ impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
let base = self.base.fold_with(folder);
let elem = match self.elem {
Deref => Deref,
Field(f, ty) => Field(f, ty.fold_with(folder)),
Field(f, ref ty) => Field(f, ty.fold_with(folder)),
Index(ref v) => Index(v.fold_with(folder)),
ref elem => elem.clone()
};
@ -1882,7 +1962,7 @@ impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
self.base.visit_with(visitor) ||
match self.elem {
Field(_, ty) => ty.visit_with(visitor),
Field(_, ref ty) => ty.visit_with(visitor),
Index(ref v) => v.visit_with(visitor),
_ => false
}

View File

@ -14,7 +14,6 @@ use ty::subst::Substs;
use ty::{ClosureSubsts, Region, Ty};
use mir::*;
use rustc_const_math::ConstUsize;
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
// # The MIR Visitor
@ -264,9 +263,15 @@ macro_rules! make_mir_visitor {
fn super_mir(&mut self,
mir: & $($mutability)* Mir<'tcx>) {
for index in 0..mir.basic_blocks().len() {
let block = BasicBlock::new(index);
self.visit_basic_block_data(block, &$($mutability)* mir[block]);
// for best performance, we want to use an iterator rather
// than a for-loop, to avoid calling Mir::invalidate for
// each basic block.
macro_rules! basic_blocks {
(mut) => (mir.basic_blocks_mut().iter_enumerated_mut());
() => (mir.basic_blocks().iter_enumerated());
};
for (bb, data) in basic_blocks!($($mutability)*) {
self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)* mir.visibility_scopes {
@ -337,6 +342,13 @@ macro_rules! make_mir_visitor {
self.visit_assign(block, lvalue, rvalue, location);
}
StatementKind::EndRegion(_) => {}
StatementKind::Validate(_, ref $($mutability)* lvalues) => {
for operand in lvalues {
self.visit_lvalue(& $($mutability)* operand.lval,
LvalueContext::Validate, location);
self.visit_ty(& $($mutability)* operand.ty, Lookup::Loc(location));
}
}
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
self.visit_lvalue(lvalue, LvalueContext::Store, location);
}
@ -807,6 +819,9 @@ pub enum LvalueContext<'tcx> {
// Starting and ending a storage live range
StorageLive,
StorageDead,
// Validation command
Validate,
}
impl<'tcx> LvalueContext<'tcx> {
@ -853,7 +868,8 @@ impl<'tcx> LvalueContext<'tcx> {
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
LvalueContext::StorageLive | LvalueContext::StorageDead => false,
LvalueContext::StorageLive | LvalueContext::StorageDead |
LvalueContext::Validate => false,
}
}
@ -865,7 +881,8 @@ impl<'tcx> LvalueContext<'tcx> {
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false,
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |
LvalueContext::Validate => false,
}
}

View File

@ -1025,6 +1025,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"the directory the MIR is dumped into"),
dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
"if set, exclude the pass number when dumping MIR (used in tests)"),
mir_emit_validate: usize = (0, parse_uint, [TRACKED],
"emit Validate MIR statements, interpreted e.g. by miri (0: do not emit; 1: if function \
contains unsafe block, only validate arguments; 2: always emit full validation)"),
perf_stats: bool = (false, parse_bool, [UNTRACKED],
"print some performance-related statistics"),
hir_stats: bool = (false, parse_bool, [UNTRACKED],
@ -1059,6 +1062,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"choose which RELRO level to use"),
nll: bool = (false, parse_bool, [UNTRACKED],
"run the non-lexical lifetimes MIR pass"),
trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
"generate a graphical HTML report of time spent in trans and LLVM"),
}
pub fn default_lib_output() -> CrateType {
@ -1498,6 +1503,23 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
early_error(error_format, "Value for codegen units must be a positive nonzero integer");
}
// It's possible that we have `codegen_units > 1` but only one item in
// `trans.modules`. We could theoretically proceed and do LTO in that
// case, but it would be confusing to have the validity of
// `-Z lto -C codegen-units=2` depend on details of the crate being
// compiled, so we complain regardless.
if cg.lto && cg.codegen_units > 1 {
// This case is impossible to handle because LTO expects to be able
// to combine the entire crate and all its dependencies into a
// single compilation unit, but each codegen unit is in a separate
// LLVM context, so they can't easily be combined.
early_error(error_format, "can't perform LTO when using multiple codegen units");
}
if cg.lto && debugging_opts.incremental.is_some() {
early_error(error_format, "can't perform LTO when compiling incrementally");
}
let mut prints = Vec::<PrintRequest>::new();
if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
prints.push(PrintRequest::TargetCPUs);

View File

@ -463,13 +463,19 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
selcx.infcx().report_overflow_error(&obligation, false);
}
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
// If we find the value in the cache, then the obligations
// have already been returned from the previous entry (and
// should therefore have been honored).
// If we find the value in the cache, then return it along
// with the obligations that went along with it. Note
// that, when using a fulfillment context, these
// obligations could in principle be ignored: they have
// already been registered when the cache entry was
// created (and hence the new ones will quickly be
// discarded as duplicated). But when doing trait
// evaluation this is not the case, and dropping the trait
// evaluations can causes ICEs (e.g. #43132).
debug!("opt_normalize_projection_type: \
found normalized ty `{:?}`",
ty);
return Some(NormalizedTy { value: ty, obligations: vec![] });
return Some(ty);
}
Err(ProjectionCacheEntry::Error) => {
debug!("opt_normalize_projection_type: \
@ -480,9 +486,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
mut obligations,
cacheable })) => {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => {
// if projection succeeded, then what we get out of this
// is also non-normalized (consider: it was derived from
// an impl, where-clause etc) and hence we must
@ -491,12 +495,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
debug!("opt_normalize_projection_type: \
projected_ty={:?} \
depth={} \
obligations={:?} \
cacheable={:?}",
obligations={:?}",
projected_ty,
depth,
obligations,
cacheable);
obligations);
let result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
@ -521,8 +523,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
obligations,
}
};
infcx.projection_cache.borrow_mut()
.complete(projection_ty, &result, cacheable);
infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
Some(result)
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
@ -533,8 +534,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
value: projected_ty,
obligations: vec![]
};
infcx.projection_cache.borrow_mut()
.complete(projection_ty, &result, true);
infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
Some(result)
}
Err(ProjectionTyError::TooManyCandidates) => {
@ -607,7 +607,6 @@ enum ProjectedTy<'tcx> {
struct Progress<'tcx> {
ty: Ty<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cacheable: bool,
}
impl<'tcx> Progress<'tcx> {
@ -615,7 +614,6 @@ impl<'tcx> Progress<'tcx> {
Progress {
ty: tcx.types.err,
obligations: vec![],
cacheable: true
}
}
@ -1286,7 +1284,6 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
Progress {
ty: ty_match.value,
obligations,
cacheable: ty_match.unconstrained_regions.is_empty(),
}
}
Err(e) => {
@ -1330,7 +1327,6 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,
cacheable: true
}
}
@ -1394,7 +1390,7 @@ enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
Error,
NormalizedTy(Ty<'tcx>),
NormalizedTy(NormalizedTy<'tcx>),
}
// NB: intentionally not Clone
@ -1438,22 +1434,11 @@ impl<'tcx> ProjectionCache<'tcx> {
Ok(())
}
/// Indicates that `key` was normalized to `value`. If `cacheable` is false,
/// then this result is sadly not cacheable.
fn complete(&mut self,
key: ty::ProjectionTy<'tcx>,
value: &NormalizedTy<'tcx>,
cacheable: bool) {
let fresh_key = if cacheable {
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
key, value);
self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value))
} else {
debug!("ProjectionCacheEntry::complete: cannot cache: key={:?}, value={:?}",
key, value);
!self.map.remove(key)
};
/// Indicates that `key` was normalized to `value`.
fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
key, value);
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.clone()));
assert!(!fresh_key, "never started projecting `{:?}`", key);
}

View File

@ -0,0 +1,35 @@
// 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 hir::BindingAnnotation::*;
use hir::BindingAnnotation;
use hir::Mutability;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum BindingMode {
BindByReference(Mutability),
BindByValue(Mutability),
}
impl BindingMode {
pub fn convert(ba: BindingAnnotation) -> BindingMode {
match ba {
Unannotated => BindingMode::BindByValue(Mutability::MutImmutable),
Mutable => BindingMode::BindByValue(Mutability::MutMutable),
Ref => BindingMode::BindByReference(Mutability::MutImmutable),
RefMut => BindingMode::BindByReference(Mutability::MutMutable),
}
}
}
impl_stable_hash_for!(enum self::BindingMode {
BindByReference(mutability),
BindByValue(mutability)
});

View File

@ -40,6 +40,7 @@ use ty::layout::{Layout, TargetDataLayout};
use ty::inhabitedness::DefIdForest;
use ty::maps;
use ty::steal::Steal;
use ty::BindingMode;
use util::nodemap::{NodeMap, NodeSet, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
@ -223,6 +224,9 @@ pub struct TypeckTables<'tcx> {
pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
// Stores the actual binding mode for all instances of hir::BindingAnnotation.
pub pat_binding_modes: NodeMap<BindingMode>,
/// Borrows
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
@ -278,6 +282,7 @@ impl<'tcx> TypeckTables<'tcx> {
node_types: FxHashMap(),
node_substs: NodeMap(),
adjustments: NodeMap(),
pat_binding_modes: NodeMap(),
upvar_capture_map: FxHashMap(),
generator_sigs: NodeMap(),
generator_interiors: NodeMap(),

View File

@ -39,8 +39,8 @@ pub enum TypeError<'tcx> {
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
RegionsNotSame(Region<'tcx>, Region<'tcx>),
RegionsNoOverlap(Region<'tcx>, Region<'tcx>),
RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>),
RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>),
RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
Sorts(ExpectedFound<Ty<'tcx>>),
IntMismatch(ExpectedFound<ty::IntVarValue>),
FloatMismatch(ExpectedFound<ast::FloatTy>),
@ -116,13 +116,13 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
RegionsNoOverlap(..) => {
write!(f, "lifetimes do not intersect")
}
RegionsInsufficientlyPolymorphic(br, _, _) => {
RegionsInsufficientlyPolymorphic(br, _) => {
write!(f,
"expected bound lifetime parameter{}{}, found concrete lifetime",
if br.is_named() { " " } else { "" },
br)
}
RegionsOverlyPolymorphic(br, _, _) => {
RegionsOverlyPolymorphic(br, _) => {
write!(f,
"expected concrete lifetime, found bound lifetime parameter{}{}",
if br.is_named() { " " } else { "" },
@ -258,15 +258,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.note_and_explain_region(db, "...does not overlap ",
region2, "");
}
RegionsInsufficientlyPolymorphic(_, conc_region, _) => {
RegionsInsufficientlyPolymorphic(_, conc_region) => {
self.note_and_explain_region(db, "concrete lifetime that was found is ",
conc_region, "");
}
RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => {
RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
// don't bother to print out the message below for
// inference variables, it's not very illuminating.
}
RegionsOverlyPolymorphic(_, conc_region, _) => {
RegionsOverlyPolymorphic(_, conc_region) => {
self.note_and_explain_region(db, "expected concrete lifetime is ",
conc_region, "");
}

View File

@ -581,14 +581,14 @@ pub struct Struct {
pub min_size: Size,
}
// Info required to optimize struct layout.
/// Info required to optimize struct layout.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
enum StructKind {
// A tuple, closure, or univariant which cannot be coerced to unsized.
/// A tuple, closure, or univariant which cannot be coerced to unsized.
AlwaysSizedUnivariant,
// A univariant, the last field of which may be coerced to unsized.
/// A univariant, the last field of which may be coerced to unsized.
MaybeUnsizedUnivariant,
// A univariant, but part of an enum.
/// A univariant, but part of an enum.
EnumVariant,
}
@ -1020,7 +1020,7 @@ pub enum Layout {
/// TyRawPtr or TyRef with a !Sized pointee.
FatPointer {
metadata: Primitive,
// If true, the pointer cannot be null.
/// If true, the pointer cannot be null.
non_zero: bool
},
@ -1031,8 +1031,8 @@ pub enum Layout {
discr: Integer,
signed: bool,
non_zero: bool,
// Inclusive discriminant range.
// If min > max, it represents min...u64::MAX followed by 0...max.
/// Inclusive discriminant range.
/// If min > max, it represents min...u64::MAX followed by 0...max.
// FIXME(eddyb) always use the shortest range, e.g. by finding
// the largest space between two consecutive discriminants and
// taking everything else as the (shortest) discriminant range.
@ -1043,7 +1043,7 @@ pub enum Layout {
/// Single-case enums, and structs/tuples.
Univariant {
variant: Struct,
// If true, the structure is NonZero.
/// If true, the structure is NonZero.
// FIXME(eddyb) use a newtype Layout kind for this.
non_zero: bool
},
@ -1084,9 +1084,9 @@ pub enum Layout {
StructWrappedNullablePointer {
nndiscr: u64,
nonnull: Struct,
// N.B. There is a 0 at the start, for LLVM GEP through a pointer.
/// N.B. There is a 0 at the start, for LLVM GEP through a pointer.
discrfield: FieldPath,
// Like discrfield, but in source order. For debuginfo.
/// Like discrfield, but in source order. For debuginfo.
discrfield_source: FieldPath
}
}
@ -1954,11 +1954,11 @@ pub enum SizeSkeleton<'tcx> {
/// A potentially-fat pointer.
Pointer {
// If true, this pointer is never null.
/// If true, this pointer is never null.
non_zero: bool,
// The type which determines the unsized metadata, if any,
// of this pointer. Either a type parameter or a projection
// depending on one, with regions erased.
/// The type which determines the unsized metadata, if any,
/// of this pointer. Either a type parameter or a projection
/// depending on one, with regions erased.
tail: Ty<'tcx>
}
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
use dep_graph::{DepConstructor, DepNode, DepNodeIndex};
use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::def::Def;
use hir;
use middle::const_val;
@ -942,7 +942,7 @@ define_maps! { <'tcx>
/// Checks all types in the krate for overlap in their inherent impls. Reports errors.
/// Not meant to be used directly outside of coherence.
/// (Defined only for LOCAL_CRATE)
[] crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
[] crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) -> (),
/// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants).
@ -1025,6 +1025,10 @@ fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::Coherence
}
fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::CoherenceInherentImplOverlapCheck
}
fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::Reachability
}
@ -1043,10 +1047,9 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::TypeckBodiesKrate
}
fn const_eval_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
fn const_eval_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> DepConstructor<'tcx> {
let (def_id, substs) = key.value;
DepConstructor::ConstEval { def_id, substs }
DepConstructor::ConstEval
}
fn mir_keys<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
@ -1061,32 +1064,22 @@ fn relevant_trait_impls_for<'tcx>((def_id, t): (DefId, SimplifiedType)) -> DepCo
DepConstructor::RelevantTraitImpls(def_id, t)
}
fn is_copy_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepConstructor::IsCopy(def_id)
fn is_copy_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::IsCopy
}
fn is_sized_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepConstructor::IsSized(def_id)
fn is_sized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::IsSized
}
fn is_freeze_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepConstructor::IsFreeze(def_id)
fn is_freeze_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::IsFreeze
}
fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepConstructor::NeedsDrop(def_id)
fn needs_drop_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::NeedsDrop
}
fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepConstructor::Layout(def_id)
fn layout_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::Layout
}

View File

@ -68,13 +68,15 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::RegionKind;
pub use self::sty::Issue32330;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::InferTy::*;
pub use self::sty::RegionKind::*;
pub use self::sty::TypeVariants::*;
pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*;
pub use self::context::{TyCtxt, GlobalArenas, tls};
pub use self::context::{Lift, TypeckTables};
@ -85,6 +87,7 @@ pub use self::trait_def::TraitDef;
pub use self::maps::queries;
pub mod adjustment;
pub mod binding;
pub mod cast;
pub mod error;
pub mod fast_reject;
@ -158,7 +161,7 @@ pub struct ImplHeader<'tcx> {
pub predicates: Vec<Predicate<'tcx>>,
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct AssociatedItem {
pub def_id: DefId,
pub name: Name,
@ -172,7 +175,7 @@ pub struct AssociatedItem {
pub method_has_self_argument: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
pub enum AssociatedKind {
Const,
Method,
@ -679,7 +682,6 @@ pub struct RegionParameterDef {
pub name: Name,
pub def_id: DefId,
pub index: u32,
pub issue_32330: Option<ty::Issue32330>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `'a`, asserts data of lifetime `'a`

View File

@ -377,13 +377,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
RegionsNoOverlap(a, b) => {
return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
}
RegionsInsufficientlyPolymorphic(a, b, ref c) => {
let c = c.clone();
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c))
RegionsInsufficientlyPolymorphic(a, b) => {
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
}
RegionsOverlyPolymorphic(a, b, ref c) => {
let c = c.clone();
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c))
RegionsOverlyPolymorphic(a, b) => {
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
}
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
@ -1065,13 +1063,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => {
RegionsNoOverlap(a.fold_with(folder), b.fold_with(folder))
},
RegionsInsufficientlyPolymorphic(a, b, ref c) => {
let c = c.clone();
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder), c)
RegionsInsufficientlyPolymorphic(a, b) => {
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
},
RegionsOverlyPolymorphic(a, b, ref c) => {
let c = c.clone();
RegionsOverlyPolymorphic(a, b.fold_with(folder), c)
RegionsOverlyPolymorphic(a, b) => {
RegionsOverlyPolymorphic(a, b.fold_with(folder))
},
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
@ -1097,8 +1093,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => {
a.visit_with(visitor) || b.visit_with(visitor)
},
RegionsInsufficientlyPolymorphic(_, b, _) |
RegionsOverlyPolymorphic(_, b, _) => {
RegionsInsufficientlyPolymorphic(_, b) |
RegionsOverlyPolymorphic(_, b) => {
b.visit_with(visitor)
},
Sorts(x) => x.visit_with(visitor),

View File

@ -77,20 +77,6 @@ impl BoundRegion {
}
}
/// When a region changed from late-bound to early-bound when #32330
/// was fixed, its `RegionParameterDef` will have one of these
/// structures that we can use to give nicer errors.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub struct Issue32330 {
/// fn where is region declared
pub fn_def_id: DefId,
/// name of region; duplicates the info in BrNamed but convenient
/// to have it here, and this code is only temporary
pub region_name: ast::Name,
}
/// NB: If you change this, you'll probably want to change the corresponding
/// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]

View File

@ -57,6 +57,32 @@ pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
let rv = f();
let dur = start.elapsed();
print_time_passes_entry_internal(what, dur);
TIME_DEPTH.with(|slot| slot.set(old));
rv
}
pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) {
if !do_it {
return
}
let old = TIME_DEPTH.with(|slot| {
let r = slot.get();
slot.set(r + 1);
r
});
print_time_passes_entry_internal(what, dur);
TIME_DEPTH.with(|slot| slot.set(old));
}
fn print_time_passes_entry_internal(what: &str, dur: Duration) {
let indentation = TIME_DEPTH.with(|slot| slot.get());
let mem_string = match get_resident() {
Some(n) => {
let mb = n as f64 / 1_000_000.0;
@ -65,14 +91,10 @@ pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
None => "".to_owned(),
};
println!("{}time: {}{}\t{}",
repeat(" ").take(old).collect::<String>(),
repeat(" ").take(indentation).collect::<String>(),
duration_to_secs_str(dur),
mem_string,
what);
TIME_DEPTH.with(|slot| slot.set(old));
rv
}
// Hack up our own formatting for the duration to make it easier for scripts

View File

@ -0,0 +1,11 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_apfloat"
version = "0.0.0"
[lib]
name = "rustc_apfloat"
path = "lib.rs"
[dependencies]
rustc_bitflags = { path = "../librustc_bitflags" }

2733
src/librustc_apfloat/ieee.rs Normal file

File diff suppressed because it is too large Load Diff

693
src/librustc_apfloat/lib.rs Normal file
View File

@ -0,0 +1,693 @@
// 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.
//! Port of LLVM's APFloat software floating-point implementation from the
//! following C++ sources (please update commit hash when backporting):
//! https://github.com/llvm-mirror/llvm/tree/23efab2bbd424ed13495a420ad8641cb2c6c28f9
//! * `include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits
//! * `lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules
//! * `unittests/ADT/APFloatTest.cpp` -> `tests` directory
//!
//! The port contains no unsafe code, global state, or side-effects in general,
//! and the only allocations are in the conversion to/from decimal strings.
//!
//! Most of the API and the testcases are intact in some form or another,
//! with some ergonomic changes, such as idiomatic short names, returning
//! new values instead of mutating the receiver, and having separate method
//! variants that take a non-default rounding mode (with the suffix `_r`).
//! Comments have been preserved where possible, only slightly adapted.
//!
//! Instead of keeping a pointer to a configuration struct and inspecting it
//! dynamically on every operation, types (e.g. `ieee::Double`), traits
//! (e.g. `ieee::Semantics`) and associated constants are employed for
//! increased type safety and performance.
//!
//! On-heap bigints are replaced everywhere (except in decimal conversion),
//! with short arrays of `type Limb = u128` elements (instead of `u64`),
//! This allows fitting the largest supported significands in one integer
//! (`ieee::Quad` and `ppc::Fallback` use slightly less than 128 bits).
//! All of the functions in the `ieee::sig` module operate on slices.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.
#![crate_name = "rustc_apfloat"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
#![forbid(unsafe_code)]
#![feature(const_fn)]
#![feature(i128_type)]
#![feature(slice_patterns)]
#![feature(try_from)]
#[macro_use]
extern crate rustc_bitflags;
use std::cmp::Ordering;
use std::fmt;
use std::ops::{Neg, Add, Sub, Mul, Div, Rem};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, BitOrAssign};
use std::str::FromStr;
bitflags! {
/// IEEE-754R 7: Default exception handling.
///
/// UNDERFLOW or OVERFLOW are always returned or-ed with INEXACT.
#[must_use]
#[derive(Debug)]
flags Status: u8 {
const OK = 0x00,
const INVALID_OP = 0x01,
const DIV_BY_ZERO = 0x02,
const OVERFLOW = 0x04,
const UNDERFLOW = 0x08,
const INEXACT = 0x10
}
}
impl BitOrAssign for Status {
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
#[must_use]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct StatusAnd<T> {
pub status: Status,
pub value: T,
}
impl Status {
pub fn and<T>(self, value: T) -> StatusAnd<T> {
StatusAnd {
status: self,
value,
}
}
}
impl<T> StatusAnd<T> {
fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> {
StatusAnd {
status: self.status,
value: f(self.value),
}
}
}
#[macro_export]
macro_rules! unpack {
($status:ident|=, $e:expr) => {
match $e {
$crate::StatusAnd { status, value } => {
$status |= status;
value
}
}
};
($status:ident=, $e:expr) => {
match $e {
$crate::StatusAnd { status, value } => {
$status = status;
value
}
}
}
}
/// Category of internally-represented number.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
Infinity,
NaN,
Normal,
Zero,
}
/// IEEE-754R 4.3: Rounding-direction attributes.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Round {
NearestTiesToEven,
TowardPositive,
TowardNegative,
TowardZero,
NearestTiesToAway,
}
impl Neg for Round {
type Output = Round;
fn neg(self) -> Round {
match self {
Round::TowardPositive => Round::TowardNegative,
Round::TowardNegative => Round::TowardPositive,
Round::NearestTiesToEven | Round::TowardZero | Round::NearestTiesToAway => self,
}
}
}
/// A signed type to represent a floating point number's unbiased exponent.
pub type ExpInt = i16;
// \c ilogb error results.
pub const IEK_INF: ExpInt = ExpInt::max_value();
pub const IEK_NAN: ExpInt = ExpInt::min_value();
pub const IEK_ZERO: ExpInt = ExpInt::min_value() + 1;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ParseError(pub &'static str);
/// A self-contained host- and target-independent arbitrary-precision
/// floating-point software implementation.
///
/// `apfloat` uses significand bignum integer arithmetic as provided by functions
/// in the `ieee::sig`.
///
/// Written for clarity rather than speed, in particular with a view to use in
/// the front-end of a cross compiler so that target arithmetic can be correctly
/// performed on the host. Performance should nonetheless be reasonable,
/// particularly for its intended use. It may be useful as a base
/// implementation for a run-time library during development of a faster
/// target-specific one.
///
/// All 5 rounding modes in the IEEE-754R draft are handled correctly for all
/// implemented operations. Currently implemented operations are add, subtract,
/// multiply, divide, fused-multiply-add, conversion-to-float,
/// conversion-to-integer and conversion-from-integer. New rounding modes
/// (e.g. away from zero) can be added with three or four lines of code.
///
/// Four formats are built-in: IEEE single precision, double precision,
/// quadruple precision, and x87 80-bit extended double (when operating with
/// full extended precision). Adding a new format that obeys IEEE semantics
/// only requires adding two lines of code: a declaration and definition of the
/// format.
///
/// All operations return the status of that operation as an exception bit-mask,
/// so multiple operations can be done consecutively with their results or-ed
/// together. The returned status can be useful for compiler diagnostics; e.g.,
/// inexact, underflow and overflow can be easily diagnosed on constant folding,
/// and compiler optimizers can determine what exceptions would be raised by
/// folding operations and optimize, or perhaps not optimize, accordingly.
///
/// At present, underflow tininess is detected after rounding; it should be
/// straight forward to add support for the before-rounding case too.
///
/// The library reads hexadecimal floating point numbers as per C99, and
/// correctly rounds if necessary according to the specified rounding mode.
/// Syntax is required to have been validated by the caller.
///
/// It also reads decimal floating point numbers and correctly rounds according
/// to the specified rounding mode.
///
/// Non-zero finite numbers are represented internally as a sign bit, a 16-bit
/// signed exponent, and the significand as an array of integer limbs. After
/// normalization of a number of precision P the exponent is within the range of
/// the format, and if the number is not denormal the P-th bit of the
/// significand is set as an explicit integer bit. For denormals the most
/// significant bit is shifted right so that the exponent is maintained at the
/// format's minimum, so that the smallest denormal has just the least
/// significant bit of the significand set. The sign of zeros and infinities
/// is significant; the exponent and significand of such numbers is not stored,
/// but has a known implicit (deterministic) value: 0 for the significands, 0
/// for zero exponent, all 1 bits for infinity exponent. For NaNs the sign and
/// significand are deterministic, although not really meaningful, and preserved
/// in non-conversion operations. The exponent is implicitly all 1 bits.
///
/// `apfloat` does not provide any exception handling beyond default exception
/// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
/// by encoding Signaling NaNs with the first bit of its trailing significand as
/// 0.
///
/// Future work
/// ===========
///
/// Some features that may or may not be worth adding:
///
/// Optional ability to detect underflow tininess before rounding.
///
/// New formats: x87 in single and double precision mode (IEEE apart from
/// extended exponent range) (hard).
///
/// New operations: sqrt, nexttoward.
///
pub trait Float
: Copy
+ Default
+ FromStr<Err = ParseError>
+ PartialOrd
+ fmt::Display
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ RemAssign
+ Add<Output = StatusAnd<Self>>
+ Sub<Output = StatusAnd<Self>>
+ Mul<Output = StatusAnd<Self>>
+ Div<Output = StatusAnd<Self>>
+ Rem<Output = StatusAnd<Self>> {
/// Total number of bits in the in-memory format.
const BITS: usize;
/// Number of bits in the significand. This includes the integer bit.
const PRECISION: usize;
/// The largest E such that 2^E is representable; this matches the
/// definition of IEEE 754.
const MAX_EXP: ExpInt;
/// The smallest E such that 2^E is a normalized number; this
/// matches the definition of IEEE 754.
const MIN_EXP: ExpInt;
/// Positive Zero.
const ZERO: Self;
/// Positive Infinity.
const INFINITY: Self;
/// NaN (Not a Number).
// FIXME(eddyb) provide a default when qnan becomes const fn.
const NAN: Self;
/// Factory for QNaN values.
// FIXME(eddyb) should be const fn.
fn qnan(payload: Option<u128>) -> Self;
/// Factory for SNaN values.
// FIXME(eddyb) should be const fn.
fn snan(payload: Option<u128>) -> Self;
/// Largest finite number.
// FIXME(eddyb) should be const (but FloatPair::largest is nontrivial).
fn largest() -> Self;
/// Smallest (by magnitude) finite number.
/// Might be denormalized, which implies a relative loss of precision.
const SMALLEST: Self;
/// Smallest (by magnitude) normalized finite number.
// FIXME(eddyb) should be const (but FloatPair::smallest_normalized is nontrivial).
fn smallest_normalized() -> Self;
// Arithmetic
fn add_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
fn sub_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
self.add_r(-rhs, round)
}
fn mul_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self>;
fn mul_add(self, multiplicand: Self, addend: Self) -> StatusAnd<Self> {
self.mul_add_r(multiplicand, addend, Round::NearestTiesToEven)
}
fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
/// IEEE remainder.
// This is not currently correct in all cases.
fn ieee_rem(self, rhs: Self) -> StatusAnd<Self> {
let mut v = self;
let status;
v = unpack!(status=, v / rhs);
if status == Status::DIV_BY_ZERO {
return status.and(self);
}
assert!(Self::PRECISION < 128);
let status;
let x = unpack!(status=, v.to_i128_r(128, Round::NearestTiesToEven, &mut false));
if status == Status::INVALID_OP {
return status.and(self);
}
let status;
let mut v = unpack!(status=, Self::from_i128(x));
assert_eq!(status, Status::OK); // should always work
let status;
v = unpack!(status=, v * rhs);
assert_eq!(status - Status::INEXACT, Status::OK); // should not overflow or underflow
let status;
v = unpack!(status=, self - v);
assert_eq!(status - Status::INEXACT, Status::OK); // likewise
if v.is_zero() {
status.and(v.copy_sign(self)) // IEEE754 requires this
} else {
status.and(v)
}
}
/// C fmod, or llvm frem.
fn c_fmod(self, rhs: Self) -> StatusAnd<Self>;
fn round_to_integral(self, round: Round) -> StatusAnd<Self>;
/// IEEE-754R 2008 5.3.1: nextUp.
fn next_up(self) -> StatusAnd<Self>;
/// IEEE-754R 2008 5.3.1: nextDown.
///
/// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
/// appropriate sign switching before/after the computation.
fn next_down(self) -> StatusAnd<Self> {
(-self).next_up().map(|r| -r)
}
fn abs(self) -> Self {
if self.is_negative() { -self } else { self }
}
fn copy_sign(self, rhs: Self) -> Self {
if self.is_negative() != rhs.is_negative() {
-self
} else {
self
}
}
// Conversions
fn from_bits(input: u128) -> Self;
fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> {
if input < 0 {
Self::from_u128_r(-input as u128, -round).map(|r| -r)
} else {
Self::from_u128_r(input as u128, round)
}
}
fn from_i128(input: i128) -> StatusAnd<Self> {
Self::from_i128_r(input, Round::NearestTiesToEven)
}
fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self>;
fn from_u128(input: u128) -> StatusAnd<Self> {
Self::from_u128_r(input, Round::NearestTiesToEven)
}
fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>;
fn to_bits(self) -> u128;
/// Convert a floating point number to an integer according to the
/// rounding mode. In case of an invalid operation exception,
/// deterministic values are returned, namely zero for NaNs and the
/// minimal or maximal value respectively for underflow or overflow.
/// If the rounded value is in range but the floating point number is
/// not the exact integer, the C standard doesn't require an inexact
/// exception to be raised. IEEE-854 does require it so we do that.
///
/// Note that for conversions to integer type the C standard requires
/// round-to-zero to always be used.
///
/// The *is_exact output tells whether the result is exact, in the sense
/// that converting it back to the original floating point type produces
/// the original value. This is almost equivalent to result==Status::OK,
/// except for negative zeroes.
fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
let status;
if self.is_negative() {
if self.is_zero() {
// Negative zero can't be represented as an int.
*is_exact = false;
}
let r = unpack!(status=, (-self).to_u128_r(width, -round, is_exact));
// Check for values that don't fit in the signed integer.
if r > (1 << (width - 1)) {
// Return the most negative integer for the given width.
*is_exact = false;
Status::INVALID_OP.and(-1 << (width - 1))
} else {
status.and(r.wrapping_neg() as i128)
}
} else {
// Positive case is simpler, can pretend it's a smaller unsigned
// integer, and `to_u128` will take care of all the edge cases.
self.to_u128_r(width - 1, round, is_exact).map(
|r| r as i128,
)
}
}
fn to_i128(self, width: usize) -> StatusAnd<i128> {
self.to_i128_r(width, Round::TowardZero, &mut true)
}
fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>;
fn to_u128(self, width: usize) -> StatusAnd<u128> {
self.to_u128_r(width, Round::TowardZero, &mut true)
}
fn cmp_abs_normal(self, rhs: Self) -> Ordering;
/// Bitwise comparison for equality (QNaNs compare equal, 0!=-0).
fn bitwise_eq(self, rhs: Self) -> bool;
// IEEE-754R 5.7.2 General operations.
/// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
/// both are not NaN. If either argument is a NaN, returns the other argument.
fn min(self, other: Self) -> Self {
if self.is_nan() {
other
} else if other.is_nan() {
self
} else if other.partial_cmp(&self) == Some(Ordering::Less) {
other
} else {
self
}
}
/// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if
/// both are not NaN. If either argument is a NaN, returns the other argument.
fn max(self, other: Self) -> Self {
if self.is_nan() {
other
} else if other.is_nan() {
self
} else if self.partial_cmp(&other) == Some(Ordering::Less) {
other
} else {
self
}
}
/// IEEE-754R isSignMinus: Returns true if and only if the current value is
/// negative.
///
/// This applies to zeros and NaNs as well.
fn is_negative(self) -> bool;
/// IEEE-754R isNormal: Returns true if and only if the current value is normal.
///
/// This implies that the current value of the float is not zero, subnormal,
/// infinite, or NaN following the definition of normality from IEEE-754R.
fn is_normal(self) -> bool {
!self.is_denormal() && self.is_finite_non_zero()
}
/// Returns true if and only if the current value is zero, subnormal, or
/// normal.
///
/// This means that the value is not infinite or NaN.
fn is_finite(self) -> bool {
!self.is_nan() && !self.is_infinite()
}
/// Returns true if and only if the float is plus or minus zero.
fn is_zero(self) -> bool {
self.category() == Category::Zero
}
/// IEEE-754R isSubnormal(): Returns true if and only if the float is a
/// denormal.
fn is_denormal(self) -> bool;
/// IEEE-754R isInfinite(): Returns true if and only if the float is infinity.
fn is_infinite(self) -> bool {
self.category() == Category::Infinity
}
/// Returns true if and only if the float is a quiet or signaling NaN.
fn is_nan(self) -> bool {
self.category() == Category::NaN
}
/// Returns true if and only if the float is a signaling NaN.
fn is_signaling(self) -> bool;
// Simple Queries
fn category(self) -> Category;
fn is_non_zero(self) -> bool {
!self.is_zero()
}
fn is_finite_non_zero(self) -> bool {
self.is_finite() && !self.is_zero()
}
fn is_pos_zero(self) -> bool {
self.is_zero() && !self.is_negative()
}
fn is_neg_zero(self) -> bool {
self.is_zero() && self.is_negative()
}
/// Returns true if and only if the number has the smallest possible non-zero
/// magnitude in the current semantics.
fn is_smallest(self) -> bool {
Self::SMALLEST.copy_sign(self).bitwise_eq(self)
}
/// Returns true if and only if the number has the largest possible finite
/// magnitude in the current semantics.
fn is_largest(self) -> bool {
Self::largest().copy_sign(self).bitwise_eq(self)
}
/// Returns true if and only if the number is an exact integer.
fn is_integer(self) -> bool {
// This could be made more efficient; I'm going for obviously correct.
if !self.is_finite() {
return false;
}
self.round_to_integral(Round::TowardZero).value.bitwise_eq(
self,
)
}
/// If this value has an exact multiplicative inverse, return it.
fn get_exact_inverse(self) -> Option<Self>;
/// Returns the exponent of the internal representation of the Float.
///
/// Because the radix of Float is 2, this is equivalent to floor(log2(x)).
/// For special Float values, this returns special error codes:
///
/// NaN -> \c IEK_NAN
/// 0 -> \c IEK_ZERO
/// Inf -> \c IEK_INF
///
fn ilogb(self) -> ExpInt;
/// Returns: self * 2^exp for integral exponents.
fn scalbn_r(self, exp: ExpInt, round: Round) -> Self;
fn scalbn(self, exp: ExpInt) -> Self {
self.scalbn_r(exp, Round::NearestTiesToEven)
}
/// Equivalent of C standard library function.
///
/// While the C standard says exp is an unspecified value for infinity and nan,
/// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`).
fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self;
fn frexp(self, exp: &mut ExpInt) -> Self {
self.frexp_r(exp, Round::NearestTiesToEven)
}
}
pub trait FloatConvert<T: Float>: Float {
/// Convert a value of one floating point type to another.
/// The return value corresponds to the IEEE754 exceptions. *loses_info
/// records whether the transformation lost information, i.e. whether
/// converting the result back to the original type will produce the
/// original value (this is almost the same as return value==Status::OK,
/// but there are edge cases where this is not so).
fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<T>;
fn convert(self, loses_info: &mut bool) -> StatusAnd<T> {
self.convert_r(Round::NearestTiesToEven, loses_info)
}
}
macro_rules! float_common_impls {
($ty:ident<$t:tt>) => {
impl<$t> Default for $ty<$t> where Self: Float {
fn default() -> Self {
Self::ZERO
}
}
impl<$t> ::std::str::FromStr for $ty<$t> where Self: Float {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, ParseError> {
Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value)
}
}
// Rounding ties to the nearest even, by default.
impl<$t> ::std::ops::Add for $ty<$t> where Self: Float {
type Output = StatusAnd<Self>;
fn add(self, rhs: Self) -> StatusAnd<Self> {
self.add_r(rhs, Round::NearestTiesToEven)
}
}
impl<$t> ::std::ops::Sub for $ty<$t> where Self: Float {
type Output = StatusAnd<Self>;
fn sub(self, rhs: Self) -> StatusAnd<Self> {
self.sub_r(rhs, Round::NearestTiesToEven)
}
}
impl<$t> ::std::ops::Mul for $ty<$t> where Self: Float {
type Output = StatusAnd<Self>;
fn mul(self, rhs: Self) -> StatusAnd<Self> {
self.mul_r(rhs, Round::NearestTiesToEven)
}
}
impl<$t> ::std::ops::Div for $ty<$t> where Self: Float {
type Output = StatusAnd<Self>;
fn div(self, rhs: Self) -> StatusAnd<Self> {
self.div_r(rhs, Round::NearestTiesToEven)
}
}
impl<$t> ::std::ops::Rem for $ty<$t> where Self: Float {
type Output = StatusAnd<Self>;
fn rem(self, rhs: Self) -> StatusAnd<Self> {
self.c_fmod(rhs)
}
}
impl<$t> ::std::ops::AddAssign for $ty<$t> where Self: Float {
fn add_assign(&mut self, rhs: Self) {
*self = (*self + rhs).value;
}
}
impl<$t> ::std::ops::SubAssign for $ty<$t> where Self: Float {
fn sub_assign(&mut self, rhs: Self) {
*self = (*self - rhs).value;
}
}
impl<$t> ::std::ops::MulAssign for $ty<$t> where Self: Float {
fn mul_assign(&mut self, rhs: Self) {
*self = (*self * rhs).value;
}
}
impl<$t> ::std::ops::DivAssign for $ty<$t> where Self: Float {
fn div_assign(&mut self, rhs: Self) {
*self = (*self / rhs).value;
}
}
impl<$t> ::std::ops::RemAssign for $ty<$t> where Self: Float {
fn rem_assign(&mut self, rhs: Self) {
*self = (*self % rhs).value;
}
}
}
}
pub mod ieee;
pub mod ppc;

461
src/librustc_apfloat/ppc.rs Normal file
View File

@ -0,0 +1,461 @@
// 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 {Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd};
use ieee;
use std::cmp::Ordering;
use std::fmt;
use std::ops::Neg;
#[must_use]
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub struct DoubleFloat<F>(F, F);
pub type DoubleDouble = DoubleFloat<ieee::Double>;
// These are legacy semantics for the Fallback, inaccrurate implementation of
// IBM double-double, if the accurate DoubleDouble doesn't handle the
// operation. It's equivalent to having an IEEE number with consecutive 106
// bits of mantissa and 11 bits of exponent.
//
// It's not equivalent to IBM double-double. For example, a legit IBM
// double-double, 1 + epsilon:
//
// 1 + epsilon = 1 + (1 >> 1076)
//
// is not representable by a consecutive 106 bits of mantissa.
//
// Currently, these semantics are used in the following way:
//
// DoubleDouble -> (Double, Double) ->
// DoubleDouble's Fallback -> IEEE operations
//
// FIXME: Implement all operations in DoubleDouble, and delete these
// semantics.
// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
pub struct FallbackS<F>(F);
type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
impl<F: Float> ieee::Semantics for FallbackS<F> {
// Forbid any conversion to/from bits.
const BITS: usize = 0;
const PRECISION: usize = F::PRECISION * 2;
const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
const MIN_EXP: ExpInt = F::MIN_EXP as ExpInt + F::PRECISION as ExpInt;
}
// Convert number to F. To avoid spurious underflows, we re-
// normalize against the F exponent range first, and only *then*
// truncate the mantissa. The result of that second conversion
// may be inexact, but should never underflow.
// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
pub struct FallbackExtendedS<F>(F);
type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
// Forbid any conversion to/from bits.
const BITS: usize = 0;
const PRECISION: usize = Fallback::<F>::PRECISION;
const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
}
impl<F: Float> From<Fallback<F>> for DoubleFloat<F>
where
F: FloatConvert<FallbackExtended<F>>,
FallbackExtended<F>: FloatConvert<F>,
{
fn from(x: Fallback<F>) -> Self {
let mut status;
let mut loses_info = false;
let extended: FallbackExtended<F> = unpack!(status=, x.convert(&mut loses_info));
assert_eq!((status, loses_info), (Status::OK, false));
let a = unpack!(status=, extended.convert(&mut loses_info));
assert_eq!(status - Status::INEXACT, Status::OK);
// If conversion was exact or resulted in a special case, we're done;
// just set the second double to zero. Otherwise, re-convert back to
// the extended format and compute the difference. This now should
// convert exactly to double.
let b = if a.is_finite_non_zero() && loses_info {
let u: FallbackExtended<F> = unpack!(status=, a.convert(&mut loses_info));
assert_eq!((status, loses_info), (Status::OK, false));
let v = unpack!(status=, extended - u);
assert_eq!(status, Status::OK);
let v = unpack!(status=, v.convert(&mut loses_info));
assert_eq!((status, loses_info), (Status::OK, false));
v
} else {
F::ZERO
};
DoubleFloat(a, b)
}
}
impl<F: FloatConvert<Self>> From<DoubleFloat<F>> for Fallback<F> {
fn from(DoubleFloat(a, b): DoubleFloat<F>) -> Self {
let mut status;
let mut loses_info = false;
// Get the first F and convert to our format.
let a = unpack!(status=, a.convert(&mut loses_info));
assert_eq!((status, loses_info), (Status::OK, false));
// Unless we have a special case, add in second F.
if a.is_finite_non_zero() {
let b = unpack!(status=, b.convert(&mut loses_info));
assert_eq!((status, loses_info), (Status::OK, false));
(a + b).value
} else {
a
}
}
}
float_common_impls!(DoubleFloat<F>);
impl<F: Float> Neg for DoubleFloat<F> {
type Output = Self;
fn neg(self) -> Self {
if self.1.is_finite_non_zero() {
DoubleFloat(-self.0, -self.1)
} else {
DoubleFloat(-self.0, self.1)
}
}
}
impl<F: FloatConvert<Fallback<F>>> fmt::Display for DoubleFloat<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&Fallback::from(*self), f)
}
}
impl<F: FloatConvert<Fallback<F>>> Float for DoubleFloat<F>
where
Self: From<Fallback<F>>,
{
const BITS: usize = F::BITS * 2;
const PRECISION: usize = Fallback::<F>::PRECISION;
const MAX_EXP: ExpInt = Fallback::<F>::MAX_EXP;
const MIN_EXP: ExpInt = Fallback::<F>::MIN_EXP;
const ZERO: Self = DoubleFloat(F::ZERO, F::ZERO);
const INFINITY: Self = DoubleFloat(F::INFINITY, F::ZERO);
// FIXME(eddyb) remove when qnan becomes const fn.
const NAN: Self = DoubleFloat(F::NAN, F::ZERO);
fn qnan(payload: Option<u128>) -> Self {
DoubleFloat(F::qnan(payload), F::ZERO)
}
fn snan(payload: Option<u128>) -> Self {
DoubleFloat(F::snan(payload), F::ZERO)
}
fn largest() -> Self {
let status;
let mut r = DoubleFloat(F::largest(), F::largest());
r.1 = r.1.scalbn(-(F::PRECISION as ExpInt + 1));
r.1 = unpack!(status=, r.1.next_down());
assert_eq!(status, Status::OK);
r
}
const SMALLEST: Self = DoubleFloat(F::SMALLEST, F::ZERO);
fn smallest_normalized() -> Self {
DoubleFloat(
F::smallest_normalized().scalbn(F::PRECISION as ExpInt),
F::ZERO,
)
}
// Implement addition, subtraction, multiplication and division based on:
// "Software for Doubled-Precision Floating-Point Computations",
// by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
match (self.category(), rhs.category()) {
(Category::Infinity, Category::Infinity) => {
if self.is_negative() != rhs.is_negative() {
Status::INVALID_OP.and(Self::NAN.copy_sign(self))
} else {
Status::OK.and(self)
}
}
(_, Category::Zero) |
(Category::NaN, _) |
(Category::Infinity, Category::Normal) => Status::OK.and(self),
(Category::Zero, _) |
(_, Category::NaN) |
(_, Category::Infinity) => Status::OK.and(rhs),
(Category::Normal, Category::Normal) => {
let mut status = Status::OK;
let (a, aa, c, cc) = (self.0, self.1, rhs.0, rhs.1);
let mut z = a;
z = unpack!(status|=, z.add_r(c, round));
if !z.is_finite() {
if !z.is_infinite() {
return status.and(DoubleFloat(z, F::ZERO));
}
status = Status::OK;
let a_cmp_c = a.cmp_abs_normal(c);
z = cc;
z = unpack!(status|=, z.add_r(aa, round));
if a_cmp_c == Ordering::Greater {
// z = cc + aa + c + a;
z = unpack!(status|=, z.add_r(c, round));
z = unpack!(status|=, z.add_r(a, round));
} else {
// z = cc + aa + a + c;
z = unpack!(status|=, z.add_r(a, round));
z = unpack!(status|=, z.add_r(c, round));
}
if !z.is_finite() {
return status.and(DoubleFloat(z, F::ZERO));
}
self.0 = z;
let mut zz = aa;
zz = unpack!(status|=, zz.add_r(cc, round));
if a_cmp_c == Ordering::Greater {
// self.1 = a - z + c + zz;
self.1 = a;
self.1 = unpack!(status|=, self.1.sub_r(z, round));
self.1 = unpack!(status|=, self.1.add_r(c, round));
self.1 = unpack!(status|=, self.1.add_r(zz, round));
} else {
// self.1 = c - z + a + zz;
self.1 = c;
self.1 = unpack!(status|=, self.1.sub_r(z, round));
self.1 = unpack!(status|=, self.1.add_r(a, round));
self.1 = unpack!(status|=, self.1.add_r(zz, round));
}
} else {
// q = a - z;
let mut q = a;
q = unpack!(status|=, q.sub_r(z, round));
// zz = q + c + (a - (q + z)) + aa + cc;
// Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
let mut zz = q;
zz = unpack!(status|=, zz.add_r(c, round));
q = unpack!(status|=, q.add_r(z, round));
q = unpack!(status|=, q.sub_r(a, round));
q = -q;
zz = unpack!(status|=, zz.add_r(q, round));
zz = unpack!(status|=, zz.add_r(aa, round));
zz = unpack!(status|=, zz.add_r(cc, round));
if zz.is_zero() && !zz.is_negative() {
return Status::OK.and(DoubleFloat(z, F::ZERO));
}
self.0 = z;
self.0 = unpack!(status|=, self.0.add_r(zz, round));
if !self.0.is_finite() {
self.1 = F::ZERO;
return status.and(self);
}
self.1 = z;
self.1 = unpack!(status|=, self.1.sub_r(self.0, round));
self.1 = unpack!(status|=, self.1.add_r(zz, round));
}
status.and(self)
}
}
}
fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
// Interesting observation: For special categories, finding the lowest
// common ancestor of the following layered graph gives the correct
// return category:
//
// NaN
// / \
// Zero Inf
// \ /
// Normal
//
// e.g. NaN * NaN = NaN
// Zero * Inf = NaN
// Normal * Zero = Zero
// Normal * Inf = Inf
match (self.category(), rhs.category()) {
(Category::NaN, _) => Status::OK.and(self),
(_, Category::NaN) => Status::OK.and(rhs),
(Category::Zero, Category::Infinity) |
(Category::Infinity, Category::Zero) => Status::OK.and(Self::NAN),
(Category::Zero, _) |
(Category::Infinity, _) => Status::OK.and(self),
(_, Category::Zero) |
(_, Category::Infinity) => Status::OK.and(rhs),
(Category::Normal, Category::Normal) => {
let mut status = Status::OK;
let (a, b, c, d) = (self.0, self.1, rhs.0, rhs.1);
// t = a * c
let mut t = a;
t = unpack!(status|=, t.mul_r(c, round));
if !t.is_finite_non_zero() {
return status.and(DoubleFloat(t, F::ZERO));
}
// tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
let mut tau = a;
tau = unpack!(status|=, tau.mul_add_r(c, -t, round));
// v = a * d
let mut v = a;
v = unpack!(status|=, v.mul_r(d, round));
// w = b * c
let mut w = b;
w = unpack!(status|=, w.mul_r(c, round));
v = unpack!(status|=, v.add_r(w, round));
// tau += v + w
tau = unpack!(status|=, tau.add_r(v, round));
// u = t + tau
let mut u = t;
u = unpack!(status|=, u.add_r(tau, round));
self.0 = u;
if !u.is_finite() {
self.1 = F::ZERO;
} else {
// self.1 = (t - u) + tau
t = unpack!(status|=, t.sub_r(u, round));
t = unpack!(status|=, t.add_r(tau, round));
self.1 = t;
}
status.and(self)
}
}
}
fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
Fallback::from(self)
.mul_add_r(Fallback::from(multiplicand), Fallback::from(addend), round)
.map(Self::from)
}
fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
Fallback::from(self).div_r(Fallback::from(rhs), round).map(
Self::from,
)
}
fn c_fmod(self, rhs: Self) -> StatusAnd<Self> {
Fallback::from(self).c_fmod(Fallback::from(rhs)).map(
Self::from,
)
}
fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
Fallback::from(self).round_to_integral(round).map(
Self::from,
)
}
fn next_up(self) -> StatusAnd<Self> {
Fallback::from(self).next_up().map(Self::from)
}
fn from_bits(input: u128) -> Self {
let (a, b) = (input, input >> F::BITS);
DoubleFloat(
F::from_bits(a & ((1 << F::BITS) - 1)),
F::from_bits(b & ((1 << F::BITS) - 1)),
)
}
fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
Fallback::from_u128_r(input, round).map(Self::from)
}
fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
Fallback::from_str_r(s, round).map(|r| r.map(Self::from))
}
fn to_bits(self) -> u128 {
self.0.to_bits() | (self.1.to_bits() << F::BITS)
}
fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
Fallback::from(self).to_u128_r(width, round, is_exact)
}
fn cmp_abs_normal(self, rhs: Self) -> Ordering {
self.0.cmp_abs_normal(rhs.0).then_with(|| {
let result = self.1.cmp_abs_normal(rhs.1);
if result != Ordering::Equal {
let against = self.0.is_negative() ^ self.1.is_negative();
let rhs_against = rhs.0.is_negative() ^ rhs.1.is_negative();
(!against).cmp(&!rhs_against).then_with(|| if against {
result.reverse()
} else {
result
})
} else {
result
}
})
}
fn bitwise_eq(self, rhs: Self) -> bool {
self.0.bitwise_eq(rhs.0) && self.1.bitwise_eq(rhs.1)
}
fn is_negative(self) -> bool {
self.0.is_negative()
}
fn is_denormal(self) -> bool {
self.category() == Category::Normal &&
(self.0.is_denormal() || self.0.is_denormal() ||
// (double)(Hi + Lo) == Hi defines a normal number.
!(self.0 + self.1).value.bitwise_eq(self.0))
}
fn is_signaling(self) -> bool {
self.0.is_signaling()
}
fn category(self) -> Category {
self.0.category()
}
fn get_exact_inverse(self) -> Option<Self> {
Fallback::from(self).get_exact_inverse().map(Self::from)
}
fn ilogb(self) -> ExpInt {
self.0.ilogb()
}
fn scalbn_r(self, exp: ExpInt, round: Round) -> Self {
DoubleFloat(self.0.scalbn_r(exp, round), self.1.scalbn_r(exp, round))
}
fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self {
let a = self.0.frexp_r(exp, round);
let mut b = self.1;
if self.category() == Category::Normal {
b = b.scalbn_r(-*exp, round);
}
DoubleFloat(a, b)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,655 @@
// 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.
extern crate rustc_apfloat;
use rustc_apfloat::{Category, Float, Round};
use rustc_apfloat::ppc::DoubleDouble;
use std::cmp::Ordering;
#[test]
fn ppc_double_double() {
let test = DoubleDouble::ZERO;
let expected = "0x0p+0".parse::<DoubleDouble>().unwrap();
assert!(test.is_zero());
assert!(!test.is_negative());
assert!(test.bitwise_eq(expected));
assert_eq!(0, test.to_bits());
let test = -DoubleDouble::ZERO;
let expected = "-0x0p+0".parse::<DoubleDouble>().unwrap();
assert!(test.is_zero());
assert!(test.is_negative());
assert!(test.bitwise_eq(expected));
assert_eq!(0x8000000000000000, test.to_bits());
let test = "1.0".parse::<DoubleDouble>().unwrap();
assert_eq!(0x3ff0000000000000, test.to_bits());
// LDBL_MAX
let test = "1.79769313486231580793728971405301e+308"
.parse::<DoubleDouble>()
.unwrap();
assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, test.to_bits());
// LDBL_MIN
let test = "2.00416836000897277799610805135016e-292"
.parse::<DoubleDouble>()
.unwrap();
assert_eq!(0x0000000000000000_0360000000000000, test.to_bits());
}
#[test]
fn ppc_double_double_add_special() {
let data = [
// (1 + 0) + (-1 + 0) = Category::Zero
(
0x3ff0000000000000,
0xbff0000000000000,
Category::Zero,
Round::NearestTiesToEven,
),
// LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x7948000000000000,
Category::Infinity,
Round::NearestTiesToEven,
),
// FIXME: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
// DoubleDouble's fallback is gone.
// LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
// 160))) = Category::Normal
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x75effffffffffffe_7947ffffffffffff,
Category::Normal,
Round::NearestTiesToEven,
),
// LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x7c8ffffffffffffe_7fefffffffffffff,
Category::Infinity,
Round::NearestTiesToEven,
),
// NaN + (1 + 0) = Category::NaN
(
0x7ff8000000000000,
0x3ff0000000000000,
Category::NaN,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.add_r(a2, round).value;
assert_eq!(expected, a1.category(), "{:#x} + {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.add_r(a1, round).value;
assert_eq!(expected, a2.category(), "{:#x} + {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_add() {
let data = [
// (1 + 0) + (1e-105 + 0) = (1 + 1e-105)
(
0x3ff0000000000000,
0x3960000000000000,
0x3960000000000000_3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + 0) + (1e-106 + 0) = (1 + 1e-106)
(
0x3ff0000000000000,
0x3950000000000000,
0x3950000000000000_3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + 1e-106) + (1e-106 + 0) = (1 + 1e-105)
(
0x3950000000000000_3ff0000000000000,
0x3950000000000000,
0x3960000000000000_3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + 0) + (epsilon + 0) = (1 + epsilon)
(
0x3ff0000000000000,
0x0000000000000001,
0x0000000000000001_3ff0000000000000,
Round::NearestTiesToEven,
),
// FIXME: change 0xf950000000000000 to 0xf940000000000000, when
// DoubleDouble's fallback is gone.
// (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
// 1.11111... << (1023 - 52)
(
0xf950000000000000_7fefffffffffffff,
0x7c90000000000000,
0x7c8ffffffffffffe_7fefffffffffffff,
Round::NearestTiesToEven,
),
// FIXME: change 0xf950000000000000 to 0xf940000000000000, when
// DoubleDouble's fallback is gone.
// (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
// 1.11111... << (1023 - 52)
(
0x7c90000000000000,
0xf950000000000000_7fefffffffffffff,
0x7c8ffffffffffffe_7fefffffffffffff,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.add_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} + {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.add_r(a1, round).value;
assert_eq!(expected, a2.to_bits(), "{:#x} + {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_subtract() {
let data = [
// (1 + 0) - (-1e-105 + 0) = (1 + 1e-105)
(
0x3ff0000000000000,
0xb960000000000000,
0x3960000000000000_3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + 0) - (-1e-106 + 0) = (1 + 1e-106)
(
0x3ff0000000000000,
0xb950000000000000,
0x3950000000000000_3ff0000000000000,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.sub_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} - {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_multiply_special() {
let data = [
// Category::NaN * Category::NaN = Category::NaN
(
0x7ff8000000000000,
0x7ff8000000000000,
Category::NaN,
Round::NearestTiesToEven,
),
// Category::NaN * Category::Zero = Category::NaN
(
0x7ff8000000000000,
0,
Category::NaN,
Round::NearestTiesToEven,
),
// Category::NaN * Category::Infinity = Category::NaN
(
0x7ff8000000000000,
0x7ff0000000000000,
Category::NaN,
Round::NearestTiesToEven,
),
// Category::NaN * Category::Normal = Category::NaN
(
0x7ff8000000000000,
0x3ff0000000000000,
Category::NaN,
Round::NearestTiesToEven,
),
// Category::Infinity * Category::Infinity = Category::Infinity
(
0x7ff0000000000000,
0x7ff0000000000000,
Category::Infinity,
Round::NearestTiesToEven,
),
// Category::Infinity * Category::Zero = Category::NaN
(
0x7ff0000000000000,
0,
Category::NaN,
Round::NearestTiesToEven,
),
// Category::Infinity * Category::Normal = Category::Infinity
(
0x7ff0000000000000,
0x3ff0000000000000,
Category::Infinity,
Round::NearestTiesToEven,
),
// Category::Zero * Category::Zero = Category::Zero
(0, 0, Category::Zero, Round::NearestTiesToEven),
// Category::Zero * Category::Normal = Category::Zero
(
0,
0x3ff0000000000000,
Category::Zero,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.mul_r(a2, round).value;
assert_eq!(expected, a1.category(), "{:#x} * {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.mul_r(a1, round).value;
assert_eq!(expected, a2.category(), "{:#x} * {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_multiply() {
let data = [
// 1/3 * 3 = 1.0
(
0x3c75555555555556_3fd5555555555555,
0x4008000000000000,
0x3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + epsilon) * (1 + 0) = Category::Zero
(
0x0000000000000001_3ff0000000000000,
0x3ff0000000000000,
0x0000000000000001_3ff0000000000000,
Round::NearestTiesToEven,
),
// (1 + epsilon) * (1 + epsilon) = 1 + 2 * epsilon
(
0x0000000000000001_3ff0000000000000,
0x0000000000000001_3ff0000000000000,
0x0000000000000002_3ff0000000000000,
Round::NearestTiesToEven,
),
// -(1 + epsilon) * (1 + epsilon) = -1
(
0x0000000000000001_bff0000000000000,
0x0000000000000001_3ff0000000000000,
0xbff0000000000000,
Round::NearestTiesToEven,
),
// (0.5 + 0) * (1 + 2 * epsilon) = 0.5 + epsilon
(
0x3fe0000000000000,
0x0000000000000002_3ff0000000000000,
0x0000000000000001_3fe0000000000000,
Round::NearestTiesToEven,
),
// (0.5 + 0) * (1 + epsilon) = 0.5
(
0x3fe0000000000000,
0x0000000000000001_3ff0000000000000,
0x3fe0000000000000,
Round::NearestTiesToEven,
),
// __LDBL_MAX__ * (1 + 1 << 106) = inf
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x3950000000000000_3ff0000000000000,
0x7ff0000000000000,
Round::NearestTiesToEven,
),
// __LDBL_MAX__ * (1 + 1 << 107) > __LDBL_MAX__, but not inf, yes =_=|||
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x3940000000000000_3ff0000000000000,
0x7c8fffffffffffff_7fefffffffffffff,
Round::NearestTiesToEven,
),
// __LDBL_MAX__ * (1 + 1 << 108) = __LDBL_MAX__
(
0x7c8ffffffffffffe_7fefffffffffffff,
0x3930000000000000_3ff0000000000000,
0x7c8ffffffffffffe_7fefffffffffffff,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.mul_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} * {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.mul_r(a1, round).value;
assert_eq!(expected, a2.to_bits(), "{:#x} * {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_divide() {
// FIXME: Only a sanity check for now. Add more edge cases when the
// double-double algorithm is implemented.
let data = [
// 1 / 3 = 1/3
(
0x3ff0000000000000,
0x4008000000000000,
0x3c75555555555556_3fd5555555555555,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.div_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} / {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_remainder() {
let data = [
// ieee_rem(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
(
0x3cb8000000000000_4008000000000000,
0x3ca4000000000000_3ff4000000000000,
0x3c90000000000000_3fe0000000000000,
),
// ieee_rem(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (-0.5 - 0.5 << 53)
(
0x3cb8000000000000_4008000000000000,
0x3cac000000000000_3ffc000000000000,
0xbc90000000000000_bfe0000000000000,
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let result = a1.ieee_rem(a2).value;
assert_eq!(
expected,
result.to_bits(),
"ieee_rem({:#x}, {:#x})",
op1,
op2
);
}
}
#[test]
fn ppc_double_double_mod() {
let data = [
// mod(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
(
0x3cb8000000000000_4008000000000000,
0x3ca4000000000000_3ff4000000000000,
0x3c90000000000000_3fe0000000000000,
),
// mod(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (1.25 + 1.25 << 53)
// 0xbc98000000000000 doesn't seem right, but it's what we currently have.
// FIXME: investigate
(
0x3cb8000000000000_4008000000000000,
0x3cac000000000000_3ffc000000000000,
0xbc98000000000000_3ff4000000000001,
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let r = (a1 % a2).value;
assert_eq!(expected, r.to_bits(), "fmod({:#x}, {:#x})", op1, op2);
}
}
#[test]
fn ppc_double_double_fma() {
// Sanity check for now.
let mut a = "2".parse::<DoubleDouble>().unwrap();
a = a.mul_add(
"3".parse::<DoubleDouble>().unwrap(),
"4".parse::<DoubleDouble>().unwrap(),
).value;
assert_eq!(
Some(Ordering::Equal),
"10".parse::<DoubleDouble>().unwrap().partial_cmp(&a)
);
}
#[test]
fn ppc_double_double_round_to_integral() {
{
let a = "1.5".parse::<DoubleDouble>().unwrap();
let a = a.round_to_integral(Round::NearestTiesToEven).value;
assert_eq!(
Some(Ordering::Equal),
"2".parse::<DoubleDouble>().unwrap().partial_cmp(&a)
);
}
{
let a = "2.5".parse::<DoubleDouble>().unwrap();
let a = a.round_to_integral(Round::NearestTiesToEven).value;
assert_eq!(
Some(Ordering::Equal),
"2".parse::<DoubleDouble>().unwrap().partial_cmp(&a)
);
}
}
#[test]
fn ppc_double_double_compare() {
let data = [
// (1 + 0) = (1 + 0)
(
0x3ff0000000000000,
0x3ff0000000000000,
Some(Ordering::Equal),
),
// (1 + 0) < (1.00...1 + 0)
(0x3ff0000000000000, 0x3ff0000000000001, Some(Ordering::Less)),
// (1.00...1 + 0) > (1 + 0)
(
0x3ff0000000000001,
0x3ff0000000000000,
Some(Ordering::Greater),
),
// (1 + 0) < (1 + epsilon)
(
0x3ff0000000000000,
0x0000000000000001_3ff0000000000001,
Some(Ordering::Less),
),
// NaN != NaN
(0x7ff8000000000000, 0x7ff8000000000000, None),
// (1 + 0) != NaN
(0x3ff0000000000000, 0x7ff8000000000000, None),
// Inf = Inf
(
0x7ff0000000000000,
0x7ff0000000000000,
Some(Ordering::Equal),
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(
expected,
a1.partial_cmp(&a2),
"compare({:#x}, {:#x})",
op1,
op2,
);
}
}
#[test]
fn ppc_double_double_bitwise_eq() {
let data = [
// (1 + 0) = (1 + 0)
(0x3ff0000000000000, 0x3ff0000000000000, true),
// (1 + 0) != (1.00...1 + 0)
(0x3ff0000000000000, 0x3ff0000000000001, false),
// NaN = NaN
(0x7ff8000000000000, 0x7ff8000000000000, true),
// NaN != NaN with a different bit pattern
(
0x7ff8000000000000,
0x3ff0000000000000_7ff8000000000000,
false,
),
// Inf = Inf
(0x7ff0000000000000, 0x7ff0000000000000, true),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_change_sign() {
let float = DoubleDouble::from_bits(0xbcb0000000000000_400f000000000000);
{
let actual = float.copy_sign("1".parse::<DoubleDouble>().unwrap());
assert_eq!(0xbcb0000000000000_400f000000000000, actual.to_bits());
}
{
let actual = float.copy_sign("-1".parse::<DoubleDouble>().unwrap());
assert_eq!(0x3cb0000000000000_c00f000000000000, actual.to_bits());
}
}
#[test]
fn ppc_double_double_factories() {
assert_eq!(0, DoubleDouble::ZERO.to_bits());
assert_eq!(
0x7c8ffffffffffffe_7fefffffffffffff,
DoubleDouble::largest().to_bits()
);
assert_eq!(0x0000000000000001, DoubleDouble::SMALLEST.to_bits());
assert_eq!(
0x0360000000000000,
DoubleDouble::smallest_normalized().to_bits()
);
assert_eq!(
0x0000000000000000_8000000000000000,
(-DoubleDouble::ZERO).to_bits()
);
assert_eq!(
0xfc8ffffffffffffe_ffefffffffffffff,
(-DoubleDouble::largest()).to_bits()
);
assert_eq!(
0x0000000000000000_8000000000000001,
(-DoubleDouble::SMALLEST).to_bits()
);
assert_eq!(
0x0000000000000000_8360000000000000,
(-DoubleDouble::smallest_normalized()).to_bits()
);
assert!(DoubleDouble::SMALLEST.is_smallest());
assert!(DoubleDouble::largest().is_largest());
}
#[test]
fn ppc_double_double_is_denormal() {
assert!(DoubleDouble::SMALLEST.is_denormal());
assert!(!DoubleDouble::largest().is_denormal());
assert!(!DoubleDouble::smallest_normalized().is_denormal());
{
// (4 + 3) is not normalized
let data = 0x4008000000000000_4010000000000000;
assert!(DoubleDouble::from_bits(data).is_denormal());
}
}
#[test]
fn ppc_double_double_exact_inverse() {
assert!(
"2.0"
.parse::<DoubleDouble>()
.unwrap()
.get_exact_inverse()
.unwrap()
.bitwise_eq("0.5".parse::<DoubleDouble>().unwrap())
);
}
#[test]
fn ppc_double_double_scalbn() {
// 3.0 + 3.0 << 53
let input = 0x3cb8000000000000_4008000000000000;
let result = DoubleDouble::from_bits(input).scalbn(1);
// 6.0 + 6.0 << 53
assert_eq!(0x3cc8000000000000_4018000000000000, result.to_bits());
}
#[test]
fn ppc_double_double_frexp() {
// 3.0 + 3.0 << 53
let input = 0x3cb8000000000000_4008000000000000;
let mut exp = 0;
// 0.75 + 0.75 << 53
let result = DoubleDouble::from_bits(input).frexp(&mut exp);
assert_eq!(2, exp);
assert_eq!(0x3c98000000000000_3fe8000000000000, result.to_bits());
}

View File

@ -0,0 +1,32 @@
// 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 PanicStrategy;
use LinkerFlavor;
use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
pre_link_args.insert(LinkerFlavor::Ld, vec![
"-nostdlib".to_string(),
]);
TargetOptions {
executables: true,
has_elf_tls: false,
exe_allocation_crate: Some("alloc_system".to_string()),
panic_strategy: PanicStrategy::Abort,
linker: "ld".to_string(),
pre_link_args: pre_link_args,
target_family: Some("unix".to_string()),
.. Default::default()
}
}

View File

@ -69,6 +69,7 @@ mod solaris_base;
mod windows_base;
mod windows_msvc_base;
mod thumb_base;
mod l4re_base;
mod fuchsia_base;
mod redox_base;
@ -193,6 +194,8 @@ supported_targets! {
("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),
("x86_64-unknown-redox", x86_64_unknown_redox),
("i386-apple-ios", i386_apple_ios),

View File

@ -0,0 +1,31 @@
// 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 LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::l4re_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
Ok(Target {
llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
arch: "x86_64".to_string(),
target_os: "l4re".to_string(),
target_env: "uclibc".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Ld,
options: base,
})
}

View File

@ -111,19 +111,28 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
// is not yet stolen.
tcx.mir_validated(owner_def_id).borrow();
let cfg = cfg::CFG::new(bccx.tcx, &body);
let AnalysisData { all_loans,
loans: loan_dfcx,
move_data: flowed_moves } =
build_borrowck_dataflow_data(bccx, &cfg, body_id);
check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
// option dance because you can't capture an uninitialized variable
// by mut-ref.
let mut cfg = None;
if let Some(AnalysisData { all_loans,
loans: loan_dfcx,
move_data: flowed_moves }) =
build_borrowck_dataflow_data(bccx, false, body_id,
|bccx| {
cfg = Some(cfg::CFG::new(bccx.tcx, &body));
cfg.as_mut().unwrap()
})
{
check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
}
}
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
cfg: &cfg::CFG,
body_id: hir::BodyId)
-> AnalysisData<'a, 'tcx>
fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>,
force_analysis: bool,
body_id: hir::BodyId,
get_cfg: F)
-> Option<AnalysisData<'a, 'tcx>>
where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG
{
// Check the body of fn items.
let tcx = this.tcx;
@ -135,6 +144,18 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
let (all_loans, move_data) =
gather_loans::gather_loans_in_fn(this, body_id);
if !force_analysis && move_data.is_empty() && all_loans.is_empty() {
// large arrays of data inserted as constants can take a lot of
// time and memory to borrow-check - see issue #36799. However,
// they don't have lvalues, so no borrow-check is actually needed.
// Recognize that case and skip borrow-checking.
debug!("skipping loan propagation for {:?} because of no loans", body_id);
return None;
} else {
debug!("propagating loans in {:?}", body_id);
}
let cfg = get_cfg(this);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
"borrowck",
@ -157,9 +178,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
id_range,
this.body);
AnalysisData { all_loans: all_loans,
loans: loan_dfcx,
move_data:flowed_moves }
Some(AnalysisData { all_loans: all_loans,
loans: loan_dfcx,
move_data:flowed_moves })
}
/// Accessor for introspective clients inspecting `AnalysisData` and
@ -177,8 +198,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
let body = tcx.hir.body(body_id);
let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body };
let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id);
(bccx, dataflow_data)
let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
(bccx, dataflow_data.unwrap())
}
// ----------------------------------------------------------------------
@ -1072,14 +1093,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
fn local_binding_mode(&self, node_id: ast::NodeId) -> ty::BindingMode {
let pat = match self.tcx.hir.get(node_id) {
hir_map::Node::NodeLocal(pat) => pat,
node => bug!("bad node for local: {:?}", node)
};
match pat.node {
hir::PatKind::Binding(mode, ..) => mode,
hir::PatKind::Binding(..) =>
*self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"),
_ => bug!("local is not a binding: {:?}", pat)
}
}
@ -1114,7 +1136,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
let let_span = self.tcx.hir.span(node_id);
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
if let ty::BindByValue(..) = self.local_binding_mode(node_id) {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
let (_, is_implicit_self) = self.local_ty(node_id);
if is_implicit_self && snippet != "self" {
@ -1131,7 +1153,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
let let_span = self.tcx.hir.span(node_id);
match self.local_binding_mode(node_id) {
hir::BindingMode::BindByRef(..) => {
ty::BindByReference(..) => {
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
if let Ok(snippet) = snippet {
db.span_label(
@ -1141,7 +1163,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
);
}
}
hir::BindingMode::BindByValue(..) => {
ty::BindByValue(..) => {
if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
if let Some(msg) =
self.suggest_mut_for_immutable(local_ty, is_implicit_self) {

View File

@ -220,6 +220,15 @@ impl<'a, 'tcx> MoveData<'tcx> {
}
}
/// return true if there are no trackable assignments or moves
/// in this move data - that means that there is nothing that
/// could cause a borrow error.
pub fn is_empty(&self) -> bool {
self.moves.borrow().is_empty() &&
self.path_assignments.borrow().is_empty() &&
self.var_assignments.borrow().is_empty()
}
pub fn path_loan_path(&self, index: MovePathIndex) -> Rc<LoanPath<'tcx>> {
(*self.paths.borrow())[index.get()].loan_path.clone()
}

View File

@ -1132,6 +1132,24 @@ fn main() {
```
"##,
E0595: r##"
Closures cannot mutate immutable captured variables.
Erroneous code example:
```compile_fail,E0595
let x = 3; // error: closure cannot assign to immutable local variable `x`
let mut c = || { x += 1 };
```
Make the variable binding mutable:
```
let mut x = 3; // ok!
let mut c = || { x += 1 };
```
"##,
E0596: r##"
This error occurs because you tried to mutably borrow a non-mutable variable.
@ -1275,6 +1293,5 @@ register_diagnostics! {
// E0385, // {} in an aliasable location
E0524, // two closures require unique access to `..` at the same time
E0594, // cannot assign to {}
E0595, // closure cannot assign to {}
E0598, // lifetime of {} is too short to guarantee its contents can be...
}

View File

@ -268,7 +268,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
pat.walk(|p| {
if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), _, name, None) = p.node {
if let PatKind::Binding(_, _, name, None) = p.node {
let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
if bm != ty::BindByValue(hir::MutImmutable) {
// Nothing to check.
return true;
}
let pat_ty = cx.tables.pat_ty(p);
if let ty::TyAdt(edef, _) = pat_ty.sty {
if edef.is_enum() && edef.variants.iter().any(|variant| {
@ -452,8 +457,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
pats: &[P<Pat>]) {
let mut by_ref_span = None;
for pat in pats {
pat.each_binding(|bm, _, span, _path| {
if let hir::BindByRef(..) = bm {
pat.each_binding(|_, id, span, _path| {
let bm = *cx.tables.pat_binding_modes.get(&id).expect("missing binding mode");
if let ty::BindByReference(..) = bm {
by_ref_span = Some(span);
}
})
@ -484,10 +490,16 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
for pat in pats {
pat.walk(|p| {
if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
let pat_ty = cx.tables.node_id_to_type(p.id);
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
if let PatKind::Binding(_, _, _, ref sub) = p.node {
let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
match bm {
ty::BindByValue(..) => {
let pat_ty = cx.tables.node_id_to_type(p.id);
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
}
_ => {}
}
}
true

View File

@ -26,6 +26,7 @@ use rustc::util::nodemap::DefIdMap;
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr;
use rustc::hir::{self, Expr};
use syntax_pos::Span;
@ -560,8 +561,15 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty::TyUint(ast::UintTy::Us) => {
Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
},
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
ty::TyFloat(fty) => {
if let Some(i) = val.to_u128() {
Ok(Float(ConstFloat::from_u128(i, fty)))
} else {
// The value must be negative, go through signed integers.
let i = val.to_u128_unchecked() as i128;
Ok(Float(ConstFloat::from_i128(i, fty)))
}
}
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
ty::TyChar => match val {
U8(u) => Ok(Char(u as char)),
@ -574,30 +582,25 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: ConstFloat,
ty: Ty<'tcx>) -> CastResult<'tcx> {
let int_width = |ty| {
ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
};
match ty.sty {
ty::TyInt(_) | ty::TyUint(_) => {
let i = match val {
F32(f) if f >= 0.0 => U128(f as u128),
F64(f) if f >= 0.0 => U128(f as u128),
F32(f) => I128(f as i128),
F64(f) => I128(f as i128)
};
if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
return Err(CannotCast);
ty::TyInt(ity) => {
if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
cast_const_int(tcx, I128(i), ty)
} else {
Err(CannotCast)
}
cast_const_int(tcx, i, ty)
}
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
F32(f) => f as f64,
F64(f) => f
}))),
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
F64(f) => f as f32,
F32(f) => f
}))),
ty::TyUint(uty) => {
if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
cast_const_int(tcx, U128(i), ty)
} else {
Err(CannotCast)
}
}
ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
_ => Err(CannotCast),
}
}
@ -691,11 +694,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
-> Result<ConstFloat, ErrKind<'tcx>> {
let val = match fty {
ast::FloatTy::F32 => num.parse::<f32>().map(F32),
ast::FloatTy::F64 => num.parse::<f64>().map(F64)
};
val.map_err(|_| {
ConstFloat::from_str(num, fty).map_err(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
})

View File

@ -374,27 +374,31 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
}
PatKind::Binding(bm, def_id, ref ident, ref sub) => {
PatKind::Binding(_, def_id, ref ident, ref sub) => {
let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let var_ty = self.tables.node_id_to_type(pat.id);
let region = match var_ty.sty {
ty::TyRef(r, _) => Some(r),
_ => None,
};
let bm = *self.tables.pat_binding_modes.get(&pat.id)
.expect("missing binding mode");
let (mutability, mode) = match bm {
hir::BindByValue(hir::MutMutable) =>
ty::BindByValue(hir::MutMutable) =>
(Mutability::Mut, BindingMode::ByValue),
hir::BindByValue(hir::MutImmutable) =>
ty::BindByValue(hir::MutImmutable) =>
(Mutability::Not, BindingMode::ByValue),
hir::BindByRef(hir::MutMutable) =>
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
hir::BindByRef(hir::MutImmutable) =>
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
ty::BindByReference(hir::MutMutable) =>
(Mutability::Not, BindingMode::ByRef(
region.unwrap(), BorrowKind::Mut)),
ty::BindByReference(hir::MutImmutable) =>
(Mutability::Not, BindingMode::ByRef(
region.unwrap(), BorrowKind::Shared)),
};
// A ref x pattern is the same node used for x, and as such it has
// x's type, which is &T, where we want T (the type being matched).
if let hir::BindByRef(_) = bm {
if let ty::BindByReference(_) = bm {
if let ty::TyRef(_, mt) = ty.sty {
ty = mt.ty;
} else {

View File

@ -9,5 +9,6 @@ path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
rustc_apfloat = { path = "../librustc_apfloat" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }

View File

@ -9,102 +9,164 @@
// except according to those terms.
use std::cmp::Ordering;
use std::hash;
use std::mem::transmute;
use std::num::ParseFloatError;
use syntax::ast;
use rustc_apfloat::{Float, FloatConvert, Status};
use rustc_apfloat::ieee::{Single, Double};
use super::err::*;
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstFloat {
F32(f32),
F64(f64)
// Note that equality for `ConstFloat` means that the it is the same
// constant, not that the rust values are equal. In particular, `NaN
// == NaN` (at least if it's the same NaN; distinct encodings for NaN
// are considering unequal).
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct ConstFloat {
pub ty: ast::FloatTy,
// This is a bit inefficient but it makes conversions below more
// ergonomic, and all of this will go away once `miri` is merged.
pub bits: u128,
}
pub use self::ConstFloat::*;
impl ConstFloat {
/// Description of the type, not the value
pub fn description(&self) -> &'static str {
match *self {
F32(_) => "f32",
F64(_) => "f64",
}
self.ty.ty_to_string()
}
pub fn is_nan(&self) -> bool {
match *self {
F32(f) => f.is_nan(),
F64(f) => f.is_nan(),
match self.ty {
ast::FloatTy::F32 => Single::from_bits(self.bits).is_nan(),
ast::FloatTy::F64 => Double::from_bits(self.bits).is_nan(),
}
}
/// Compares the values if they are of the same type
pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
match (self, rhs) {
(F64(a), F64(b)) => {
match (self.ty, rhs.ty) {
(ast::FloatTy::F64, ast::FloatTy::F64) => {
let a = Double::from_bits(self.bits);
let b = Double::from_bits(rhs.bits);
// This is pretty bad but it is the existing behavior.
Ok(if a == b {
Ordering::Equal
} else if a < b {
Ordering::Less
} else {
Ordering::Greater
})
Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater))
}
(F32(a), F32(b)) => {
Ok(if a == b {
Ordering::Equal
} else if a < b {
Ordering::Less
} else {
Ordering::Greater
})
(ast::FloatTy::F32, ast::FloatTy::F32) => {
let a = Single::from_bits(self.bits);
let b = Single::from_bits(rhs.bits);
Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater))
}
_ => Err(CmpBetweenUnequalTypes),
}
}
}
/// Note that equality for `ConstFloat` means that the it is the same
/// constant, not that the rust values are equal. In particular, `NaN
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
/// are considering unequal).
impl PartialEq for ConstFloat {
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
(F64(a), F64(b)) => {
unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
pub fn from_i128(input: i128, ty: ast::FloatTy) -> Self {
let bits = match ty {
ast::FloatTy::F32 => Single::from_i128(input).value.to_bits(),
ast::FloatTy::F64 => Double::from_i128(input).value.to_bits()
};
ConstFloat { bits, ty }
}
pub fn from_u128(input: u128, ty: ast::FloatTy) -> Self {
let bits = match ty {
ast::FloatTy::F32 => Single::from_u128(input).value.to_bits(),
ast::FloatTy::F64 => Double::from_u128(input).value.to_bits()
};
ConstFloat { bits, ty }
}
pub fn from_str(num: &str, ty: ast::FloatTy) -> Result<Self, ParseFloatError> {
let bits = match ty {
ast::FloatTy::F32 => {
let rust_bits = num.parse::<f32>()?.to_bits() as u128;
let apfloat = num.parse::<Single>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e);
});
let apfloat_bits = apfloat.to_bits();
assert!(rust_bits == apfloat_bits,
"apfloat::ieee::Single gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
num, apfloat, apfloat_bits,
Single::from_bits(rust_bits), rust_bits);
apfloat_bits
}
(F32(a), F32(b)) => {
unsafe{transmute::<_,u32>(a) == transmute::<_,u32>(b)}
ast::FloatTy::F64 => {
let rust_bits = num.parse::<f64>()?.to_bits() as u128;
let apfloat = num.parse::<Double>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e);
});
let apfloat_bits = apfloat.to_bits();
assert!(rust_bits == apfloat_bits,
"apfloat::ieee::Double gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
num, apfloat, apfloat_bits,
Double::from_bits(rust_bits), rust_bits);
apfloat_bits
}
_ => false
};
Ok(ConstFloat { bits, ty })
}
pub fn to_i128(self, width: usize) -> Option<i128> {
assert!(width <= 128);
let r = match self.ty {
ast::FloatTy::F32 => Single::from_bits(self.bits).to_i128(width),
ast::FloatTy::F64 => Double::from_bits(self.bits).to_i128(width)
};
if r.status.intersects(Status::INVALID_OP) {
None
} else {
Some(r.value)
}
}
}
impl Eq for ConstFloat {}
impl hash::Hash for ConstFloat {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
F64(a) => {
unsafe { transmute::<_,u64>(a) }.hash(state)
}
F32(a) => {
unsafe { transmute::<_,u32>(a) }.hash(state)
}
pub fn to_u128(self, width: usize) -> Option<u128> {
assert!(width <= 128);
let r = match self.ty {
ast::FloatTy::F32 => Single::from_bits(self.bits).to_u128(width),
ast::FloatTy::F64 => Double::from_bits(self.bits).to_u128(width)
};
if r.status.intersects(Status::INVALID_OP) {
None
} else {
Some(r.value)
}
}
pub fn convert(self, to: ast::FloatTy) -> Self {
let bits = match (self.ty, to) {
(ast::FloatTy::F32, ast::FloatTy::F32) |
(ast::FloatTy::F64, ast::FloatTy::F64) => return self,
(ast::FloatTy::F32, ast::FloatTy::F64) => {
Double::to_bits(Single::from_bits(self.bits).convert(&mut false).value)
}
(ast::FloatTy::F64, ast::FloatTy::F32) => {
Single::to_bits(Double::from_bits(self.bits).convert(&mut false).value)
}
};
ConstFloat { bits, ty: to }
}
}
impl ::std::fmt::Display for ConstFloat {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
F32(f) => write!(fmt, "{}f32", f),
F64(f) => write!(fmt, "{}f64", f),
match self.ty {
ast::FloatTy::F32 => write!(fmt, "{:#}", Single::from_bits(self.bits))?,
ast::FloatTy::F64 => write!(fmt, "{:#}", Double::from_bits(self.bits))?,
}
write!(fmt, "{}", self.ty)
}
}
impl ::std::fmt::Debug for ConstFloat {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(self, fmt)
}
}
@ -113,11 +175,20 @@ macro_rules! derive_binop {
impl ::std::ops::$op for ConstFloat {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match (self, rhs) {
(F32(a), F32(b)) => Ok(F32(a.$func(b))),
(F64(a), F64(b)) => Ok(F64(a.$func(b))),
_ => Err(UnequalTypes(Op::$op)),
}
let bits = match (self.ty, rhs.ty) {
(ast::FloatTy::F32, ast::FloatTy::F32) =>{
let a = Single::from_bits(self.bits);
let b = Single::from_bits(rhs.bits);
a.$func(b).value.to_bits()
}
(ast::FloatTy::F64, ast::FloatTy::F64) => {
let a = Double::from_bits(self.bits);
let b = Double::from_bits(rhs.bits);
a.$func(b).value.to_bits()
}
_ => return Err(UnequalTypes(Op::$op)),
};
Ok(ConstFloat { bits, ty: self.ty })
}
}
}
@ -132,9 +203,10 @@ derive_binop!(Rem, rem);
impl ::std::ops::Neg for ConstFloat {
type Output = Self;
fn neg(self) -> Self {
match self {
F32(f) => F32(-f),
F64(f) => F64(-f),
}
let bits = match self.ty {
ast::FloatTy::F32 => (-Single::from_bits(self.bits)).to_bits(),
ast::FloatTy::F64 => (-Double::from_bits(self.bits)).to_bits(),
};
ConstFloat { bits, ty: self.ty }
}
}

View File

@ -211,48 +211,6 @@ impl ConstInt {
}
}
pub fn to_f32(self) -> f32 {
match self {
I8(i) => i as f32,
I16(i) => i as f32,
I32(i) => i as f32,
I64(i) => i as f32,
I128(i) => i as f32,
Isize(Is16(i)) => i as f32,
Isize(Is32(i)) => i as f32,
Isize(Is64(i)) => i as f32,
U8(i) => i as f32,
U16(i) => i as f32,
U32(i) => i as f32,
U64(i) => i as f32,
U128(i) => i as f32,
Usize(Us16(i)) => i as f32,
Usize(Us32(i)) => i as f32,
Usize(Us64(i)) => i as f32,
}
}
pub fn to_f64(self) -> f64 {
match self {
I8(i) => i as f64,
I16(i) => i as f64,
I32(i) => i as f64,
I64(i) => i as f64,
I128(i) => i as f64,
Isize(Is16(i)) => i as f64,
Isize(Is32(i)) => i as f64,
Isize(Is64(i)) => i as f64,
U8(i) => i as f64,
U16(i) => i as f64,
U32(i) => i as f64,
U64(i) => i as f64,
U128(i) => i as f64,
Usize(Us16(i)) => i as f64,
Usize(Us32(i)) => i as f64,
Usize(Us64(i)) => i as f64,
}
}
pub fn is_negative(&self) -> bool {
match *self {
I8(v) => v < 0,

View File

@ -26,6 +26,8 @@
#![feature(i128)]
#![feature(i128_type)]
extern crate rustc_apfloat;
extern crate syntax;
extern crate serialize as rustc_serialize; // used by deriving

View File

@ -134,9 +134,11 @@ pub trait BitwiseOperator {
pub struct Union;
impl BitwiseOperator for Union {
#[inline]
fn join(&self, a: usize, b: usize) -> usize { a | b }
}
pub struct Subtract;
impl BitwiseOperator for Subtract {
#[inline]
fn join(&self, a: usize, b: usize) -> usize { a & !b }
}

View File

@ -1,66 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::hash::{Hasher, Hash, BuildHasherDefault};
pub type FnvHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
pub type FnvHashSet<V> = HashSet<V, BuildHasherDefault<FnvHasher>>;
#[allow(non_snake_case)]
pub fn FnvHashMap<K: Hash + Eq, V>() -> FnvHashMap<K, V> {
HashMap::default()
}
#[allow(non_snake_case)]
pub fn FnvHashSet<V: Hash + Eq>() -> FnvHashSet<V> {
HashSet::default()
}
/// A speedy hash algorithm for node ids and def ids. The hashmap in
/// liballoc by default uses SipHash which isn't quite as speedy as we
/// want. In the compiler we're not really worried about DOS attempts, so we
/// just default to a non-cryptographic hash.
///
/// This uses FNV hashing, as described here:
/// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
pub struct FnvHasher(u64);
impl Default for FnvHasher {
/// Creates a `FnvHasher`, with a 64-bit hex initial value.
#[inline]
fn default() -> FnvHasher {
FnvHasher(0xcbf29ce484222325)
}
}
impl Hasher for FnvHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
let FnvHasher(mut hash) = *self;
for byte in bytes {
hash = hash ^ (*byte as u64);
hash = hash.wrapping_mul(0x100000001b3);
}
*self = FnvHasher(hash);
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
pub fn hash<T: Hash>(v: &T) -> u64 {
let mut state = FnvHasher::default();
v.hash(&mut state);
state.finish()
}

View File

@ -308,6 +308,42 @@ impl<N: Debug, E: Debug> Graph<N, E> {
DepthFirstTraversal::with_start_node(self, start, direction)
}
pub fn nodes_in_postorder<'a>(&'a self,
direction: Direction,
entry_node: NodeIndex)
-> Vec<NodeIndex>
{
let mut visited = BitVector::new(self.len_nodes());
let mut stack = vec![];
let mut result = Vec::with_capacity(self.len_nodes());
let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| {
if visited.insert(node.0) {
stack.push((node, self.adjacent_edges(node, direction)));
}
};
for node in Some(entry_node).into_iter()
.chain(self.enumerated_nodes().map(|(node, _)| node))
{
push_node(&mut stack, node);
while let Some((node, mut iter)) = stack.pop() {
if let Some((_, child)) = iter.next() {
let target = child.source_or_target(direction);
// the current node needs more processing, so
// add it back to the stack
stack.push((node, iter));
// and then push the new node
push_node(&mut stack, target);
} else {
result.push(node);
}
}
}
assert_eq!(result.len(), self.len_nodes());
result
}
/// Whether or not a node can be reached from itself.
pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool {
// This is similar to depth traversal below, but we

View File

@ -175,3 +175,46 @@ fn is_node_cyclic_b() {
let graph = create_graph_with_cycle();
assert!(graph.is_node_cyclic(NodeIndex(1)));
}
#[test]
fn nodes_in_postorder() {
let expected = vec![
("A", vec!["C", "E", "D", "B", "A", "F"]),
("B", vec!["C", "E", "D", "B", "A", "F"]),
("C", vec!["C", "E", "D", "B", "A", "F"]),
("D", vec!["C", "E", "D", "B", "A", "F"]),
("E", vec!["C", "E", "D", "B", "A", "F"]),
("F", vec!["C", "E", "D", "B", "F", "A"])
];
let graph = create_graph();
for ((idx, node), &(node_name, ref expected))
in graph.enumerated_nodes().zip(&expected)
{
assert_eq!(node.data, node_name);
assert_eq!(expected,
&graph.nodes_in_postorder(OUTGOING, idx)
.into_iter().map(|idx| *graph.node_data(idx))
.collect::<Vec<&str>>());
}
let expected = vec![
("A", vec!["D", "C", "B", "A"]),
("B", vec!["D", "C", "B", "A"]),
("C", vec!["B", "D", "C", "A"]),
("D", vec!["C", "B", "D", "A"]),
];
let graph = create_graph_with_cycle();
for ((idx, node), &(node_name, ref expected))
in graph.enumerated_nodes().zip(&expected)
{
assert_eq!(node.data, node_name);
assert_eq!(expected,
&graph.nodes_in_postorder(OUTGOING, idx)
.into_iter().map(|idx| *graph.node_data(idx))
.collect::<Vec<&str>>());
}
}

View File

@ -65,7 +65,6 @@ pub mod snapshot_vec;
pub mod stable_hasher;
pub mod transitive_relation;
pub mod unify;
pub mod fnv;
pub mod fx;
pub mod tuple_slice;
pub mod veccell;

View File

@ -15,8 +15,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
use rustc_mir as mir;
use rustc::session::{Session, CompileResult};
use rustc::session::CompileIncomplete;
use rustc::session::config::{self, Input, OutputFilenames, OutputType,
OutputTypes};
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::middle::{self, dependency_format, stability, reachable};
@ -26,7 +25,6 @@ use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc::traits;
use rustc::util::common::{ErrorReported, time};
use rustc::util::nodemap::NodeSet;
use rustc::util::fs::rename_or_copy_remove;
use rustc_allocator as allocator;
use rustc_borrowck as borrowck;
use rustc_incremental::{self, IncrementalHashesMap};
@ -208,7 +206,7 @@ pub fn compile_input(sess: &Session,
println!("Pre-trans");
tcx.print_debug_stats();
}
let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map,
let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
&outputs);
if log_enabled!(::log::LogLevel::Info) {
@ -231,7 +229,7 @@ pub fn compile_input(sess: &Session,
sess.code_stats.borrow().print_type_sizes();
}
let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
controller_entry_point!(after_llvm,
sess,
@ -239,8 +237,6 @@ pub fn compile_input(sess: &Session,
phase5_result);
phase5_result?;
write::cleanup_llvm(&trans);
phase_6_link_output(sess, &trans, &outputs);
// Now that we won't touch anything in the incremental compilation directory
@ -933,6 +929,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
passes.push_pass(MIR_CONST, mir::transform::rustc_peek::SanityCheck);
// We compute "constant qualifications" betwen MIR_CONST and MIR_VALIDATED.
// What we need to run borrowck etc.
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(MIR_VALIDATED,
@ -940,18 +938,23 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL);
// Optimizations begin.
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
// borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
// These next passes must be executed together
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
// No lifetime analysis based on borrowing can be done from here on out.
// AddValidation needs to run after ElaborateDrops and before EraseRegions.
passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
// Optimizations begin.
passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
@ -1059,9 +1062,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
/// be discarded.
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis: ty::CrateAnalysis,
incremental_hashes_map: &IncrementalHashesMap,
incremental_hashes_map: IncrementalHashesMap,
output_filenames: &OutputFilenames)
-> trans::CrateTranslation {
-> write::OngoingCrateTranslation {
let time_passes = tcx.sess.time_passes();
time(time_passes,
@ -1071,63 +1074,27 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let translation =
time(time_passes,
"translation",
move || trans::trans_crate(tcx, analysis, &incremental_hashes_map, output_filenames));
move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames));
time(time_passes,
"assert dep graph",
|| rustc_incremental::assert_dep_graph(tcx));
time(time_passes,
"serialize dep graph",
|| rustc_incremental::save_dep_graph(tcx,
&incremental_hashes_map,
&translation.metadata.hashes,
translation.link.crate_hash));
translation
}
/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
pub fn phase_5_run_llvm_passes(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) -> CompileResult {
if sess.opts.cg.no_integrated_as ||
(sess.target.target.options.no_integrated_as &&
(outputs.outputs.contains_key(&OutputType::Object) ||
outputs.outputs.contains_key(&OutputType::Exe)))
{
let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]);
time(sess.time_passes(),
"LLVM passes",
|| write::run_passes(sess, trans, &output_types, outputs));
trans: write::OngoingCrateTranslation)
-> (CompileResult, trans::CrateTranslation) {
let trans = trans.join(sess);
write::run_assembler(sess, outputs);
// HACK the linker expects the object file to be named foo.0.o but
// `run_assembler` produces an object named just foo.o. Rename it if we
// are going to build an executable
if sess.opts.output_types.contains_key(&OutputType::Exe) {
let f = outputs.path(OutputType::Object);
rename_or_copy_remove(&f,
f.with_file_name(format!("{}.0.o",
f.file_stem().unwrap().to_string_lossy()))).unwrap();
}
// Remove assembly source, unless --save-temps was specified
if !sess.opts.cg.save_temps {
fs::remove_file(&outputs.temp_path(OutputType::Assembly, None)).unwrap();
}
} else {
time(sess.time_passes(),
"LLVM passes",
|| write::run_passes(sess, trans, &sess.opts.output_types, outputs));
if sess.opts.debugging_opts.incremental_info {
write::dump_incremental_data(&trans);
}
time(sess.time_passes(),
"serialize work products",
move || rustc_incremental::save_work_products(sess));
sess.compile_status()
(sess.compile_status(), trans)
}
/// Run the linker on any artifacts that resulted from the LLVM run.

View File

@ -795,7 +795,12 @@ fn usage(verbose: bool, include_unstable_options: bool) {
(option.apply)(&mut options);
}
let message = format!("Usage: rustc [OPTIONS] INPUT");
let extra_help = if verbose {
let nightly_help = if nightly_options::is_nightly_build() {
"\n -Z help Print internal options for debugging rustc"
} else {
""
};
let verbose_help = if verbose {
""
} else {
"\n --help -v Print the full set of options rustc accepts"
@ -803,11 +808,10 @@ fn usage(verbose: bool, include_unstable_options: bool) {
println!("{}\nAdditional help:
-C help Print codegen options
-W help \
Print 'lint' options and default settings
-Z help Print internal \
options for debugging rustc{}\n",
Print 'lint' options and default settings{}{}\n",
options.usage(&message),
extra_help);
nightly_help,
verbose_help);
}
fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
@ -1203,6 +1207,10 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS);
all_errors.extend_from_slice(&syntax::DIAGNOSTICS);
Registry::new(&all_errors)
}

View File

@ -82,26 +82,27 @@ impl<'a> DiagnosticBuilder<'a> {
return;
}
match self.level {
let is_error = match self.level {
Level::Bug |
Level::Fatal |
Level::PhaseFatal |
Level::Error => {
self.handler.bump_err_count();
true
}
Level::Warning |
Level::Note |
Level::Help |
Level::Cancelled => {
false
}
}
};
self.handler.emitter.borrow_mut().emit(&self);
self.cancel();
if self.level == Level::Error {
self.handler.panic_if_treat_err_as_bug();
if is_error {
self.handler.bump_err_count();
}
// if self.is_fatal() {
@ -210,4 +211,3 @@ impl<'a> Drop for DiagnosticBuilder<'a> {
}
}
}

View File

@ -399,7 +399,6 @@ impl Handler {
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
self.emit(&sp.into(), msg, Fatal);
self.panic_if_treat_err_as_bug();
FatalError
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
@ -408,12 +407,10 @@ impl Handler {
code: &str)
-> FatalError {
self.emit_with_code(&sp.into(), msg, code, Fatal);
self.panic_if_treat_err_as_bug();
FatalError
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Error);
self.panic_if_treat_err_as_bug();
}
pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
@ -425,7 +422,6 @@ impl Handler {
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
self.emit_with_code(&sp.into(), msg, code, Error);
self.panic_if_treat_err_as_bug();
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Warning);
@ -494,6 +490,7 @@ impl Handler {
}
pub fn bump_err_count(&self) {
self.panic_if_treat_err_as_bug();
self.err_count.set(self.err_count.get() + 1);
}

View File

@ -34,7 +34,7 @@ use super::file_format;
use super::work_product;
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
incremental_hashes_map: &IncrementalHashesMap,
incremental_hashes_map: IncrementalHashesMap,
metadata_hashes: &EncodedMetadataHashes,
svh: Svh) {
debug!("save_dep_graph()");
@ -51,7 +51,7 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
eprintln!("incremental: {} edges in dep-graph", query.graph.len_edges());
}
let mut hcx = HashContext::new(tcx, incremental_hashes_map);
let mut hcx = HashContext::new(tcx, &incremental_hashes_map);
let preds = Predecessors::new(&query, &mut hcx);
let mut current_metadata_hashes = FxHashMap();

View File

@ -722,6 +722,46 @@ impl EarlyLintPass for IllegalFloatLiteralPattern {
}
}
declare_lint! {
pub UNUSED_DOC_COMMENT,
Warn,
"detects doc comments that aren't used by rustdoc"
}
#[derive(Copy, Clone)]
pub struct UnusedDocComment;
impl LintPass for UnusedDocComment {
fn get_lints(&self) -> LintArray {
lint_array![UNUSED_DOC_COMMENT]
}
}
impl UnusedDocComment {
fn warn_if_doc<'a, 'tcx,
I: Iterator<Item=&'a ast::Attribute>,
C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) {
if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) {
cx.struct_span_lint(UNUSED_DOC_COMMENT, attr.span, "doc comment not used by rustdoc")
.emit();
}
}
}
impl EarlyLintPass for UnusedDocComment {
fn check_local(&mut self, cx: &EarlyContext, decl: &ast::Local) {
self.warn_if_doc(decl.attrs.iter(), cx);
}
fn check_arm(&mut self, cx: &EarlyContext, arm: &ast::Arm) {
self.warn_if_doc(arm.attrs.iter(), cx);
}
fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) {
self.warn_if_doc(expr.attrs.iter(), cx);
}
}
declare_lint! {
pub UNCONDITIONAL_RECURSION,
Warn,

View File

@ -111,6 +111,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedImportBraces,
AnonymousParameters,
IllegalFloatLiteralPattern,
UnusedDocComment,
);
add_early_builtin_with_new!(sess,

View File

@ -44,9 +44,13 @@ impl UnusedMut {
let mut mutables = FxHashMap();
for p in pats {
p.each_binding(|mode, id, _, path1| {
p.each_binding(|_, id, span, path1| {
let bm = match cx.tables.pat_binding_modes.get(&id) {
Some(&bm) => bm,
None => span_bug!(span, "missing binding mode"),
};
let name = path1.node;
if let hir::BindByValue(hir::MutMutable) = mode {
if let ty::BindByValue(hir::MutMutable) = bm {
if !name.as_str().starts_with("_") {
match mutables.entry(name) {
Vacant(entry) => {

View File

@ -39,14 +39,14 @@ impl ArchiveRO {
///
/// If this archive is used with a mutable method, then an error will be
/// raised.
pub fn open(dst: &Path) -> Option<ArchiveRO> {
pub fn open(dst: &Path) -> Result<ArchiveRO, String> {
return unsafe {
let s = path2cstr(dst);
let ar = ::LLVMRustOpenArchive(s.as_ptr());
if ar.is_null() {
None
Err(::last_error().unwrap_or("failed to open archive".to_string()))
} else {
Some(ArchiveRO { ptr: ar })
Ok(ArchiveRO { ptr: ar })
}
};

View File

@ -598,7 +598,6 @@ extern "C" {
// Operations on scalar constants
pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef;
pub fn LLVMConstIntOfArbitraryPrecision(IntTy: TypeRef, Wn: c_uint, Ws: *const u64) -> ValueRef;
pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef;
pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong;
pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong;
pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool,

View File

@ -15,7 +15,8 @@ use schema;
use rustc::ty::maps::QueryConfig;
use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind,
NativeLibrary, MetadataLoader, LinkMeta,
LinkagePreference, LoadedMacro, EncodedMetadata};
LinkagePreference, LoadedMacro, EncodedMetadata,
EncodedMetadataHashes};
use rustc::hir::def;
use rustc::middle::lang_items;
use rustc::session::Session;
@ -390,6 +391,7 @@ impl CrateStore for cstore::CStore {
legacy: def.legacy,
}),
vis: ast::Visibility::Inherited,
tokens: None,
})
}
@ -443,7 +445,7 @@ impl CrateStore for cstore::CStore {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &LinkMeta,
reachable: &NodeSet)
-> EncodedMetadata
-> (EncodedMetadata, EncodedMetadataHashes)
{
encoder::encode_metadata(tcx, link_meta, reachable)
}

View File

@ -1648,7 +1648,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &LinkMeta,
exported_symbols: &NodeSet)
-> EncodedMetadata
-> (EncodedMetadata, EncodedMetadataHashes)
{
let mut cursor = Cursor::new(vec![]);
cursor.write_all(METADATA_HEADER).unwrap();
@ -1691,10 +1691,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
result[header + 2] = (pos >> 8) as u8;
result[header + 3] = (pos >> 0) as u8;
EncodedMetadata {
raw_data: result,
hashes: metadata_hashes,
}
(EncodedMetadata { raw_data: result }, metadata_hashes)
}
pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions {

View File

@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let tcx = this.hir.tcx();
// Enter the remainder scope, i.e. the bindings' destruction scope.
this.push_scope(remainder_scope);
this.push_scope((remainder_scope, source_info));
let_extent_stack.push(remainder_scope);
// Declare the bindings, which may create a visibility scope.

View File

@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Yield { value } => {
let value = unpack!(block = this.as_operand(block, scope, value));
let resume = this.cfg.start_new_block();
let cleanup = this.generator_drop_cleanup(expr_span);
let cleanup = this.generator_drop_cleanup();
this.cfg.terminate(block, source_info, TerminatorKind::Yield {
value: value,
resume: resume,

View File

@ -237,7 +237,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.collect();
let success = this.cfg.start_new_block();
let cleanup = this.diverge_cleanup(expr_span);
let cleanup = this.diverge_cleanup();
this.cfg.terminate(block, source_info, TerminatorKind::Call {
func: fun,
args: args,

Some files were not shown because too many files have changed in this diff Show More