# =============================================================================
[target.x86_64-unknown-linux-gnu]
-# C compiler to be used to compiler C code and link Rust code. Note that the
+# C compiler to be used to compiler C code. Note that the
# default value is platform specific, and if not specified it may also depend on
# what platform is crossing to what platform.
#cc = "cc"
# This is only used for host targets.
#cxx = "c++"
+# Archiver to be used to assemble static libraries compiled from C/C++ code.
+# Note: an absolute path should be used, otherwise LLVM build will break.
+#ar = "ar"
+
+# Linker to be used to link Rust code. Note that the
+# default value is platform specific, and if not specified it may also depend on
+# what platform is crossing to what platform.
+#linker = "cc"
+
# Path to the `llvm-config` binary of the installation of a custom LLVM to link
# against. Note that if this is specifed we don't compile LLVM at all for this
# target.
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
"libc 0.0.0",
]
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "cc"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "compiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.9.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
name = "profiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
]
version = "0.0.0"
dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"alloc_jemalloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"collections 0.0.0",
"compiler_builtins 0.0.0",
"core 0.0.0",
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cde24d1b2e2216a726368b2363a273739c91f4e3eb4e0dd12d672d396ad989"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
+"checksum cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c674f0870e3dbd4105184ea035acb1c32c8ae69939c9e228d2b11bbfe29efad"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "357c07e7a1fc95732793c1edb5901e1a1f305cfcf63a90eb12dbd22bdb6b789d"
filetime = "0.1"
num_cpus = "1.0"
getopts = "0.2"
-cc = "1.0"
+cc = "1.0.1"
libc = "0.2"
serde = "1.0.8"
serde_derive = "1.0.8"
configure your directory to use this build, like so:
```
-# configure to use local rust instead of downloding a beta.
+# configure to use local rust instead of downloading a beta.
# `--local-rust-root` is optional here. If elided, we will
# use whatever rustc we find on your PATH.
> configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild
cmd.arg("-L").arg(&root);
}
- // Pass down extra flags, commonly used to configure `-Clinker` when
- // cross compiling.
- if let Ok(s) = env::var("RUSTC_FLAGS") {
- cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
+ // Override linker if necessary.
+ if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") {
+ cmd.arg(format!("-Clinker={}", target_linker));
}
// Pass down incremental directory, if any.
if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
cmd.arg("-Z").arg("force-unstable-if-unmarked");
}
+ } else {
+ // Override linker if necessary.
+ if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
+ cmd.arg(format!("-Clinker={}", host_linker));
+ }
}
let color = match env::var("RUSTC_COLOR") {
if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
cmd.arg("-Z").arg("force-unstable-if-unmarked");
}
+ if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") {
+ cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options");
+ }
// Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick
// it up so we can make rustdoc print this into the docs
pub fn rustdoc_cmd(&self, host: Interned<String>) -> Command {
let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
let compiler = self.compiler(self.top_stage, host);
- cmd
- .env("RUSTC_STAGE", compiler.stage.to_string())
- .env("RUSTC_SYSROOT", self.sysroot(compiler))
- .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
- .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
- .env("RUSTDOC_REAL", self.rustdoc(host))
- .env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
+ cmd.env("RUSTC_STAGE", compiler.stage.to_string())
+ .env("RUSTC_SYSROOT", self.sysroot(compiler))
+ .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
+ .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
+ .env("RUSTDOC_REAL", self.rustdoc(host))
+ .env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
+ if let Some(linker) = self.build.linker(host) {
+ cmd.env("RUSTC_TARGET_LINKER", linker);
+ }
cmd
}
} else {
PathBuf::from("/path/to/nowhere/rustdoc/not/required")
})
- .env("TEST_MIRI", self.config.test_miri.to_string())
- .env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
+ .env("TEST_MIRI", self.config.test_miri.to_string());
+
+ if let Some(host_linker) = self.build.linker(compiler.host) {
+ cargo.env("RUSTC_HOST_LINKER", host_linker);
+ }
+ if let Some(target_linker) = self.build.linker(target) {
+ cargo.env("RUSTC_TARGET_LINKER", target_linker);
+ }
if mode != Mode::Tool {
// Tools don't get debuginfo right now, e.g. cargo and rls don't
cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
- // Specify some various options for build scripts used throughout
- // the build.
+ // Throughout the build Cargo can execute a number of build scripts
+ // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
+ // obtained previously to those build scripts.
+ // Build scripts use either the `cc` crate or `configure/make` so we pass
+ // the options through environment variables that are fetched and understood by both.
//
// FIXME: the guard against msvc shouldn't need to be here
if !target.contains("msvc") {
- cargo.env(format!("CC_{}", target), self.cc(target))
- .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None
- .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
+ let cc = self.cc(target);
+ cargo.env(format!("CC_{}", target), cc)
+ .env("CC", cc);
+
+ let cflags = self.cflags(target).join(" ");
+ cargo.env(format!("CFLAGS_{}", target), cflags.clone())
+ .env("CFLAGS", cflags.clone());
+
+ if let Some(ar) = self.ar(target) {
+ let ranlib = format!("{} s", ar.display());
+ cargo.env(format!("AR_{}", target), ar)
+ .env("AR", ar)
+ .env(format!("RANLIB_{}", target), ranlib.clone())
+ .env("RANLIB", ranlib);
+ }
if let Ok(cxx) = self.cxx(target) {
- cargo.env(format!("CXX_{}", target), cxx);
+ cargo.env(format!("CXX_{}", target), cxx)
+ .env("CXX", cxx)
+ .env(format!("CXXFLAGS_{}", target), cflags.clone())
+ .env("CXXFLAGS", cflags);
}
}
//! ever be probed for. Instead the compilers found here will be used for
//! everything.
+use std::collections::HashSet;
+use std::{env, iter};
+use std::path::{Path, PathBuf};
use std::process::Command;
-use std::iter;
-use build_helper::{cc2ar, output};
+use build_helper::output;
use cc;
use Build;
use config::Target;
use cache::Interned;
+// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
+// so use some simplified logic here. First we respect the environment variable `AR`, then
+// try to infer the archiver path from the C compiler path.
+// In the future this logic should be replaced by calling into the `cc` crate.
+fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
+ if let Some(ar) = env::var_os("AR") {
+ Some(PathBuf::from(ar))
+ } else if target.contains("msvc") {
+ None
+ } else if target.contains("musl") {
+ Some(PathBuf::from("ar"))
+ } else if target.contains("openbsd") {
+ Some(PathBuf::from("ar"))
+ } else {
+ let parent = cc.parent().unwrap();
+ let file = cc.file_name().unwrap().to_str().unwrap();
+ for suffix in &["gcc", "cc", "clang"] {
+ if let Some(idx) = file.rfind(suffix) {
+ let mut file = file[..idx].to_owned();
+ file.push_str("ar");
+ return Some(parent.join(&file));
+ }
+ }
+ Some(parent.join(file))
+ }
+}
+
pub fn find(build: &mut Build) {
// For all targets we're going to need a C compiler for building some shims
// and such as well as for being a linker for Rust code.
- for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) {
+ let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build))
+ .collect::<HashSet<_>>();
+ for target in targets.into_iter() {
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false)
.target(&target).host(&build.build);
}
let compiler = cfg.get_compiler();
- let ar = cc2ar(compiler.path(), &target);
+ let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
+ ar
+ } else {
+ cc2ar(compiler.path(), &target)
+ };
+
build.verbose(&format!("CC_{} = {:?}", &target, compiler.path()));
- if let Some(ref ar) = ar {
+ build.cc.insert(target, compiler);
+ if let Some(ar) = ar {
build.verbose(&format!("AR_{} = {:?}", &target, ar));
+ build.ar.insert(target, ar);
}
- build.cc.insert(target, (compiler, ar));
}
// For all host triples we need to find a C++ compiler as well
- for host in build.hosts.iter().cloned().chain(iter::once(build.build)) {
+ let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::<HashSet<_>>();
+ for host in hosts.into_iter() {
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true)
.target(&host).host(&build.build);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Clippy {
+ stage: u32,
host: Interned<String>,
}
fn make_run(run: RunConfig) {
run.builder.ensure(Clippy {
+ stage: run.builder.top_stage,
host: run.target,
});
}
/// Runs `cargo test` for clippy.
fn run(self, builder: &Builder) {
let build = builder.build;
+ let stage = self.stage;
let host = self.host;
- let compiler = builder.compiler(1, host);
+ let compiler = builder.compiler(stage, host);
- let _clippy = builder.ensure(tool::Clippy { compiler, target: self.host });
+ let clippy = builder.ensure(tool::Clippy { compiler, target: self.host });
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
// clippy tests need to know about the stage sysroot
cargo.env("SYSROOT", builder.sysroot(compiler));
+ // clippy tests need to find the driver
+ cargo.env("CLIPPY_DRIVER_PATH", clippy);
builder.add_rustc_lib_path(compiler, &mut cargo);
flags.push("-g".to_string());
}
- let mut hostflags = build.rustc_flags(compiler.host);
- hostflags.extend(flags.clone());
+ if let Some(linker) = build.linker(target) {
+ cmd.arg("--linker").arg(linker);
+ }
+
+ let hostflags = flags.clone();
cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
- let mut targetflags = build.rustc_flags(target);
- targetflags.extend(flags);
+ let mut targetflags = flags.clone();
targetflags.push(format!("-Lnative={}",
build.test_helpers_out(target).display()));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
.arg("--cflags").arg(build.cflags(target).join(" "))
.arg("--llvm-components").arg(llvm_components.trim())
.arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
+ if let Some(ar) = build.ar(target) {
+ cmd.arg("--ar").arg(ar);
+ }
}
}
if suite == "run-make" && !build.config.llvm_enabled {
// Note that if we encounter `PATH` we make sure to append to our own `PATH`
// rather than stomp over it.
if target.contains("msvc") {
- for &(ref k, ref v) in build.cc[&target].0.env() {
+ for &(ref k, ref v) in build.cc[&target].env() {
if k != "PATH" {
cmd.env(k, v);
}
pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
pub cxx: Option<PathBuf>,
+ pub ar: Option<PathBuf>,
+ pub linker: Option<PathBuf>,
pub ndk: Option<PathBuf>,
pub crt_static: Option<bool>,
pub musl_root: Option<PathBuf>,
jemalloc: Option<String>,
cc: Option<String>,
cxx: Option<String>,
+ ar: Option<String>,
+ linker: Option<String>,
android_ndk: Option<String>,
crt_static: Option<bool>,
musl_root: Option<String>,
if let Some(ref s) = cfg.android_ndk {
target.ndk = Some(env::current_dir().unwrap().join(s));
}
- target.cxx = cfg.cxx.clone().map(PathBuf::from);
target.cc = cfg.cc.clone().map(PathBuf::from);
+ target.cxx = cfg.cxx.clone().map(PathBuf::from);
+ target.ar = cfg.ar.clone().map(PathBuf::from);
+ target.linker = cfg.linker.clone().map(PathBuf::from);
target.crt_static = cfg.crt_static.clone();
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
lldb_python_dir: Option<String>,
// Runtime state filled in later on
- // target -> (cc, ar)
- cc: HashMap<Interned<String>, (cc::Tool, Option<PathBuf>)>,
- // host -> (cc, ar)
+ // C/C++ compilers and archiver for all targets
+ cc: HashMap<Interned<String>, cc::Tool>,
cxx: HashMap<Interned<String>, cc::Tool>,
+ ar: HashMap<Interned<String>, PathBuf>,
+ // Misc
crates: HashMap<Interned<String>, Crate>,
is_sudo: bool,
ci_env: CiEnv,
rls_info,
cc: HashMap::new(),
cxx: HashMap::new(),
+ ar: HashMap::new(),
crates: HashMap::new(),
lldb_version: None,
lldb_python_dir: None,
/// Returns the path to the C compiler for the target specified.
fn cc(&self, target: Interned<String>) -> &Path {
- self.cc[&target].0.path()
+ self.cc[&target].path()
}
/// Returns a list of flags to pass to the C compiler for the target
fn cflags(&self, target: Interned<String>) -> Vec<String> {
// Filter out -O and /O (the optimization flags) that we picked up from
// cc-rs because the build scripts will determine that for themselves.
- let mut base = self.cc[&target].0.args().iter()
+ let mut base = self.cc[&target].args().iter()
.map(|s| s.to_string_lossy().into_owned())
.filter(|s| !s.starts_with("-O") && !s.starts_with("/O"))
.collect::<Vec<_>>();
/// Returns the path to the `ar` archive utility for the target specified.
fn ar(&self, target: Interned<String>) -> Option<&Path> {
- self.cc[&target].1.as_ref().map(|p| &**p)
+ self.ar.get(&target).map(|p| &**p)
}
/// Returns the path to the C++ compiler for the target specified.
}
}
- /// Returns flags to pass to the compiler to generate code for `target`.
- fn rustc_flags(&self, target: Interned<String>) -> Vec<String> {
- // New flags should be added here with great caution!
- //
- // It's quite unfortunate to **require** flags to generate code for a
- // target, so it should only be passed here if absolutely necessary!
- // Most default configuration should be done through target specs rather
- // than an entry here.
-
- let mut base = Vec::new();
- if target != self.config.build && !target.contains("msvc") &&
- !target.contains("emscripten") {
- base.push(format!("-Clinker={}", self.cc(target).display()));
+ /// Returns the path to the linker for the given target if it needs to be overriden.
+ fn linker(&self, target: Interned<String>) -> Option<&Path> {
+ if let Some(linker) = self.config.target_config.get(&target)
+ .and_then(|c| c.linker.as_ref()) {
+ Some(linker)
+ } else if target != self.config.build &&
+ !target.contains("msvc") && !target.contains("emscripten") {
+ Some(self.cc(target))
+ } else {
+ None
}
- base
}
/// Returns if this target should statically link the C runtime, if specified
cfg.build_arg("-j").build_arg(build.jobs().to_string());
cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" "));
+ if let Some(ar) = build.ar(target) {
+ if ar.is_absolute() {
+ // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
+ // tries to resolve this path in the LLVM build directory.
+ cfg.define("CMAKE_AR", sanitize_cc(ar));
+ }
+ }
};
configure_compilers(&mut cfg);
impl Step for Clippy {
type Output = PathBuf;
- const DEFAULT: bool = false;
+ const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
builder.ensure(ToolBuild {
compiler: self.compiler,
target: self.target,
- tool: "clippy",
+ tool: "clippy-driver",
mode: Mode::Librustc,
path: "src/tools/clippy",
expectation: builder.build.config.toolstate.clippy.passes(ToolState::Compiling),
if compiler.host.contains("msvc") {
let curpaths = env::var_os("PATH").unwrap_or_default();
let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
- for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
+ for &(ref k, ref v) in self.cc[&compiler.host].env() {
if k != "PATH" {
continue
}
}
}
-pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
- if target.contains("msvc") {
- None
- } else if target.contains("musl") {
- Some(PathBuf::from("ar"))
- } else if target.contains("openbsd") {
- Some(PathBuf::from("ar"))
- } else {
- let parent = cc.parent().unwrap();
- let file = cc.file_name().unwrap().to_str().unwrap();
- for suffix in &["gcc", "cc", "clang"] {
- if let Some(idx) = file.rfind(suffix) {
- let mut file = file[..idx].to_owned();
- file.push_str("ar");
- return Some(parent.join(&file));
- }
- }
- Some(parent.join(file))
- }
-}
-
pub fn make(host: &str) -> PathBuf {
if host.contains("bitrig") || host.contains("dragonfly") ||
host.contains("freebsd") || host.contains("netbsd") ||
RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \
build-essential \
+ gcc-multilib \
libedit-dev \
libgmp-dev \
libisl-dev \
AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \
- AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-ar \
- CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-gcc \
- CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-g++ \
- AR_x86_64_sun_solaris=x86_64-sun-solaris2.11-ar \
- CC_x86_64_sun_solaris=x86_64-sun-solaris2.11-gcc \
- CXX_x86_64_sun_solaris=x86_64-sun-solaris2.11-g++
+ AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
+ CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
+ CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
+ AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+ CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+ CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++
ENV TARGETS=x86_64-unknown-fuchsia
ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
ENV TARGETS=$TARGETS,x86_64-sun-solaris
+ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
mkdir binutils-build
cd binutils-build
-hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.11
+hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.10
hide_output make -j10
hide_output make install
dpkg -x $deb .
done
-mkdir /usr/local/$ARCH-sun-solaris2.11/usr
-mv usr/include /usr/local/$ARCH-sun-solaris2.11/usr/include
-mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
-mv lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
+# Strip Solaris 11 functions that are optionally used by libbacktrace.
+# This is for Solaris 10 compatibility.
+$ARCH-sun-solaris2.10-strip -N dl_iterate_phdr -N strnlen lib/$LIB_ARCH/libc.so
-ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/sys-include
-ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/include
+mkdir /usr/local/$ARCH-sun-solaris2.10/usr
+mv usr/include /usr/local/$ARCH-sun-solaris2.10/usr/include
+mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
+mv lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
+
+ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include
+ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/include
cd ..
rm -rf solaris
cd ../gcc-build
hide_output ../gcc-$GCC/configure \
--enable-languages=c,c++ \
- --target=$ARCH-sun-solaris2.11 \
+ --target=$ARCH-sun-solaris2.10 \
--with-gnu-as \
--with-gnu-ld \
--disable-multilib \
--disable-libsanitizer \
--disable-libquadmath-support \
--disable-lto \
- --with-sysroot=/usr/local/$ARCH-sun-solaris2.11
+ --with-sysroot=/usr/local/$ARCH-sun-solaris2.10
hide_output make -j10
hide_output make install
const ε: f64 = 0.00001f64;
const Î : f64 = 3.14f64;
-```
\ No newline at end of file
+```
+
+## Changes to the language reference
+
+> **<sup>Lexer:<sup>**
+> IDENTIFIER :
+> XID_start XID_continue<sup>\*</sup>
+> | `_` XID_continue<sup>+</sup>
+
+An identifier is any nonempty Unicode string of the following form:
+
+Either
+
+ * The first character has property [`XID_start`]
+ * The remaining characters have property [`XID_continue`]
+
+Or
+
+ * The first character is `_`
+ * The identifier is more than one character, `_` alone is not an identifier
+ * The remaining characters have property [`XID_continue`]
+
+that does _not_ occur in the set of [strict keywords].
+
+> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the
+> character ranges used to form the more familiar C and Java language-family
+> identifiers.
+
+[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=
+[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=
+[strict keywords]: ../reference/keywords.html#strict-keywords
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
[features]
debug = []
_ => return,
};
- let compiler = cc::Build::new().get_compiler();
- // only msvc returns None for ar so unwrap is okay
- let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
- let cflags = compiler.args()
- .iter()
- .map(|s| s.to_str().unwrap())
- .collect::<Vec<_>>()
- .join(" ");
-
let mut cmd = Command::new("sh");
cmd.arg(native.src_dir.join("configure")
.to_str()
.replace("C:\\", "/c/")
.replace("\\", "/"))
.current_dir(&native.out_dir)
- .env("CC", compiler.path())
- .env("EXTRA_CFLAGS", cflags.clone())
// jemalloc generates Makefile deps using GCC's "-MM" flag. This means
// that GCC will run the preprocessor, and only the preprocessor, over
// jemalloc's source files. If we don't specify CPPFLAGS, then at least
// passed to GCC, and then GCC won't define the
// "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
// select an atomic operation implementation.
- .env("CPPFLAGS", cflags.clone())
- .env("AR", &ar)
- .env("RANLIB", format!("{} s", ar.display()));
+ .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default());
if target.contains("ios") {
cmd.arg("--disable-tls");
core = { path = "../libcore" }
[build-dependencies]
-cc = "1.0"
+cc = "1.0.1"
let expr = self.lower_body(None, |this| this.lower_expr(expr));
hir::TyTypeof(expr)
}
- TyKind::TraitObject(ref bounds) => {
+ TyKind::TraitObject(ref bounds, ..) => {
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
}
}
+ /// Ensure that either this query has all green inputs or been executed.
+ /// Executing query::ensure(D) is considered a read of the dep-node D.
+ ///
+ /// This function is particularly useful when executing passes for their
+ /// side-effects -- e.g., in order to report errors for erroneous programs.
+ ///
+ /// Note: The optimization is only available during incr. comp.
+ pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () {
+ let dep_node = Self::to_dep_node(tcx, &key);
+
+ // Ensuring an "input" or anonymous query makes no sense
+ assert!(!dep_node.kind.is_anon());
+ assert!(!dep_node.kind.is_input());
+ use dep_graph::DepNodeColor;
+ match tcx.dep_graph.node_color(&dep_node) {
+ Some(DepNodeColor::Green(dep_node_index)) => {
+ tcx.dep_graph.read_index(dep_node_index);
+ }
+ Some(DepNodeColor::Red) => {
+ // A DepNodeColor::Red DepNode means that this query was executed
+ // before. We can not call `dep_graph.read()` here as we don't have
+ // the DepNodeIndex. Instead, We call the query again to issue the
+ // appropriate `dep_graph.read()` call. The performance cost this
+ // introduces should be negligible as we'll immediately hit the
+ // in-memory cache.
+ let _ = tcx.$name(key);
+ }
+ None => {
+ // Huh
+ if !tcx.dep_graph.is_fully_enabled() {
+ let _ = tcx.$name(key);
+ return;
+ }
+ match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
+ Some(dep_node_index) => {
+ debug_assert!(tcx.dep_graph.is_green(dep_node_index));
+ tcx.dep_graph.read_index(dep_node_index);
+ }
+ None => {
+ let _ = tcx.$name(key);
+ }
+ }
+ }
+ }
+ }
+
fn compute_result(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V {
let provider = tcx.maps.providers[key.map_crate()].$name;
provider(tcx.global_tcx(), key)
supported_targets! {
("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
+ ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
--- /dev/null
+// 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::linux_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.max_atomic_width = Some(64);
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
+ base.stack_probes = true;
+ base.has_elf_tls = false;
+
+ Ok(Target {
+ llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
let partial = moved_lp.depth() > lp.depth();
let msg = if !has_fork && partial { "partially " }
else if has_fork && !has_common { "collaterally "}
- else { "" };
- let mut err = struct_span_err!(
- self.tcx.sess, use_span, E0382,
- "{} of {}moved value: `{}`",
- verb, msg, nl);
+ else { "" };
+ let mut err = self.cannot_act_on_moved_value(use_span,
+ verb,
+ msg,
+ &format!("{}", nl),
+ Origin::Ast);
let need_note = match lp.ty.sty {
ty::TypeVariants::TyClosure(id, _) => {
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
&self,
span: Span,
lp: &LoanPath<'tcx>) {
- span_err!(
- self.tcx.sess, span, E0383,
- "partial reinitialization of uninitialized structure `{}`",
- self.loan_path_to_string(lp));
+ self.cannot_partially_reinit_an_uninit_struct(span,
+ &self.loan_path_to_string(lp),
+ Origin::Ast)
+ .emit();
}
pub fn report_reassigned_immutable_variable(&self,
db
}
BorrowViolation(euv::ClosureCapture(_)) => {
- struct_span_err!(self.tcx.sess, error_span, E0595,
- "closure cannot assign to {}", descr)
+ self.closure_cannot_assign_to_borrowed(error_span, &descr, Origin::Ast)
}
BorrowViolation(euv::OverloadedOperator) |
BorrowViolation(euv::AddrOf) |
BorrowViolation(euv::AutoUnsafe) |
BorrowViolation(euv::ForLoop) |
BorrowViolation(euv::MatchDiscriminant) => {
- struct_span_err!(self.tcx.sess, error_span, E0596,
- "cannot borrow {} as mutable", descr)
+ self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast)
}
BorrowViolation(euv::ClosureInvocation) => {
span_bug!(err.span,
if let Some((yield_span, _)) = maybe_borrow_across_yield {
debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
- struct_span_err!(self.tcx.sess,
- error_span,
- E0626,
- "borrow may still be in use when generator yields")
- .span_label(yield_span, "possible yield occurs here")
+ self.cannot_borrow_across_generator_yield(error_span, yield_span, Origin::Ast)
.emit();
return;
}
- let mut db = struct_span_err!(self.tcx.sess,
- error_span,
- E0597,
- "{} does not live long enough",
- msg);
-
+ let mut db = self.path_does_not_live_long_enough(error_span, &msg, Origin::Ast);
let (value_kind, value_msg) = match err.cmt.cat {
mc::Categorization::Rvalue(..) =>
("temporary value", "temporary value created here"),
}
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
let descr = self.cmt_to_path_or_string(&err.cmt);
- let mut db = struct_span_err!(self.tcx.sess, error_span, E0598,
- "lifetime of {} is too short to guarantee \
- its contents can be safely reborrowed",
- descr);
-
+ let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
let descr = match opt_loan_path(&err.cmt) {
Some(lp) => {
format!("`{}`", self.loan_path_to_string(&lp))
let blame = cmt.immutability_blame();
let mut err = match blame {
Some(ImmutabilityBlame::ClosureEnv(id)) => {
- let mut err = struct_span_err!(
- self.tcx.sess, span, E0387,
- "{} in a captured outer variable in an `Fn` closure", prefix);
-
// FIXME: the distinction between these 2 messages looks wrong.
- let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
+ let help_msg = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
// The aliasability violation with closure captures can
// happen for nested closures, so we know the enclosing
// closure incorrectly accepts an `Fn` while it needs to
"consider changing this closure to take self by mutable reference"
};
let node_id = self.tcx.hir.def_index_to_node_id(id);
- err.span_help(self.tcx.hir.span(node_id), help);
- err
+ let help_span = self.tcx.hir.span(node_id);
+ self.cannot_act_on_capture_in_sharable_fn(span,
+ prefix,
+ (help_span, help_msg),
+ Origin::Ast)
}
_ => {
- let mut err = struct_span_err!(
- self.tcx.sess, span, E0389,
- "{} in a `&` reference", prefix);
- err.span_label(span, "assignment into an immutable reference");
- err
+ self.cannot_assign_into_immutable_reference(span, prefix,
+ Origin::Ast)
}
};
self.note_immutability_blame(&mut err, blame);
Err(_) => format!("move |<args>| <body>")
};
- struct_span_err!(self.tcx.sess, err.span, E0373,
- "closure may outlive the current function, \
- but it borrows {}, \
- which is owned by the current function",
- cmt_path_or_string)
- .span_label(capture_span,
- format!("{} is borrowed here",
- cmt_path_or_string))
- .span_label(err.span,
- format!("may outlive borrowed value {}",
- cmt_path_or_string))
+ self.cannot_capture_in_long_lived_closure(err.span,
+ &cmt_path_or_string,
+ capture_span,
+ Origin::Ast)
.span_suggestion(err.span,
&format!("to force the closure to take ownership of {} \
(and any other referenced variables), \
// except according to those terms.
#![allow(non_snake_case)]
-
-register_long_diagnostics! {
-
-E0373: r##"
-This error occurs when an attempt is made to use data captured by a closure,
-when that data may no longer exist. It's most commonly seen when attempting to
-return a closure:
-
-```compile_fail,E0373
-fn foo() -> Box<Fn(u32) -> u32> {
- let x = 0u32;
- Box::new(|y| x + y)
-}
-```
-
-Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
-closed-over data by reference. This means that once `foo()` returns, `x` no
-longer exists. An attempt to access `x` within the closure would thus be
-unsafe.
-
-Another situation where this might be encountered is when spawning threads:
-
-```compile_fail,E0373
-fn foo() {
- let x = 0u32;
- let y = 1u32;
-
- let thr = std::thread::spawn(|| {
- x + y
- });
-}
-```
-
-Since our new thread runs in parallel, the stack frame containing `x` and `y`
-may well have disappeared by the time we try to use them. Even if we call
-`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
-stack frame won't disappear), we will not succeed: the compiler cannot prove
-that this behaviour is safe, and so won't let us do it.
-
-The solution to this problem is usually to switch to using a `move` closure.
-This approach moves (or copies, where possible) data into the closure, rather
-than taking references to it. For example:
-
-```
-fn foo() -> Box<Fn(u32) -> u32> {
- let x = 0u32;
- Box::new(move |y| x + y)
-}
-```
-
-Now that the closure has its own copy of the data, there's no need to worry
-about safety.
-"##,
-
-E0382: r##"
-This error occurs when an attempt is made to use a variable after its contents
-have been moved elsewhere. For example:
-
-```compile_fail,E0382
-struct MyStruct { s: u32 }
-
-fn main() {
- let mut x = MyStruct{ s: 5u32 };
- let y = x;
- x.s = 6;
- println!("{}", x.s);
-}
-```
-
-Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
-of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
-of workarounds like `Rc`, a value cannot be owned by more than one variable.
-
-If we own the type, the easiest way to address this problem is to implement
-`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
-information in `x`, while leaving the original version owned by `x`. Subsequent
-changes to `x` will not be reflected when accessing `y`.
-
-```
-#[derive(Copy, Clone)]
-struct MyStruct { s: u32 }
-
-fn main() {
- let mut x = MyStruct{ s: 5u32 };
- let y = x;
- x.s = 6;
- println!("{}", x.s);
-}
-```
-
-Alternatively, if we don't control the struct's definition, or mutable shared
-ownership is truly required, we can use `Rc` and `RefCell`:
-
-```
-use std::cell::RefCell;
-use std::rc::Rc;
-
-struct MyStruct { s: u32 }
-
-fn main() {
- let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
- let y = x.clone();
- x.borrow_mut().s = 6;
- println!("{}", x.borrow().s);
-}
-```
-
-With this approach, x and y share ownership of the data via the `Rc` (reference
-count type). `RefCell` essentially performs runtime borrow checking: ensuring
-that at most one writer or multiple readers can access the data at any one time.
-
-If you wish to learn more about ownership in Rust, start with the chapter in the
-Book:
-
-https://doc.rust-lang.org/book/first-edition/ownership.html
-"##,
-
-E0383: r##"
-This error occurs when an attempt is made to partially reinitialize a
-structure that is currently uninitialized.
-
-For example, this can happen when a drop has taken place:
-
-```compile_fail,E0383
-struct Foo {
- a: u32,
-}
-impl Drop for Foo {
- fn drop(&mut self) { /* ... */ }
-}
-
-let mut x = Foo { a: 1 };
-drop(x); // `x` is now uninitialized
-x.a = 2; // error, partial reinitialization of uninitialized structure `t`
-```
-
-This error can be fixed by fully reinitializing the structure in question:
-
-```
-struct Foo {
- a: u32,
-}
-impl Drop for Foo {
- fn drop(&mut self) { /* ... */ }
-}
-
-let mut x = Foo { a: 1 };
-drop(x);
-x = Foo { a: 2 };
-```
-"##,
-
-/*E0386: r##"
-This error occurs when an attempt is made to mutate the target of a mutable
-reference stored inside an immutable container.
-
-For example, this can happen when storing a `&mut` inside an immutable `Box`:
-
-```compile_fail,E0386
-let mut x: i64 = 1;
-let y: Box<_> = Box::new(&mut x);
-**y = 2; // error, cannot assign to data in an immutable container
-```
-
-This error can be fixed by making the container mutable:
-
-```
-let mut x: i64 = 1;
-let mut y: Box<_> = Box::new(&mut x);
-**y = 2;
-```
-
-It can also be fixed by using a type with interior mutability, such as `Cell`
-or `RefCell`:
-
-```
-use std::cell::Cell;
-
-let x: i64 = 1;
-let y: Box<Cell<_>> = Box::new(Cell::new(x));
-y.set(2);
-```
-"##,*/
-
-E0387: r##"
-This error occurs when an attempt is made to mutate or mutably reference data
-that a closure has captured immutably. Examples of this error are shown below:
-
-```compile_fail,E0387
-// Accepts a function or a closure that captures its environment immutably.
-// Closures passed to foo will not be able to mutate their closed-over state.
-fn foo<F: Fn()>(f: F) { }
-
-// Attempts to mutate closed-over data. Error message reads:
-// `cannot assign to data in a captured outer variable...`
-fn mutable() {
- let mut x = 0u32;
- foo(|| x = 2);
-}
-
-// Attempts to take a mutable reference to closed-over data. Error message
-// reads: `cannot borrow data mutably in a captured outer variable...`
-fn mut_addr() {
- let mut x = 0u32;
- foo(|| { let y = &mut x; });
-}
-```
-
-The problem here is that foo is defined as accepting a parameter of type `Fn`.
-Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
-they capture their context immutably.
-
-If the definition of `foo` is under your control, the simplest solution is to
-capture the data mutably. This can be done by defining `foo` to take FnMut
-rather than Fn:
-
-```
-fn foo<F: FnMut()>(f: F) { }
-```
-
-Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
-interior mutability through a shared reference. Our example's `mutable`
-function could be redefined as below:
-
-```
-use std::cell::Cell;
-
-fn foo<F: Fn()>(f: F) { }
-
-fn mutable() {
- let x = Cell::new(0u32);
- foo(|| x.set(2));
-}
-```
-
-You can read more about cell types in the API documentation:
-
-https://doc.rust-lang.org/std/cell/
-"##,
-
-E0388: r##"
-E0388 was removed and is no longer issued.
-"##,
-
-E0389: r##"
-An attempt was made to mutate data using a non-mutable reference. This
-commonly occurs when attempting to assign to a non-mutable reference of a
-mutable reference (`&(&mut T)`).
-
-Example of erroneous code:
-
-```compile_fail,E0389
-struct FancyNum {
- num: u8,
-}
-
-fn main() {
- let mut fancy = FancyNum{ num: 5 };
- let fancy_ref = &(&mut fancy);
- fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
- println!("{}", fancy_ref.num);
-}
-```
-
-Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
-immutable reference to a value borrows it immutably. There can be multiple
-references of type `&(&mut T)` that point to the same value, so they must be
-immutable to prevent multiple mutable references to the same value.
-
-To fix this, either remove the outer reference:
-
-```
-struct FancyNum {
- num: u8,
-}
-
-fn main() {
- let mut fancy = FancyNum{ num: 5 };
-
- let fancy_ref = &mut fancy;
- // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
-
- fancy_ref.num = 6; // No error!
-
- println!("{}", fancy_ref.num);
-}
-```
-
-Or make the outer reference mutable:
-
-```
-struct FancyNum {
- num: u8
-}
-
-fn main() {
- let mut fancy = FancyNum{ num: 5 };
-
- let fancy_ref = &mut (&mut fancy);
- // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
-
- fancy_ref.num = 6; // No error!
-
- println!("{}", fancy_ref.num);
-}
-```
-"##,
-
-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.
-
-Example of erroneous code:
-
-```compile_fail,E0596
-let x = 1;
-let y = &mut x; // error: cannot borrow mutably
-```
-
-In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
-fails. To fix this error, you need to make `x` mutable:
-
-```
-let mut x = 1;
-let y = &mut x; // ok!
-```
-"##,
-
-E0597: r##"
-This error occurs because a borrow was made inside a variable which has a
-greater lifetime than the borrowed one.
-
-Example of erroneous code:
-
-```compile_fail,E0597
-struct Foo<'a> {
- x: Option<&'a u32>,
-}
-
-let mut x = Foo { x: None };
-let y = 0;
-x.x = Some(&y); // error: `y` does not live long enough
-```
-
-In here, `x` is created before `y` and therefore has a greater lifetime. Always
-keep in mind that values in a scope are dropped in the opposite order they are
-created. So to fix the previous example, just make the `y` lifetime greater than
-the `x`'s one:
-
-```
-struct Foo<'a> {
- x: Option<&'a u32>,
-}
-
-let y = 0;
-let mut x = Foo { x: None };
-x.x = Some(&y);
-```
-"##,
-
-E0626: r##"
-This error occurs because a borrow in a generator persists across a
-yield point.
-
-```compile_fail,E0626
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
- let a = &String::new(); // <-- This borrow...
- yield (); // ...is still in scope here, when the yield occurs.
- println!("{}", a);
-};
-b.resume();
-```
-
-At present, it is not permitted to have a yield that occurs while a
-borrow is still in scope. To resolve this error, the borrow must
-either be "contained" to a smaller scope that does not overlap the
-yield or else eliminated in another way. So, for example, we might
-resolve the previous example by removing the borrow and just storing
-the integer by value:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
- let a = 3;
- yield ();
- println!("{}", a);
-};
-b.resume();
-```
-
-This is a very simple case, of course. In more complex cases, we may
-wish to have more than one reference to the value that was borrowed --
-in those cases, something like the `Rc` or `Arc` types may be useful.
-
-This error also frequently arises with iteration:
-
-```compile_fail,E0626
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
- let v = vec![1,2,3];
- for &x in &v { // <-- borrow of `v` is still in scope...
- yield x; // ...when this yield occurs.
- }
-};
-b.resume();
-```
-
-Such cases can sometimes be resolved by iterating "by value" (or using
-`into_iter()`) to avoid borrowing:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
- let v = vec![1,2,3];
- for x in v { // <-- Take ownership of the values instead!
- yield x; // <-- Now yield is OK.
- }
-};
-b.resume();
-```
-
-If taking ownership is not an option, using indices can work too:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
- let v = vec![1,2,3];
- let len = v.len(); // (*)
- for i in 0..len {
- let x = v[i]; // (*)
- yield x; // <-- Now yield is OK.
- }
-};
-b.resume();
-
-// (*) -- Unfortunately, these temporaries are currently required.
-// See <https://github.com/rust-lang/rust/issues/43122>.
-```
-"##,
-
-}
-
-register_diagnostics! {
-// E0385, // {} in an aliasable location
- E0598, // lifetime of {} is too short to guarantee its contents can be...
-}
#![allow(non_camel_case_types)]
#![feature(quote)]
-#![feature(rustc_diagnostic_macros)]
#[macro_use] extern crate log;
-#[macro_use] extern crate syntax;
+extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
extern crate rustc_back;
pub use borrowck::check_crate;
pub use borrowck::build_borrowck_dataflow_data_for_fn;
-// NB: This module needs to be declared first so diagnostics are
-// registered before they are used.
-mod diagnostics;
-
mod borrowck;
pub mod graphviz;
pub use borrowck::provide;
-
-__build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
let mut all_errors = Vec::new();
all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
- all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
#[cfg(feature="llvm")]
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
use rustc::hir;
use hair::*;
use syntax::ast::{Name, NodeId};
-use syntax_pos::Span;
+use syntax_pos::{DUMMY_SP, Span};
// helper functions, broken out by category:
mod simplify;
candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
debug!("match_candidates: {:?} candidates fully matched", fully_matched);
let mut unmatched_candidates = candidates.split_off(fully_matched);
- for candidate in candidates {
+ for (index, candidate) in candidates.into_iter().enumerate() {
// If so, apply any bindings, test the guard (if any), and
// branch to the arm.
- if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
+ let is_last = index == fully_matched - 1;
+ if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks,
+ candidate, is_last) {
block = b;
} else {
// if None is returned, then any remaining candidates
fn bind_and_guard_matched_candidate<'pat>(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
- candidate: Candidate<'pat, 'tcx>)
+ candidate: Candidate<'pat, 'tcx>,
+ is_last_arm: bool)
-> Option<BasicBlock> {
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
block, candidate);
self.cfg.terminate(block, source_info,
TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
Some(otherwise)
+ } else if !is_last_arm {
+ // Add always true guard in case of more than one arm
+ // it creates false edges and allow MIR borrowck detects errors
+ // FIXME(#45184) -- permit "false edges"
+ let source_info = self.source_info(candidate.span);
+ let true_expr = Expr {
+ temp_lifetime: None,
+ ty: self.hir.tcx().types.bool,
+ span: DUMMY_SP,
+ kind: ExprKind::Literal{literal: self.hir.true_literal()},
+ };
+ let cond = unpack!(block = self.as_local_operand(block, true_expr));
+ let otherwise = self.cfg.start_new_block();
+ self.cfg.terminate(block, source_info,
+ TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
+ Some(otherwise)
} else {
let source_info = self.source_info(candidate.span);
self.cfg.terminate(block, source_info,
- TerminatorKind::Goto { target: arm_block });
+ TerminatorKind::Goto { target: arm_block });
None
}
}
See also https://doc.rust-lang.org/book/first-edition/unsafe.html
"##,
+E0373: r##"
+This error occurs when an attempt is made to use data captured by a closure,
+when that data may no longer exist. It's most commonly seen when attempting to
+return a closure:
+
+```compile_fail,E0373
+fn foo() -> Box<Fn(u32) -> u32> {
+ let x = 0u32;
+ Box::new(|y| x + y)
+}
+```
+
+Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
+closed-over data by reference. This means that once `foo()` returns, `x` no
+longer exists. An attempt to access `x` within the closure would thus be
+unsafe.
+
+Another situation where this might be encountered is when spawning threads:
+
+```compile_fail,E0373
+fn foo() {
+ let x = 0u32;
+ let y = 1u32;
+
+ let thr = std::thread::spawn(|| {
+ x + y
+ });
+}
+```
+
+Since our new thread runs in parallel, the stack frame containing `x` and `y`
+may well have disappeared by the time we try to use them. Even if we call
+`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
+stack frame won't disappear), we will not succeed: the compiler cannot prove
+that this behaviour is safe, and so won't let us do it.
+
+The solution to this problem is usually to switch to using a `move` closure.
+This approach moves (or copies, where possible) data into the closure, rather
+than taking references to it. For example:
+
+```
+fn foo() -> Box<Fn(u32) -> u32> {
+ let x = 0u32;
+ Box::new(move |y| x + y)
+}
+```
+
+Now that the closure has its own copy of the data, there's no need to worry
+about safety.
+"##,
+
E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:
```
"##,
+E0382: r##"
+This error occurs when an attempt is made to use a variable after its contents
+have been moved elsewhere. For example:
+
+```compile_fail,E0382
+struct MyStruct { s: u32 }
+
+fn main() {
+ let mut x = MyStruct{ s: 5u32 };
+ let y = x;
+ x.s = 6;
+ println!("{}", x.s);
+}
+```
+
+Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
+of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
+of workarounds like `Rc`, a value cannot be owned by more than one variable.
+
+If we own the type, the easiest way to address this problem is to implement
+`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
+information in `x`, while leaving the original version owned by `x`. Subsequent
+changes to `x` will not be reflected when accessing `y`.
+
+```
+#[derive(Copy, Clone)]
+struct MyStruct { s: u32 }
+
+fn main() {
+ let mut x = MyStruct{ s: 5u32 };
+ let y = x;
+ x.s = 6;
+ println!("{}", x.s);
+}
+```
+
+Alternatively, if we don't control the struct's definition, or mutable shared
+ownership is truly required, we can use `Rc` and `RefCell`:
+
+```
+use std::cell::RefCell;
+use std::rc::Rc;
+
+struct MyStruct { s: u32 }
+
+fn main() {
+ let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
+ let y = x.clone();
+ x.borrow_mut().s = 6;
+ println!("{}", x.borrow().s);
+}
+```
+
+With this approach, x and y share ownership of the data via the `Rc` (reference
+count type). `RefCell` essentially performs runtime borrow checking: ensuring
+that at most one writer or multiple readers can access the data at any one time.
+
+If you wish to learn more about ownership in Rust, start with the chapter in the
+Book:
+
+https://doc.rust-lang.org/book/first-edition/ownership.html
+"##,
+
+E0383: r##"
+This error occurs when an attempt is made to partially reinitialize a
+structure that is currently uninitialized.
+
+For example, this can happen when a drop has taken place:
+
+```compile_fail,E0383
+struct Foo {
+ a: u32,
+}
+impl Drop for Foo {
+ fn drop(&mut self) { /* ... */ }
+}
+
+let mut x = Foo { a: 1 };
+drop(x); // `x` is now uninitialized
+x.a = 2; // error, partial reinitialization of uninitialized structure `t`
+```
+
+This error can be fixed by fully reinitializing the structure in question:
+
+```
+struct Foo {
+ a: u32,
+}
+impl Drop for Foo {
+ fn drop(&mut self) { /* ... */ }
+}
+
+let mut x = Foo { a: 1 };
+drop(x);
+x = Foo { a: 2 };
+```
+"##,
+
E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:
```
"##,
+/*E0386: r##"
+This error occurs when an attempt is made to mutate the target of a mutable
+reference stored inside an immutable container.
+
+For example, this can happen when storing a `&mut` inside an immutable `Box`:
+
+```compile_fail,E0386
+let mut x: i64 = 1;
+let y: Box<_> = Box::new(&mut x);
+**y = 2; // error, cannot assign to data in an immutable container
+```
+
+This error can be fixed by making the container mutable:
+
+```
+let mut x: i64 = 1;
+let mut y: Box<_> = Box::new(&mut x);
+**y = 2;
+```
+
+It can also be fixed by using a type with interior mutability, such as `Cell`
+or `RefCell`:
+
+```
+use std::cell::Cell;
+
+let x: i64 = 1;
+let y: Box<Cell<_>> = Box::new(Cell::new(x));
+y.set(2);
+```
+"##,*/
+
+E0387: r##"
+This error occurs when an attempt is made to mutate or mutably reference data
+that a closure has captured immutably. Examples of this error are shown below:
+
+```compile_fail,E0387
+// Accepts a function or a closure that captures its environment immutably.
+// Closures passed to foo will not be able to mutate their closed-over state.
+fn foo<F: Fn()>(f: F) { }
+
+// Attempts to mutate closed-over data. Error message reads:
+// `cannot assign to data in a captured outer variable...`
+fn mutable() {
+ let mut x = 0u32;
+ foo(|| x = 2);
+}
+
+// Attempts to take a mutable reference to closed-over data. Error message
+// reads: `cannot borrow data mutably in a captured outer variable...`
+fn mut_addr() {
+ let mut x = 0u32;
+ foo(|| { let y = &mut x; });
+}
+```
+
+The problem here is that foo is defined as accepting a parameter of type `Fn`.
+Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
+they capture their context immutably.
+
+If the definition of `foo` is under your control, the simplest solution is to
+capture the data mutably. This can be done by defining `foo` to take FnMut
+rather than Fn:
+
+```
+fn foo<F: FnMut()>(f: F) { }
+```
+
+Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
+interior mutability through a shared reference. Our example's `mutable`
+function could be redefined as below:
+
+```
+use std::cell::Cell;
+
+fn foo<F: Fn()>(f: F) { }
+
+fn mutable() {
+ let x = Cell::new(0u32);
+ foo(|| x.set(2));
+}
+```
+
+You can read more about cell types in the API documentation:
+
+https://doc.rust-lang.org/std/cell/
+"##,
+
+E0388: r##"
+E0388 was removed and is no longer issued.
+"##,
+
+E0389: r##"
+An attempt was made to mutate data using a non-mutable reference. This
+commonly occurs when attempting to assign to a non-mutable reference of a
+mutable reference (`&(&mut T)`).
+
+Example of erroneous code:
+
+```compile_fail,E0389
+struct FancyNum {
+ num: u8,
+}
+
+fn main() {
+ let mut fancy = FancyNum{ num: 5 };
+ let fancy_ref = &(&mut fancy);
+ fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
+ println!("{}", fancy_ref.num);
+}
+```
+
+Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
+immutable reference to a value borrows it immutably. There can be multiple
+references of type `&(&mut T)` that point to the same value, so they must be
+immutable to prevent multiple mutable references to the same value.
+
+To fix this, either remove the outer reference:
+
+```
+struct FancyNum {
+ num: u8,
+}
+
+fn main() {
+ let mut fancy = FancyNum{ num: 5 };
+
+ let fancy_ref = &mut fancy;
+ // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
+
+ fancy_ref.num = 6; // No error!
+
+ println!("{}", fancy_ref.num);
+}
+```
+
+Or make the outer reference mutable:
+
+```
+struct FancyNum {
+ num: u8
+}
+
+fn main() {
+ let mut fancy = FancyNum{ num: 5 };
+
+ let fancy_ref = &mut (&mut fancy);
+ // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
+
+ fancy_ref.num = 6; // No error!
+
+ println!("{}", fancy_ref.num);
+}
+```
+"##,
E0394: r##"
A static was referred to by value by another static.
```
"##,
+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.
+
+Example of erroneous code:
+
+```compile_fail,E0596
+let x = 1;
+let y = &mut x; // error: cannot borrow mutably
+```
+
+In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
+fails. To fix this error, you need to make `x` mutable:
+
+```
+let mut x = 1;
+let y = &mut x; // ok!
+```
+"##,
+
+E0597: r##"
+This error occurs because a borrow was made inside a variable which has a
+greater lifetime than the borrowed one.
+
+Example of erroneous code:
+
+```compile_fail,E0597
+struct Foo<'a> {
+ x: Option<&'a u32>,
+}
+
+let mut x = Foo { x: None };
+let y = 0;
+x.x = Some(&y); // error: `y` does not live long enough
+```
+
+In here, `x` is created before `y` and therefore has a greater lifetime. Always
+keep in mind that values in a scope are dropped in the opposite order they are
+created. So to fix the previous example, just make the `y` lifetime greater than
+the `x`'s one:
+
+```
+struct Foo<'a> {
+ x: Option<&'a u32>,
+}
+
+let y = 0;
+let mut x = Foo { x: None };
+x.x = Some(&y);
+```
+"##,
+
+E0626: r##"
+This error occurs because a borrow in a generator persists across a
+yield point.
+
+```compile_fail,E0626
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+ let a = &String::new(); // <-- This borrow...
+ yield (); // ...is still in scope here, when the yield occurs.
+ println!("{}", a);
+};
+b.resume();
+```
+
+At present, it is not permitted to have a yield that occurs while a
+borrow is still in scope. To resolve this error, the borrow must
+either be "contained" to a smaller scope that does not overlap the
+yield or else eliminated in another way. So, for example, we might
+resolve the previous example by removing the borrow and just storing
+the integer by value:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+ let a = 3;
+ yield ();
+ println!("{}", a);
+};
+b.resume();
+```
+
+This is a very simple case, of course. In more complex cases, we may
+wish to have more than one reference to the value that was borrowed --
+in those cases, something like the `Rc` or `Arc` types may be useful.
+
+This error also frequently arises with iteration:
+
+```compile_fail,E0626
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+ let v = vec![1,2,3];
+ for &x in &v { // <-- borrow of `v` is still in scope...
+ yield x; // ...when this yield occurs.
+ }
+};
+b.resume();
+```
+
+Such cases can sometimes be resolved by iterating "by value" (or using
+`into_iter()`) to avoid borrowing:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+ let v = vec![1,2,3];
+ for x in v { // <-- Take ownership of the values instead!
+ yield x; // <-- Now yield is OK.
+ }
+};
+b.resume();
+```
+
+If taking ownership is not an option, using indices can work too:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+ let v = vec![1,2,3];
+ let len = v.len(); // (*)
+ for i in 0..len {
+ let x = v[i]; // (*)
+ yield x; // <-- Now yield is OK.
+ }
+};
+b.resume();
+
+// (*) -- Unfortunately, these temporaries are currently required.
+// See <https://github.com/rust-lang/rust/issues/43122>.
+```
+"##,
+
}
register_diagnostics! {
+// E0385, // {} in an aliasable location
E0493, // destructors cannot be evaluated at compile-time
E0524, // two closures require unique access to `..` at the same time
E0526, // shuffle indices are not constant
E0594, // cannot assign to {}
+ E0598, // lifetime of {} is too short to guarantee its contents can be...
E0625, // thread-local statics cannot be accessed at compile-time
}
err.span_label(move_from_span, "cannot move out of here");
err
}
+
+ fn cannot_act_on_moved_value(&self,
+ use_span: Span,
+ verb: &str,
+ optional_adverb_for_moved: &str,
+ moved_path: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self, use_span, E0382,
+ "{} of {}moved value: `{}`{OGN}",
+ verb, optional_adverb_for_moved, moved_path, OGN=o);
+ err
+ }
+
+ fn cannot_partially_reinit_an_uninit_struct(&self,
+ span: Span,
+ uninit_path: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self,
+ span,
+ E0383,
+ "partial reinitialization of uninitialized structure `{}`{OGN}",
+ uninit_path, OGN=o);
+ err
+ }
+
+ fn closure_cannot_assign_to_borrowed(&self,
+ span: Span,
+ descr: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self, span, E0595, "closure cannot assign to {}{OGN}",
+ descr, OGN=o);
+ err
+ }
+
+ fn cannot_borrow_path_as_mutable(&self,
+ span: Span,
+ path: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{OGN}",
+ path, OGN=o);
+ err
+ }
+
+ fn cannot_borrow_across_generator_yield(&self,
+ span: Span,
+ yield_span: Span,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let mut err = struct_span_err!(self,
+ span,
+ E0626,
+ "borrow may still be in use when generator yields{OGN}",
+ OGN=o);
+ err.span_label(yield_span, "possible yield occurs here");
+ err
+ }
+
+ fn path_does_not_live_long_enough(&self,
+ span: Span,
+ path: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self, span, E0597, "{} does not live long enough{OGN}",
+ path, OGN=o);
+ err
+ }
+
+ fn lifetime_too_short_for_reborrow(&self,
+ span: Span,
+ path: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let err = struct_span_err!(self, span, E0598,
+ "lifetime of {} is too short to guarantee \
+ its contents can be safely reborrowed{OGN}",
+ path, OGN=o);
+ err
+ }
+
+ fn cannot_act_on_capture_in_sharable_fn(&self,
+ span: Span,
+ bad_thing: &str,
+ help: (Span, &str),
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let (help_span, help_msg) = help;
+ let mut err = struct_span_err!(self, span, E0387,
+ "{} in a captured outer variable in an `Fn` closure{OGN}",
+ bad_thing, OGN=o);
+ err.span_help(help_span, help_msg);
+ err
+ }
+
+ fn cannot_assign_into_immutable_reference(&self,
+ span: Span,
+ bad_thing: &str,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let mut err = struct_span_err!(self, span, E0389, "{} in a `&` reference{OGN}",
+ bad_thing, OGN=o);
+ err.span_label(span, "assignment into an immutable reference");
+ err
+ }
+
+ fn cannot_capture_in_long_lived_closure(&self,
+ closure_span: Span,
+ borrowed_path: &str,
+ capture_span: Span,
+ o: Origin)
+ -> DiagnosticBuilder
+ {
+ let mut err = struct_span_err!(self, closure_span, E0373,
+ "closure may outlive the current function, \
+ but it borrows {}, \
+ which is owned by the current function{OGN}",
+ borrowed_path, OGN=o);
+ err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
+ .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
+ err
+ }
}
impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
err.emit();
});
}
- TyKind::TraitObject(ref bounds) => {
+ TyKind::TraitObject(ref bounds, ..) => {
let mut any_lifetime_bounds = false;
for bound in bounds {
if let RegionTyParamBound(ref lifetime) = *bound {
"##,
E0154: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.
"##,
E0251: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.
"##,
E0256: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.
})
}
}
- ast::TyKind::TraitObject(ref bounds) => {
+ ast::TyKind::TraitObject(ref bounds, ..) => {
// FIXME recurse into bounds
let nested = pprust::bounds_to_string(bounds);
Ok(text_sig(nested))
syntax_pos = { path = "../libsyntax_pos" }
[target."cfg(windows)".dependencies]
-cc = "1.0"
+cc = "1.0.1"
.filter_map(symbol_filter)
.collect::<Vec<CString>>();
timeline.record("whitelist");
+ info!("{} symbols to preserve in this crate", symbol_white_list.len());
// If we're performing LTO for the entire crate graph, then for each of our
// upstream dependencies, find the corresponding rlib and load the bitcode
assert!(!pass.is_null());
llvm::LLVMRustAddPass(pm, pass);
- with_llvm_pmb(llmod, config, &mut |b| {
+ // When optimizing for LTO we don't actually pass in `-O0`, but we force
+ // it to always happen at least with `-O1`.
+ //
+ // With ThinLTO we mess around a lot with symbol visibility in a way
+ // that will actually cause linking failures if we optimize at O0 which
+ // notable is lacking in dead code elimination. To ensure we at least
+ // get some optimizations and correctly link we forcibly switch to `-O1`
+ // to get dead code elimination.
+ //
+ // Note that in general this shouldn't matter too much as you typically
+ // only turn on ThinLTO when you're compiling with optimizations
+ // otherwise.
+ let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+ let opt_level = match opt_level {
+ llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
+ level => level,
+ };
+ with_llvm_pmb(llmod, config, opt_level, &mut |b| {
if thin {
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
panic!("this version of LLVM does not support ThinLTO");
passes: Vec<String>,
/// Some(level) to optimize at a certain level, or None to run
/// absolutely no optimizations (used for the metadata module).
- opt_level: Option<llvm::CodeGenOptLevel>,
+ pub opt_level: Option<llvm::CodeGenOptLevel>,
/// Some(level) to optimize binary size, or None to not affect program size.
opt_size: Option<llvm::CodeGenOptSize>,
if !config.no_prepopulate_passes {
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
- with_llvm_pmb(llmod, &config, &mut |b| {
+ let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+ with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
})
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
config: &ModuleConfig,
+ opt_level: llvm::CodeGenOptLevel,
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
- let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
let inline_threshold = config.inline_threshold;
- llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
+ llvm::LLVMRustConfigurePassManagerBuilder(builder,
+ opt_level,
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop);
fn_sig.output(),
fn_sig.inputs());
self.check_argument_types(call_expr.span,
+ call_expr.span,
fn_sig.inputs(),
&expected_arg_tys[..],
arg_exprs,
fn_sig.inputs());
self.check_argument_types(call_expr.span,
+ call_expr.span,
fn_sig.inputs(),
&expected_arg_tys,
arg_exprs,
method_callee: MethodCallee<'tcx>)
-> Ty<'tcx> {
let output_type = self.check_method_argument_types(call_expr.span,
+ call_expr.span,
Ok(method_callee),
arg_exprs,
TupleArgumentsFlag::TupleArguments,
debug_assert!(crate_num == LOCAL_CRATE);
Ok(tcx.sess.track_errors(|| {
for body_owner_def_id in tcx.body_owners() {
- tcx.typeck_tables_of(body_owner_def_id);
+ ty::maps::queries::typeck_tables_of::ensure(tcx, body_owner_def_id);
}
})?)
}
fn check_method_argument_types(&self,
sp: Span,
+ expr_sp: Span,
method: Result<MethodCallee<'tcx>, ()>,
args_no_rcvr: &'gcx [hir::Expr],
tuple_arguments: TupleArgumentsFlag,
TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)],
};
- self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
+ self.check_argument_types(sp, expr_sp, &err_inputs[..], &[], args_no_rcvr,
false, tuple_arguments, None);
return self.tcx.types.err;
}
method.sig.output(),
&method.sig.inputs()[1..]
);
- self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
+ self.check_argument_types(sp, expr_sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
args_no_rcvr, method.sig.variadic, tuple_arguments,
self.tcx.hir.span_if_local(method.def_id));
method.sig.output()
/// method calls and overloaded operators.
fn check_argument_types(&self,
sp: Span,
+ expr_sp: Span,
fn_inputs: &[Ty<'tcx>],
expected_arg_tys: &[Ty<'tcx>],
args: &'gcx [hir::Expr],
sp
};
- fn parameter_count_error<'tcx>(sess: &Session, sp: Span, expected_count: usize,
- arg_count: usize, error_code: &str, variadic: bool,
- def_span: Option<Span>, sugg_unit: bool) {
+ fn parameter_count_error<'tcx>(sess: &Session,
+ sp: Span,
+ expr_sp: Span,
+ expected_count: usize,
+ arg_count: usize,
+ error_code: &str,
+ variadic: bool,
+ def_span: Option<Span>,
+ sugg_unit: bool) {
let mut err = sess.struct_span_err_with_code(sp,
&format!("this function takes {}{} parameter{} but {} parameter{} supplied",
if variadic {"at least "} else {""},
err.span_label(def_s, "defined here");
}
if sugg_unit {
- let sugg_span = sp.end_point();
+ let sugg_span = expr_sp.end_point();
// remove closing `)` from the span
let sugg_span = sugg_span.with_hi(sugg_span.lo());
err.span_suggestion(
sugg_span,
- "expected the unit value `()`. You can create one with a pair of parenthesis",
+ "expected the unit value `()`; create it with empty parentheses",
String::from("()"));
} else {
err.span_label(sp, format!("expected {}{} parameter{}",
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
match tuple_type.sty {
ty::TyTuple(arg_types, _) if arg_types.len() != args.len() => {
- parameter_count_error(tcx.sess, sp_args, arg_types.len(), args.len(),
+ parameter_count_error(tcx.sess, sp_args, expr_sp, arg_types.len(), args.len(),
"E0057", false, def_span, false);
expected_arg_tys = &[];
self.err_args(args.len())
if supplied_arg_count >= expected_arg_count {
fn_inputs.to_vec()
} else {
- parameter_count_error(tcx.sess, sp_args, expected_arg_count,
+ parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count,
supplied_arg_count, "E0060", true, def_span, false);
expected_arg_tys = &[];
self.err_args(supplied_arg_count)
} else {
false
};
- parameter_count_error(tcx.sess, sp_args, expected_arg_count,
+ parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count,
supplied_arg_count, "E0061", false, def_span, sugg_unit);
expected_arg_tys = &[];
self.err_args(supplied_arg_count)
};
// Call the generic checker.
- self.check_method_argument_types(span, method,
+ self.check_method_argument_types(span,
+ expr.span,
+ method,
&args[1..],
DontTupleArguments,
expected)
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
<dd>Show this help dialog</dd>
<dt>S</dt>
<dd>Focus the search field</dd>
- <dt>⇤</dt>
+ <dt>↑</dt>
<dd>Move up in search results</dd>
- <dt>⇥</dt>
+ <dt>↓</dt>
<dd>Move down in search results</dd>
<dt>⏎</dt>
<dd>Go to active search result</dd>
/// Warnings for the user if rendering would differ using different markdown
/// parsers.
pub markdown_warnings: RefCell<Vec<(Span, String, Vec<html_diff::Difference>)>>,
+ /// The directories that have already been created in this doc run. Used to reduce the number
+ /// of spurious `create_dir_all` calls.
+ pub created_dirs: RefCell<FxHashSet<PathBuf>>,
+}
+
+impl SharedContext {
+ fn ensure_dir(&self, dst: &Path) -> io::Result<()> {
+ let mut dirs = self.created_dirs.borrow_mut();
+ if !dirs.contains(dst) {
+ fs::create_dir_all(dst)?;
+ dirs.insert(dst.to_path_buf());
+ }
+
+ Ok(())
+ }
}
/// Indicates where an external crate can be found.
},
css_file_extension: css_file_extension.clone(),
markdown_warnings: RefCell::new(vec![]),
+ created_dirs: RefCell::new(FxHashSet()),
};
// If user passed in `--playground-url` arg, we fill in crate name here
// Write out the shared files. Note that these are shared among all rustdoc
// docs placed in the output directory, so this needs to be a synchronized
// operation with respect to all other rustdocs running around.
- try_err!(fs::create_dir_all(&cx.dst), &cx.dst);
let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true);
// Add all the static files. These may already exist, but we just
this.render_item(&mut buf, &item, false).unwrap();
// buf will be empty if the module is stripped and there is no redirect for it
if !buf.is_empty() {
+ try_err!(this.shared.ensure_dir(&this.dst), &this.dst);
let joint_dst = this.dst.join("index.html");
- try_err!(fs::create_dir_all(&this.dst), &this.dst);
let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
try_err!(dst.write_all(&buf), &joint_dst);
}
let name = item.name.as_ref().unwrap();
let item_type = item.type_();
let file_name = &item_path(item_type, name);
+ try_err!(self.shared.ensure_dir(&self.dst), &self.dst);
let joint_dst = self.dst.join(file_name);
- try_err!(fs::create_dir_all(&self.dst), &self.dst);
let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
try_err!(dst.write_all(&buf), &joint_dst);
// URL for the page.
let redir_name = format!("{}.{}.html", name, item_type.name_space());
let redir_dst = self.dst.join(redir_name);
- if let Ok(mut redirect_out) = OpenOptions::new().create_new(true)
+ if let Ok(redirect_out) = OpenOptions::new().create_new(true)
.write(true)
.open(&redir_dst) {
+ let mut redirect_out = BufWriter::new(redirect_out);
try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
}
if item_type == ItemType::Macro {
let redir_name = format!("{}.{}!.html", item_type, name);
let redir_dst = self.dst.join(redir_name);
- let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst);
+ let redirect_out = try_err!(File::create(&redir_dst), &redir_dst);
+ let mut redirect_out = BufWriter::new(redirect_out);
try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
}
}
.toggle-wrapper {
height: 1.5em;
}
+
+ #search {
+ margin-left: 0;
+ }
}
@media print {
unstable("crate-version", |o| {
o.optopt("", "crate-version", "crate version to print into documentation", "VERSION")
}),
+ unstable("linker", |o| {
+ o.optopt("", "linker", "linker used for building executable test code", "PATH")
+ }),
]
}
let playground_url = matches.opt_str("playground-url");
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
let display_warnings = matches.opt_present("display-warnings");
+ let linker = matches.opt_str("linker");
match (should_test, markdown_input) {
(true, true) => {
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type,
- display_warnings)
+ display_warnings, linker)
}
(true, false) => {
return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
- render_type, display_warnings)
+ render_type, display_warnings, linker)
}
(false, true) => return markdown::render(input,
output.unwrap_or(PathBuf::from("doc")),
/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
- render_type: RenderType, display_warnings: bool) -> isize {
+ render_type: RenderType, display_warnings: bool, linker: Option<String>) -> isize {
let input_str = match load_string(input) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
true, opts, maybe_sysroot, None,
Some(input.to_owned()),
- render_type);
+ render_type, linker);
if render_type == RenderType::Pulldown {
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
find_testable_code(&input_str, &mut collector, DUMMY_SP);
crate_name: Option<String>,
maybe_sysroot: Option<PathBuf>,
render_type: RenderType,
- display_warnings: bool)
+ display_warnings: bool,
+ linker: Option<String>)
-> isize {
let input_path = PathBuf::from(input);
let input = config::Input::File(input_path.clone());
maybe_sysroot,
Some(codemap),
None,
- render_type);
+ render_type,
+ linker);
{
let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
externs: Externs,
should_panic: bool, no_run: bool, as_test_harness: bool,
compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
- maybe_sysroot: Option<PathBuf>) {
+ maybe_sysroot: Option<PathBuf>,
+ linker: Option<String>) {
// the test harness wants its own `main` & top level functions, so
// never wrap the test in `fn main() { ... }`
let test = make_test(test, Some(cratename), as_test_harness, opts);
externs,
cg: config::CodegenOptions {
prefer_dynamic: true,
+ linker,
.. config::basic_codegen_options()
},
test: as_test_harness,
pub tests: Vec<testing::TestDescAndFn>,
// to be removed when hoedown will be definitely gone
pub old_tests: HashMap<String, Vec<String>>,
+
+ // The name of the test displayed to the user, separated by `::`.
+ //
+ // In tests from Rust source, this is the path to the item
+ // e.g. `["std", "vec", "Vec", "push"]`.
+ //
+ // In tests from a markdown file, this is the titles of all headers (h1~h6)
+ // of the sections that contain the code block, e.g. if the markdown file is
+ // written as:
+ //
+ // ``````markdown
+ // # Title
+ //
+ // ## Subtitle
+ //
+ // ```rust
+ // assert!(true);
+ // ```
+ // ``````
+ //
+ // the `names` vector of that test will be `["Title", "Subtitle"]`.
names: Vec<String>,
+
cfgs: Vec<String>,
libs: SearchPaths,
externs: Externs,
- cnt: usize,
use_headers: bool,
- current_header: Option<String>,
cratename: String,
opts: TestOptions,
maybe_sysroot: Option<PathBuf>,
filename: Option<String>,
// to be removed when hoedown will be removed as well
pub render_type: RenderType,
+ linker: Option<String>,
}
impl Collector {
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
codemap: Option<Rc<CodeMap>>, filename: Option<String>,
- render_type: RenderType) -> Collector {
+ render_type: RenderType, linker: Option<String>) -> Collector {
Collector {
tests: Vec::new(),
old_tests: HashMap::new(),
cfgs,
libs,
externs,
- cnt: 0,
use_headers,
- current_header: None,
cratename,
opts,
maybe_sysroot,
codemap,
filename,
render_type,
+ linker,
}
}
fn generate_name(&self, line: usize, filename: &str) -> String {
- if self.use_headers {
- if let Some(ref header) = self.current_header {
- format!("{} - {} (line {})", filename, header, line)
- } else {
- format!("{} - (line {})", filename, line)
- }
- } else {
- format!("{} - {} (line {})", filename, self.names.join("::"), line)
- }
+ format!("{} - {} (line {})", filename, self.names.join("::"), line)
}
// to be removed once hoedown is gone
fn generate_name_beginning(&self, filename: &str) -> String {
- if self.use_headers {
- if let Some(ref header) = self.current_header {
- format!("{} - {} (line", filename, header)
- } else {
- format!("{} - (line", filename)
- }
- } else {
- format!("{} - {} (line", filename, self.names.join("::"))
- }
+ format!("{} - {} (line", filename, self.names.join("::"))
}
pub fn add_old_test(&mut self, test: String, filename: String) {
let cratename = self.cratename.to_string();
let opts = self.opts.clone();
let maybe_sysroot = self.maybe_sysroot.clone();
+ let linker = self.linker.clone();
debug!("Creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
compile_fail,
error_codes,
&opts,
- maybe_sysroot)
+ maybe_sysroot,
+ linker)
})
} {
Ok(()) => (),
}
pub fn register_header(&mut self, name: &str, level: u32) {
- if self.use_headers && level == 1 {
+ if self.use_headers {
// we use these headings as test names, so it's good if
// they're valid identifiers.
let name = name.chars().enumerate().map(|(i, c)| {
}
}).collect::<String>();
- // new header => reset count.
- self.cnt = 0;
- self.current_header = Some(name);
+ // Here we try to efficiently assemble the header titles into the
+ // test name in the form of `h1::h2::h3::h4::h5::h6`.
+ //
+ // Suppose originally `self.names` contains `[h1, h2, h3]`...
+ let level = level as usize;
+ if level <= self.names.len() {
+ // ... Consider `level == 2`. All headers in the lower levels
+ // are irrelevant in this new level. So we should reset
+ // `self.names` to contain headers until <h2>, and replace that
+ // slot with the new name: `[h1, name]`.
+ self.names.truncate(level);
+ self.names[level - 1] = name;
+ } else {
+ // ... On the other hand, consider `level == 5`. This means we
+ // need to extend `self.names` to contain five headers. We fill
+ // in the missing level (<h4>) with `_`. Thus `self.names` will
+ // become `[h1, h2, h3, "_", name]`.
+ if level - 1 > self.names.len() {
+ self.names.resize(level - 1, "_".to_owned());
+ }
+ self.names.push(name);
+ }
}
}
}
attrs.collapse_doc_comments();
attrs.unindent_doc_comments();
if let Some(doc) = attrs.doc_value() {
- self.collector.cnt = 0;
if self.collector.render_type == RenderType::Pulldown {
markdown::old_find_testable_code(doc, self.collector,
attrs.span.unwrap_or(DUMMY_SP));
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0"
[features]
backtrace = []
#![deny(warnings)]
extern crate build_helper;
-extern crate cc;
use std::env;
use std::process::Command;
fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;
- let compiler = cc::Build::new().get_compiler();
- // only msvc returns None for ar so unwrap is okay
- let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
- let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
- .collect::<Vec<_>>().join(" ");
- cflags.push_str(" -fvisibility=hidden");
run(Command::new("sh")
.current_dir(&native.out_dir)
.arg(native.src_dir.join("configure").to_str().unwrap()
.arg("--disable-host-shared")
.arg(format!("--host={}", build_helper::gnu_target(target)))
.arg(format!("--build={}", build_helper::gnu_target(host)))
- .env("CC", compiler.path())
- .env("AR", &ar)
- .env("RANLIB", format!("{} s", ar.display()))
- .env("CFLAGS", cflags),
+ .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"),
BuildExpectation::None);
run(Command::new(build_helper::make(host))
(pairs_offset, end_of_pairs, oflo)
}
-// Returns a tuple of (minimum required malloc alignment, hash_offset,
+// Returns a tuple of (minimum required malloc alignment,
// array_size), from the start of a mallocated array.
fn calculate_allocation(hash_size: usize,
hash_align: usize,
pairs_size: usize,
pairs_align: usize)
- -> (usize, usize, usize, bool) {
- let hash_offset = 0;
+ -> (usize, usize, bool) {
let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
let align = cmp::max(hash_align, pairs_align);
- (align, hash_offset, end_of_pairs, oflo)
+ (align, end_of_pairs, oflo)
}
#[test]
fn test_offset_calculation() {
- assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false));
- assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false));
- assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false));
+ assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false));
+ assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false));
+ assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false));
assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
// This is great in theory, but in practice getting the alignment
// right is a little subtle. Therefore, calculating offsets has been
// factored out into a different function.
- let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
- align_of::<HashUint>(),
- pairs_size,
- align_of::<(K, V)>());
+ let (alignment, size, oflo) = calculate_allocation(hashes_size,
+ align_of::<HashUint>(),
+ pairs_size,
+ align_of::<(K, V)>());
assert!(!oflo, "capacity overflow");
// One check for overflow that covers calculation and rounding of size.
let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap())
.unwrap_or_else(|e| Heap.oom(e));
- let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
+ let hashes = buffer as *mut HashUint;
RawTable {
capacity_mask: capacity.wrapping_sub(1),
}
new_ht.size = self.size();
+ new_ht.set_tag(self.tag());
new_ht
}
let hashes_size = self.capacity() * size_of::<HashUint>();
let pairs_size = self.capacity() * size_of::<(K, V)>();
- let (align, _, size, oflo) = calculate_allocation(hashes_size,
- align_of::<HashUint>(),
- pairs_size,
- align_of::<(K, V)>());
+ let (align, size, oflo) = calculate_allocation(hashes_size,
+ align_of::<HashUint>(),
+ pairs_size,
+ align_of::<(K, V)>());
debug_assert!(!oflo, "should be impossible");
"bad error: {} {:?}", e, e.kind());
}
+ #[test]
+ fn connect_timeout_unbound() {
+ // bind and drop a socket to track down a "probably unassigned" port
+ let socket = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = socket.local_addr().unwrap();
+ drop(socket);
+
+ let timeout = Duration::from_secs(1);
+ let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err();
+ assert!(e.kind() == io::ErrorKind::ConnectionRefused ||
+ e.kind() == io::ErrorKind::TimedOut ||
+ e.kind() == io::ErrorKind::Other,
+ "bad error: {} {:?}", e, e.kind());
+ }
+
#[test]
fn connect_timeout_valid() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
}
/// The output of a finished process.
+///
+/// This is returned in a Result by either the [`output`] method of a
+/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
+/// process.
+///
+/// [`Command`]: struct.Command.html
+/// [`Child`]: struct.Child.html
+/// [`output`]: struct.Command.html#method.output
+/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
#[derive(PartialEq, Eq, Clone)]
#[stable(feature = "process", since = "1.0.0")]
pub struct Output {
}
0 => {}
_ => {
- if pollfd.revents & libc::POLLOUT == 0 {
- if let Some(e) = self.take_error()? {
- return Err(e);
- }
+ // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+ // for POLLHUP rather than read readiness
+ if pollfd.revents & libc::POLLHUP != 0 {
+ let e = self.take_error()?
+ .unwrap_or_else(|| {
+ io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+ });
+ return Err(e);
}
+
return Ok(());
}
}
Path(Option<QSelf>, Path),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
- TraitObject(TyParamBounds),
+ TraitObject(TyParamBounds, TraitObjectSyntax),
/// An `impl Bound1 + Bound2 + Bound3` type
/// where `Bound` is a trait or a lifetime.
ImplTrait(TyParamBounds),
Err,
}
+/// Syntax used to declare a trait object.
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitObjectSyntax {
+ Dyn,
+ None,
+}
+
/// Inline assembly dialect.
///
/// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")``
// Default match binding modes (RFC 2005)
(active, match_default_bindings, "1.22.0", Some(42640)),
+
+ // Trait object syntax with `dyn` prefix
+ (active, dyn_trait, "1.22.0", Some(44662)),
);
declare_features! (
gate_feature_post!(&self, never_type, ty.span,
"The `!` type is experimental");
},
+ ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
+ gate_feature_post!(&self, dyn_trait, ty.span,
+ "`dyn Trait` syntax is unstable");
+ }
_ => {}
}
visit::walk_ty(self, ty)
TyKind::Typeof(expr) => {
TyKind::Typeof(fld.fold_expr(expr))
}
- TyKind::TraitObject(bounds) => {
- TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+ TyKind::TraitObject(bounds, syntax) => {
+ TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax)
}
TyKind::ImplTrait(bounds) => {
TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
use ast::{VariantData, StructField};
use ast::StrStyle;
use ast::SelfKind;
-use ast::{TraitItem, TraitRef};
+use ast::{TraitItem, TraitRef, TraitObjectSyntax};
use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
t.is_ident() || *t == token::Underscore
}
+// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
+fn can_continue_type_after_ident(t: &token::Token) -> bool {
+ t == &token::ModSep || t == &token::Lt ||
+ t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+}
+
/// Information about the path to a module.
pub struct ModulePath {
pub name: String,
TyKind::Path(None, ref path) if maybe_bounds => {
self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
}
- TyKind::TraitObject(ref bounds)
+ TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
let path = match bounds[0] {
TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
} else if self.eat(&token::Underscore) {
// A type to be inferred `_`
TyKind::Infer
- } else if self.eat_lt() {
- // Qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Type)?;
- TyKind::Path(Some(qself), path)
- } else if self.token.is_path_start() {
- // Simple path
- let path = self.parse_path(PathStyle::Type)?;
- if self.eat(&token::Not) {
- // Macro invocation in type position
- let (_, tts) = self.expect_delimited_token_tree()?;
- TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
- } else {
- // Just a type path or bound list (trait object type) starting with a trait.
- // `Type`
- // `Trait1 + Trait2 + 'a`
- if allow_plus && self.check(&token::BinOp(token::Plus)) {
- self.parse_remaining_bounds(Vec::new(), path, lo, true)?
- } else {
- TyKind::Path(None, path)
- }
- }
} else if self.token_is_bare_fn_keyword() {
// Function pointer type
self.parse_ty_bare_fn(Vec::new())?
} else if self.eat_keyword(keywords::Impl) {
// FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
TyKind::ImplTrait(self.parse_ty_param_bounds()?)
+ } else if self.check_keyword(keywords::Dyn) &&
+ self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+ // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
+ self.bump(); // `dyn`
+ TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
} else if self.check(&token::Question) ||
- self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){
+ self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
// Bound list (trait object type)
- TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?)
+ TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
+ TraitObjectSyntax::None)
+ } else if self.eat_lt() {
+ // Qualified path
+ let (qself, path) = self.parse_qpath(PathStyle::Type)?;
+ TyKind::Path(Some(qself), path)
+ } else if self.token.is_path_start() {
+ // Simple path
+ let path = self.parse_path(PathStyle::Type)?;
+ if self.eat(&token::Not) {
+ // Macro invocation in type position
+ let (_, tts) = self.expect_delimited_token_tree()?;
+ TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
+ } else {
+ // Just a type path or bound list (trait object type) starting with a trait.
+ // `Type`
+ // `Trait1 + Trait2 + 'a`
+ if allow_plus && self.check(&token::BinOp(token::Plus)) {
+ self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+ } else {
+ TyKind::Path(None, path)
+ }
+ }
} else {
let msg = format!("expected type, found {}", self.this_token_descr());
return Err(self.fatal(&msg));
self.bump(); // `+`
bounds.append(&mut self.parse_ty_param_bounds()?);
}
- Ok(TyKind::TraitObject(bounds))
+ Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
let mut bounds = Vec::new();
loop {
+ // This needs to be syncronized with `Token::can_begin_bound`.
let is_bound_start = self.check_path() || self.check_lifetime() ||
self.check(&token::Question) ||
self.check_keyword(keywords::For) ||
}
}
+ /// Returns `true` if the token can appear at the start of a generic bound.
+ pub fn can_begin_bound(&self) -> bool {
+ self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
+ self == &Question || self == &OpenDelim(Paren)
+ }
+
/// Returns `true` if the token is any literal
pub fn is_lit(&self) -> bool {
match *self {
ast::TyKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false)?
}
- ast::TyKind::TraitObject(ref bounds) => {
- self.print_bounds("", &bounds[..])?;
+ ast::TyKind::TraitObject(ref bounds, syntax) => {
+ let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" };
+ self.print_bounds(prefix, &bounds[..])?;
}
ast::TyKind::ImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
visitor.visit_ty(ty);
visitor.visit_expr(expression)
}
- TyKind::TraitObject(ref bounds) |
+ TyKind::TraitObject(ref bounds, ..) |
TyKind::ImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
(54, Yield, "yield")
// Weak keywords, have special meaning only in specific contexts.
- (55, Default, "default")
- (56, StaticLifetime, "'static")
- (57, Union, "union")
- (58, Catch, "catch")
+ (55, Catch, "catch")
+ (56, Default, "default")
+ (57, Dyn, "dyn")
+ (58, StaticLifetime, "'static")
+ (59, Union, "union")
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
core = { path = "../../libcore" }
[build-dependencies]
-cc = "1.0"
+cc = "1.0.1"
[features]
c = []
}
}
- GlobalValueSummary *GVSummary = Summary.get();
- if (isa<FunctionSummary>(GVSummary)) {
- FunctionSummary *FS = cast<FunctionSummary>(GVSummary);
+ if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
for (auto &Call: FS->calls()) {
if (Call.first.isGUID()) {
addPreservedGUID(Index, Preserved, Call.first.getGUID());
addPreservedGUID(Index, Preserved, GUID);
}
}
+ if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
+ auto GUID = AS->getAliasee().getOriginalName();
+ addPreservedGUID(Index, Preserved, GUID);
+ }
}
}
// combined index
//
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
- computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+ auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
ComputeCrossModuleImport(
Ret->Index,
Ret->ModuleToDefinedGVSummaries,
Ret->ImportLists,
- Ret->ExportLists
+ Ret->ExportLists,
+ &DeadSymbols
);
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
--- /dev/null
+// 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.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn main() {
+ let mut x = 1;
+ let _x = &mut x;
+ let _ = match x {
+ x => x + 1, //[ast]~ ERROR E0503
+ //[mir]~^ ERROR (Mir) [E0503]
+ //[mir]~| ERROR (Ast) [E0503]
+ y => y + 2, //[ast]~ ERROR [E0503]
+ //[mir]~^ ERROR (Mir) [E0503]
+ //[mir]~| ERROR (Ast) [E0503]
+ };
+}
--- /dev/null
+// 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.
+
+type A0 = dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+type A1 = dyn::dyn;
+//~^ ERROR Use of undeclared type or module `dyn`
+type A2 = dyn<dyn, dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+type A3 = dyn<<dyn as dyn>::dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR Use of undeclared type or module `dyn`
+type A4 = dyn(dyn, dyn) -> dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+
+fn main() {}
--- /dev/null
+// Copyright 2016 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.
+
+trait Trait {}
+type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable
+
+fn main() {}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that parameter cardinality or missing method error gets span exactly.
-
-pub struct Foo;
-impl Foo {
- fn zero(self) -> Foo { self }
- //~^ NOTE defined here
- fn one(self, _: isize) -> Foo { self }
- //~^ NOTE defined here
- fn two(self, _: isize, _: isize) -> Foo { self }
- //~^ NOTE defined here
-}
-
-fn main() {
- let x = Foo;
- x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied
- //~^ NOTE expected 0 parameters
- .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied
- //~^ NOTE expected 1 parameter
- .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied
- //~^ NOTE expected 2 parameters
-
- let y = Foo;
- y.zero()
- .take() //~ ERROR no method named `take` found for type `Foo` in the current scope
- //~^ NOTE the method `take` exists but the following trait bounds were not satisfied
- //~| NOTE the following traits define an item `take`, perhaps you need to implement one of them
- .one(0);
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(dyn_trait)]
struct Foo;
fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
+type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+
fn main() { }
//~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)`
let _: Box<(Copy +) + Copy>;
//~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)`
+ let _: Box<(dyn Copy) + Copy>;
+ //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Copy)`
}
mkdir $(TMPDIR)/b
$(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c)
$(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c)
- ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
+ $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
$(RUSTC) foo.rs
$(RUSTC) bar.rs
$(call RUN,bar)
ifneq (,$(findstring MINGW,$(UNAME)))
ifndef IS_MSVC
all:
- g++ foo.cpp -c -o $(TMPDIR)/foo.o
- ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o
+ $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o
+ $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o
$(RUSTC) foo.rs -lfoo -lstdc++
$(call RUN,foo)
else
all:
touch $(TMPDIR)/rust.metadata.bin
- ar crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin
+ $(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin
$(RUSTC) foo.rs 2>&1 | grep "can't find crate for"
extern crate rustc_trans;
extern crate syntax;
-use rustc::dep_graph::DepGraph;
use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, build_configuration, Input,
OutputType, OutputTypes};
let mut opts = basic_options();
opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
opts.maybe_sysroot = Some(sysroot);
+ if let Ok(linker) = std::env::var("RUSTC_LINKER") {
+ opts.cg.linker = Some(linker);
+ }
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
let (sess, cstore) = basic_sess(sysroot);
- let cfg = build_configuration(&sess, HashSet::new());
let control = CompileController::basic();
let input = Input::Str { name: anon_src(), input: code };
- compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control);
+ let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control);
}
all: foo.rs
$(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs
- $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \
+ $(RUSTDOC) --test --cfg 'feature="bar"' \
-L $(TMPDIR) foo.rs |\
grep -q 'foo.rs - foo (line 11) ... ok'
-include ../tools.mk
all:
- $(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs
+ $(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs
-include ../tools.mk
all:
- ar crus $(TMPDIR)/libfoo.a foo.rs
- ar d $(TMPDIR)/libfoo.a foo.rs
+ $(AR) crus $(TMPDIR)/libfoo.a foo.rs
+ $(AR) d $(TMPDIR)/libfoo.a foo.rs
$(RUSTC) foo.rs
RUSTC_ORIGINAL := $(RUSTC)
BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)'
+BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)'
RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS)
+RUSTDOC := $(BARE_RUSTDOC)
+ifdef RUSTC_LINKER
+RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER)
+RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options
+endif
#CC := $(CC) -L $(TMPDIR)
HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py
REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
%.a: %.o
- ar crus $@ $<
+ $(AR) crus $@ $<
ifdef IS_MSVC
%.lib: lib%.o
$(MSVC_LIB) -out:`cygpath -w $@` $<
else
%.lib: lib%.o
- ar crus $@ $<
+ $(AR) crus $@ $<
endif
%.dylib: %.o
$(CC) -dynamiclib -Wl,-dylib -o $@ $<
+++ /dev/null
-// 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.
-
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn bar() -> u32 {
- 3
-}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(dyn_trait)]
+
+use std::fmt::Display;
+
+static BYTE: u8 = 33;
+
+fn main() {
+ let x: &(dyn 'static + Display) = &BYTE;
+ let y: Box<dyn Display + 'static> = Box::new(BYTE);
+ let xstr = format!("{}", x);
+ let ystr = format!("{}", y);
+ assert_eq!(xstr, "33");
+ assert_eq!(ystr, "33");
+}
+++ /dev/null
-// 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.
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O
-// min-llvm-version 4.0
-// ignore-emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-mod bar {
- pub fn bar() -> u32 {
- 3
- }
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// 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.
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
-// aux-build:thin-lto-inlines-aux.rs
-// min-llvm-version 4.0
-// no-prefer-dynamic
-// ignore-emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-extern crate thin_lto_inlines_aux as bar;
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
-
--- /dev/null
+// 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.
+
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+ b.to_string();
+}
--- /dev/null
+// 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn bar() -> u32 {
+ 3
+}
--- /dev/null
+// 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.
+
+// aux-build:dylib.rs
+// min-llvm-version 4.0
+
+extern crate dylib;
+
+fn main() {
+ dylib::foo(1);
+}
--- /dev/null
+// 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.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// min-llvm-version 4.0
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+mod bar {
+ pub fn bar() -> u32 {
+ 3
+ }
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// 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.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
+// aux-build:thin-lto-inlines-aux.rs
+// min-llvm-version 4.0
+// no-prefer-dynamic
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
+
18 | foo!(true);
| ^^^^ expecting a type here because of type ascription
-error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true`
+error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true`
--> $DIR/issue-44406.rs:18:10
|
13 | bar(baz: $rest)
- | - expected one of 19 possible tokens here
+ | - expected one of 20 possible tokens here
...
18 | foo!(true);
| ^^^^ unexpected token
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that parameter cardinality or missing method error gets span exactly.
+
+pub struct Foo;
+impl Foo {
+ fn zero(self) -> Foo { self }
+ //~^ NOTE defined here
+ fn one(self, _: isize) -> Foo { self }
+ //~^ NOTE defined here
+ fn two(self, _: isize, _: isize) -> Foo { self }
+ //~^ NOTE defined here
+}
+
+fn main() {
+ let x = Foo;
+ x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied
+ //~^ NOTE expected 0 parameters
+ .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+ //~^ NOTE expected 1 parameter
+ .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied
+ //~^ NOTE expected 2 parameters
+
+ let y = Foo;
+ y.zero()
+ .take() //~ ERROR no method named `take` found for type `Foo` in the current scope
+ //~^ NOTE the method `take` exists but the following trait bounds were not satisfied
+ //~| NOTE the following traits define an item `take`, perhaps you need to implement one of them
+ .one(0);
+}
--- /dev/null
+error[E0061]: this function takes 0 parameters but 1 parameter was supplied
+ --> $DIR/method-call-err-msg.rs:25:12
+ |
+15 | fn zero(self) -> Foo { self }
+ | ----------------------------- defined here
+...
+25 | x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied
+ | ^ expected 0 parameters
+
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+ --> $DIR/method-call-err-msg.rs:27:7
+ |
+17 | fn one(self, _: isize) -> Foo { self }
+ | -------------------------------------- defined here
+...
+27 | .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+ | ^^^ expected 1 parameter
+
+error[E0061]: this function takes 2 parameters but 1 parameter was supplied
+ --> $DIR/method-call-err-msg.rs:29:11
+ |
+19 | fn two(self, _: isize, _: isize) -> Foo { self }
+ | ------------------------------------------------ defined here
+...
+29 | .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied
+ | ^ expected 2 parameters
+
+error[E0599]: no method named `take` found for type `Foo` in the current scope
+ --> $DIR/method-call-err-msg.rs:34:7
+ |
+34 | .take() //~ ERROR no method named `take` found for type `Foo` in the current scope
+ | ^^^^
+ |
+ = note: the method `take` exists but the following trait bounds were not satisfied:
+ `&mut Foo : std::iter::Iterator`
+ = help: items from traits can only be used if the trait is implemented and in scope
+ = note: the following traits define an item `take`, perhaps you need to implement one of them:
+ candidate #1: `std::collections::hash::Recover`
+ candidate #2: `std::io::Read`
+ candidate #3: `std::iter::Iterator`
+ candidate #4: `alloc::btree::Recover`
+
+error: aborting due to 4 previous errors
+
fn foo(():(), ():()) {}
fn bar(():()) {}
+struct S;
+impl S {
+ fn baz(self, (): ()) { }
+ fn generic<T>(self, _: T) { }
+}
+
fn main() {
let _: Result<(), String> = Ok();
foo();
foo(());
bar();
+ S.baz();
+ S.generic::<()>();
}
error[E0061]: this function takes 1 parameter but 0 parameters were supplied
- --> $DIR/missing-unit-argument.rs:15:33
+ --> $DIR/missing-unit-argument.rs:21:33
|
-15 | let _: Result<(), String> = Ok();
+21 | let _: Result<(), String> = Ok();
| ^^^^
|
-help: expected the unit value `()`. You can create one with a pair of parenthesis
+help: expected the unit value `()`; create it with empty parentheses
|
-15 | let _: Result<(), String> = Ok(());
+21 | let _: Result<(), String> = Ok(());
| ^^
error[E0061]: this function takes 2 parameters but 0 parameters were supplied
- --> $DIR/missing-unit-argument.rs:16:5
+ --> $DIR/missing-unit-argument.rs:22:5
|
11 | fn foo(():(), ():()) {}
| ----------------------- defined here
...
-16 | foo();
+22 | foo();
| ^^^^^ expected 2 parameters
error[E0061]: this function takes 2 parameters but 1 parameter was supplied
- --> $DIR/missing-unit-argument.rs:17:9
+ --> $DIR/missing-unit-argument.rs:23:9
|
11 | fn foo(():(), ():()) {}
| ----------------------- defined here
...
-17 | foo(());
+23 | foo(());
| ^^ expected 2 parameters
error[E0061]: this function takes 1 parameter but 0 parameters were supplied
- --> $DIR/missing-unit-argument.rs:18:5
+ --> $DIR/missing-unit-argument.rs:24:5
|
12 | fn bar(():()) {}
| ---------------- defined here
...
-18 | bar();
+24 | bar();
| ^^^^^
|
-help: expected the unit value `()`. You can create one with a pair of parenthesis
+help: expected the unit value `()`; create it with empty parentheses
|
-18 | bar(());
+24 | bar(());
| ^^
-error: aborting due to 4 previous errors
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+ --> $DIR/missing-unit-argument.rs:25:7
+ |
+16 | fn baz(self, (): ()) { }
+ | ------------------------ defined here
+...
+25 | S.baz();
+ | ^^^
+ |
+help: expected the unit value `()`; create it with empty parentheses
+ |
+25 | S.baz(());
+ | ^^
+
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+ --> $DIR/missing-unit-argument.rs:26:7
+ |
+17 | fn generic<T>(self, _: T) { }
+ | ----------------------------- defined here
+...
+26 | S.generic::<()>();
+ | ^^^^^^^
+ |
+help: expected the unit value `()`; create it with empty parentheses
+ |
+26 | S.generic::<()>(());
+ | ^^
+
+error: aborting due to 6 previous errors
"x86_64-unknown-freebsd",
"x86_64-unknown-fuchsia",
"x86_64-unknown-linux-gnu",
+ "x86_64-unknown-linux-gnux32",
"x86_64-unknown-linux-musl",
"x86_64-unknown-netbsd",
"x86_64-unknown-redox",
-Subproject commit 25444585592f5da648edd5317fcdd21f2db8bb64
+Subproject commit b62b1b68edcdf23a70cb12f31403c80e97f13634
pub cc: String,
pub cxx: String,
pub cflags: String,
+ pub ar: String,
+ pub linker: Option<String>,
pub llvm_components: String,
pub llvm_cxxflags: String,
pub nodejs: Option<String>,
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- ErrorKind::Help => write!(f, "help"),
+ ErrorKind::Help => write!(f, "help message"),
ErrorKind::Error => write!(f, "error"),
ErrorKind::Note => write!(f, "note"),
ErrorKind::Suggestion => write!(f, "suggestion"),
.reqopt("", "cc", "path to a C compiler", "PATH")
.reqopt("", "cxx", "path to a C++ compiler", "PATH")
.reqopt("", "cflags", "flags for the C compiler", "FLAGS")
+ .optopt("", "ar", "path to an archiver", "PATH")
+ .optopt("", "linker", "path to a linker", "PATH")
.reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
.reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS")
.optopt("", "nodejs", "the name of nodejs", "PATH")
cc: matches.opt_str("cc").unwrap(),
cxx: matches.opt_str("cxx").unwrap(),
cflags: matches.opt_str("cflags").unwrap(),
+ ar: matches.opt_str("ar").unwrap_or("ar".into()),
+ linker: matches.opt_str("linker"),
llvm_components: matches.opt_str("llvm-components").unwrap(),
llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
nodejs: matches.opt_str("nodejs"),
logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
logv(c, format!("adb_device_status: {}",
config.adb_device_status));
+ logv(c, format!("ar: {}", config.ar));
+ logv(c, format!("linker: {:?}", config.linker));
logv(c, format!("verbose: {}", config.verbose));
logv(c, format!("quiet: {}", config.quiet));
logv(c, "\n".to_string());
None => {
if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
self.error(
- &format!("{}:{}: unexpected {:?}: '{}'",
+ &format!("{}:{}: unexpected {}: '{}'",
file_name,
actual_error.line_num,
actual_error.kind.as_ref()
.arg("-o").arg(out_dir)
.arg(&self.testpaths.file)
.args(&self.props.compile_flags);
+ if let Some(ref linker) = self.config.linker {
+ rustdoc.arg("--linker").arg(linker).arg("-Z").arg("unstable-options");
+ }
self.compose_and_run_compiler(rustdoc, None)
}
} else {
rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
}
+ if let Some(ref linker) = self.config.linker {
+ rustc.arg(format!("-Clinker={}", linker));
+ }
rustc.args(&self.props.compile_flags);
.env("LLVM_COMPONENTS", &self.config.llvm_components)
.env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags);
+ if let Some(ref linker) = self.config.linker {
+ cmd.env("RUSTC_LINKER", linker);
+ }
+
// We don't want RUSTFLAGS set from the outside to interfere with
// compiler flags set in the test cases:
cmd.env_remove("RUSTFLAGS");
.env("CXX", &self.config.cxx);
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
- .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags));
+ .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
+ .env("AR", &self.config.ar);
if self.config.target.contains("windows") {
cmd.env("IS_WINDOWS", "1");
-Subproject commit 22eb5241c0ee5bb7eaf95e270a2b1500e82bf767
+Subproject commit 16a478368c8dcc0c0ee47372a9f663b23d28b097
#
# There are three states a tool can be in:
# 1. Broken: The tool doesn't build
-# 2. Building: The tool builds but its tests are failing
+# 2. Compiling: The tool builds but its tests are failing
# 3. Testing: The tool builds and its tests are passing
#
# In the future there will be further states like "Distributing", which
miri = "Broken"
# ping @Manishearth @llogiq @mcarton @oli-obk
-clippy = "Broken"
+clippy = "Compiling"
# ping @nrc
rls = "Testing"