version.texi
.cargo
!src/vendor/**
+/src/target/
-language: minimal
+language: generic
sudo: required
dist: trusty
services:
echo "#### Disk usage before running script:";
df -h;
du . | sort -nr | head -n100
-
-script:
- >
if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
- echo skipping, not a full build
+ export RUN_SCRIPT="echo 'skipping, not a full build'";
else
- stamp src/ci/init_repo.sh . "$HOME/rustsrc" &&
+ RUN_SCRIPT="stamp src/ci/init_repo.sh . $HOME/rustsrc";
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- stamp src/ci/run.sh;
+ export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/run.sh";
else
- stamp src/ci/docker/run.sh $IMAGE;
+ export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/docker/run.sh $IMAGE";
fi
fi
+script:
+ - sh -x -c "$RUN_SCRIPT"
+
after_success:
- >
echo "#### Build successful; Disk usage after running script:";
dependencies = [
"build_helper 0.1.0",
"core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
]
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
"build_helper 0.1.0",
"cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
dependencies = [
"build_helper 0.1.0",
"core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "gcc"
-version = "0.3.46"
+version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (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.0.0"
dependencies = [
"build_helper 0.1.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_bitflags 0.0.0",
]
version = "0.0.0"
dependencies = [
"flate 0.0.0",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"arena 0.0.0",
"build_helper 0.1.0",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"collections 0.0.0",
"compiler_builtins 0.0.0",
"core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
[[package]]
name = "tar"
-version = "0.4.12"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
-"checksum gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "181e3cebba1d663bd92eb90e2da787e10597e027eb00de8d742b260a7850948f"
+"checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9de9df4358c17e448a778d90cd0272e1dab5eae30244502333fa2001c4e24357"
"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047"
"checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791"
-"checksum tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0ef9ead2fe0aa9e18475a96a207bfd5143f4124779ef7429503a8665416ce8"
+"checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
toml = "0.1"
getopts = "0.2"
rustc-serialize = "0.3"
-gcc = "0.3.46"
+gcc = "0.3.50"
libc = "0.2"
/// otherwise just implements a few lint-like checks that are specific to the
/// compiler itself.
pub fn tidy(build: &Build, host: &str) {
+ let _folder = build.fold_output(|| "tidy");
println!("tidy check ({})", host);
let compiler = Compiler::new(0, host);
let mut cmd = build.tool_cmd(&compiler, "tidy");
if !build.config.vendor {
cmd.arg("--no-vendor");
}
+ if build.config.quiet_tests {
+ cmd.arg("--quiet");
+ }
build.run(&mut cmd);
}
target: &str,
mode: &str,
suite: &str) {
+ let _folder = build.fold_output(|| format!("test_{}", suite));
println!("Check compiletest suite={} mode={} ({} -> {})",
suite, mode, compiler.host, target);
let mut cmd = Command::new(build.tool(&Compiler::new(0, compiler.host),
cmd.arg("--android-cross-path").arg("");
}
+ build.ci_env.force_coloring_in_ci(&mut cmd);
+
let _time = util::timeit();
build.run(&mut cmd);
}
// tests for all files that end in `*.md`
let mut stack = vec![build.src.join("src/doc")];
let _time = util::timeit();
+ let _folder = build.fold_output(|| "test_docs");
while let Some(p) = stack.pop() {
if p.is_dir() {
/// generate a markdown file from the error indexes of the code base which is
/// then passed to `rustdoc --test`.
pub fn error_index(build: &Build, compiler: &Compiler) {
+ let _folder = build.fold_output(|| "test_error_index");
println!("Testing error-index stage{}", compiler.stage);
let dir = testdir(build, compiler.host);
cmd.arg(markdown);
cmd.env("RUSTC_BOOTSTRAP", "1");
- let mut test_args = build.flags.cmd.test_args().join(" ");
- if build.config.quiet_tests {
- test_args.push_str(" --quiet");
- }
+ let test_args = build.flags.cmd.test_args().join(" ");
cmd.arg("--test-args").arg(test_args);
- build.run(&mut cmd);
+ if build.config.quiet_tests {
+ build.run_quiet(&mut cmd);
+ } else {
+ build.run(&mut cmd);
+ }
}
/// Run all unit tests plus documentation tests for an entire crate DAG defined
}
_ => panic!("can only test libraries"),
};
+ let _folder = build.fold_output(|| {
+ format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name)
+ });
println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
compiler.host, target);
let libdir = build.sysroot_libdir(compiler, target);
t!(fs::create_dir_all(&libdir));
+ let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
compiler.host, target);
/// the build using the `compiler` targeting the `target` architecture. The
/// artifacts created will also be linked into the sysroot directory.
pub fn test(build: &Build, target: &str, compiler: &Compiler) {
+ let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
compiler.host, target);
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
+ let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
println!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, compiler.host, target);
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
+ let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
println!("Building stage{} tool {} ({})", stage, tool, target);
let compiler = Compiler::new(stage, &build.config.build);
use build_helper::{run_silent, run_suppressed, output, mtime};
-use util::{exe, libdir, add_lib_path};
+use util::{exe, libdir, add_lib_path, OutputFolder, CiEnv};
mod cc;
mod channel;
crates: HashMap<String, Crate>,
is_sudo: bool,
src_is_git: bool,
+ ci_env: CiEnv,
}
#[derive(Debug)]
lldb_python_dir: None,
is_sudo: is_sudo,
src_is_git: src_is_git,
+ ci_env: CiEnv::current(),
}
}
if self.config.vendor || self.is_sudo {
cargo.arg("--frozen");
}
+
+ self.ci_env.force_coloring_in_ci(&mut cargo);
+
return cargo
}
"nightly" | _ => true,
}
}
+
+ /// Fold the output of the commands after this method into a group. The fold
+ /// ends when the returned object is dropped. Folding can only be used in
+ /// the Travis CI environment.
+ pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
+ where D: Into<String>, F: FnOnce() -> D
+ {
+ if self.ci_env == CiEnv::Travis {
+ Some(OutputFolder::new(name().into()))
+ } else {
+ None
+ }
+ }
}
impl<'a> Compiler<'a> {
drop(fs::remove_dir_all(&out_dir));
}
+ let _folder = build.fold_output(|| "llvm");
println!("Building LLVM for {}", target);
let _time = util::timeit();
t!(fs::create_dir_all(&out_dir));
return
}
+ let _folder = build.fold_output(|| "build_test_helpers");
println!("Building test helpers");
t!(fs::create_dir_all(&dst));
let mut cfg = gcc::Config::new();
use std::env;
use std::ffi::OsString;
use std::fs;
-use std::io;
+use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::Command;
-use std::time::Instant;
+use std::time::{SystemTime, Instant};
use filetime::{self, FileTime};
}
}
}
+
+/// An RAII structure that indicates all output until this instance is dropped
+/// is part of the same group.
+///
+/// On Travis CI, these output will be folded by default, together with the
+/// elapsed time in this block. This reduces noise from unnecessary logs,
+/// allowing developers to quickly identify the error.
+///
+/// Travis CI supports folding by printing `travis_fold:start:<name>` and
+/// `travis_fold:end:<name>` around the block. Time elapsed is recognized
+/// similarly with `travis_time:[start|end]:<name>`. These are undocumented, but
+/// can easily be deduced from source code of the [Travis build commands].
+///
+/// [Travis build commands]:
+/// https://github.com/travis-ci/travis-build/blob/f603c0089/lib/travis/build/templates/header.sh
+pub struct OutputFolder {
+ name: String,
+ start_time: SystemTime, // we need SystemTime to get the UNIX timestamp.
+}
+
+impl OutputFolder {
+ /// Creates a new output folder with the given group name.
+ pub fn new(name: String) -> OutputFolder {
+ // "\r" moves the cursor to the beginning of the line, and "\x1b[0K" is
+ // the ANSI escape code to clear from the cursor to end of line.
+ // Travis seems to have trouble when _not_ using "\r\x1b[0K", that will
+ // randomly put lines to the top of the webpage.
+ print!("travis_fold:start:{0}\r\x1b[0Ktravis_time:start:{0}\r\x1b[0K", name);
+ OutputFolder {
+ name,
+ start_time: SystemTime::now(),
+ }
+ }
+}
+
+impl Drop for OutputFolder {
+ fn drop(&mut self) {
+ use std::time::*;
+ use std::u64;
+
+ fn to_nanos(duration: Result<Duration, SystemTimeError>) -> u64 {
+ match duration {
+ Ok(d) => d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64,
+ Err(_) => u64::MAX,
+ }
+ }
+
+ let end_time = SystemTime::now();
+ let duration = end_time.duration_since(self.start_time);
+ let start = self.start_time.duration_since(UNIX_EPOCH);
+ let finish = end_time.duration_since(UNIX_EPOCH);
+ println!(
+ "travis_fold:end:{0}\r\x1b[0K\n\
+ travis_time:end:{0}:start={1},finish={2},duration={3}\r\x1b[0K",
+ self.name,
+ to_nanos(start),
+ to_nanos(finish),
+ to_nanos(duration)
+ );
+ io::stdout().flush().unwrap();
+ }
+}
+
+/// The CI environment rustbuild is running in. This mainly affects how the logs
+/// are printed.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum CiEnv {
+ /// Not a CI environment.
+ None,
+ /// The Travis CI environment, for Linux (including Docker) and macOS builds.
+ Travis,
+ /// The AppVeyor environment, for Windows builds.
+ AppVeyor,
+}
+
+impl CiEnv {
+ /// Obtains the current CI environment.
+ pub fn current() -> CiEnv {
+ if env::var("TRAVIS").ok().map_or(false, |e| &*e == "true") {
+ CiEnv::Travis
+ } else if env::var("APPVEYOR").ok().map_or(false, |e| &*e == "True") {
+ CiEnv::AppVeyor
+ } else {
+ CiEnv::None
+ }
+ }
+
+ /// If in a CI environment, forces the command to run with colors.
+ pub fn force_coloring_in_ci(self, cmd: &mut Command) {
+ if self != CiEnv::None {
+ // Due to use of stamp/docker, the output stream of rustbuild is not
+ // a TTY in CI, so coloring is by-default turned off.
+ // The explicit `TERM=xterm` environment is needed for
+ // `--color always` to actually work. This env var was lost when
+ // compiling through the Makefile. Very strange.
+ cmd.env("TERM", "xterm").args(&["--color", "always"]);
+ }
+ }
+}
\ No newline at end of file
source "$ci_dir/shared.sh"
+travis_fold start build_docker
+travis_time_start
+
if [ -f "$docker_dir/$image/Dockerfile" ]; then
retry docker \
build \
exit 1
fi
+travis_fold end build_docker
+travis_time_finish
+
objdir=$root_dir/obj
mkdir -p $HOME/.cargo
--env DEPLOY=$DEPLOY \
--env DEPLOY_ALT=$DEPLOY_ALT \
--env LOCAL_USER_ID=`id -u` \
+ --env TRAVIS=${TRAVIS-false} \
--volume "$HOME/.cargo:/cargo" \
--volume "$HOME/rustsrc:$HOME/rustsrc" \
--privileged \
set -o pipefail
set -o nounset
-set -o xtrace
-
ci_dir=$(cd $(dirname $0) && pwd)
. "$ci_dir/shared.sh"
+travis_fold start init_repo
+
REPO_DIR="$1"
CACHE_DIR="$2"
# Wipe the cache if it's not valid, or mark it as invalid while we update it
if [ ! -f "$cache_valid_file" ]; then
+ echo "Invalid cache, wiping ($cache_valid_file missing)"
rm -rf "$CACHE_DIR"
mkdir "$CACHE_DIR"
else
rm -rf "$CACHE_DIR"
mkdir "$CACHE_DIR"
else
+ echo "Valid cache ($cache_valid_file exists)"
rm "$cache_valid_file"
fi
fi
+travis_fold start update_cache
+travis_time_start
+
# Update the cache (a pristine copy of the rust source master)
if [ ! -d "$cache_src_dir/.git" ]; then
retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
git submodule deinit -f . && git submodule sync && git submodule update --init"
# Cache was updated without errors, mark it as valid
+echo "Refreshed cache (touch $cache_valid_file)"
touch "$cache_valid_file"
+travis_fold end update_cache
+travis_time_finish
+
+travis_fold start update_submodules
+travis_time_start
+
# Update the submodules of the repo we're in, using the pristine repo as
# a cache for any object files
# No, `git submodule foreach` won't work:
retry sh -c "git submodule deinit -f $module && \
git submodule update --init --reference $cache_src_dir/$module $module"
done
+
+travis_fold end update_submodules
+travis_time_finish
+
+travis_fold end init_repo
fi
fi
+travis_fold start configure
+travis_time_start
$SRC/configure $RUST_CONFIGURE_ARGS
+travis_fold end configure
+travis_time_finish
+
+travis_fold start make-prepare
+travis_time_start
retry make prepare
+travis_fold end make-prepare
+travis_time_finish
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
ncpus=$(sysctl -n hw.ncpu)
ncpus=$(grep processor /proc/cpuinfo | wc -l)
fi
-set -x
-
if [ ! -z "$SCRIPT" ]; then
sh -x -c "$SCRIPT"
else
- make -j $ncpus tidy
- make -j $ncpus
- make $RUST_CHECK_TARGET -j $ncpus
+ do_make() {
+ travis_fold start "make-$1"
+ travis_time_start
+ echo "make -j $ncpus $1"
+ make -j $ncpus "$1"
+ local retval=$?
+ travis_fold end "make-$1"
+ travis_time_finish
+ return $retval
+ }
+
+ do_make tidy
+ do_make all
+ do_make "$RUST_CHECK_TARGET"
fi
}
done
}
+
+if ! declare -F travis_fold; then
+ if [ "${TRAVIS-false}" = 'true' ]; then
+ # This is a trimmed down copy of
+ # https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/templates/header.sh
+ travis_fold() {
+ echo -en "travis_fold:$1:$2\r\033[0K"
+ }
+ travis_time_start() {
+ travis_timer_id=$(printf %08x $(( RANDOM * RANDOM )))
+ travis_start_time=$(travis_nanoseconds)
+ echo -en "travis_time:start:$travis_timer_id\r\033[0K"
+ }
+ travis_time_finish() {
+ travis_end_time=$(travis_nanoseconds)
+ local duration=$(($travis_end_time-$travis_start_time))
+ local msg="travis_time:end:$travis_timer_id"
+ echo -en "\n$msg:start=$travis_start_time,finish=$travis_end_time,duration=$duration\r\033[0K"
+ }
+ if [ $(uname) = 'Darwin' ]; then
+ travis_nanoseconds() {
+ date -u '+%s000000000'
+ }
+ else
+ travis_nanoseconds() {
+ date -u '+%s%N'
+ }
+ fi
+ else
+ travis_fold() { return 0; }
+ travis_time_start() { return 0; }
+ travis_time_finish() { return 0; }
+ fi
+fi
- [sip_hash_13](library-features/sip-hash-13.md)
- [slice_concat_ext](library-features/slice-concat-ext.md)
- [slice_get_slice](library-features/slice-get-slice.md)
+ - [slice_rotate](library-features/slice-rotate.md)
- [slice_rsplit](library-features/slice-rsplit.md)
- [sort_internals](library-features/sort-internals.md)
- [sort_unstable](library-features/sort-unstable.md)
--- /dev/null
+# `slice_rotate`
+
+The tracking issue for this feature is: [#41891]
+
+[#41891]: https://github.com/rust-lang/rust/issues/41891
+
+------------------------
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
[features]
debug = []
#![feature(i128_type)]
#![feature(rand)]
#![feature(repr_simd)]
+#![feature(slice_rotate)]
#![feature(sort_unstable)]
#![feature(test)]
rng.gen_iter::<u64>().take(len).collect()
}
+fn gen_random_bytes(len: usize) -> Vec<u8> {
+ let mut rng = thread_rng();
+ rng.gen_iter::<u8>().take(len).collect()
+}
+
fn gen_mostly_ascending(len: usize) -> Vec<u64> {
let mut rng = thread_rng();
let mut v = gen_ascending(len);
reverse!(reverse_u128, u128, |x| x as u128);
#[repr(simd)] struct F64x4(f64, f64, f64, f64);
reverse!(reverse_simd_f64x4, F64x4, |x| { let x = x as f64; F64x4(x,x,x,x) });
+
+macro_rules! rotate {
+ ($name:ident, $gen:expr, $len:expr, $mid:expr) => {
+ #[bench]
+ fn $name(b: &mut Bencher) {
+ let size = mem::size_of_val(&$gen(1)[0]);
+ let mut v = $gen($len * 8 / size);
+ b.iter(|| black_box(&mut v).rotate(($mid*8+size-1)/size));
+ b.bytes = (v.len() * size) as u64;
+ }
+ }
+}
+
+rotate!(rotate_tiny_by1, gen_random, 16, 1);
+rotate!(rotate_tiny_half, gen_random, 16, 16/2);
+rotate!(rotate_tiny_half_plus_one, gen_random, 16, 16/2+1);
+
+rotate!(rotate_medium_by1, gen_random, 9158, 1);
+rotate!(rotate_medium_by727_u64, gen_random, 9158, 727);
+rotate!(rotate_medium_by727_bytes, gen_random_bytes, 9158, 727);
+rotate!(rotate_medium_by727_strings, gen_strings, 9158, 727);
+rotate!(rotate_medium_half, gen_random, 9158, 9158/2);
+rotate!(rotate_medium_half_plus_one, gen_random, 9158, 9158/2+1);
+
+// Intended to use more RAM than the machine has cache
+rotate!(rotate_huge_by1, gen_random, 5*1024*1024, 1);
+rotate!(rotate_huge_by9199_u64, gen_random, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_bytes, gen_random_bytes, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_strings, gen_strings, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_big, gen_big_random, 5*1024*1024, 9199);
+rotate!(rotate_huge_by1234577_u64, gen_random, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_bytes, gen_random_bytes, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_strings, gen_strings, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_big, gen_big_random, 5*1024*1024, 1234577);
+rotate!(rotate_huge_half, gen_random, 5*1024*1024, 5*1024*1024/2);
+rotate!(rotate_huge_half_plus_one, gen_random, 5*1024*1024, 5*1024*1024/2+1);
#![feature(shared)]
#![feature(slice_get_slice)]
#![feature(slice_patterns)]
+#![cfg_attr(not(test), feature(slice_rotate))]
#![feature(slice_rsplit)]
#![cfg_attr(not(test), feature(sort_unstable))]
#![feature(specialization)]
core_slice::SliceExt::sort_unstable_by_key(self, f);
}
+ /// Permutes the slice in-place such that `self[mid..]` moves to the
+ /// beginning of the slice while `self[..mid]` moves to the end of the
+ /// slice. Equivalently, rotates the slice `mid` places to the left
+ /// or `k = self.len() - mid` places to the right.
+ ///
+ /// This is a "k-rotation", a permutation in which item `i` moves to
+ /// position `i + k`, modulo the length of the slice. See _Elements
+ /// of Programming_ [§10.4][eop].
+ ///
+ /// Rotation by `mid` and rotation by `k` are inverse operations.
+ ///
+ /// [eop]: https://books.google.com/books?id=CO9ULZGINlsC&pg=PA178&q=k-rotation
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `mid` is greater than the length of the
+ /// slice. (Note that `mid == self.len()` does _not_ panic; it's a nop
+ /// rotation with `k == 0`, the inverse of a rotation with `mid == 0`.)
+ ///
+ /// # Complexity
+ ///
+ /// Takes linear (in `self.len()`) time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_rotate)]
+ ///
+ /// let mut a = [1, 2, 3, 4, 5, 6, 7];
+ /// let mid = 2;
+ /// a.rotate(mid);
+ /// assert_eq!(&a, &[3, 4, 5, 6, 7, 1, 2]);
+ /// let k = a.len() - mid;
+ /// a.rotate(k);
+ /// assert_eq!(&a, &[1, 2, 3, 4, 5, 6, 7]);
+ ///
+ /// use std::ops::Range;
+ /// fn slide<T>(slice: &mut [T], range: Range<usize>, to: usize) {
+ /// if to < range.start {
+ /// slice[to..range.end].rotate(range.start-to);
+ /// } else if to > range.end {
+ /// slice[range.start..to].rotate(range.end-range.start);
+ /// }
+ /// }
+ /// let mut v: Vec<_> = (0..10).collect();
+ /// slide(&mut v, 1..4, 7);
+ /// assert_eq!(&v, &[0, 4, 5, 6, 1, 2, 3, 7, 8, 9]);
+ /// slide(&mut v, 6..8, 1);
+ /// assert_eq!(&v, &[0, 3, 7, 4, 5, 6, 1, 2, 8, 9]);
+ /// ```
+ #[unstable(feature = "slice_rotate", issue = "41891")]
+ pub fn rotate(&mut self, mid: usize) {
+ core_slice::SliceExt::rotate(self, mid);
+ }
+
/// Copies the elements from `src` into `self`.
///
/// The length of `src` must be the same as `self`.
#![feature(collections)]
#![feature(const_fn)]
#![feature(exact_size_is_empty)]
+#![feature(iterator_step_by)]
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
+#![feature(slice_rotate)]
#![feature(splice)]
-#![feature(step_by)]
#![feature(str_escape)]
#![feature(test)]
#![feature(unboxed_closures)]
}
}
+#[test]
+fn test_rotate() {
+ let expected: Vec<_> = (0..13).collect();
+ let mut v = Vec::new();
+
+ // no-ops
+ v.clone_from(&expected);
+ v.rotate(0);
+ assert_eq!(v, expected);
+ v.rotate(expected.len());
+ assert_eq!(v, expected);
+ let mut zst_array = [(), (), ()];
+ zst_array.rotate(2);
+
+ // happy path
+ v = (5..13).chain(0..5).collect();
+ v.rotate(8);
+ assert_eq!(v, expected);
+
+ let expected: Vec<_> = (0..1000).collect();
+
+ // small rotations in large slice, uses ptr::copy
+ v = (2..1000).chain(0..2).collect();
+ v.rotate(998);
+ assert_eq!(v, expected);
+ v = (998..1000).chain(0..998).collect();
+ v.rotate(2);
+ assert_eq!(v, expected);
+
+ // non-small prime rotation, has a few rounds of swapping
+ v = (389..1000).chain(0..389).collect();
+ v.rotate(1000-389);
+ assert_eq!(v, expected);
+}
+
#[test]
fn test_concat() {
let v: [Vec<i32>; 0] = [];
let u: Vec<_> = deq.iter().cloned().collect();
assert_eq!(u, v);
- let seq = (0..).step_by(2).take(256);
+ // FIXME #27741: Remove `.skip(0)` when Range::step_by is fully removed
+ let seq = (0..).skip(0).step_by(2).take(256);
let deq: VecDeque<_> = seq.collect();
for (i, &x) in deq.iter().enumerate() {
assert_eq!(2 * i, x);
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
pub fn atomic_umax_rel<T>(dst: *mut T, src: T) -> T;
pub fn atomic_umax_acqrel<T>(dst: *mut T, src: T) -> T;
pub fn atomic_umax_relaxed<T>(dst: *mut T, src: T) -> T;
+
+ /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+ /// if supported; otherwise, it is a noop.
+ /// Prefetches have no effect on the behavior of the program but can change its performance
+ /// characteristics.
+ ///
+ /// The `locality` argument must be a constant integer and is a temporal locality specifier
+ /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+ #[cfg(not(stage0))]
+ pub fn prefetch_read_data<T>(data: *const T, locality: i32);
+ /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+ /// if supported; otherwise, it is a noop.
+ /// Prefetches have no effect on the behavior of the program but can change its performance
+ /// characteristics.
+ ///
+ /// The `locality` argument must be a constant integer and is a temporal locality specifier
+ /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+ #[cfg(not(stage0))]
+ pub fn prefetch_write_data<T>(data: *const T, locality: i32);
+ /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+ /// if supported; otherwise, it is a noop.
+ /// Prefetches have no effect on the behavior of the program but can change its performance
+ /// characteristics.
+ ///
+ /// The `locality` argument must be a constant integer and is a temporal locality specifier
+ /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+ #[cfg(not(stage0))]
+ pub fn prefetch_read_instruction<T>(data: *const T, locality: i32);
+ /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+ /// if supported; otherwise, it is a noop.
+ /// Prefetches have no effect on the behavior of the program but can change its performance
+ /// characteristics.
+ ///
+ /// The `locality` argument must be a constant integer and is a temporal locality specifier
+ /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+ #[cfg(not(stage0))]
+ pub fn prefetch_write_instruction<T>(data: *const T, locality: i32);
}
+// Empty bootstrap implementations for stage0 compilation
+#[cfg(stage0)]
+pub fn prefetch_read_data<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_write_data<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_read_instruction<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_write_instruction<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+
extern "rust-intrinsic" {
pub fn atomic_fence();
pub use self::range::Step;
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+#[rustc_deprecated(since = "1.19.0",
+ reason = "replaced by `iter::StepBy`")]
+#[allow(deprecated)]
pub use self::range::StepBy as DeprecatedStepBy;
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone, Debug)]
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+#[rustc_deprecated(since = "1.19.0",
+ reason = "replaced by `iter::StepBy`")]
+#[allow(deprecated)]
pub struct StepBy<A, R> {
step_by: A,
range: R,
/// ```
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+ #[rustc_deprecated(since = "1.19.0",
+ reason = "replaced by `Iterator::step_by`")]
+ #[allow(deprecated)]
pub fn step_by(self, by: A) -> StepBy<A, Self> {
StepBy {
step_by: by,
/// ```
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+ #[rustc_deprecated(since = "1.19.0",
+ reason = "replaced by `Iterator::step_by`")]
+ #[allow(deprecated)]
pub fn step_by(self, by: A) -> StepBy<A, Self> {
StepBy {
step_by: by,
/// ```
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+ #[rustc_deprecated(since = "1.19.0",
+ reason = "replaced by `Iterator::step_by`")]
+ #[allow(deprecated)]
pub fn step_by(self, by: A) -> StepBy<A, Self> {
StepBy {
step_by: by,
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+#[allow(deprecated)]
impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
A: Clone,
for<'a> &'a A: Add<&'a A, Output = A>
}
#[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
+#[allow(deprecated)]
impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
type Item = A;
}
#[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {}
#[unstable(feature = "inclusive_range",
reason = "recently added, follows RFC",
issue = "28237")]
+#[allow(deprecated)]
impl<A: Step + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
type Item = A;
}
#[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {}
macro_rules! range_exact_iter_impl {
use marker::{Copy, Send, Sync, Sized, self};
use iter_private::TrustedRandomAccess;
+mod rotate;
mod sort;
#[repr(C)]
#[stable(feature = "core", since = "1.6.0")]
fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
+ #[unstable(feature = "slice_rotate", issue = "41891")]
+ fn rotate(&mut self, mid: usize);
+
#[stable(feature = "clone_from_slice", since = "1.7.0")]
fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone;
self.binary_search_by(|p| p.borrow().cmp(x))
}
+ fn rotate(&mut self, mid: usize) {
+ assert!(mid <= self.len());
+ let k = self.len() - mid;
+
+ unsafe {
+ let p = self.as_mut_ptr();
+ rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+ }
+ }
+
#[inline]
fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
assert!(self.len() == src.len(),
--- /dev/null
+// Copyright 2012-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 cmp;
+use mem;
+use ptr;
+
+/// Rotation is much faster if it has access to a little bit of memory. This
+/// union provides a RawVec-like interface, but to a fixed-size stack buffer.
+#[allow(unions_with_drop_fields)]
+union RawArray<T> {
+ /// Ensure this is appropriately aligned for T, and is big
+ /// enough for two elements even if T is enormous.
+ typed: [T; 2],
+ /// For normally-sized types, especially things like u8, having more
+ /// than 2 in the buffer is necessary for usefulness, so pad it out
+ /// enough to be helpful, but not so big as to risk overflow.
+ _extra: [usize; 32],
+}
+
+impl<T> RawArray<T> {
+ fn new() -> Self {
+ unsafe { mem::uninitialized() }
+ }
+ fn ptr(&self) -> *mut T {
+ unsafe { &self.typed as *const T as *mut T }
+ }
+ fn cap() -> usize {
+ if mem::size_of::<T>() == 0 {
+ usize::max_value()
+ } else {
+ mem::size_of::<Self>() / mem::size_of::<T>()
+ }
+ }
+}
+
+/// Rotates the range `[mid-left, mid+right)` such that the element at `mid`
+/// becomes the first element. Equivalently, rotates the range `left`
+/// elements to the left or `right` elements to the right.
+///
+/// # Safety
+///
+/// The specified range must be valid for reading and writing.
+/// The type `T` must have non-zero size.
+///
+/// # Algorithm
+///
+/// For longer rotations, swap the left-most `delta = min(left, right)`
+/// elements with the right-most `delta` elements. LLVM vectorizes this,
+/// which is profitable as we only reach this step for a "large enough"
+/// rotation. Doing this puts `delta` elements on the larger side into the
+/// correct position, leaving a smaller rotate problem. Demonstration:
+///
+/// ```text
+/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ]
+/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ]
+/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13
+/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13
+/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13
+/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13
+/// ```
+///
+/// Once the rotation is small enough, copy some elements into a stack
+/// buffer, `memmove` the others, and move the ones back from the buffer.
+pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
+ loop {
+ let delta = cmp::min(left, right);
+ if delta <= RawArray::<T>::cap() {
+ break;
+ }
+
+ ptr_swap_n(
+ mid.offset(-(left as isize)),
+ mid.offset((right-delta) as isize),
+ delta);
+
+ if left <= right {
+ right -= delta;
+ } else {
+ left -= delta;
+ }
+ }
+
+ let rawarray = RawArray::new();
+ let buf = rawarray.ptr();
+
+ let dim = mid.offset(-(left as isize)).offset(right as isize);
+ if left <= right {
+ ptr::copy_nonoverlapping(mid.offset(-(left as isize)), buf, left);
+ ptr::copy(mid, mid.offset(-(left as isize)), right);
+ ptr::copy_nonoverlapping(buf, dim, left);
+ }
+ else {
+ ptr::copy_nonoverlapping(mid, buf, right);
+ ptr::copy(mid.offset(-(left as isize)), dim, left);
+ ptr::copy_nonoverlapping(buf, mid.offset(-(left as isize)), right);
+ }
+}
+
+unsafe fn ptr_swap_n<T>(a: *mut T, b: *mut T, n: usize) {
+ for i in 0..n {
+ // These are nonoverlapping, so use mem::swap instead of ptr::swap
+ mem::swap(&mut *a.offset(i as isize), &mut *b.offset(i as isize));
+ }
+}
use core::{i8, i16, isize};
use core::usize;
+// FIXME #27741: This is here to simplify calling Iterator::step_by. Remove
+// once Range::step_by is completely gone (not just deprecated).
+trait IterEx: Sized {
+ fn iter_step_by(self, n: usize) -> StepBy<Self>;
+}
+impl<I:Iterator> IterEx for I {
+ fn iter_step_by(self, n: usize) -> StepBy<Self> { self.step_by(n) }
+}
+
#[test]
fn test_lt() {
let empty: [isize; 0] = [];
#[test]
fn test_counter_from_iter() {
- let it = (0..).step_by(5).take(10);
+ let it = (0..).iter_step_by(5).take(10);
let xs: Vec<isize> = FromIterator::from_iter(it);
assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}
}
assert_eq!(i, expected.len());
- let ys = (30..).step_by(10).take(4);
+ let ys = (30..).iter_step_by(10).take(4);
let it = xs.iter().cloned().chain(ys);
let mut i = 0;
for x in it {
#[test]
fn test_iterator_step_by() {
// Identity
- // Replace with (0..).step_by(1) after Range::step_by gets removed
- let mut it = Iterator::step_by((0..), 1).take(3);
+ let mut it = (0..).iter_step_by(1).take(3);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(1));
assert_eq!(it.next(), Some(2));
assert_eq!(it.next(), None);
- // Replace with (0..).step_by(3) after Range::step_by gets removed
- let mut it = Iterator::step_by((0..), 3).take(4);
+ let mut it = (0..).iter_step_by(3).take(4);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(3));
assert_eq!(it.next(), Some(6));
#[test]
#[should_panic]
fn test_iterator_step_by_zero() {
- // Replace with (0..).step_by(0) after Range::step_by gets removed
- let mut it = Iterator::step_by((0..), 0);
+ let mut it = (0..).iter_step_by(0);
it.next();
}
#[test]
fn test_filter_map() {
- let it = (0..).step_by(1).take(10)
+ let it = (0..).iter_step_by(1).take(10)
.filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
}
fn test_iterator_flat_map() {
let xs = [0, 3, 6];
let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
- let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
+ let it = xs.iter().flat_map(|&x| (x..).iter_step_by(1).take(3));
let mut i = 0;
for x in it {
assert_eq!(x, ys[i]);
#[test]
fn test_cycle() {
let cycle_len = 3;
- let it = (0..).step_by(1).take(cycle_len).cycle();
+ let it = (0..).iter_step_by(1).take(cycle_len).cycle();
assert_eq!(it.size_hint(), (usize::MAX, None));
for (i, x) in it.take(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
- let mut it = (0..).step_by(1).take(0).cycle();
+ let mut it = (0..).iter_step_by(1).take(0).cycle();
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_size_hint() {
- let c = (0..).step_by(1);
+ let c = (0..).iter_step_by(1);
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let v2 = &[10, 11, 12];
let vi = v.iter();
#[test]
fn test_range_step() {
+ #![allow(deprecated)]
+
assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
assert_eq!((20..0).step_by(-5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
assert_eq!((20..0).step_by(-6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
#![feature(raw)]
#![feature(sip_hash_13)]
#![feature(slice_patterns)]
+#![feature(slice_rotate)]
#![feature(sort_internals)]
#![feature(sort_unstable)]
#![feature(specialization)]
assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3));
}
+#[test]
+fn test_rotate() {
+ const N: usize = 600;
+ let a: &mut [_] = &mut [0; N];
+ for i in 0..N {
+ a[i] = i;
+ }
+
+ a.rotate(42);
+ let k = N - 42;
+
+ for i in 0..N {
+ assert_eq!(a[(i+k)%N], i);
+ }
+}
+
#[test]
fn sort_unstable() {
let mut v = [0; 600];
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
In particular, using the memoize helper is much better than writing
the obvious code yourself:
-```
+```rust
if let Some(result) = map.get(key) {
return result;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
use rustc_data_structures::stable_hasher;
use std::mem;
use std::slice;
-#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
pub struct Fingerprint(u64, u64);
impl Fingerprint {
}
}
-impl Encodable for Fingerprint {
- #[inline]
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_u64(self.0.to_le())?;
- s.emit_u64(self.1.to_le())
- }
-}
-
-impl Decodable for Fingerprint {
- #[inline]
- fn decode<D: Decoder>(d: &mut D) -> Result<Fingerprint, D::Error> {
- let _0 = u64::from_le(d.read_u64()?);
- let _1 = u64::from_le(d.read_u64()?);
- Ok(Fingerprint(_0, _1))
- }
-}
-
impl ::std::fmt::Display for Fingerprint {
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(formatter, "{:x}-{:x}", self.0, self.1)
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
+
+[target."cfg(windows)".dependencies]
+gcc = "0.3.50"
use super::linker::Linker;
use super::rpath::RPathConfig;
use super::rpath;
-use super::msvc;
use metadata::METADATA_FILENAME;
use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
use rustc::session::filesearch;
return r;
}
-// The third parameter is for an extra path to add to PATH for MSVC
-// cross linkers for host toolchain DLL dependencies
-pub fn get_linker(sess: &Session) -> (String, Command, Option<PathBuf>) {
+// The third parameter is for an env vars, used to set up the path for MSVC
+// to find its DLLs
+pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) {
if let Some(ref linker) = sess.opts.cg.linker {
- (linker.clone(), Command::new(linker), None)
+ (linker.clone(), Command::new(linker), vec![])
} else if sess.target.target.options.is_like_msvc {
- let (cmd, host) = msvc::link_exe_cmd(sess);
- ("link.exe".to_string(), cmd, host)
+ let (cmd, envs) = msvc_link_exe_cmd(sess);
+ ("link.exe".to_string(), cmd, envs)
} else {
(sess.target.target.options.linker.clone(),
- Command::new(&sess.target.target.options.linker), None)
+ Command::new(&sess.target.target.options.linker), vec![])
}
}
+#[cfg(windows)]
+pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
+ use gcc::windows_registry;
+
+ let target = &sess.opts.target_triple;
+ let tool = windows_registry::find_tool(target, "link.exe");
+
+ if let Some(tool) = tool {
+ let envs = tool.env().to_vec();
+ (tool.to_command(), envs)
+ } else {
+ debug!("Failed to locate linker.");
+ (Command::new("link.exe"), vec![])
+ }
+}
+
+#[cfg(not(windows))]
+pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
+ (Command::new("link.exe"), vec![])
+}
+
pub fn get_ar_prog(sess: &Session) -> String {
sess.opts.cg.ar.clone().unwrap_or_else(|| {
sess.target.target.options.ar.clone()
let flavor = sess.linker_flavor();
// The invocations of cc share some flags across platforms
- let (pname, mut cmd, extra) = get_linker(sess);
- cmd.env("PATH", command_path(sess, extra));
+ let (pname, mut cmd, envs) = get_linker(sess);
+ // This will set PATH on MSVC
+ cmd.envs(envs);
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
+++ /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.
-
-#![allow(non_camel_case_types, non_snake_case)]
-
-use libc::c_void;
-use std::mem;
-
-type DWORD = u32;
-type WORD = u16;
-type LPVOID = *mut c_void;
-type DWORD_PTR = usize;
-
-const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0;
-const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9;
-
-#[repr(C)]
-struct SYSTEM_INFO {
- wProcessorArchitecture: WORD,
- _wReserved: WORD,
- _dwPageSize: DWORD,
- _lpMinimumApplicationAddress: LPVOID,
- _lpMaximumApplicationAddress: LPVOID,
- _dwActiveProcessorMask: DWORD_PTR,
- _dwNumberOfProcessors: DWORD,
- _dwProcessorType: DWORD,
- _dwAllocationGranularity: DWORD,
- _wProcessorLevel: WORD,
- _wProcessorRevision: WORD,
-}
-
-extern "system" {
- fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
-}
-
-pub enum Arch {
- X86,
- Amd64,
-}
-
-pub fn host_arch() -> Option<Arch> {
- let mut info = unsafe { mem::zeroed() };
- unsafe { GetNativeSystemInfo(&mut info) };
- match info.wProcessorArchitecture {
- PROCESSOR_ARCHITECTURE_INTEL => Some(Arch::X86),
- PROCESSOR_ARCHITECTURE_AMD64 => Some(Arch::Amd64),
- _ => None,
- }
-}
+++ /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.
-
-//! MSVC-specific logic for linkers and such.
-//!
-//! This module contains a cross-platform interface but has a blank unix
-//! implementation. The Windows implementation builds on top of Windows native
-//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
-//!
-//! Note that we don't have much special logic for finding the system linker on
-//! any other platforms, so it may seem a little odd to single out MSVC to have
-//! a good deal of code just to find the linker. Unlike Unix systems, however,
-//! the MSVC linker is not in the system PATH by default. It also additionally
-//! needs a few environment variables or command line flags to be able to link
-//! against system libraries.
-//!
-//! In order to have a nice smooth experience on Windows, the logic in this file
-//! is here to find the MSVC linker and set it up in the default configuration
-//! one would need to set up anyway. This means that the Rust compiler can be
-//! run not only in the developer shells of MSVC but also the standard cmd.exe
-//! shell or MSYS shells.
-//!
-//! As a high-level note, all logic in this module for looking up various
-//! paths/files is based on Microsoft's logic in their vcvars bat files, but
-//! comments can also be found below leading through the various code paths.
-
-// A simple macro to make this option mess easier to read
-#[cfg(windows)]
-macro_rules! otry {
- ($expr:expr) => (match $expr {
- Some(val) => val,
- None => return None,
- })
-}
-
-#[cfg(windows)]
-mod registry;
-#[cfg(windows)]
-mod arch;
-
-#[cfg(windows)]
-mod platform {
- use std::env;
- use std::ffi::OsString;
- use std::fs;
- use std::path::{Path, PathBuf};
- use std::process::Command;
- use rustc::session::Session;
- use super::arch::{host_arch, Arch};
- use super::registry::LOCAL_MACHINE;
-
- // First we need to figure out whether the environment is already correctly
- // configured by vcvars. We do this by looking at the environment variable
- // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
- // otherwise. If it is defined, then we find `link.exe` in `PATH and trust
- // that everything else is configured correctly.
- //
- // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where
- // it claimed it should be), then we resort to finding everything
- // ourselves. First we find where the latest version of MSVC is installed
- // and what version it is. Then based on the version we find the
- // appropriate SDKs.
- //
- // If despite our best efforts we are still unable to find MSVC then we
- // just blindly call `link.exe` and hope for the best.
- //
- // This code only supports VC 11 through 15. For versions older than that
- // the user will need to manually execute the appropriate vcvars bat file
- // and it should hopefully work.
- //
- // The second member of the tuple we return is the directory for the host
- // linker toolchain, which is necessary when using the cross linkers.
- pub fn link_exe_cmd(sess: &Session) -> (Command, Option<PathBuf>) {
- let arch = &sess.target.target.arch;
- env::var_os("VCINSTALLDIR").and_then(|_| {
- debug!("Detected that vcvars was already run.");
- let path = otry!(env::var_os("PATH"));
- // Mingw has its own link which is not the link we want so we
- // look for `cl.exe` too as a precaution.
- env::split_paths(&path).find(|path| {
- path.join("cl.exe").is_file()
- && path.join("link.exe").is_file()
- }).map(|path| {
- (Command::new(path.join("link.exe")), None)
- })
- }).or_else(|| {
- None.or_else(|| {
- find_msvc_latest(arch, "15.0")
- }).or_else(|| {
- find_msvc_latest(arch, "14.0")
- }).or_else(|| {
- find_msvc_12(arch)
- }).or_else(|| {
- find_msvc_11(arch)
- }).map(|(cmd, path)| (cmd, Some(path)))
- }).unwrap_or_else(|| {
- debug!("Failed to locate linker.");
- (Command::new("link.exe"), None)
- })
- }
-
- // For MSVC 14 or newer we need to find the Universal CRT as well as either
- // the Windows 10 SDK or Windows 8.1 SDK.
- fn find_msvc_latest(arch: &str, ver: &str) -> Option<(Command, PathBuf)> {
- let vcdir = otry!(get_vc_dir(ver));
- let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
- let sub = otry!(lib_subdir(arch));
- let ucrt = otry!(get_ucrt_dir());
- debug!("Found Universal CRT {:?}", ucrt);
- add_lib(&mut cmd, &ucrt.join("ucrt").join(sub));
- if let Some(dir) = get_sdk10_dir() {
- debug!("Found Win10 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(sub));
- } else if let Some(dir) = get_sdk81_dir() {
- debug!("Found Win8.1 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(sub));
- } else {
- return None
- }
- Some((cmd, host))
- }
-
- // For MSVC 12 we need to find the Windows 8.1 SDK.
- fn find_msvc_12(arch: &str) -> Option<(Command, PathBuf)> {
- let vcdir = otry!(get_vc_dir("12.0"));
- let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
- let sub = otry!(lib_subdir(arch));
- let sdk81 = otry!(get_sdk81_dir());
- debug!("Found Win8.1 SDK {:?}", sdk81);
- add_lib(&mut cmd, &sdk81.join("um").join(sub));
- Some((cmd, host))
- }
-
- // For MSVC 11 we need to find the Windows 8 SDK.
- fn find_msvc_11(arch: &str) -> Option<(Command, PathBuf)> {
- let vcdir = otry!(get_vc_dir("11.0"));
- let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
- let sub = otry!(lib_subdir(arch));
- let sdk8 = otry!(get_sdk8_dir());
- debug!("Found Win8 SDK {:?}", sdk8);
- add_lib(&mut cmd, &sdk8.join("um").join(sub));
- Some((cmd, host))
- }
-
- // A convenience function to append library paths.
- fn add_lib(cmd: &mut Command, lib: &Path) {
- let mut arg: OsString = "/LIBPATH:".into();
- arg.push(lib);
- cmd.arg(arg);
- }
-
- // Given a possible MSVC installation directory, we look for the linker and
- // then add the MSVC library path.
- fn get_linker(path: &Path, arch: &str) -> Option<(Command, PathBuf)> {
- debug!("Looking for linker in {:?}", path);
- bin_subdir(arch).into_iter().map(|(sub, host)| {
- (path.join("bin").join(sub).join("link.exe"),
- path.join("bin").join(host))
- }).filter(|&(ref path, _)| {
- path.is_file()
- }).map(|(path, host)| {
- (Command::new(path), host)
- }).filter_map(|(mut cmd, host)| {
- let sub = otry!(vc_lib_subdir(arch));
- add_lib(&mut cmd, &path.join("lib").join(sub));
- Some((cmd, host))
- }).next()
- }
-
- // To find MSVC we look in a specific registry key for the version we are
- // trying to find.
- fn get_vc_dir(ver: &str) -> Option<PathBuf> {
- let key = otry!(LOCAL_MACHINE
- .open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref()).ok());
- let path = otry!(key.query_str(ver).ok());
- Some(path.into())
- }
-
- // To find the Universal CRT we look in a specific registry key for where
- // all the Universal CRTs are located and then sort them asciibetically to
- // find the newest version. While this sort of sorting isn't ideal, it is
- // what vcvars does so that's good enough for us.
- fn get_ucrt_dir() -> Option<PathBuf> {
- let key = otry!(LOCAL_MACHINE
- .open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref()).ok());
- let root = otry!(key.query_str("KitsRoot10").ok());
- let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
- readdir.filter_map(|dir| {
- dir.ok()
- }).map(|dir| {
- dir.path()
- }).filter(|dir| {
- dir.components().last().and_then(|c| {
- c.as_os_str().to_str()
- }).map(|c| {
- c.starts_with("10.") && dir.join("ucrt").is_dir()
- }).unwrap_or(false)
- }).max()
- }
-
- // Vcvars finds the correct version of the Windows 10 SDK by looking
- // for the include `um\Windows.h` because sometimes a given version will
- // only have UCRT bits without the rest of the SDK. Since we only care about
- // libraries and not includes, we instead look for `um\x64\kernel32.lib`.
- // Since the 32-bit and 64-bit libraries are always installed together we
- // only need to bother checking x64, making this code a tiny bit simpler.
- // Like we do for the Universal CRT, we sort the possibilities
- // asciibetically to find the newest one as that is what vcvars does.
- fn get_sdk10_dir() -> Option<PathBuf> {
- let key = otry!(LOCAL_MACHINE
- .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
- let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
- let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
- .map(|dir| dir.path()).collect();
- dirs.sort();
- dirs.into_iter().rev().filter(|dir| {
- dir.join("um").join("x64").join("kernel32.lib").is_file()
- }).next()
- }
-
- // Interestingly there are several subdirectories, `win7` `win8` and
- // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
- // applies to us. Note that if we were targetting kernel mode drivers
- // instead of user mode applications, we would care.
- fn get_sdk81_dir() -> Option<PathBuf> {
- let key = otry!(LOCAL_MACHINE
- .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
- Some(Path::new(&root).join("lib").join("winv6.3"))
- }
-
- fn get_sdk8_dir() -> Option<PathBuf> {
- let key = otry!(LOCAL_MACHINE
- .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
- Some(Path::new(&root).join("lib").join("win8"))
- }
-
- // When choosing the linker toolchain to use, we have to choose the one
- // which matches the host architecture. Otherwise we end up in situations
- // where someone on 32-bit Windows is trying to cross compile to 64-bit and
- // it tries to invoke the native 64-bit linker which won't work.
- //
- // For the return value of this function, the first member of the tuple is
- // the folder of the linker we will be invoking, while the second member
- // is the folder of the host toolchain for that linker which is essential
- // when using a cross linker. We return a Vec since on x64 there are often
- // two linkers that can target the architecture we desire. The 64-bit host
- // linker is preferred, and hence first, due to 64-bit allowing it more
- // address space to work with and potentially being faster.
- //
- // FIXME - Figure out what happens when the host architecture is arm.
- fn bin_subdir(arch: &str) -> Vec<(&'static str, &'static str)> {
- match (arch, host_arch()) {
- ("x86", Some(Arch::X86)) => vec![("", "")],
- ("x86", Some(Arch::Amd64)) => vec![("amd64_x86", "amd64"), ("", "")],
- ("x86_64", Some(Arch::X86)) => vec![("x86_amd64", "")],
- ("x86_64", Some(Arch::Amd64)) => vec![("amd64", "amd64"), ("x86_amd64", "")],
- ("arm", Some(Arch::X86)) => vec![("x86_arm", "")],
- ("arm", Some(Arch::Amd64)) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
- _ => vec![],
- }
- }
-
- fn lib_subdir(arch: &str) -> Option<&'static str> {
- match arch {
- "x86" => Some("x86"),
- "x86_64" => Some("x64"),
- "arm" => Some("arm"),
- _ => None,
- }
- }
-
- // MSVC's x86 libraries are not in a subfolder
- fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
- match arch {
- "x86" => Some(""),
- "x86_64" => Some("amd64"),
- "arm" => Some("arm"),
- _ => None,
- }
- }
-}
-
-// If we're not on Windows, then there's no registry to search through and MSVC
-// wouldn't be able to run, so we just call `link.exe` and hope for the best.
-#[cfg(not(windows))]
-mod platform {
- use std::path::PathBuf;
- use std::process::Command;
- use rustc::session::Session;
- pub fn link_exe_cmd(_sess: &Session) -> (Command, Option<PathBuf>) {
- (Command::new("link.exe"), None)
- }
-}
-
-pub use self::platform::*;
+++ /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.
-
-use std::io;
-use std::ffi::{OsString, OsStr};
-use std::os::windows::prelude::*;
-use std::ptr;
-use libc::c_long;
-
-pub type DWORD = u32;
-type LPCWSTR = *const u16;
-type LONG = c_long;
-type LPDWORD = *mut DWORD;
-type LPBYTE = *mut u8;
-
-
-const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
-const KEY_WOW64_32KEY: REGSAM = 0x0200;
-const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE |
- KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE;
-const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL;
-const READ_CONTROL: REGSAM = 0x00020000;
-const KEY_QUERY_VALUE: REGSAM = 0x0001;
-const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008;
-const KEY_NOTIFY: REGSAM = 0x0010;
-const SYNCHRONIZE: REGSAM = 0x00100000;
-const REG_SZ: DWORD = 1;
-const ERROR_SUCCESS: i32 = 0;
-
-pub enum __HKEY__ {}
-pub type HKEY = *mut __HKEY__;
-pub type PHKEY = *mut HKEY;
-pub type REGSAM = DWORD;
-
-#[link(name = "advapi32")]
-extern "system" {
- fn RegOpenKeyExW(hKey: HKEY,
- lpSubKey: LPCWSTR,
- ulOptions: DWORD,
- samDesired: REGSAM,
- phkResult: PHKEY) -> LONG;
- fn RegQueryValueExW(hKey: HKEY,
- lpValueName: LPCWSTR,
- lpReserved: LPDWORD,
- lpType: LPDWORD,
- lpData: LPBYTE,
- lpcbData: LPDWORD) -> LONG;
- fn RegCloseKey(hKey: HKEY) -> LONG;
-}
-
-pub struct RegistryKey(Repr);
-
-struct OwnedKey(HKEY);
-
-enum Repr {
- Const(HKEY),
- Owned(OwnedKey),
-}
-
-unsafe impl Sync for RegistryKey {}
-unsafe impl Send for RegistryKey {}
-
-pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
-
-impl RegistryKey {
- fn raw(&self) -> HKEY {
- match self.0 {
- Repr::Const(val) => val,
- Repr::Owned(ref val) => val.0,
- }
- }
-
- pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
- let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
- let mut ret = ptr::null_mut();
- let err = unsafe {
- RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
- KEY_READ | KEY_WOW64_32KEY, &mut ret)
- };
- if err == ERROR_SUCCESS {
- Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
- } else {
- Err(io::Error::from_raw_os_error(err as i32))
- }
- }
-
- pub fn query_str(&self, name: &str) -> io::Result<OsString> {
- let name: &OsStr = name.as_ref();
- let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
- let mut len = 0;
- let mut kind = 0;
- unsafe {
- let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
- &mut kind, ptr::null_mut(), &mut len);
- if err != ERROR_SUCCESS {
- return Err(io::Error::from_raw_os_error(err as i32))
- }
- if kind != REG_SZ {
- return Err(io::Error::new(io::ErrorKind::Other,
- "registry key wasn't a string"))
- }
-
- // The length here is the length in bytes, but we're using wide
- // characters so we need to be sure to halve it for the capacity
- // passed in.
- let mut v = Vec::with_capacity(len as usize / 2);
- let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
- ptr::null_mut(), v.as_mut_ptr() as *mut _,
- &mut len);
- if err != ERROR_SUCCESS {
- return Err(io::Error::from_raw_os_error(err as i32))
- }
- v.set_len(len as usize / 2);
-
- // Some registry keys may have a terminating nul character, but
- // we're not interested in that, so chop it off if it's there.
- if v[v.len() - 1] == 0 {
- v.pop();
- }
- Ok(OsString::from_wide(&v))
- }
- }
-}
-
-impl Drop for OwnedKey {
- fn drop(&mut self) {
- unsafe { RegCloseKey(self.0); }
- }
-}
ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p);
ifn!("llvm.assume", fn(i1) -> void);
+ ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
if ccx.sess().opts.debuginfo != NoDebugInfo {
ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
}
C_nil(ccx)
},
-
+ "prefetch_read_data" | "prefetch_write_data" |
+ "prefetch_read_instruction" | "prefetch_write_instruction" => {
+ let expect = ccx.get_intrinsic(&("llvm.prefetch"));
+ let (rw, cache_type) = match name {
+ "prefetch_read_data" => (0, 1),
+ "prefetch_write_data" => (1, 1),
+ "prefetch_read_instruction" => (0, 0),
+ "prefetch_write_instruction" => (1, 0),
+ _ => bug!()
+ };
+ bcx.call(expect, &[llargs[0], C_i32(ccx, rw), llargs[1], C_i32(ccx, cache_type)], None)
+ },
"ctlz" | "cttz" | "ctpop" | "bswap" |
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
"overflowing_add" | "overflowing_sub" | "overflowing_mul" |
#![feature(slice_patterns)]
#![feature(unicode)]
#![feature(conservative_impl_trait)]
+#![feature(command_envs)]
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(rustc_private))]
extern crate syntax_pos;
extern crate rustc_errors as errors;
extern crate serialize;
+#[cfg(windows)]
+extern crate gcc; // Used to locate MSVC, not gcc :)
pub use base::trans_crate;
pub use back::symbol_names::provide;
pub(crate) mod symbol_export;
pub(crate) mod symbol_names;
pub mod write;
- mod msvc;
- mod rpath;
+ pub mod rpath;
}
mod diagnostics;
],
tcx.mk_nil())
}
+ "prefetch_read_data" | "prefetch_write_data" |
+ "prefetch_read_instruction" | "prefetch_write_instruction" => {
+ (1, vec![tcx.mk_ptr(ty::TypeAndMut {
+ ty: param(0),
+ mutbl: hir::MutImmutable
+ }), tcx.types.i32],
+ tcx.mk_nil())
+ }
"drop_in_place" => {
(1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_nil())
}
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
/// extern "ABI" fn
BareFunction(Box<BareFunctionDecl>),
Tuple(Vec<Type>),
- Vector(Box<Type>),
- FixedVector(Box<Type>, String),
+ Slice(Box<Type>),
+ Array(Box<Type>, usize),
Never,
Unique(Box<Type>),
RawPointer(Mutability, Box<Type>),
pub fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
- Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(PrimitiveType::Slice),
- FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
- Some(PrimitiveType::Array)
- }
+ Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
+ Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
Tuple(..) => Some(PrimitiveType::Tuple),
RawPointer(..) => Some(PrimitiveType::RawPointer),
_ => None,
BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)}
}
- TySlice(ref ty) => Vector(box ty.clean(cx)),
+ TySlice(ref ty) => Slice(box ty.clean(cx)),
TyArray(ref ty, length) => {
use rustc::middle::const_val::eval_length;
let n = eval_length(cx.tcx, length, "array length").unwrap();
- FixedVector(box ty.clean(cx), n.to_string())
+ Array(box ty.clean(cx), n)
},
TyTup(ref tys) => Tuple(tys.clean(cx)),
TyPath(hir::QPath::Resolved(None, ref path)) => {
ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
ty::TyFloat(float_ty) => Primitive(float_ty.into()),
ty::TyStr => Primitive(PrimitiveType::Str),
- ty::TySlice(ty) => Vector(box ty.clean(cx)),
- ty::TyArray(ty, i) => FixedVector(box ty.clean(cx),
- format!("{}", i)),
+ ty::TySlice(ty) => Slice(box ty.clean(cx)),
+ ty::TyArray(ty, n) => Array(box ty.clean(cx), n),
ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
ty::TyRef(r, mt) => BorrowedRef {
lifetime: r.clean(cx),
use clean::{self, PrimitiveType};
use core::DocAccessLevels;
use html::item_type::ItemType;
-use html::escape::Escape;
use html::render;
use html::render::{cache, CURRENT_LOCATION_KEY};
}
}
}
- clean::Vector(ref t) => {
+ clean::Slice(ref t) => {
primitive_link(f, PrimitiveType::Slice, "[")?;
fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Slice, "]")
}
- clean::FixedVector(ref t, ref s) => {
+ clean::Array(ref t, n) => {
primitive_link(f, PrimitiveType::Array, "[")?;
fmt::Display::fmt(t, f)?;
- if f.alternate() {
- primitive_link(f, PrimitiveType::Array,
- &format!("; {}]", s))
- } else {
- primitive_link(f, PrimitiveType::Array,
- &format!("; {}]", Escape(s)))
- }
+ primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
};
let m = MutableSpace(mutability);
match **ty {
- clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
+ clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
match **bt {
clean::Generic(_) => {
if f.alternate() {
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
[features]
backtrace = []
/// An owned permission to join on a thread (block on its termination).
///
-/// A `JoinHandle` *detaches* the child thread when it is dropped.
+/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
+/// means that there is no longer any handle to thread and no way to `join`
+/// on it.
///
/// Due to platform restrictions, it is not possible to [`Clone`] this
-/// handle: the ability to join a child thread is a uniquely-owned
-/// permission.
+/// handle: the ability to join a thread is a uniquely-owned permission.
///
/// This `struct` is created by the [`thread::spawn`] function and the
/// [`thread::Builder::spawn`] method.
/// }).unwrap();
/// ```
///
+/// Child being detached and outliving its parent:
+///
+/// ```no_run
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let original_thread = thread::spawn(|| {
+/// let _detached_thread = thread::spawn(|| {
+/// // Here we sleep to make sure that the first thread returns before.
+/// thread::sleep(Duration::from_millis(10));
+/// // This will be called, even though the JoinHandle is dropped.
+/// println!("♫ Still alive ♫");
+/// });
+/// });
+///
+/// let _ = original_thread.join();
+/// println!("Original thread is joined.");
+///
+/// // We make sure that the new thread has time to run, before the main
+/// // thread returns.
+///
+/// thread::sleep(Duration::from_millis(1000));
+/// ```
+///
/// [`Clone`]: ../../std/clone/trait.Clone.html
/// [`thread::spawn`]: fn.spawn.html
/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn
return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?));
}
+ if self.check_keyword(keywords::Const) {
+ return Err(self.span_fatal(self.span, "extern items cannot be `const`"));
+ }
+
// FIXME #5668: this will occur for a macro invocation:
match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
Some(item) => {
--- /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: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{prefetch_read_data, prefetch_write_data,
+ prefetch_read_instruction, prefetch_write_instruction};
+
+#[no_mangle]
+pub fn check_prefetch_read_data(data: &[i8]) {
+ unsafe {
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 1)
+ prefetch_read_data(data.as_ptr(), 0);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 1)
+ prefetch_read_data(data.as_ptr(), 1);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 1)
+ prefetch_read_data(data.as_ptr(), 2);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 1)
+ prefetch_read_data(data.as_ptr(), 3);
+ }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_data(data: &[i8]) {
+ unsafe {
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 1)
+ prefetch_write_data(data.as_ptr(), 0);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 1)
+ prefetch_write_data(data.as_ptr(), 1);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 1)
+ prefetch_write_data(data.as_ptr(), 2);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 1)
+ prefetch_write_data(data.as_ptr(), 3);
+ }
+}
+
+#[no_mangle]
+pub fn check_prefetch_read_instruction(data: &[i8]) {
+ unsafe {
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 0)
+ prefetch_read_instruction(data.as_ptr(), 0);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 0)
+ prefetch_read_instruction(data.as_ptr(), 1);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 0)
+ prefetch_read_instruction(data.as_ptr(), 2);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 0)
+ prefetch_read_instruction(data.as_ptr(), 3);
+ }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_instruction(data: &[i8]) {
+ unsafe {
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 0)
+ prefetch_write_instruction(data.as_ptr(), 0);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 0)
+ prefetch_write_instruction(data.as_ptr(), 1);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 0)
+ prefetch_write_instruction(data.as_ptr(), 2);
+ // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
+ prefetch_write_instruction(data.as_ptr(), 3);
+ }
+}
+
+
extern {
const i: isize;
- //~^ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `const`
+ //~^ ERROR extern items cannot be `const`
}
use std::str::FromStr;
use std::path::PathBuf;
+use test::ColorConfig;
+
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode {
CompileFail,
// Print one character per test instead of one line
pub quiet: bool,
+ // Whether to use colors in test.
+ pub color: ColorConfig,
+
// where to find the remote test client process, if we're using it
pub remote_test_client: Option<PathBuf>,
use getopts::{optopt, optflag, reqopt};
use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode};
-use test::TestPaths;
+use test::{TestPaths, ColorConfig};
use util::logv;
use self::header::EarlyProps;
optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
optflag("", "verbose", "run tests verbosely, showing all output"),
optflag("", "quiet", "print one character per test instead of one line"),
+ optopt("", "color", "coloring: auto, always, never", "WHEN"),
optopt("", "logfile", "file to log test execution to", "FILE"),
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"),
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"));
+ let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+ Some("auto") | None => ColorConfig::AutoColor,
+ Some("always") => ColorConfig::AlwaysColor,
+ Some("never") => ColorConfig::NeverColor,
+ Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
+ };
+
Config {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
lldb_python_dir: matches.opt_str("lldb-python-dir"),
verbose: matches.opt_present("verbose"),
quiet: matches.opt_present("quiet"),
+ color: color,
remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
cc: matches.opt_str("cc").unwrap(),
Ok(val) => &val != "0",
Err(_) => false
},
- color: test::AutoColor,
+ color: config.color,
test_threads: None,
skip: vec![],
list: false,
-Subproject commit 8707ceaf040f6d87b67a002de16a8d2bc4db7a41
+Subproject commit b4ff403041f17957f735ad750c3241a3a428b9b7
pub has_gate_test: bool,
}
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
let mut features = collect_lang_features(path);
assert!(!features.is_empty());
if *bad {
return;
}
+ if quiet {
+ println!("* {} features", features.len());
+ return;
+ }
let mut lines = Vec::new();
for (name, feature) in features.iter() {
let args: Vec<String> = env::args().skip(1).collect();
let mut bad = false;
+ let quiet = args.iter().any(|s| *s == "--quiet");
bins::check(&path, &mut bad);
style::check(&path, &mut bad);
errors::check(&path, &mut bad);
cargo::check(&path, &mut bad);
- features::check(&path, &mut bad);
+ features::check(&path, &mut bad, quiet);
pal::check(&path, &mut bad);
unstable_book::check(&path, &mut bad);
if !args.iter().any(|s| *s == "--no-vendor") {