]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #39265 - est31:master, r=petrochenkov
authorbors <bors@rust-lang.org>
Thu, 9 Feb 2017 11:42:49 +0000 (11:42 +0000)
committerbors <bors@rust-lang.org>
Thu, 9 Feb 2017 11:42:49 +0000 (11:42 +0000)
Stabilize static lifetime in statics

Stabilize the "static_in_const" feature. Blockers before this PR can be merged:

* [x] The [FCP with inclination to stabilize](https://github.com/rust-lang/rust/issues/35897#issuecomment-270441437) needs to be over. FCP lasts roughly three weeks, so will be over at Jan 25, aka this thursday.
* [x] Documentation needs to be added (#37928)

Closes #35897.

153 files changed:
RELEASES.md
configure
mk/cfg/aarch64-unknown-freebsd.mk [deleted file]
mk/cfg/i686-unknown-netbsd.mk [deleted file]
src/Cargo.lock
src/bootstrap/check.rs
src/bootstrap/clean.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/config.toml.example
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/ci/docker/dist-x86-linux/Dockerfile
src/ci/docker/dist-x86-linux/build-headers.sh [new file with mode: 0755]
src/ci/docker/x86_64-gnu/Dockerfile
src/compiler-rt
src/doc/reference.md
src/libcollections/Cargo.toml
src/libcollections/benches/btree/map.rs [new file with mode: 0644]
src/libcollections/benches/btree/mod.rs [new file with mode: 0644]
src/libcollections/benches/lib.rs [new file with mode: 0644]
src/libcollections/benches/linked_list.rs [new file with mode: 0644]
src/libcollections/benches/slice.rs [new file with mode: 0644]
src/libcollections/benches/str.rs [new file with mode: 0644]
src/libcollections/benches/string.rs [new file with mode: 0644]
src/libcollections/benches/vec.rs [new file with mode: 0644]
src/libcollections/benches/vec_deque.rs [new file with mode: 0644]
src/libcollectionstest/bench.rs [deleted file]
src/libcollectionstest/btree/map.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/linked_list.rs
src/libcollectionstest/slice.rs
src/libcollectionstest/str.rs
src/libcollectionstest/string.rs
src/libcollectionstest/vec.rs
src/libcollectionstest/vec_deque.rs
src/libcore/Cargo.toml
src/libcore/bench/any.rs [deleted file]
src/libcore/bench/hash/mod.rs [deleted file]
src/libcore/bench/hash/sip.rs [deleted file]
src/libcore/bench/iter.rs [deleted file]
src/libcore/bench/lib.rs [deleted file]
src/libcore/bench/mem.rs [deleted file]
src/libcore/bench/num/dec2flt/mod.rs [deleted file]
src/libcore/bench/num/flt2dec/mod.rs [deleted file]
src/libcore/bench/num/flt2dec/strategy/dragon.rs [deleted file]
src/libcore/bench/num/flt2dec/strategy/grisu.rs [deleted file]
src/libcore/bench/num/mod.rs [deleted file]
src/libcore/bench/ops.rs [deleted file]
src/libcore/benches/any.rs [new file with mode: 0644]
src/libcore/benches/hash/mod.rs [new file with mode: 0644]
src/libcore/benches/hash/sip.rs [new file with mode: 0644]
src/libcore/benches/iter.rs [new file with mode: 0644]
src/libcore/benches/lib.rs [new file with mode: 0644]
src/libcore/benches/mem.rs [new file with mode: 0644]
src/libcore/benches/num/dec2flt/mod.rs [new file with mode: 0644]
src/libcore/benches/num/flt2dec/mod.rs [new file with mode: 0644]
src/libcore/benches/num/flt2dec/strategy/dragon.rs [new file with mode: 0644]
src/libcore/benches/num/flt2dec/strategy/grisu.rs [new file with mode: 0644]
src/libcore/benches/num/mod.rs [new file with mode: 0644]
src/libcore/benches/ops.rs [new file with mode: 0644]
src/librustc/middle/cstore.rs
src/librustc/session/config.rs
src/librustc_asan/Cargo.toml [new file with mode: 0644]
src/librustc_asan/build.rs [new file with mode: 0644]
src/librustc_asan/lib.rs [new file with mode: 0644]
src/librustc_incremental/persist/load.rs
src/librustc_lint/types.rs
src/librustc_llvm/ffi.rs
src/librustc_lsan/Cargo.toml [new file with mode: 0644]
src/librustc_lsan/build.rs [new file with mode: 0644]
src/librustc_lsan/lib.rs [new file with mode: 0644]
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_msan/Cargo.toml [new file with mode: 0644]
src/librustc_msan/build.rs [new file with mode: 0644]
src/librustc_msan/lib.rs [new file with mode: 0644]
src/librustc_trans/adt.rs
src/librustc_trans/asm.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/builder.rs
src/librustc_trans/callee.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/utils.rs
src/librustc_trans/declare.rs
src/librustc_trans/glue.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/meth.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_tsan/Cargo.toml [new file with mode: 0644]
src/librustc_tsan/build.rs [new file with mode: 0644]
src/librustc_tsan/lib.rs [new file with mode: 0644]
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/markdown.rs
src/librustdoc/test.rs
src/libstd/Cargo.toml
src/libstd/env.rs
src/libstd/process.rs
src/libstd/sys/redox/process.rs
src/libstd/sys/unix/process/process_fuchsia.rs
src/libstd/sys/unix/process/process_unix.rs
src/libstd/sys/windows/process.rs
src/libsyntax/feature_gate.rs
src/libsyntax/print/pp.rs
src/rustc/std_shim/Cargo.toml
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.h
src/test/codegen/packed.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-sanitizer-runtime.rs [new file with mode: 0644]
src/test/compile-fail/issue-27433.rs [new file with mode: 0644]
src/test/compile-fail/lint-ctypes.rs
src/test/incremental/issue-39569.rs [new file with mode: 0644]
src/test/run-make/sanitizer-address/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-address/overflow.rs [new file with mode: 0644]
src/test/run-make/sanitizer-dylib/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-dylib/hello.rs [new file with mode: 0644]
src/test/run-make/sanitizer-invalid-target/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-invalid-target/hello.rs [new file with mode: 0644]
src/test/run-make/sanitizer-leak/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-leak/leak.rs [new file with mode: 0644]
src/test/run-make/sanitizer-memory/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-memory/uninit.rs [new file with mode: 0644]
src/test/run-make/sanitizer-thread/Makefile [new file with mode: 0644]
src/test/run-make/sanitizer-thread/racy.rs [new file with mode: 0644]
src/test/run-pass/issue-34798.rs [new file with mode: 0644]
src/test/run-pass/try-wait.rs
src/test/rustdoc/impl-disambiguation.rs [new file with mode: 0644]
src/test/rustdoc/test_option_check/bar.rs [new file with mode: 0644]
src/test/rustdoc/test_option_check/test.rs
src/tools/build-manifest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/vendor/gcc/.cargo-checksum.json
src/vendor/gcc/.gitignore
src/vendor/gcc/.travis.yml
src/vendor/gcc/Cargo.toml
src/vendor/gcc/README.md
src/vendor/gcc/src/bin/gcc-shim.rs
src/vendor/gcc/src/lib.rs
src/vendor/gcc/src/registry.rs
src/vendor/gcc/src/windows_registry.rs
src/vendor/gcc/tests/support/mod.rs
src/vendor/gcc/tests/test.rs

index f26c0b6b6116194cd1fbc74fb64fa4d384b08239..2df1a83db81ffb3a5fa806a3ffd44863e582ae3b 100644 (file)
@@ -1,4 +1,4 @@
-Version 1.15.1 (2017-02-07)
+Version 1.15.1 (2017-02-08)
 ===========================
 
 * [Fix IntoIter::as_mut_slice's signature][39466]
index 597f007633640fbb079bde04d002ba4f733e0816..c751ad9731a7db9ff5690d67105e017260a882ce 100755 (executable)
--- a/configure
+++ b/configure
@@ -649,6 +649,7 @@ opt codegen-tests 1 "run the src/test/codegen tests"
 opt option-checking 1 "complain about unrecognized options in this configure script"
 opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
 opt vendor 0 "enable usage of vendored Rust crates"
+opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)"
 
 # Optimization and debugging options. These may be overridden by the release channel, etc.
 opt_nosave optimize 1 "build optimized rust code"
diff --git a/mk/cfg/aarch64-unknown-freebsd.mk b/mk/cfg/aarch64-unknown-freebsd.mk
deleted file mode 100644 (file)
index 34aee77..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# rustbuild-only target
diff --git a/mk/cfg/i686-unknown-netbsd.mk b/mk/cfg/i686-unknown-netbsd.mk
deleted file mode 100644 (file)
index 34aee77..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# rustbuild-only target
index 6d814619eb6083f096bebaa2d76600cec099179b..09aefd45e94c88964ce6bdcd1515c6f9dc5b2460 100644 (file)
@@ -19,7 +19,7 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "core 0.0.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
 ]
 
@@ -42,7 +42,7 @@ dependencies = [
  "build_helper 0.1.0",
  "cmake 0.1.18 (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.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (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.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -74,7 +74,7 @@ name = "cmake"
 version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -91,7 +91,7 @@ name = "compiler_builtins"
 version = "0.0.0"
 dependencies = [
  "core 0.0.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -133,7 +133,7 @@ name = "flate"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -142,7 +142,7 @@ version = "0.0.0"
 
 [[package]]
 name = "gcc"
-version = "0.3.40"
+version = "0.3.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -277,6 +277,16 @@ name = "rustc-serialize"
 version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "rustc_asan"
+version = "0.0.0"
+dependencies = [
+ "alloc_system 0.0.0",
+ "build_helper 0.1.0",
+ "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core 0.0.0",
+]
+
 [[package]]
 name = "rustc_back"
 version = "0.0.0"
@@ -406,10 +416,20 @@ name = "rustc_llvm"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_bitflags 0.0.0",
 ]
 
+[[package]]
+name = "rustc_lsan"
+version = "0.0.0"
+dependencies = [
+ "alloc_system 0.0.0",
+ "build_helper 0.1.0",
+ "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core 0.0.0",
+]
+
 [[package]]
 name = "rustc_metadata"
 version = "0.0.0"
@@ -444,6 +464,16 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
+[[package]]
+name = "rustc_msan"
+version = "0.0.0"
+dependencies = [
+ "alloc_system 0.0.0",
+ "build_helper 0.1.0",
+ "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core 0.0.0",
+]
+
 [[package]]
 name = "rustc_passes"
 version = "0.0.0"
@@ -525,6 +555,16 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
+[[package]]
+name = "rustc_tsan"
+version = "0.0.0"
+dependencies = [
+ "alloc_system 0.0.0",
+ "build_helper 0.1.0",
+ "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core 0.0.0",
+]
+
 [[package]]
 name = "rustc_typeck"
 version = "0.0.0"
@@ -549,7 +589,7 @@ version = "0.0.0"
 dependencies = [
  "arena 0.0.0",
  "build_helper 0.1.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.0.0",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
@@ -581,11 +621,15 @@ dependencies = [
  "collections 0.0.0",
  "compiler_builtins 0.0.0",
  "core 0.0.0",
- "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
  "panic_abort 0.0.0",
  "panic_unwind 0.0.0",
  "rand 0.0.0",
+ "rustc_asan 0.0.0",
+ "rustc_lsan 0.0.0",
+ "rustc_msan 0.0.0",
+ "rustc_tsan 0.0.0",
  "std_unicode 0.0.0",
  "unwind 0.0.0",
 ]
@@ -671,7 +715,7 @@ dependencies = [
 "checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
-"checksum gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"
+"checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
 "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
index 0ebd10551329002068d6beb736140465b7c27337..cbfbcbe4f0c6eb85ef2c4431c41553bbbcd9764a 100644 (file)
@@ -242,6 +242,10 @@ pub fn compiletest(build: &Build,
     cmd.env("RUSTC_BOOTSTRAP", "1");
     build.add_rust_test_threads(&mut cmd);
 
+    if build.config.sanitizers {
+        cmd.env("SANITIZER_SUPPORT", "1");
+    }
+
     cmd.arg("--adb-path").arg("adb");
     cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
     if target.contains("android") {
index e7655458aed8a71128437a1ff921b5bfa39a3417..a66ed46fe464f5bb1185e4a25a4fb4d2a50b4ba0 100644 (file)
@@ -24,6 +24,7 @@
 pub fn clean(build: &Build) {
     rm_rf(build, "tmp".as_ref());
     rm_rf(build, &build.out.join("tmp"));
+    rm_rf(build, &build.out.join("dist"));
 
     for host in build.config.host.iter() {
         let entries = match build.out.join(host).read_dir() {
index 81dd42a1e906a04f4578adf8ba8168ad0b691911..0b1a1f39d8d42e1765950e7c0d3fcdf9871ca366 100644 (file)
@@ -51,6 +51,17 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
     if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
         features.push_str(" force_alloc_system");
     }
+
+    if compiler.stage != 0 && build.config.sanitizers {
+        // This variable is used by the sanitizer runtime crates, e.g.
+        // rustc_lsan, to build the sanitizer runtime from C code
+        // When this variable is missing, those crates won't compile the C code,
+        // so we don't set this variable during stage0 where llvm-config is
+        // missing
+        // We also only build the runtimes when --enable-sanitizers (or its
+        // config.toml equivalent) is used
+        cargo.env("LLVM_CONFIG", build.llvm_config(target));
+    }
     cargo.arg("--features").arg(features)
          .arg("--manifest-path")
          .arg(build.src.join("src/rustc/std_shim/Cargo.toml"));
index 4e67a14345b9e3af4f995560effb187b04a5e11f..604c0397d5242972a118b26b4e0bd2ced74bf9d8 100644 (file)
@@ -48,6 +48,7 @@ pub struct Config {
     pub target_config: HashMap<String, Target>,
     pub full_bootstrap: bool,
     pub extended: bool,
+    pub sanitizers: bool,
 
     // llvm codegen options
     pub llvm_assertions: bool,
@@ -149,6 +150,7 @@ struct Build {
     python: Option<String>,
     full_bootstrap: Option<bool>,
     extended: Option<bool>,
+    sanitizers: Option<bool>,
 }
 
 /// TOML representation of various global install decisions.
@@ -294,6 +296,7 @@ pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
         set(&mut config.vendor, build.vendor);
         set(&mut config.full_bootstrap, build.full_bootstrap);
         set(&mut config.extended, build.extended);
+        set(&mut config.sanitizers, build.sanitizers);
 
         if let Some(ref install) = toml.install {
             config.prefix = install.prefix.clone().map(PathBuf::from);
@@ -438,6 +441,7 @@ macro_rules! check {
                 ("VENDOR", self.vendor),
                 ("FULL_BOOTSTRAP", self.full_bootstrap),
                 ("EXTENDED", self.extended),
+                ("SANITIZERS", self.sanitizers),
             }
 
             match key {
index a53419ad7fd780a28b41fcf6433a5081510187bc..025fe990f91dab67e27e338e8bd9f08faa754ffb 100644 (file)
 # disabled by default.
 #extended = false
 
+# Build the sanitizer runtimes
+#sanitizers = false
+
 # =============================================================================
 # General install configuration options
 # =============================================================================
index 1c3901bf2a14349619d1fdc379fb57bfd7b33970..2da2892150b4fba53817b2bee9a7c436b03c4390 100644 (file)
@@ -515,9 +515,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) {
 
     let branch = match &build.config.channel[..] {
         "stable" |
-        "beta" => {
-            build.release.split(".").take(2).collect::<Vec<_>>().join(".")
-        }
+        "beta" => format!("rust-{}", build.release_num),
         _ => "master".to_string(),
     };
 
index e58dcc9fce92f5c2c6bb038c5f241d10d585460b..ba6b34343f0b35d15554fd0f5b142c71daa9c627 100644 (file)
@@ -599,7 +599,8 @@ fn prepare_tool_cmd(&self, compiler: &Compiler, cmd: &mut Command) {
     /// Get the space-separated set of activated features for the standard
     /// library.
     fn std_features(&self) -> String {
-        let mut features = "panic-unwind".to_string();
+        let mut features = "panic-unwind asan lsan msan tsan".to_string();
+
         if self.config.debug_jemalloc {
             features.push_str(" debug-jemalloc");
         }
index 4e4f5dd6f1e5328614cf650e14bdaac571e508c5..12e24ff1af6a2fc505c67887491c9a9fedd6a737 100644 (file)
@@ -21,17 +21,7 @@ RUN yum upgrade -y && yum install -y \
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
 WORKDIR /tmp
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
 COPY shared.sh build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
-# Need a newer version of gcc than centos has to compile LLVM nowadays
-COPY build-gcc.sh /tmp/
-RUN ./build-gcc.sh
 
 # We need a build of openssl which supports SNI to download artifacts from
 # static.rust-lang.org. This'll be used to link into libcurl below (and used
@@ -49,6 +39,16 @@ RUN ./build-openssl.sh
 COPY build-curl.sh /tmp/
 RUN ./build-curl.sh
 
+# binutils < 2.22 has a bug where the 32-bit executables it generates
+# immediately segfault in Rust, so we need to install our own binutils.
+#
+# See https://github.com/rust-lang/rust/issues/20440 for more info
+RUN ./build-binutils.sh
+
+# Need a newer version of gcc than centos has to compile LLVM nowadays
+COPY build-gcc.sh /tmp/
+RUN ./build-gcc.sh
+
 # CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
 COPY build-python.sh /tmp/
 RUN ./build-python.sh
@@ -63,6 +63,11 @@ RUN ./build-git.sh
 COPY build-cmake.sh /tmp/
 RUN ./build-cmake.sh
 
+# for sanitizers, we need kernel headers files newer than the ones CentOS ships
+# with so we install newer ones here
+COPY build-headers.sh /tmp/
+RUN ./build-headers.sh
+
 RUN curl -Lo /rustroot/dumb-init \
       https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \
       chmod +x /rustroot/dumb-init
@@ -76,5 +81,5 @@ RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST |
 ENV HOSTS=i686-unknown-linux-gnu
 ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended --enable-sanitizers
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-x86-linux/build-headers.sh
new file mode 100755 (executable)
index 0000000..4ce38fd
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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.
+
+set -ex
+source shared.sh
+
+curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
+
+cd linux-3.2.84
+hide_output make mrproper
+hide_output make INSTALL_HDR_PATH=dest headers_install
+
+find dest/include \( -name .install -o -name ..install.cmd \) -delete
+yes | cp -fr dest/include/* /usr/include
+
+cd ..
+rm -rf linux-3.2.84
index 6919487e17c3e6f1a78fa3da13e48a522979e53f..e903b6ddc64cd0ef54c761321cbe154b68a49cae 100644 (file)
@@ -22,5 +22,5 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
     rm dumb-init_*.deb
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-sanitizers
 ENV SCRIPT python2.7 ../x.py test && python2.7 ../x.py dist
index a8fc4c169fac43a5dc204d4fd56ddb1739f8c178..d30da544a8afc5d78391dee270bdf40e74a215d3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
+Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
index f9013490418f3da598ef9bfe112411d5b0a2e9d6..8aefabe61fdf68b17294ea63662240d7b17908e1 100644 (file)
@@ -1291,15 +1291,18 @@ guaranteed to refer to the same memory address.
 
 Constant values must not have destructors, and otherwise permit most forms of
 data. Constants may refer to the address of other constants, in which case the
-address will have the `static` lifetime. The compiler is, however, still at
-liberty to translate the constant many times, so the address referred to may not
-be stable.
+address will have elided lifetimes where applicable, otherwise – in most cases –
+defaulting to the `static` lifetime. (See below on [static lifetime elision].)
+The compiler is, however, still at liberty to translate the constant many times,
+so the address referred to may not be stable.
+
+[static lifetime elision]: #static-lifetime-elision
 
 Constants must be explicitly typed. The type may be `bool`, `char`, a number, or
 a type derived from those primitive types. The derived types are references with
 the `static` lifetime, fixed-size arrays, tuples, enum variants, and structs.
 
-```
+```rust
 const BIT1: u32 = 1 << 0;
 const BIT2: u32 = 1 << 1;
 
@@ -1317,6 +1320,8 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
 };
 ```
 
+
+
 ### Static items
 
 A *static item* is similar to a *constant*, except that it represents a precise
@@ -1351,7 +1356,7 @@ running in the same process.
 Mutable statics are still very useful, however. They can be used with C
 libraries and can also be bound from C libraries (in an `extern` block).
 
-```
+```rust
 # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 }
 
 static mut LEVELS: u32 = 0;
@@ -1375,6 +1380,53 @@ unsafe fn bump_levels_unsafe2() -> u32 {
 Mutable statics have the same restrictions as normal statics, except that the
 type of the value is not required to ascribe to `Sync`.
 
+#### `'static` lifetime elision
+
+[Unstable] Both constant and static declarations of reference types have
+*implicit* `'static` lifetimes unless an explicit lifetime is specified. As
+such, the constant declarations involving `'static` above may be written
+without the lifetimes. Returning to our previous example:
+
+```rust
+# #![feature(static_in_const)]
+const BIT1: u32 = 1 << 0;
+const BIT2: u32 = 1 << 1;
+
+const BITS: [u32; 2] = [BIT1, BIT2];
+const STRING: &str = "bitstring";
+
+struct BitsNStrings<'a> {
+    mybits: [u32; 2],
+    mystring: &'a str,
+}
+
+const BITS_N_STRINGS: BitsNStrings = BitsNStrings {
+    mybits: BITS,
+    mystring: STRING,
+};
+```
+
+Note that if the `static` or `const` items include function or closure
+references, which themselves include references, the compiler will first try the
+standard elision rules ([see discussion in the nomicon][elision-nomicon]). If it
+is unable to resolve the lifetimes by its usual rules, it will default to using
+the `'static` lifetime. By way of example:
+
+[elision-nomicon]: https://doc.rust-lang.org/nomicon/lifetime-elision.html
+
+```rust,ignore
+// Resolved as `fn<'a>(&'a str) -> &'a str`.
+const RESOLVED_SINGLE: fn(&str) -> &str = ..
+
+// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`.
+const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
+
+// There is insufficient information to bound the return reference lifetime
+// relative to the argument lifetimes, so the signature is resolved as
+// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
+const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
+```
+
 ### Traits
 
 A _trait_ describes an abstract interface that types can
@@ -2072,7 +2124,9 @@ macro scope.
 
 ### Miscellaneous attributes
 
-- `deprecated` - mark the item as deprecated; the full attribute is `#[deprecated(since = "crate version", note = "...")`, where both arguments are optional.
+- `deprecated` - mark the item as deprecated; the full attribute is 
+  `#[deprecated(since = "crate version", note = "...")`, where both arguments 
+  are optional.
 - `export_name` - on statics and functions, this determines the name of the
   exported symbol.
 - `link_section` - on statics and functions, this specifies the section of the
@@ -2489,9 +2543,6 @@ The currently implemented features of the reference compiler are:
             into a Rust program. This capability, especially the signature for the
             annotated function, is subject to change.
 
-* `static_in_const` - Enables lifetime elision with a `'static` default for
-                      `const` and `static` item declarations.
-
 * `thread_local` - The usage of the `#[thread_local]` attribute is experimental
                    and should be seen as unstable. This attribute is used to
                    declare a `static` as being unique per-thread leveraging
index 186ba6e8f211243512c1814c6598a36f1b75dc48..02b2171a224d0ae2b0111a5445f83b54fc88c9c3 100644 (file)
@@ -16,7 +16,6 @@ std_unicode = { path = "../libstd_unicode" }
 name = "collectionstest"
 path = "../libcollectionstest/lib.rs"
 
-# FIXME: need to extract benchmarks to separate crate
-#[[bench]]
-#name = "collectionstest"
-#path = "../libcollectionstest/lib.rs"
+[[bench]]
+name = "collectionsbenches"
+path = "../libcollections/benches/lib.rs"
diff --git a/src/libcollections/benches/btree/map.rs b/src/libcollections/benches/btree/map.rs
new file mode 100644 (file)
index 0000000..744afb9
--- /dev/null
@@ -0,0 +1,157 @@
+// 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 std::iter::Iterator;
+use std::vec::Vec;
+use std::collections::BTreeMap;
+use std::__rand::{Rng, thread_rng};
+use test::{Bencher, black_box};
+
+macro_rules! map_insert_rand_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut Bencher) {
+            let n: usize = $n;
+            let mut map = $map::new();
+            // setup
+            let mut rng = thread_rng();
+
+            for _ in 0..n {
+                let i = rng.gen::<usize>() % n;
+                map.insert(i, i);
+            }
+
+            // measure
+            b.iter(|| {
+                let k = rng.gen::<usize>() % n;
+                map.insert(k, k);
+                map.remove(&k);
+            });
+            black_box(map);
+        }
+    )
+}
+
+macro_rules! map_insert_seq_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut Bencher) {
+            let mut map = $map::new();
+            let n: usize = $n;
+            // setup
+            for i in 0..n {
+                map.insert(i * 2, i * 2);
+            }
+
+            // measure
+            let mut i = 1;
+            b.iter(|| {
+                map.insert(i, i);
+                map.remove(&i);
+                i = (i + 2) % n;
+            });
+            black_box(map);
+        }
+    )
+}
+
+macro_rules! map_find_rand_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut Bencher) {
+            let mut map = $map::new();
+            let n: usize = $n;
+
+            // setup
+            let mut rng = thread_rng();
+            let mut keys: Vec<_> = (0..n).map(|_| rng.gen::<usize>() % n).collect();
+
+            for &k in &keys {
+                map.insert(k, k);
+            }
+
+            rng.shuffle(&mut keys);
+
+            // measure
+            let mut i = 0;
+            b.iter(|| {
+                let t = map.get(&keys[i]);
+                i = (i + 1) % n;
+                black_box(t);
+            })
+        }
+    )
+}
+
+macro_rules! map_find_seq_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut Bencher) {
+            let mut map = $map::new();
+            let n: usize = $n;
+
+            // setup
+            for i in 0..n {
+                map.insert(i, i);
+            }
+
+            // measure
+            let mut i = 0;
+            b.iter(|| {
+                let x = map.get(&i);
+                i = (i + 1) % n;
+                black_box(x);
+            })
+        }
+    )
+}
+
+map_insert_rand_bench!{insert_rand_100,    100,    BTreeMap}
+map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap}
+
+map_insert_seq_bench!{insert_seq_100,    100,    BTreeMap}
+map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap}
+
+map_find_rand_bench!{find_rand_100,    100,    BTreeMap}
+map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap}
+
+map_find_seq_bench!{find_seq_100,    100,    BTreeMap}
+map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap}
+
+fn bench_iter(b: &mut Bencher, size: i32) {
+    let mut map = BTreeMap::<i32, i32>::new();
+    let mut rng = thread_rng();
+
+    for _ in 0..size {
+        map.insert(rng.gen(), rng.gen());
+    }
+
+    b.iter(|| {
+        for entry in &map {
+            black_box(entry);
+        }
+    });
+}
+
+#[bench]
+pub fn iter_20(b: &mut Bencher) {
+    bench_iter(b, 20);
+}
+
+#[bench]
+pub fn iter_1000(b: &mut Bencher) {
+    bench_iter(b, 1000);
+}
+
+#[bench]
+pub fn iter_100000(b: &mut Bencher) {
+    bench_iter(b, 100000);
+}
diff --git a/src/libcollections/benches/btree/mod.rs b/src/libcollections/benches/btree/mod.rs
new file mode 100644 (file)
index 0000000..f436b0a
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+mod map;
diff --git a/src/libcollections/benches/lib.rs b/src/libcollections/benches/lib.rs
new file mode 100644 (file)
index 0000000..1a21db5
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+#![deny(warnings)]
+
+#![feature(rand)]
+#![feature(test)]
+
+extern crate test;
+
+mod btree;
+mod linked_list;
+mod string;
+mod str;
+mod slice;
+mod vec;
+mod vec_deque;
diff --git a/src/libcollections/benches/linked_list.rs b/src/libcollections/benches/linked_list.rs
new file mode 100644 (file)
index 0000000..bbac445
--- /dev/null
@@ -0,0 +1,87 @@
+// 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 std::collections::LinkedList;
+use test::Bencher;
+
+#[bench]
+fn bench_collect_into(b: &mut Bencher) {
+    let v = &[0; 64];
+    b.iter(|| {
+        let _: LinkedList<_> = v.iter().cloned().collect();
+    })
+}
+
+#[bench]
+fn bench_push_front(b: &mut Bencher) {
+    let mut m: LinkedList<_> = LinkedList::new();
+    b.iter(|| {
+        m.push_front(0);
+    })
+}
+
+#[bench]
+fn bench_push_back(b: &mut Bencher) {
+    let mut m: LinkedList<_> = LinkedList::new();
+    b.iter(|| {
+        m.push_back(0);
+    })
+}
+
+#[bench]
+fn bench_push_back_pop_back(b: &mut Bencher) {
+    let mut m: LinkedList<_> = LinkedList::new();
+    b.iter(|| {
+        m.push_back(0);
+        m.pop_back();
+    })
+}
+
+#[bench]
+fn bench_push_front_pop_front(b: &mut Bencher) {
+    let mut m: LinkedList<_> = LinkedList::new();
+    b.iter(|| {
+        m.push_front(0);
+        m.pop_front();
+    })
+}
+
+#[bench]
+fn bench_iter(b: &mut Bencher) {
+    let v = &[0; 128];
+    let m: LinkedList<_> = v.iter().cloned().collect();
+    b.iter(|| {
+        assert!(m.iter().count() == 128);
+    })
+}
+#[bench]
+fn bench_iter_mut(b: &mut Bencher) {
+    let v = &[0; 128];
+    let mut m: LinkedList<_> = v.iter().cloned().collect();
+    b.iter(|| {
+        assert!(m.iter_mut().count() == 128);
+    })
+}
+#[bench]
+fn bench_iter_rev(b: &mut Bencher) {
+    let v = &[0; 128];
+    let m: LinkedList<_> = v.iter().cloned().collect();
+    b.iter(|| {
+        assert!(m.iter().rev().count() == 128);
+    })
+}
+#[bench]
+fn bench_iter_mut_rev(b: &mut Bencher) {
+    let v = &[0; 128];
+    let mut m: LinkedList<_> = v.iter().cloned().collect();
+    b.iter(|| {
+        assert!(m.iter_mut().rev().count() == 128);
+    })
+}
diff --git a/src/libcollections/benches/slice.rs b/src/libcollections/benches/slice.rs
new file mode 100644 (file)
index 0000000..eb4b765
--- /dev/null
@@ -0,0 +1,280 @@
+// 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 std::{mem, ptr};
+use std::__rand::{Rng, thread_rng};
+
+use test::{Bencher, black_box};
+
+#[bench]
+fn iterator(b: &mut Bencher) {
+    // peculiar numbers to stop LLVM from optimising the summation
+    // out.
+    let v: Vec<_> = (0..100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect();
+
+    b.iter(|| {
+        let mut sum = 0;
+        for x in &v {
+            sum += *x;
+        }
+        // sum == 11806, to stop dead code elimination.
+        if sum == 0 {
+            panic!()
+        }
+    })
+}
+
+#[bench]
+fn mut_iterator(b: &mut Bencher) {
+    let mut v = vec![0; 100];
+
+    b.iter(|| {
+        let mut i = 0;
+        for x in &mut v {
+            *x = i;
+            i += 1;
+        }
+    })
+}
+
+#[bench]
+fn concat(b: &mut Bencher) {
+    let xss: Vec<Vec<i32>> = (0..100).map(|i| (0..i).collect()).collect();
+    b.iter(|| {
+        xss.concat();
+    });
+}
+
+#[bench]
+fn join(b: &mut Bencher) {
+    let xss: Vec<Vec<i32>> = (0..100).map(|i| (0..i).collect()).collect();
+    b.iter(|| xss.join(&0));
+}
+
+#[bench]
+fn push(b: &mut Bencher) {
+    let mut vec = Vec::<i32>::new();
+    b.iter(|| {
+        vec.push(0);
+        black_box(&vec);
+    });
+}
+
+#[bench]
+fn starts_with_same_vector(b: &mut Bencher) {
+    let vec: Vec<_> = (0..100).collect();
+    b.iter(|| vec.starts_with(&vec))
+}
+
+#[bench]
+fn starts_with_single_element(b: &mut Bencher) {
+    let vec: Vec<_> = vec![0];
+    b.iter(|| vec.starts_with(&vec))
+}
+
+#[bench]
+fn starts_with_diff_one_element_at_end(b: &mut Bencher) {
+    let vec: Vec<_> = (0..100).collect();
+    let mut match_vec: Vec<_> = (0..99).collect();
+    match_vec.push(0);
+    b.iter(|| vec.starts_with(&match_vec))
+}
+
+#[bench]
+fn ends_with_same_vector(b: &mut Bencher) {
+    let vec: Vec<_> = (0..100).collect();
+    b.iter(|| vec.ends_with(&vec))
+}
+
+#[bench]
+fn ends_with_single_element(b: &mut Bencher) {
+    let vec: Vec<_> = vec![0];
+    b.iter(|| vec.ends_with(&vec))
+}
+
+#[bench]
+fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) {
+    let vec: Vec<_> = (0..100).collect();
+    let mut match_vec: Vec<_> = (0..100).collect();
+    match_vec[0] = 200;
+    b.iter(|| vec.starts_with(&match_vec))
+}
+
+#[bench]
+fn contains_last_element(b: &mut Bencher) {
+    let vec: Vec<_> = (0..100).collect();
+    b.iter(|| vec.contains(&99))
+}
+
+#[bench]
+fn zero_1kb_from_elem(b: &mut Bencher) {
+    b.iter(|| vec![0u8; 1024]);
+}
+
+#[bench]
+fn zero_1kb_set_memory(b: &mut Bencher) {
+    b.iter(|| {
+        let mut v = Vec::<u8>::with_capacity(1024);
+        unsafe {
+            let vp = v.as_mut_ptr();
+            ptr::write_bytes(vp, 0, 1024);
+            v.set_len(1024);
+        }
+        v
+    });
+}
+
+#[bench]
+fn zero_1kb_loop_set(b: &mut Bencher) {
+    b.iter(|| {
+        let mut v = Vec::<u8>::with_capacity(1024);
+        unsafe {
+            v.set_len(1024);
+        }
+        for i in 0..1024 {
+            v[i] = 0;
+        }
+    });
+}
+
+#[bench]
+fn zero_1kb_mut_iter(b: &mut Bencher) {
+    b.iter(|| {
+        let mut v = Vec::<u8>::with_capacity(1024);
+        unsafe {
+            v.set_len(1024);
+        }
+        for x in &mut v {
+            *x = 0;
+        }
+        v
+    });
+}
+
+#[bench]
+fn random_inserts(b: &mut Bencher) {
+    let mut rng = thread_rng();
+    b.iter(|| {
+        let mut v = vec![(0, 0); 30];
+        for _ in 0..100 {
+            let l = v.len();
+            v.insert(rng.gen::<usize>() % (l + 1), (1, 1));
+        }
+    })
+}
+#[bench]
+fn random_removes(b: &mut Bencher) {
+    let mut rng = thread_rng();
+    b.iter(|| {
+        let mut v = vec![(0, 0); 130];
+        for _ in 0..100 {
+            let l = v.len();
+            v.remove(rng.gen::<usize>() % l);
+        }
+    })
+}
+
+fn gen_ascending(len: usize) -> Vec<u64> {
+    (0..len as u64).collect()
+}
+
+fn gen_descending(len: usize) -> Vec<u64> {
+    (0..len as u64).rev().collect()
+}
+
+fn gen_random(len: usize) -> Vec<u64> {
+    let mut rng = thread_rng();
+    rng.gen_iter::<u64>().take(len).collect()
+}
+
+fn gen_mostly_ascending(len: usize) -> Vec<u64> {
+    let mut rng = thread_rng();
+    let mut v = gen_ascending(len);
+    for _ in (0usize..).take_while(|x| x * x <= len) {
+        let x = rng.gen::<usize>() % len;
+        let y = rng.gen::<usize>() % len;
+        v.swap(x, y);
+    }
+    v
+}
+
+fn gen_mostly_descending(len: usize) -> Vec<u64> {
+    let mut rng = thread_rng();
+    let mut v = gen_descending(len);
+    for _ in (0usize..).take_while(|x| x * x <= len) {
+        let x = rng.gen::<usize>() % len;
+        let y = rng.gen::<usize>() % len;
+        v.swap(x, y);
+    }
+    v
+}
+
+fn gen_big_random(len: usize) -> Vec<[u64; 16]> {
+    let mut rng = thread_rng();
+    rng.gen_iter().map(|x| [x; 16]).take(len).collect()
+}
+
+fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> {
+    (0..len as u64).map(|x| [x; 16]).take(len).collect()
+}
+
+fn gen_big_descending(len: usize) -> Vec<[u64; 16]> {
+    (0..len as u64).rev().map(|x| [x; 16]).take(len).collect()
+}
+
+macro_rules! sort_bench {
+    ($name:ident, $gen:expr, $len:expr) => {
+        #[bench]
+        fn $name(b: &mut Bencher) {
+            b.iter(|| $gen($len).sort());
+            b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
+        }
+    }
+}
+
+sort_bench!(sort_small_random, gen_random, 10);
+sort_bench!(sort_small_ascending, gen_ascending, 10);
+sort_bench!(sort_small_descending, gen_descending, 10);
+
+sort_bench!(sort_small_big_random, gen_big_random, 10);
+sort_bench!(sort_small_big_ascending, gen_big_ascending, 10);
+sort_bench!(sort_small_big_descending, gen_big_descending, 10);
+
+sort_bench!(sort_medium_random, gen_random, 100);
+sort_bench!(sort_medium_ascending, gen_ascending, 100);
+sort_bench!(sort_medium_descending, gen_descending, 100);
+
+sort_bench!(sort_large_random, gen_random, 10000);
+sort_bench!(sort_large_ascending, gen_ascending, 10000);
+sort_bench!(sort_large_descending, gen_descending, 10000);
+sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000);
+sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000);
+
+sort_bench!(sort_large_big_random, gen_big_random, 10000);
+sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000);
+sort_bench!(sort_large_big_descending, gen_big_descending, 10000);
+
+#[bench]
+fn sort_large_random_expensive(b: &mut Bencher) {
+    let len = 10000;
+    b.iter(|| {
+        let mut v = gen_random(len);
+        let mut count = 0;
+        v.sort_by(|a: &u64, b: &u64| {
+            count += 1;
+            if count % 1_000_000_000 == 0 {
+                panic!("should not happen");
+            }
+            (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap()
+        });
+        black_box(count);
+    });
+    b.bytes = len as u64 * mem::size_of::<u64>() as u64;
+}
\ No newline at end of file
diff --git a/src/libcollections/benches/str.rs b/src/libcollections/benches/str.rs
new file mode 100644 (file)
index 0000000..7f72707
--- /dev/null
@@ -0,0 +1,298 @@
+// 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 test::{Bencher, black_box};
+
+#[bench]
+fn char_iterator(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+    b.iter(|| s.chars().count());
+}
+
+#[bench]
+fn char_iterator_for(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+    b.iter(|| {
+        for ch in s.chars() { black_box(ch); }
+    });
+}
+
+#[bench]
+fn char_iterator_ascii(b: &mut Bencher) {
+    let s = "Mary had a little lamb, Little lamb
+    Mary had a little lamb, Little lamb
+    Mary had a little lamb, Little lamb
+    Mary had a little lamb, Little lamb
+    Mary had a little lamb, Little lamb
+    Mary had a little lamb, Little lamb";
+
+    b.iter(|| s.chars().count());
+}
+
+#[bench]
+fn char_iterator_rev(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+    b.iter(|| s.chars().rev().count());
+}
+
+#[bench]
+fn char_iterator_rev_for(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+    b.iter(|| {
+        for ch in s.chars().rev() { black_box(ch); }
+    });
+}
+
+#[bench]
+fn char_indicesator(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+    let len = s.chars().count();
+
+    b.iter(|| assert_eq!(s.char_indices().count(), len));
+}
+
+#[bench]
+fn char_indicesator_rev(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+    let len = s.chars().count();
+
+    b.iter(|| assert_eq!(s.char_indices().rev().count(), len));
+}
+
+#[bench]
+fn split_unicode_ascii(b: &mut Bencher) {
+    let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
+
+    b.iter(|| assert_eq!(s.split('V').count(), 3));
+}
+
+#[bench]
+fn split_ascii(b: &mut Bencher) {
+    let s = "Mary had a little lamb, Little lamb, little-lamb.";
+    let len = s.split(' ').count();
+
+    b.iter(|| assert_eq!(s.split(' ').count(), len));
+}
+
+#[bench]
+fn split_extern_fn(b: &mut Bencher) {
+    let s = "Mary had a little lamb, Little lamb, little-lamb.";
+    let len = s.split(' ').count();
+    fn pred(c: char) -> bool { c == ' ' }
+
+    b.iter(|| assert_eq!(s.split(pred).count(), len));
+}
+
+#[bench]
+fn split_closure(b: &mut Bencher) {
+    let s = "Mary had a little lamb, Little lamb, little-lamb.";
+    let len = s.split(' ').count();
+
+    b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len));
+}
+
+#[bench]
+fn split_slice(b: &mut Bencher) {
+    let s = "Mary had a little lamb, Little lamb, little-lamb.";
+    let len = s.split(' ').count();
+
+    let c: &[char] = &[' '];
+    b.iter(|| assert_eq!(s.split(c).count(), len));
+}
+
+#[bench]
+fn bench_join(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+    let sep = "→";
+    let v = vec![s, s, s, s, s, s, s, s, s, s];
+    b.iter(|| {
+        assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9);
+    })
+}
+
+#[bench]
+fn bench_contains_short_short(b: &mut Bencher) {
+    let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+    let needle = "sit";
+
+    b.iter(|| {
+        assert!(haystack.contains(needle));
+    })
+}
+
+#[bench]
+fn bench_contains_short_long(b: &mut Bencher) {
+    let haystack = "\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
+ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
+eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
+sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
+tempus vel, gravida nec quam.
+
+In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
+sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
+diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
+lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
+eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
+interdum. Curabitur ut nisi justo.
+
+Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
+mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
+lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
+est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
+felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
+ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
+feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
+Aliquam sit amet placerat lorem.
+
+Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
+mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
+Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
+lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
+suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
+cursus accumsan.
+
+Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
+feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
+vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
+leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
+malesuada sollicitudin quam eu fermentum.";
+    let needle = "english";
+
+    b.iter(|| {
+        assert!(!haystack.contains(needle));
+    })
+}
+
+#[bench]
+fn bench_contains_bad_naive(b: &mut Bencher) {
+    let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    let needle = "aaaaaaaab";
+
+    b.iter(|| {
+        assert!(!haystack.contains(needle));
+    })
+}
+
+#[bench]
+fn bench_contains_equal(b: &mut Bencher) {
+    let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+    let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+
+    b.iter(|| {
+        assert!(haystack.contains(needle));
+    })
+}
+
+macro_rules! make_test_inner {
+    ($s:ident, $code:expr, $name:ident, $str:expr) => {
+        #[bench]
+        fn $name(bencher: &mut Bencher) {
+            let mut $s = $str;
+            black_box(&mut $s);
+            bencher.iter(|| $code);
+        }
+    }
+}
+
+macro_rules! make_test {
+    ($name:ident, $s:ident, $code:expr) => {
+        mod $name {
+            use test::Bencher;
+            use test::black_box;
+
+            // Short strings: 65 bytes each
+            make_test_inner!($s, $code, short_ascii,
+                "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!");
+            make_test_inner!($s, $code, short_mixed,
+                "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!");
+            make_test_inner!($s, $code, short_pile_of_poo,
+                "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!");
+            make_test_inner!($s, $code, long_lorem_ipsum,"\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
+ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
+eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
+sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
+tempus vel, gravida nec quam.
+
+In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
+sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
+diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
+lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
+eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
+interdum. Curabitur ut nisi justo.
+
+Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
+mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
+lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
+est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
+felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
+ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
+feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
+Aliquam sit amet placerat lorem.
+
+Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
+mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
+Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
+lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
+suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
+cursus accumsan.
+
+Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
+feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
+vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
+leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
+malesuada sollicitudin quam eu fermentum!");
+        }
+    }
+}
+
+make_test!(chars_count, s, s.chars().count());
+
+make_test!(contains_bang_str, s, s.contains("!"));
+make_test!(contains_bang_char, s, s.contains('!'));
+
+make_test!(match_indices_a_str, s, s.match_indices("a").count());
+
+make_test!(split_a_str, s, s.split("a").count());
+
+make_test!(trim_ascii_char, s, {
+    use std::ascii::AsciiExt;
+    s.trim_matches(|c: char| c.is_ascii())
+});
+make_test!(trim_left_ascii_char, s, {
+    use std::ascii::AsciiExt;
+    s.trim_left_matches(|c: char| c.is_ascii())
+});
+make_test!(trim_right_ascii_char, s, {
+    use std::ascii::AsciiExt;
+    s.trim_right_matches(|c: char| c.is_ascii())
+});
+
+make_test!(find_underscore_char, s, s.find('_'));
+make_test!(rfind_underscore_char, s, s.rfind('_'));
+make_test!(find_underscore_str, s, s.find("_"));
+
+make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
+make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
+make_test!(find_zzz_str, s, s.find("\u{1F4A4}"));
+
+make_test!(split_space_char, s, s.split(' ').count());
+make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());
+
+make_test!(splitn_space_char, s, s.splitn(10, ' ').count());
+make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
+
+make_test!(split_space_str, s, s.split(" ").count());
+make_test!(split_ad_str, s, s.split("ad").count());
diff --git a/src/libcollections/benches/string.rs b/src/libcollections/benches/string.rs
new file mode 100644 (file)
index 0000000..36be21d
--- /dev/null
@@ -0,0 +1,134 @@
+// 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 std::iter::repeat;
+use test::Bencher;
+
+#[bench]
+fn bench_with_capacity(b: &mut Bencher) {
+    b.iter(|| String::with_capacity(100));
+}
+
+#[bench]
+fn bench_push_str(b: &mut Bencher) {
+    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+    b.iter(|| {
+        let mut r = String::new();
+        r.push_str(s);
+    });
+}
+
+const REPETITIONS: u64 = 10_000;
+
+#[bench]
+fn bench_push_str_one_byte(b: &mut Bencher) {
+    b.bytes = REPETITIONS;
+    b.iter(|| {
+        let mut r = String::new();
+        for _ in 0..REPETITIONS {
+            r.push_str("a")
+        }
+    });
+}
+
+#[bench]
+fn bench_push_char_one_byte(b: &mut Bencher) {
+    b.bytes = REPETITIONS;
+    b.iter(|| {
+        let mut r = String::new();
+        for _ in 0..REPETITIONS {
+            r.push('a')
+        }
+    });
+}
+
+#[bench]
+fn bench_push_char_two_bytes(b: &mut Bencher) {
+    b.bytes = REPETITIONS * 2;
+    b.iter(|| {
+        let mut r = String::new();
+        for _ in 0..REPETITIONS {
+            r.push('â')
+        }
+    });
+}
+
+#[bench]
+fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
+    let s = b"Hello there, the quick brown fox jumped over the lazy dog! \
+              Lorem ipsum dolor sit amet, consectetur. ";
+
+    assert_eq!(100, s.len());
+    b.iter(|| {
+        let _ = String::from_utf8_lossy(s);
+    });
+}
+
+#[bench]
+fn from_utf8_lossy_100_multibyte(b: &mut Bencher) {
+    let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes();
+    assert_eq!(100, s.len());
+    b.iter(|| {
+        let _ = String::from_utf8_lossy(s);
+    });
+}
+
+#[bench]
+fn from_utf8_lossy_invalid(b: &mut Bencher) {
+    let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
+    b.iter(|| {
+        let _ = String::from_utf8_lossy(s);
+    });
+}
+
+#[bench]
+fn from_utf8_lossy_100_invalid(b: &mut Bencher) {
+    let s = repeat(0xf5).take(100).collect::<Vec<_>>();
+    b.iter(|| {
+        let _ = String::from_utf8_lossy(&s);
+    });
+}
+
+#[bench]
+fn bench_exact_size_shrink_to_fit(b: &mut Bencher) {
+    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
+             Lorem ipsum dolor sit amet, consectetur. ";
+    // ensure our operation produces an exact-size string before we benchmark it
+    let mut r = String::with_capacity(s.len());
+    r.push_str(s);
+    assert_eq!(r.len(), r.capacity());
+    b.iter(|| {
+        let mut r = String::with_capacity(s.len());
+        r.push_str(s);
+        r.shrink_to_fit();
+        r
+    });
+}
+
+#[bench]
+fn bench_from_str(b: &mut Bencher) {
+    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
+             Lorem ipsum dolor sit amet, consectetur. ";
+    b.iter(|| String::from(s))
+}
+
+#[bench]
+fn bench_from(b: &mut Bencher) {
+    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
+             Lorem ipsum dolor sit amet, consectetur. ";
+    b.iter(|| String::from(s))
+}
+
+#[bench]
+fn bench_to_string(b: &mut Bencher) {
+    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
+             Lorem ipsum dolor sit amet, consectetur. ";
+    b.iter(|| s.to_string())
+}
diff --git a/src/libcollections/benches/vec.rs b/src/libcollections/benches/vec.rs
new file mode 100644 (file)
index 0000000..4149011
--- /dev/null
@@ -0,0 +1,492 @@
+// 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 test::Bencher;
+use std::iter::{FromIterator, repeat};
+
+#[bench]
+fn bench_new(b: &mut Bencher) {
+    b.iter(|| {
+        let v: Vec<u32> = Vec::new();
+        assert_eq!(v.len(), 0);
+        assert_eq!(v.capacity(), 0);
+    })
+}
+
+fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) {
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let v: Vec<u32> = Vec::with_capacity(src_len);
+        assert_eq!(v.len(), 0);
+        assert_eq!(v.capacity(), src_len);
+    })
+}
+
+#[bench]
+fn bench_with_capacity_0000(b: &mut Bencher) {
+    do_bench_with_capacity(b, 0)
+}
+
+#[bench]
+fn bench_with_capacity_0010(b: &mut Bencher) {
+    do_bench_with_capacity(b, 10)
+}
+
+#[bench]
+fn bench_with_capacity_0100(b: &mut Bencher) {
+    do_bench_with_capacity(b, 100)
+}
+
+#[bench]
+fn bench_with_capacity_1000(b: &mut Bencher) {
+    do_bench_with_capacity(b, 1000)
+}
+
+fn do_bench_from_fn(b: &mut Bencher, src_len: usize) {
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let dst = (0..src_len).collect::<Vec<_>>();
+        assert_eq!(dst.len(), src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    })
+}
+
+#[bench]
+fn bench_from_fn_0000(b: &mut Bencher) {
+    do_bench_from_fn(b, 0)
+}
+
+#[bench]
+fn bench_from_fn_0010(b: &mut Bencher) {
+    do_bench_from_fn(b, 10)
+}
+
+#[bench]
+fn bench_from_fn_0100(b: &mut Bencher) {
+    do_bench_from_fn(b, 100)
+}
+
+#[bench]
+fn bench_from_fn_1000(b: &mut Bencher) {
+    do_bench_from_fn(b, 1000)
+}
+
+fn do_bench_from_elem(b: &mut Bencher, src_len: usize) {
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let dst: Vec<usize> = repeat(5).take(src_len).collect();
+        assert_eq!(dst.len(), src_len);
+        assert!(dst.iter().all(|x| *x == 5));
+    })
+}
+
+#[bench]
+fn bench_from_elem_0000(b: &mut Bencher) {
+    do_bench_from_elem(b, 0)
+}
+
+#[bench]
+fn bench_from_elem_0010(b: &mut Bencher) {
+    do_bench_from_elem(b, 10)
+}
+
+#[bench]
+fn bench_from_elem_0100(b: &mut Bencher) {
+    do_bench_from_elem(b, 100)
+}
+
+#[bench]
+fn bench_from_elem_1000(b: &mut Bencher) {
+    do_bench_from_elem(b, 1000)
+}
+
+fn do_bench_from_slice(b: &mut Bencher, src_len: usize) {
+    let src: Vec<_> = FromIterator::from_iter(0..src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let dst = src.clone()[..].to_vec();
+        assert_eq!(dst.len(), src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_from_slice_0000(b: &mut Bencher) {
+    do_bench_from_slice(b, 0)
+}
+
+#[bench]
+fn bench_from_slice_0010(b: &mut Bencher) {
+    do_bench_from_slice(b, 10)
+}
+
+#[bench]
+fn bench_from_slice_0100(b: &mut Bencher) {
+    do_bench_from_slice(b, 100)
+}
+
+#[bench]
+fn bench_from_slice_1000(b: &mut Bencher) {
+    do_bench_from_slice(b, 1000)
+}
+
+fn do_bench_from_iter(b: &mut Bencher, src_len: usize) {
+    let src: Vec<_> = FromIterator::from_iter(0..src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let dst: Vec<_> = FromIterator::from_iter(src.clone());
+        assert_eq!(dst.len(), src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_from_iter_0000(b: &mut Bencher) {
+    do_bench_from_iter(b, 0)
+}
+
+#[bench]
+fn bench_from_iter_0010(b: &mut Bencher) {
+    do_bench_from_iter(b, 10)
+}
+
+#[bench]
+fn bench_from_iter_0100(b: &mut Bencher) {
+    do_bench_from_iter(b, 100)
+}
+
+#[bench]
+fn bench_from_iter_1000(b: &mut Bencher) {
+    do_bench_from_iter(b, 1000)
+}
+
+fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) {
+    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
+    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let mut dst = dst.clone();
+        dst.extend(src.clone());
+        assert_eq!(dst.len(), dst_len + src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_extend_0000_0000(b: &mut Bencher) {
+    do_bench_extend(b, 0, 0)
+}
+
+#[bench]
+fn bench_extend_0000_0010(b: &mut Bencher) {
+    do_bench_extend(b, 0, 10)
+}
+
+#[bench]
+fn bench_extend_0000_0100(b: &mut Bencher) {
+    do_bench_extend(b, 0, 100)
+}
+
+#[bench]
+fn bench_extend_0000_1000(b: &mut Bencher) {
+    do_bench_extend(b, 0, 1000)
+}
+
+#[bench]
+fn bench_extend_0010_0010(b: &mut Bencher) {
+    do_bench_extend(b, 10, 10)
+}
+
+#[bench]
+fn bench_extend_0100_0100(b: &mut Bencher) {
+    do_bench_extend(b, 100, 100)
+}
+
+#[bench]
+fn bench_extend_1000_1000(b: &mut Bencher) {
+    do_bench_extend(b, 1000, 1000)
+}
+
+fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) {
+    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
+    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let mut dst = dst.clone();
+        dst.extend_from_slice(&src);
+        assert_eq!(dst.len(), dst_len + src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_push_all_0000_0000(b: &mut Bencher) {
+    do_bench_push_all(b, 0, 0)
+}
+
+#[bench]
+fn bench_push_all_0000_0010(b: &mut Bencher) {
+    do_bench_push_all(b, 0, 10)
+}
+
+#[bench]
+fn bench_push_all_0000_0100(b: &mut Bencher) {
+    do_bench_push_all(b, 0, 100)
+}
+
+#[bench]
+fn bench_push_all_0000_1000(b: &mut Bencher) {
+    do_bench_push_all(b, 0, 1000)
+}
+
+#[bench]
+fn bench_push_all_0010_0010(b: &mut Bencher) {
+    do_bench_push_all(b, 10, 10)
+}
+
+#[bench]
+fn bench_push_all_0100_0100(b: &mut Bencher) {
+    do_bench_push_all(b, 100, 100)
+}
+
+#[bench]
+fn bench_push_all_1000_1000(b: &mut Bencher) {
+    do_bench_push_all(b, 1000, 1000)
+}
+
+fn do_bench_push_all_move(b: &mut Bencher, dst_len: usize, src_len: usize) {
+    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
+    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let mut dst = dst.clone();
+        dst.extend(src.clone());
+        assert_eq!(dst.len(), dst_len + src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_push_all_move_0000_0000(b: &mut Bencher) {
+    do_bench_push_all_move(b, 0, 0)
+}
+
+#[bench]
+fn bench_push_all_move_0000_0010(b: &mut Bencher) {
+    do_bench_push_all_move(b, 0, 10)
+}
+
+#[bench]
+fn bench_push_all_move_0000_0100(b: &mut Bencher) {
+    do_bench_push_all_move(b, 0, 100)
+}
+
+#[bench]
+fn bench_push_all_move_0000_1000(b: &mut Bencher) {
+    do_bench_push_all_move(b, 0, 1000)
+}
+
+#[bench]
+fn bench_push_all_move_0010_0010(b: &mut Bencher) {
+    do_bench_push_all_move(b, 10, 10)
+}
+
+#[bench]
+fn bench_push_all_move_0100_0100(b: &mut Bencher) {
+    do_bench_push_all_move(b, 100, 100)
+}
+
+#[bench]
+fn bench_push_all_move_1000_1000(b: &mut Bencher) {
+    do_bench_push_all_move(b, 1000, 1000)
+}
+
+fn do_bench_clone(b: &mut Bencher, src_len: usize) {
+    let src: Vec<usize> = FromIterator::from_iter(0..src_len);
+
+    b.bytes = src_len as u64;
+
+    b.iter(|| {
+        let dst = src.clone();
+        assert_eq!(dst.len(), src_len);
+        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
+    });
+}
+
+#[bench]
+fn bench_clone_0000(b: &mut Bencher) {
+    do_bench_clone(b, 0)
+}
+
+#[bench]
+fn bench_clone_0010(b: &mut Bencher) {
+    do_bench_clone(b, 10)
+}
+
+#[bench]
+fn bench_clone_0100(b: &mut Bencher) {
+    do_bench_clone(b, 100)
+}
+
+#[bench]
+fn bench_clone_1000(b: &mut Bencher) {
+    do_bench_clone(b, 1000)
+}
+
+fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: usize) {
+    let dst: Vec<_> = FromIterator::from_iter(0..src_len);
+    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
+
+    b.bytes = (times * src_len) as u64;
+
+    b.iter(|| {
+        let mut dst = dst.clone();
+
+        for _ in 0..times {
+            dst.clone_from(&src);
+
+            assert_eq!(dst.len(), src_len);
+            assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x));
+        }
+    });
+}
+
+#[bench]
+fn bench_clone_from_01_0000_0000(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 0, 0)
+}
+
+#[bench]
+fn bench_clone_from_01_0000_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 0, 10)
+}
+
+#[bench]
+fn bench_clone_from_01_0000_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 0, 100)
+}
+
+#[bench]
+fn bench_clone_from_01_0000_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 0, 1000)
+}
+
+#[bench]
+fn bench_clone_from_01_0010_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 10, 10)
+}
+
+#[bench]
+fn bench_clone_from_01_0100_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 100, 100)
+}
+
+#[bench]
+fn bench_clone_from_01_1000_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 1000, 1000)
+}
+
+#[bench]
+fn bench_clone_from_01_0010_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 10, 100)
+}
+
+#[bench]
+fn bench_clone_from_01_0100_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 100, 1000)
+}
+
+#[bench]
+fn bench_clone_from_01_0010_0000(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 10, 0)
+}
+
+#[bench]
+fn bench_clone_from_01_0100_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 100, 10)
+}
+
+#[bench]
+fn bench_clone_from_01_1000_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 1, 1000, 100)
+}
+
+#[bench]
+fn bench_clone_from_10_0000_0000(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 0, 0)
+}
+
+#[bench]
+fn bench_clone_from_10_0000_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 0, 10)
+}
+
+#[bench]
+fn bench_clone_from_10_0000_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 0, 100)
+}
+
+#[bench]
+fn bench_clone_from_10_0000_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 0, 1000)
+}
+
+#[bench]
+fn bench_clone_from_10_0010_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 10, 10)
+}
+
+#[bench]
+fn bench_clone_from_10_0100_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 100, 100)
+}
+
+#[bench]
+fn bench_clone_from_10_1000_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 1000, 1000)
+}
+
+#[bench]
+fn bench_clone_from_10_0010_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 10, 100)
+}
+
+#[bench]
+fn bench_clone_from_10_0100_1000(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 100, 1000)
+}
+
+#[bench]
+fn bench_clone_from_10_0010_0000(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 10, 0)
+}
+
+#[bench]
+fn bench_clone_from_10_0100_0010(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 100, 10)
+}
+
+#[bench]
+fn bench_clone_from_10_1000_0100(b: &mut Bencher) {
+    do_bench_clone_from(b, 10, 1000, 100)
+}
diff --git a/src/libcollections/benches/vec_deque.rs b/src/libcollections/benches/vec_deque.rs
new file mode 100644 (file)
index 0000000..380645e
--- /dev/null
@@ -0,0 +1,57 @@
+// 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 std::collections::VecDeque;
+use test::{Bencher, black_box};
+
+#[bench]
+fn bench_new(b: &mut Bencher) {
+    b.iter(|| {
+        let ring: VecDeque<i32> = VecDeque::new();
+        black_box(ring);
+    })
+}
+
+#[bench]
+fn bench_grow_1025(b: &mut Bencher) {
+    b.iter(|| {
+        let mut deq = VecDeque::new();
+        for i in 0..1025 {
+            deq.push_front(i);
+        }
+        black_box(deq);
+    })
+}
+
+#[bench]
+fn bench_iter_1000(b: &mut Bencher) {
+    let ring: VecDeque<_> = (0..1000).collect();
+
+    b.iter(|| {
+        let mut sum = 0;
+        for &i in &ring {
+            sum += i;
+        }
+        black_box(sum);
+    })
+}
+
+#[bench]
+fn bench_mut_iter_1000(b: &mut Bencher) {
+    let mut ring: VecDeque<_> = (0..1000).collect();
+
+    b.iter(|| {
+        let mut sum = 0;
+        for i in &mut ring {
+            sum += *i;
+        }
+        black_box(sum);
+    })
+}
diff --git a/src/libcollectionstest/bench.rs b/src/libcollectionstest/bench.rs
deleted file mode 100644 (file)
index 4e150d4..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2013-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.
-
-macro_rules! map_insert_rand_bench {
-    ($name: ident, $n: expr, $map: ident) => (
-        #[bench]
-        pub fn $name(b: &mut ::test::Bencher) {
-            use std::__rand::{thread_rng, Rng};
-            use test::black_box;
-
-            let n: usize = $n;
-            let mut map = $map::new();
-            // setup
-            let mut rng = thread_rng();
-
-            for _ in 0..n {
-                let i = rng.gen::<usize>() % n;
-                map.insert(i, i);
-            }
-
-            // measure
-            b.iter(|| {
-                let k = rng.gen::<usize>() % n;
-                map.insert(k, k);
-                map.remove(&k);
-            });
-            black_box(map);
-        }
-    )
-}
-
-macro_rules! map_insert_seq_bench {
-    ($name: ident, $n: expr, $map: ident) => (
-        #[bench]
-        pub fn $name(b: &mut ::test::Bencher) {
-            use test::black_box;
-
-            let mut map = $map::new();
-            let n: usize = $n;
-            // setup
-            for i in 0..n {
-                map.insert(i * 2, i * 2);
-            }
-
-            // measure
-            let mut i = 1;
-            b.iter(|| {
-                map.insert(i, i);
-                map.remove(&i);
-                i = (i + 2) % n;
-            });
-            black_box(map);
-        }
-    )
-}
-
-macro_rules! map_find_rand_bench {
-    ($name: ident, $n: expr, $map: ident) => (
-        #[bench]
-        pub fn $name(b: &mut ::test::Bencher) {
-            use std::iter::Iterator;
-            use std::__rand::{thread_rng, Rng};
-            use std::vec::Vec;
-            use test::black_box;
-
-            let mut map = $map::new();
-            let n: usize = $n;
-
-            // setup
-            let mut rng = thread_rng();
-            let mut keys: Vec<_> = (0..n).map(|_| rng.gen::<usize>() % n).collect();
-
-            for &k in &keys {
-                map.insert(k, k);
-            }
-
-            rng.shuffle(&mut keys);
-
-            // measure
-            let mut i = 0;
-            b.iter(|| {
-                let t = map.get(&keys[i]);
-                i = (i + 1) % n;
-                black_box(t);
-            })
-        }
-    )
-}
-
-macro_rules! map_find_seq_bench {
-    ($name: ident, $n: expr, $map: ident) => (
-        #[bench]
-        pub fn $name(b: &mut ::test::Bencher) {
-            use test::black_box;
-
-            let mut map = $map::new();
-            let n: usize = $n;
-
-            // setup
-            for i in 0..n {
-                map.insert(i, i);
-            }
-
-            // measure
-            let mut i = 0;
-            b.iter(|| {
-                let x = map.get(&i);
-                i = (i + 1) % n;
-                black_box(x);
-            })
-        }
-    )
-}
index c84753415a258ae430c2d607fb91da06e5c7510d..11be13426e49cebb93ade022297b828e801485a5 100644 (file)
@@ -606,52 +606,3 @@ fn test_split_off_large_random_sorted() {
     assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key)));
     assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key)));
 }
-
-mod bench {
-    use std::collections::BTreeMap;
-    use std::__rand::{Rng, thread_rng};
-
-    use test::{Bencher, black_box};
-
-    map_insert_rand_bench!{insert_rand_100,    100,    BTreeMap}
-    map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap}
-
-    map_insert_seq_bench!{insert_seq_100,    100,    BTreeMap}
-    map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap}
-
-    map_find_rand_bench!{find_rand_100,    100,    BTreeMap}
-    map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap}
-
-    map_find_seq_bench!{find_seq_100,    100,    BTreeMap}
-    map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap}
-
-    fn bench_iter(b: &mut Bencher, size: i32) {
-        let mut map = BTreeMap::<i32, i32>::new();
-        let mut rng = thread_rng();
-
-        for _ in 0..size {
-            map.insert(rng.gen(), rng.gen());
-        }
-
-        b.iter(|| {
-            for entry in &map {
-                black_box(entry);
-            }
-        });
-    }
-
-    #[bench]
-    pub fn iter_20(b: &mut Bencher) {
-        bench_iter(b, 20);
-    }
-
-    #[bench]
-    pub fn iter_1000(b: &mut Bencher) {
-        bench_iter(b, 1000);
-    }
-
-    #[bench]
-    pub fn iter_100000(b: &mut Bencher) {
-        bench_iter(b, 100000);
-    }
-}
index b146672893f8dcf60ce09202a95581696ff34e8f..57e3c2df059e122775f7d98f0c082980a7a4c7bb 100644 (file)
 use std::hash::{Hash, Hasher};
 use std::collections::hash_map::DefaultHasher;
 
-#[cfg(test)]
-#[macro_use]
-mod bench;
-
 mod binary_heap;
 mod btree;
 mod cow_str;
index 956d75a95a58e9b77230ce2804a5ebbaeab9e72c..a59724a017b1241de3e9995727a719782b76ea7f 100644 (file)
@@ -10,8 +10,6 @@
 
 use std::collections::LinkedList;
 
-use test;
-
 #[test]
 fn test_basic() {
     let mut m = LinkedList::<Box<_>>::new();
@@ -356,81 +354,6 @@ fn test_extend() {
     assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7]));
 }
 
-#[bench]
-fn bench_collect_into(b: &mut test::Bencher) {
-    let v = &[0; 64];
-    b.iter(|| {
-        let _: LinkedList<_> = v.iter().cloned().collect();
-    })
-}
-
-#[bench]
-fn bench_push_front(b: &mut test::Bencher) {
-    let mut m: LinkedList<_> = LinkedList::new();
-    b.iter(|| {
-        m.push_front(0);
-    })
-}
-
-#[bench]
-fn bench_push_back(b: &mut test::Bencher) {
-    let mut m: LinkedList<_> = LinkedList::new();
-    b.iter(|| {
-        m.push_back(0);
-    })
-}
-
-#[bench]
-fn bench_push_back_pop_back(b: &mut test::Bencher) {
-    let mut m: LinkedList<_> = LinkedList::new();
-    b.iter(|| {
-        m.push_back(0);
-        m.pop_back();
-    })
-}
-
-#[bench]
-fn bench_push_front_pop_front(b: &mut test::Bencher) {
-    let mut m: LinkedList<_> = LinkedList::new();
-    b.iter(|| {
-        m.push_front(0);
-        m.pop_front();
-    })
-}
-
-#[bench]
-fn bench_iter(b: &mut test::Bencher) {
-    let v = &[0; 128];
-    let m: LinkedList<_> = v.iter().cloned().collect();
-    b.iter(|| {
-        assert!(m.iter().count() == 128);
-    })
-}
-#[bench]
-fn bench_iter_mut(b: &mut test::Bencher) {
-    let v = &[0; 128];
-    let mut m: LinkedList<_> = v.iter().cloned().collect();
-    b.iter(|| {
-        assert!(m.iter_mut().count() == 128);
-    })
-}
-#[bench]
-fn bench_iter_rev(b: &mut test::Bencher) {
-    let v = &[0; 128];
-    let m: LinkedList<_> = v.iter().cloned().collect();
-    b.iter(|| {
-        assert!(m.iter().rev().count() == 128);
-    })
-}
-#[bench]
-fn bench_iter_mut_rev(b: &mut test::Bencher) {
-    let v = &[0; 128];
-    let mut m: LinkedList<_> = v.iter().cloned().collect();
-    b.iter(|| {
-        assert!(m.iter_mut().rev().count() == 128);
-    })
-}
-
 #[test]
 fn test_contains() {
     let mut l = LinkedList::new();
index b9dec6be7b8853b9401c6089b6455e049bec145a..a7f7baf38518c186751d04f02574ba9bdac7e7ba 100644 (file)
@@ -1170,276 +1170,3 @@ fn test_copy_from_slice_dst_shorter() {
     let mut dst = [0; 3];
     dst.copy_from_slice(&src);
 }
-
-mod bench {
-    use std::{mem, ptr};
-    use std::__rand::{Rng, thread_rng};
-
-    use test::{Bencher, black_box};
-
-    #[bench]
-    fn iterator(b: &mut Bencher) {
-        // peculiar numbers to stop LLVM from optimising the summation
-        // out.
-        let v: Vec<_> = (0..100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect();
-
-        b.iter(|| {
-            let mut sum = 0;
-            for x in &v {
-                sum += *x;
-            }
-            // sum == 11806, to stop dead code elimination.
-            if sum == 0 {
-                panic!()
-            }
-        })
-    }
-
-    #[bench]
-    fn mut_iterator(b: &mut Bencher) {
-        let mut v = vec![0; 100];
-
-        b.iter(|| {
-            let mut i = 0;
-            for x in &mut v {
-                *x = i;
-                i += 1;
-            }
-        })
-    }
-
-    #[bench]
-    fn concat(b: &mut Bencher) {
-        let xss: Vec<Vec<i32>> = (0..100).map(|i| (0..i).collect()).collect();
-        b.iter(|| {
-            xss.concat();
-        });
-    }
-
-    #[bench]
-    fn join(b: &mut Bencher) {
-        let xss: Vec<Vec<i32>> = (0..100).map(|i| (0..i).collect()).collect();
-        b.iter(|| xss.join(&0));
-    }
-
-    #[bench]
-    fn push(b: &mut Bencher) {
-        let mut vec = Vec::<i32>::new();
-        b.iter(|| {
-            vec.push(0);
-            black_box(&vec);
-        });
-    }
-
-    #[bench]
-    fn starts_with_same_vector(b: &mut Bencher) {
-        let vec: Vec<_> = (0..100).collect();
-        b.iter(|| vec.starts_with(&vec))
-    }
-
-    #[bench]
-    fn starts_with_single_element(b: &mut Bencher) {
-        let vec: Vec<_> = vec![0];
-        b.iter(|| vec.starts_with(&vec))
-    }
-
-    #[bench]
-    fn starts_with_diff_one_element_at_end(b: &mut Bencher) {
-        let vec: Vec<_> = (0..100).collect();
-        let mut match_vec: Vec<_> = (0..99).collect();
-        match_vec.push(0);
-        b.iter(|| vec.starts_with(&match_vec))
-    }
-
-    #[bench]
-    fn ends_with_same_vector(b: &mut Bencher) {
-        let vec: Vec<_> = (0..100).collect();
-        b.iter(|| vec.ends_with(&vec))
-    }
-
-    #[bench]
-    fn ends_with_single_element(b: &mut Bencher) {
-        let vec: Vec<_> = vec![0];
-        b.iter(|| vec.ends_with(&vec))
-    }
-
-    #[bench]
-    fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) {
-        let vec: Vec<_> = (0..100).collect();
-        let mut match_vec: Vec<_> = (0..100).collect();
-        match_vec[0] = 200;
-        b.iter(|| vec.starts_with(&match_vec))
-    }
-
-    #[bench]
-    fn contains_last_element(b: &mut Bencher) {
-        let vec: Vec<_> = (0..100).collect();
-        b.iter(|| vec.contains(&99))
-    }
-
-    #[bench]
-    fn zero_1kb_from_elem(b: &mut Bencher) {
-        b.iter(|| vec![0u8; 1024]);
-    }
-
-    #[bench]
-    fn zero_1kb_set_memory(b: &mut Bencher) {
-        b.iter(|| {
-            let mut v = Vec::<u8>::with_capacity(1024);
-            unsafe {
-                let vp = v.as_mut_ptr();
-                ptr::write_bytes(vp, 0, 1024);
-                v.set_len(1024);
-            }
-            v
-        });
-    }
-
-    #[bench]
-    fn zero_1kb_loop_set(b: &mut Bencher) {
-        b.iter(|| {
-            let mut v = Vec::<u8>::with_capacity(1024);
-            unsafe {
-                v.set_len(1024);
-            }
-            for i in 0..1024 {
-                v[i] = 0;
-            }
-        });
-    }
-
-    #[bench]
-    fn zero_1kb_mut_iter(b: &mut Bencher) {
-        b.iter(|| {
-            let mut v = Vec::<u8>::with_capacity(1024);
-            unsafe {
-                v.set_len(1024);
-            }
-            for x in &mut v {
-                *x = 0;
-            }
-            v
-        });
-    }
-
-    #[bench]
-    fn random_inserts(b: &mut Bencher) {
-        let mut rng = thread_rng();
-        b.iter(|| {
-            let mut v = vec![(0, 0); 30];
-            for _ in 0..100 {
-                let l = v.len();
-                v.insert(rng.gen::<usize>() % (l + 1), (1, 1));
-            }
-        })
-    }
-    #[bench]
-    fn random_removes(b: &mut Bencher) {
-        let mut rng = thread_rng();
-        b.iter(|| {
-            let mut v = vec![(0, 0); 130];
-            for _ in 0..100 {
-                let l = v.len();
-                v.remove(rng.gen::<usize>() % l);
-            }
-        })
-    }
-
-    fn gen_ascending(len: usize) -> Vec<u64> {
-        (0..len as u64).collect()
-    }
-
-    fn gen_descending(len: usize) -> Vec<u64> {
-        (0..len as u64).rev().collect()
-    }
-
-    fn gen_random(len: usize) -> Vec<u64> {
-        let mut rng = thread_rng();
-        rng.gen_iter::<u64>().take(len).collect()
-    }
-
-    fn gen_mostly_ascending(len: usize) -> Vec<u64> {
-        let mut rng = thread_rng();
-        let mut v = gen_ascending(len);
-        for _ in (0usize..).take_while(|x| x * x <= len) {
-            let x = rng.gen::<usize>() % len;
-            let y = rng.gen::<usize>() % len;
-            v.swap(x, y);
-        }
-        v
-    }
-
-    fn gen_mostly_descending(len: usize) -> Vec<u64> {
-        let mut rng = thread_rng();
-        let mut v = gen_descending(len);
-        for _ in (0usize..).take_while(|x| x * x <= len) {
-            let x = rng.gen::<usize>() % len;
-            let y = rng.gen::<usize>() % len;
-            v.swap(x, y);
-        }
-        v
-    }
-
-    fn gen_big_random(len: usize) -> Vec<[u64; 16]> {
-        let mut rng = thread_rng();
-        rng.gen_iter().map(|x| [x; 16]).take(len).collect()
-    }
-
-    fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> {
-        (0..len as u64).map(|x| [x; 16]).take(len).collect()
-    }
-
-    fn gen_big_descending(len: usize) -> Vec<[u64; 16]> {
-        (0..len as u64).rev().map(|x| [x; 16]).take(len).collect()
-    }
-
-    macro_rules! sort_bench {
-        ($name:ident, $gen:expr, $len:expr) => {
-            #[bench]
-            fn $name(b: &mut Bencher) {
-                b.iter(|| $gen($len).sort());
-                b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
-            }
-        }
-    }
-
-    sort_bench!(sort_small_random, gen_random, 10);
-    sort_bench!(sort_small_ascending, gen_ascending, 10);
-    sort_bench!(sort_small_descending, gen_descending, 10);
-
-    sort_bench!(sort_small_big_random, gen_big_random, 10);
-    sort_bench!(sort_small_big_ascending, gen_big_ascending, 10);
-    sort_bench!(sort_small_big_descending, gen_big_descending, 10);
-
-    sort_bench!(sort_medium_random, gen_random, 100);
-    sort_bench!(sort_medium_ascending, gen_ascending, 100);
-    sort_bench!(sort_medium_descending, gen_descending, 100);
-
-    sort_bench!(sort_large_random, gen_random, 10000);
-    sort_bench!(sort_large_ascending, gen_ascending, 10000);
-    sort_bench!(sort_large_descending, gen_descending, 10000);
-    sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000);
-    sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000);
-
-    sort_bench!(sort_large_big_random, gen_big_random, 10000);
-    sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000);
-    sort_bench!(sort_large_big_descending, gen_big_descending, 10000);
-
-    #[bench]
-    fn sort_large_random_expensive(b: &mut Bencher) {
-        let len = 10000;
-        b.iter(|| {
-            let mut v = gen_random(len);
-            let mut count = 0;
-            v.sort_by(|a: &u64, b: &u64| {
-                count += 1;
-                if count % 1_000_000_000 == 0 {
-                    panic!("should not happen");
-                }
-                (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap()
-            });
-            black_box(count);
-        });
-        b.bytes = len as u64 * mem::size_of::<u64>() as u64;
-    }
-}
index 5e685847e3c81afcee49be68bf9b9570addde49b..6221888f5e55e7777ed4fdbe43ea6f0493592c30 100644 (file)
@@ -1564,294 +1564,3 @@ fn foo<'a, P>(p: P) where for<'b> &'b P: Pattern<'a> {
 
     foo::<&str>("x");
 }
-
-mod bench {
-    use test::{Bencher, black_box};
-
-    #[bench]
-    fn char_iterator(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-
-        b.iter(|| s.chars().count());
-    }
-
-    #[bench]
-    fn char_iterator_for(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-
-        b.iter(|| {
-            for ch in s.chars() { black_box(ch); }
-        });
-    }
-
-    #[bench]
-    fn char_iterator_ascii(b: &mut Bencher) {
-        let s = "Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb";
-
-        b.iter(|| s.chars().count());
-    }
-
-    #[bench]
-    fn char_iterator_rev(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-
-        b.iter(|| s.chars().rev().count());
-    }
-
-    #[bench]
-    fn char_iterator_rev_for(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-
-        b.iter(|| {
-            for ch in s.chars().rev() { black_box(ch); }
-        });
-    }
-
-    #[bench]
-    fn char_indicesator(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-        let len = s.chars().count();
-
-        b.iter(|| assert_eq!(s.char_indices().count(), len));
-    }
-
-    #[bench]
-    fn char_indicesator_rev(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-        let len = s.chars().count();
-
-        b.iter(|| assert_eq!(s.char_indices().rev().count(), len));
-    }
-
-    #[bench]
-    fn split_unicode_ascii(b: &mut Bencher) {
-        let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
-
-        b.iter(|| assert_eq!(s.split('V').count(), 3));
-    }
-
-    #[bench]
-    fn split_ascii(b: &mut Bencher) {
-        let s = "Mary had a little lamb, Little lamb, little-lamb.";
-        let len = s.split(' ').count();
-
-        b.iter(|| assert_eq!(s.split(' ').count(), len));
-    }
-
-    #[bench]
-    fn split_extern_fn(b: &mut Bencher) {
-        let s = "Mary had a little lamb, Little lamb, little-lamb.";
-        let len = s.split(' ').count();
-        fn pred(c: char) -> bool { c == ' ' }
-
-        b.iter(|| assert_eq!(s.split(pred).count(), len));
-    }
-
-    #[bench]
-    fn split_closure(b: &mut Bencher) {
-        let s = "Mary had a little lamb, Little lamb, little-lamb.";
-        let len = s.split(' ').count();
-
-        b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len));
-    }
-
-    #[bench]
-    fn split_slice(b: &mut Bencher) {
-        let s = "Mary had a little lamb, Little lamb, little-lamb.";
-        let len = s.split(' ').count();
-
-        let c: &[char] = &[' '];
-        b.iter(|| assert_eq!(s.split(c).count(), len));
-    }
-
-    #[bench]
-    fn bench_join(b: &mut Bencher) {
-        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-        let sep = "→";
-        let v = vec![s, s, s, s, s, s, s, s, s, s];
-        b.iter(|| {
-            assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9);
-        })
-    }
-
-    #[bench]
-    fn bench_contains_short_short(b: &mut Bencher) {
-        let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
-        let needle = "sit";
-
-        b.iter(|| {
-            assert!(haystack.contains(needle));
-        })
-    }
-
-    #[bench]
-    fn bench_contains_short_long(b: &mut Bencher) {
-        let haystack = "\
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
-ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
-eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
-sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
-tempus vel, gravida nec quam.
-
-In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
-sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
-diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
-lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
-eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
-interdum. Curabitur ut nisi justo.
-
-Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
-mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
-lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
-est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
-felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
-ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
-feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
-Aliquam sit amet placerat lorem.
-
-Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
-mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
-Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
-lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
-suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
-cursus accumsan.
-
-Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
-feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
-vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
-leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
-malesuada sollicitudin quam eu fermentum.";
-        let needle = "english";
-
-        b.iter(|| {
-            assert!(!haystack.contains(needle));
-        })
-    }
-
-    #[bench]
-    fn bench_contains_bad_naive(b: &mut Bencher) {
-        let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
-        let needle = "aaaaaaaab";
-
-        b.iter(|| {
-            assert!(!haystack.contains(needle));
-        })
-    }
-
-    #[bench]
-    fn bench_contains_equal(b: &mut Bencher) {
-        let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
-        let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
-
-        b.iter(|| {
-            assert!(haystack.contains(needle));
-        })
-    }
-
-    macro_rules! make_test_inner {
-        ($s:ident, $code:expr, $name:ident, $str:expr) => {
-            #[bench]
-            fn $name(bencher: &mut Bencher) {
-                let mut $s = $str;
-                black_box(&mut $s);
-                bencher.iter(|| $code);
-            }
-        }
-    }
-
-    macro_rules! make_test {
-        ($name:ident, $s:ident, $code:expr) => {
-            mod $name {
-                use test::Bencher;
-                use test::black_box;
-
-                // Short strings: 65 bytes each
-                make_test_inner!($s, $code, short_ascii,
-                    "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!");
-                make_test_inner!($s, $code, short_mixed,
-                    "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!");
-                make_test_inner!($s, $code, short_pile_of_poo,
-                    "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!");
-                make_test_inner!($s, $code, long_lorem_ipsum,"\
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
-ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
-eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
-sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
-tempus vel, gravida nec quam.
-
-In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
-sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
-diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
-lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
-eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
-interdum. Curabitur ut nisi justo.
-
-Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
-mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
-lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
-est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
-felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
-ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
-feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
-Aliquam sit amet placerat lorem.
-
-Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
-mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
-Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
-lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
-suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
-cursus accumsan.
-
-Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
-feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
-vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
-leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
-malesuada sollicitudin quam eu fermentum!");
-            }
-        }
-    }
-
-    make_test!(chars_count, s, s.chars().count());
-
-    make_test!(contains_bang_str, s, s.contains("!"));
-    make_test!(contains_bang_char, s, s.contains('!'));
-
-    make_test!(match_indices_a_str, s, s.match_indices("a").count());
-
-    make_test!(split_a_str, s, s.split("a").count());
-
-    make_test!(trim_ascii_char, s, {
-        use std::ascii::AsciiExt;
-        s.trim_matches(|c: char| c.is_ascii())
-    });
-    make_test!(trim_left_ascii_char, s, {
-        use std::ascii::AsciiExt;
-        s.trim_left_matches(|c: char| c.is_ascii())
-    });
-    make_test!(trim_right_ascii_char, s, {
-        use std::ascii::AsciiExt;
-        s.trim_right_matches(|c: char| c.is_ascii())
-    });
-
-    make_test!(find_underscore_char, s, s.find('_'));
-    make_test!(rfind_underscore_char, s, s.rfind('_'));
-    make_test!(find_underscore_str, s, s.find("_"));
-
-    make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
-    make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
-    make_test!(find_zzz_str, s, s.find("\u{1F4A4}"));
-
-    make_test!(split_space_char, s, s.split(' ').count());
-    make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());
-
-    make_test!(splitn_space_char, s, s.splitn(10, ' ').count());
-    make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
-
-    make_test!(split_space_str, s, s.split(" ").count());
-    make_test!(split_ad_str, s, s.split("ad").count());
-}
index a7d85d0bea13a76a22ccc355b87ea821af637e22..f77dd510303c74b3564b2acbdda66080aef50a9e 100644 (file)
@@ -9,9 +9,6 @@
 // except according to those terms.
 
 use std::borrow::Cow;
-use std::iter::repeat;
-
-use test::Bencher;
 
 pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
     fn into_cow(self) -> Cow<'a, B>;
@@ -436,125 +433,3 @@ fn test_into_boxed_str() {
     let ys = xs.into_boxed_str();
     assert_eq!(&*ys, "hello my name is bob");
 }
-
-#[bench]
-fn bench_with_capacity(b: &mut Bencher) {
-    b.iter(|| String::with_capacity(100));
-}
-
-#[bench]
-fn bench_push_str(b: &mut Bencher) {
-    let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-    b.iter(|| {
-        let mut r = String::new();
-        r.push_str(s);
-    });
-}
-
-const REPETITIONS: u64 = 10_000;
-
-#[bench]
-fn bench_push_str_one_byte(b: &mut Bencher) {
-    b.bytes = REPETITIONS;
-    b.iter(|| {
-        let mut r = String::new();
-        for _ in 0..REPETITIONS {
-            r.push_str("a")
-        }
-    });
-}
-
-#[bench]
-fn bench_push_char_one_byte(b: &mut Bencher) {
-    b.bytes = REPETITIONS;
-    b.iter(|| {
-        let mut r = String::new();
-        for _ in 0..REPETITIONS {
-            r.push('a')
-        }
-    });
-}
-
-#[bench]
-fn bench_push_char_two_bytes(b: &mut Bencher) {
-    b.bytes = REPETITIONS * 2;
-    b.iter(|| {
-        let mut r = String::new();
-        for _ in 0..REPETITIONS {
-            r.push('â')
-        }
-    });
-}
-
-#[bench]
-fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
-    let s = b"Hello there, the quick brown fox jumped over the lazy dog! \
-              Lorem ipsum dolor sit amet, consectetur. ";
-
-    assert_eq!(100, s.len());
-    b.iter(|| {
-        let _ = String::from_utf8_lossy(s);
-    });
-}
-
-#[bench]
-fn from_utf8_lossy_100_multibyte(b: &mut Bencher) {
-    let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes();
-    assert_eq!(100, s.len());
-    b.iter(|| {
-        let _ = String::from_utf8_lossy(s);
-    });
-}
-
-#[bench]
-fn from_utf8_lossy_invalid(b: &mut Bencher) {
-    let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
-    b.iter(|| {
-        let _ = String::from_utf8_lossy(s);
-    });
-}
-
-#[bench]
-fn from_utf8_lossy_100_invalid(b: &mut Bencher) {
-    let s = repeat(0xf5).take(100).collect::<Vec<_>>();
-    b.iter(|| {
-        let _ = String::from_utf8_lossy(&s);
-    });
-}
-
-#[bench]
-fn bench_exact_size_shrink_to_fit(b: &mut Bencher) {
-    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
-             Lorem ipsum dolor sit amet, consectetur. ";
-    // ensure our operation produces an exact-size string before we benchmark it
-    let mut r = String::with_capacity(s.len());
-    r.push_str(s);
-    assert_eq!(r.len(), r.capacity());
-    b.iter(|| {
-        let mut r = String::with_capacity(s.len());
-        r.push_str(s);
-        r.shrink_to_fit();
-        r
-    });
-}
-
-#[bench]
-fn bench_from_str(b: &mut Bencher) {
-    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
-             Lorem ipsum dolor sit amet, consectetur. ";
-    b.iter(|| String::from(s))
-}
-
-#[bench]
-fn bench_from(b: &mut Bencher) {
-    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
-             Lorem ipsum dolor sit amet, consectetur. ";
-    b.iter(|| String::from(s))
-}
-
-#[bench]
-fn bench_to_string(b: &mut Bencher) {
-    let s = "Hello there, the quick brown fox jumped over the lazy dog! \
-             Lorem ipsum dolor sit amet, consectetur. ";
-    b.iter(|| s.to_string())
-}
index 6d0f1eaffaa7bb6c432690f12ae437d7a9896102..edeedf1d40baf3d37b38d6c36928945c7828558a 100644 (file)
 
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
-use std::iter::{FromIterator, repeat};
 use std::mem::size_of;
 use std::panic;
 use std::vec::{Drain, IntoIter};
 
-use test::Bencher;
-
 struct DropCounter<'a> {
     count: &'a mut u32,
 }
@@ -633,483 +630,3 @@ fn mkpanic() -> usize { panic!() }
     let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
     assert_eq!(vec.len(), 3);
 }
-
-#[bench]
-fn bench_new(b: &mut Bencher) {
-    b.iter(|| {
-        let v: Vec<u32> = Vec::new();
-        assert_eq!(v.len(), 0);
-        assert_eq!(v.capacity(), 0);
-    })
-}
-
-fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) {
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let v: Vec<u32> = Vec::with_capacity(src_len);
-        assert_eq!(v.len(), 0);
-        assert_eq!(v.capacity(), src_len);
-    })
-}
-
-#[bench]
-fn bench_with_capacity_0000(b: &mut Bencher) {
-    do_bench_with_capacity(b, 0)
-}
-
-#[bench]
-fn bench_with_capacity_0010(b: &mut Bencher) {
-    do_bench_with_capacity(b, 10)
-}
-
-#[bench]
-fn bench_with_capacity_0100(b: &mut Bencher) {
-    do_bench_with_capacity(b, 100)
-}
-
-#[bench]
-fn bench_with_capacity_1000(b: &mut Bencher) {
-    do_bench_with_capacity(b, 1000)
-}
-
-fn do_bench_from_fn(b: &mut Bencher, src_len: usize) {
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let dst = (0..src_len).collect::<Vec<_>>();
-        assert_eq!(dst.len(), src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    })
-}
-
-#[bench]
-fn bench_from_fn_0000(b: &mut Bencher) {
-    do_bench_from_fn(b, 0)
-}
-
-#[bench]
-fn bench_from_fn_0010(b: &mut Bencher) {
-    do_bench_from_fn(b, 10)
-}
-
-#[bench]
-fn bench_from_fn_0100(b: &mut Bencher) {
-    do_bench_from_fn(b, 100)
-}
-
-#[bench]
-fn bench_from_fn_1000(b: &mut Bencher) {
-    do_bench_from_fn(b, 1000)
-}
-
-fn do_bench_from_elem(b: &mut Bencher, src_len: usize) {
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let dst: Vec<usize> = repeat(5).take(src_len).collect();
-        assert_eq!(dst.len(), src_len);
-        assert!(dst.iter().all(|x| *x == 5));
-    })
-}
-
-#[bench]
-fn bench_from_elem_0000(b: &mut Bencher) {
-    do_bench_from_elem(b, 0)
-}
-
-#[bench]
-fn bench_from_elem_0010(b: &mut Bencher) {
-    do_bench_from_elem(b, 10)
-}
-
-#[bench]
-fn bench_from_elem_0100(b: &mut Bencher) {
-    do_bench_from_elem(b, 100)
-}
-
-#[bench]
-fn bench_from_elem_1000(b: &mut Bencher) {
-    do_bench_from_elem(b, 1000)
-}
-
-fn do_bench_from_slice(b: &mut Bencher, src_len: usize) {
-    let src: Vec<_> = FromIterator::from_iter(0..src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let dst = src.clone()[..].to_vec();
-        assert_eq!(dst.len(), src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_from_slice_0000(b: &mut Bencher) {
-    do_bench_from_slice(b, 0)
-}
-
-#[bench]
-fn bench_from_slice_0010(b: &mut Bencher) {
-    do_bench_from_slice(b, 10)
-}
-
-#[bench]
-fn bench_from_slice_0100(b: &mut Bencher) {
-    do_bench_from_slice(b, 100)
-}
-
-#[bench]
-fn bench_from_slice_1000(b: &mut Bencher) {
-    do_bench_from_slice(b, 1000)
-}
-
-fn do_bench_from_iter(b: &mut Bencher, src_len: usize) {
-    let src: Vec<_> = FromIterator::from_iter(0..src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let dst: Vec<_> = FromIterator::from_iter(src.clone());
-        assert_eq!(dst.len(), src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_from_iter_0000(b: &mut Bencher) {
-    do_bench_from_iter(b, 0)
-}
-
-#[bench]
-fn bench_from_iter_0010(b: &mut Bencher) {
-    do_bench_from_iter(b, 10)
-}
-
-#[bench]
-fn bench_from_iter_0100(b: &mut Bencher) {
-    do_bench_from_iter(b, 100)
-}
-
-#[bench]
-fn bench_from_iter_1000(b: &mut Bencher) {
-    do_bench_from_iter(b, 1000)
-}
-
-fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) {
-    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
-    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let mut dst = dst.clone();
-        dst.extend(src.clone());
-        assert_eq!(dst.len(), dst_len + src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_extend_0000_0000(b: &mut Bencher) {
-    do_bench_extend(b, 0, 0)
-}
-
-#[bench]
-fn bench_extend_0000_0010(b: &mut Bencher) {
-    do_bench_extend(b, 0, 10)
-}
-
-#[bench]
-fn bench_extend_0000_0100(b: &mut Bencher) {
-    do_bench_extend(b, 0, 100)
-}
-
-#[bench]
-fn bench_extend_0000_1000(b: &mut Bencher) {
-    do_bench_extend(b, 0, 1000)
-}
-
-#[bench]
-fn bench_extend_0010_0010(b: &mut Bencher) {
-    do_bench_extend(b, 10, 10)
-}
-
-#[bench]
-fn bench_extend_0100_0100(b: &mut Bencher) {
-    do_bench_extend(b, 100, 100)
-}
-
-#[bench]
-fn bench_extend_1000_1000(b: &mut Bencher) {
-    do_bench_extend(b, 1000, 1000)
-}
-
-fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) {
-    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
-    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let mut dst = dst.clone();
-        dst.extend_from_slice(&src);
-        assert_eq!(dst.len(), dst_len + src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_push_all_0000_0000(b: &mut Bencher) {
-    do_bench_push_all(b, 0, 0)
-}
-
-#[bench]
-fn bench_push_all_0000_0010(b: &mut Bencher) {
-    do_bench_push_all(b, 0, 10)
-}
-
-#[bench]
-fn bench_push_all_0000_0100(b: &mut Bencher) {
-    do_bench_push_all(b, 0, 100)
-}
-
-#[bench]
-fn bench_push_all_0000_1000(b: &mut Bencher) {
-    do_bench_push_all(b, 0, 1000)
-}
-
-#[bench]
-fn bench_push_all_0010_0010(b: &mut Bencher) {
-    do_bench_push_all(b, 10, 10)
-}
-
-#[bench]
-fn bench_push_all_0100_0100(b: &mut Bencher) {
-    do_bench_push_all(b, 100, 100)
-}
-
-#[bench]
-fn bench_push_all_1000_1000(b: &mut Bencher) {
-    do_bench_push_all(b, 1000, 1000)
-}
-
-fn do_bench_push_all_move(b: &mut Bencher, dst_len: usize, src_len: usize) {
-    let dst: Vec<_> = FromIterator::from_iter(0..dst_len);
-    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let mut dst = dst.clone();
-        dst.extend(src.clone());
-        assert_eq!(dst.len(), dst_len + src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_push_all_move_0000_0000(b: &mut Bencher) {
-    do_bench_push_all_move(b, 0, 0)
-}
-
-#[bench]
-fn bench_push_all_move_0000_0010(b: &mut Bencher) {
-    do_bench_push_all_move(b, 0, 10)
-}
-
-#[bench]
-fn bench_push_all_move_0000_0100(b: &mut Bencher) {
-    do_bench_push_all_move(b, 0, 100)
-}
-
-#[bench]
-fn bench_push_all_move_0000_1000(b: &mut Bencher) {
-    do_bench_push_all_move(b, 0, 1000)
-}
-
-#[bench]
-fn bench_push_all_move_0010_0010(b: &mut Bencher) {
-    do_bench_push_all_move(b, 10, 10)
-}
-
-#[bench]
-fn bench_push_all_move_0100_0100(b: &mut Bencher) {
-    do_bench_push_all_move(b, 100, 100)
-}
-
-#[bench]
-fn bench_push_all_move_1000_1000(b: &mut Bencher) {
-    do_bench_push_all_move(b, 1000, 1000)
-}
-
-fn do_bench_clone(b: &mut Bencher, src_len: usize) {
-    let src: Vec<usize> = FromIterator::from_iter(0..src_len);
-
-    b.bytes = src_len as u64;
-
-    b.iter(|| {
-        let dst = src.clone();
-        assert_eq!(dst.len(), src_len);
-        assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
-    });
-}
-
-#[bench]
-fn bench_clone_0000(b: &mut Bencher) {
-    do_bench_clone(b, 0)
-}
-
-#[bench]
-fn bench_clone_0010(b: &mut Bencher) {
-    do_bench_clone(b, 10)
-}
-
-#[bench]
-fn bench_clone_0100(b: &mut Bencher) {
-    do_bench_clone(b, 100)
-}
-
-#[bench]
-fn bench_clone_1000(b: &mut Bencher) {
-    do_bench_clone(b, 1000)
-}
-
-fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: usize) {
-    let dst: Vec<_> = FromIterator::from_iter(0..src_len);
-    let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len);
-
-    b.bytes = (times * src_len) as u64;
-
-    b.iter(|| {
-        let mut dst = dst.clone();
-
-        for _ in 0..times {
-            dst.clone_from(&src);
-
-            assert_eq!(dst.len(), src_len);
-            assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x));
-        }
-    });
-}
-
-#[bench]
-fn bench_clone_from_01_0000_0000(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 0, 0)
-}
-
-#[bench]
-fn bench_clone_from_01_0000_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 0, 10)
-}
-
-#[bench]
-fn bench_clone_from_01_0000_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 0, 100)
-}
-
-#[bench]
-fn bench_clone_from_01_0000_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 0, 1000)
-}
-
-#[bench]
-fn bench_clone_from_01_0010_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 10, 10)
-}
-
-#[bench]
-fn bench_clone_from_01_0100_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 100, 100)
-}
-
-#[bench]
-fn bench_clone_from_01_1000_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 1000, 1000)
-}
-
-#[bench]
-fn bench_clone_from_01_0010_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 10, 100)
-}
-
-#[bench]
-fn bench_clone_from_01_0100_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 100, 1000)
-}
-
-#[bench]
-fn bench_clone_from_01_0010_0000(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 10, 0)
-}
-
-#[bench]
-fn bench_clone_from_01_0100_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 100, 10)
-}
-
-#[bench]
-fn bench_clone_from_01_1000_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 1, 1000, 100)
-}
-
-#[bench]
-fn bench_clone_from_10_0000_0000(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 0, 0)
-}
-
-#[bench]
-fn bench_clone_from_10_0000_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 0, 10)
-}
-
-#[bench]
-fn bench_clone_from_10_0000_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 0, 100)
-}
-
-#[bench]
-fn bench_clone_from_10_0000_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 0, 1000)
-}
-
-#[bench]
-fn bench_clone_from_10_0010_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 10, 10)
-}
-
-#[bench]
-fn bench_clone_from_10_0100_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 100, 100)
-}
-
-#[bench]
-fn bench_clone_from_10_1000_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 1000, 1000)
-}
-
-#[bench]
-fn bench_clone_from_10_0010_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 10, 100)
-}
-
-#[bench]
-fn bench_clone_from_10_0100_1000(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 100, 1000)
-}
-
-#[bench]
-fn bench_clone_from_10_0010_0000(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 10, 0)
-}
-
-#[bench]
-fn bench_clone_from_10_0100_0010(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 100, 10)
-}
-
-#[bench]
-fn bench_clone_from_10_1000_0100(b: &mut Bencher) {
-    do_bench_clone_from(b, 10, 1000, 100)
-}
index bb60f888f8be6e80521610fc89fa3fb290d8c809..1541061a1984214bf70a4260b2ab35136b98d894 100644 (file)
@@ -12,8 +12,6 @@
 use std::fmt::Debug;
 use std::collections::vec_deque::Drain;
 
-use test;
-
 use self::Taggy::*;
 use self::Taggypar::*;
 
@@ -124,51 +122,6 @@ fn test_index_out_of_bounds() {
     deq[3];
 }
 
-#[bench]
-fn bench_new(b: &mut test::Bencher) {
-    b.iter(|| {
-        let ring: VecDeque<i32> = VecDeque::new();
-        test::black_box(ring);
-    })
-}
-
-#[bench]
-fn bench_grow_1025(b: &mut test::Bencher) {
-    b.iter(|| {
-        let mut deq = VecDeque::new();
-        for i in 0..1025 {
-            deq.push_front(i);
-        }
-        test::black_box(deq);
-    })
-}
-
-#[bench]
-fn bench_iter_1000(b: &mut test::Bencher) {
-    let ring: VecDeque<_> = (0..1000).collect();
-
-    b.iter(|| {
-        let mut sum = 0;
-        for &i in &ring {
-            sum += i;
-        }
-        test::black_box(sum);
-    })
-}
-
-#[bench]
-fn bench_mut_iter_1000(b: &mut test::Bencher) {
-    let mut ring: VecDeque<_> = (0..1000).collect();
-
-    b.iter(|| {
-        let mut sum = 0;
-        for i in &mut ring {
-            sum += *i;
-        }
-        test::black_box(sum);
-    })
-}
-
 #[derive(Clone, PartialEq, Debug)]
 enum Taggy {
     One(i32),
index 4f7cd7b016d66ac7f8a38ab05e0516825a4e7210..e847c7fa3a0ec9580c82431ebe0d86bd8a88e9c2 100644 (file)
@@ -14,5 +14,5 @@ name = "coretest"
 path = "../libcoretest/lib.rs"
 
 [[bench]]
-name = "corebench"
-path = "../libcore/bench/lib.rs"
+name = "corebenches"
+path = "../libcore/benches/lib.rs"
diff --git a/src/libcore/bench/any.rs b/src/libcore/bench/any.rs
deleted file mode 100644 (file)
index 67e02cf..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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 core::any::*;
-use test::{Bencher, black_box};
-
-#[bench]
-fn bench_downcast_ref(b: &mut Bencher) {
-    b.iter(|| {
-        let mut x = 0;
-        let mut y = &mut x as &mut Any;
-        black_box(&mut y);
-        black_box(y.downcast_ref::<isize>() == Some(&0));
-    });
-}
diff --git a/src/libcore/bench/hash/mod.rs b/src/libcore/bench/hash/mod.rs
deleted file mode 100644 (file)
index 55d9e3e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-mod sip;
diff --git a/src/libcore/bench/hash/sip.rs b/src/libcore/bench/hash/sip.rs
deleted file mode 100644 (file)
index 3379c85..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-// 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.
-
-#![allow(deprecated)]
-
-use core::hash::*;
-use test::{Bencher, black_box};
-
-fn hash_bytes<H: Hasher>(mut s: H, x: &[u8]) -> u64 {
-    Hasher::write(&mut s, x);
-    s.finish()
-}
-
-fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
-    x.hash(&mut st);
-    st.finish()
-}
-
-fn hash<T: Hash>(x: &T) -> u64 {
-    hash_with(SipHasher::new(), x)
-}
-
-#[bench]
-fn bench_str_under_8_bytes(b: &mut Bencher) {
-    let s = "foo";
-    b.iter(|| {
-        assert_eq!(hash(&s), 16262950014981195938);
-    })
-}
-
-#[bench]
-fn bench_str_of_8_bytes(b: &mut Bencher) {
-    let s = "foobar78";
-    b.iter(|| {
-        assert_eq!(hash(&s), 4898293253460910787);
-    })
-}
-
-#[bench]
-fn bench_str_over_8_bytes(b: &mut Bencher) {
-    let s = "foobarbaz0";
-    b.iter(|| {
-        assert_eq!(hash(&s), 10581415515220175264);
-    })
-}
-
-#[bench]
-fn bench_long_str(b: &mut Bencher) {
-    let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
-incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
-exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
-irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
-pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
-officia deserunt mollit anim id est laborum.";
-    b.iter(|| {
-        assert_eq!(hash(&s), 17717065544121360093);
-    })
-}
-
-#[bench]
-fn bench_u32(b: &mut Bencher) {
-    let u = 162629500u32;
-    let u = black_box(u);
-    b.iter(|| {
-        hash(&u)
-    });
-    b.bytes = 8;
-}
-
-#[bench]
-fn bench_u32_keyed(b: &mut Bencher) {
-    let u = 162629500u32;
-    let u = black_box(u);
-    let k1 = black_box(0x1);
-    let k2 = black_box(0x2);
-    b.iter(|| {
-        hash_with(SipHasher::new_with_keys(k1, k2), &u)
-    });
-    b.bytes = 8;
-}
-
-#[bench]
-fn bench_u64(b: &mut Bencher) {
-    let u = 16262950014981195938u64;
-    let u = black_box(u);
-    b.iter(|| {
-        hash(&u)
-    });
-    b.bytes = 8;
-}
-
-#[bench]
-fn bench_bytes_4(b: &mut Bencher) {
-    let data = black_box([b' '; 4]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 4;
-}
-
-#[bench]
-fn bench_bytes_7(b: &mut Bencher) {
-    let data = black_box([b' '; 7]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 7;
-}
-
-#[bench]
-fn bench_bytes_8(b: &mut Bencher) {
-    let data = black_box([b' '; 8]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 8;
-}
-
-#[bench]
-fn bench_bytes_a_16(b: &mut Bencher) {
-    let data = black_box([b' '; 16]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 16;
-}
-
-#[bench]
-fn bench_bytes_b_32(b: &mut Bencher) {
-    let data = black_box([b' '; 32]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 32;
-}
-
-#[bench]
-fn bench_bytes_c_128(b: &mut Bencher) {
-    let data = black_box([b' '; 128]);
-    b.iter(|| {
-        hash_bytes(SipHasher::default(), &data)
-    });
-    b.bytes = 128;
-}
diff --git a/src/libcore/bench/iter.rs b/src/libcore/bench/iter.rs
deleted file mode 100644 (file)
index 93d38a5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// 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 core::iter::*;
-use test::{Bencher, black_box};
-
-#[bench]
-fn bench_rposition(b: &mut Bencher) {
-    let it: Vec<usize> = (0..300).collect();
-    b.iter(|| {
-        it.iter().rposition(|&x| x <= 150);
-    });
-}
-
-#[bench]
-fn bench_skip_while(b: &mut Bencher) {
-    b.iter(|| {
-        let it = 0..100;
-        let mut sum = 0;
-        it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true);
-    });
-}
-
-#[bench]
-fn bench_multiple_take(b: &mut Bencher) {
-    let mut it = (0..42).cycle();
-    b.iter(|| {
-        let n = it.next().unwrap();
-        for _ in 0..n {
-            it.clone().take(it.next().unwrap()).all(|_| true);
-        }
-    });
-}
-
-fn scatter(x: i32) -> i32 { (x * 31) % 127 }
-
-#[bench]
-fn bench_max_by_key(b: &mut Bencher) {
-    b.iter(|| {
-        let it = 0..100;
-        it.max_by_key(|&x| scatter(x))
-    })
-}
-
-// http://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/
-#[bench]
-fn bench_max_by_key2(b: &mut Bencher) {
-    fn max_index_iter(array: &[i32]) -> usize {
-        array.iter().enumerate().max_by_key(|&(_, item)| item).unwrap().0
-    }
-
-    let mut data = vec![0; 1638];
-    data[514] = 9999;
-
-    b.iter(|| max_index_iter(&data));
-}
-
-#[bench]
-fn bench_max(b: &mut Bencher) {
-    b.iter(|| {
-        let it = 0..100;
-        it.map(scatter).max()
-    })
-}
-
-pub fn copy_zip(xs: &[u8], ys: &mut [u8]) {
-    for (a, b) in ys.iter_mut().zip(xs) {
-        *a = *b;
-    }
-}
-
-pub fn add_zip(xs: &[f32], ys: &mut [f32]) {
-    for (a, b) in ys.iter_mut().zip(xs) {
-        *a += *b;
-    }
-}
-
-#[bench]
-fn bench_zip_copy(b: &mut Bencher) {
-    let source = vec![0u8; 16 * 1024];
-    let mut dst = black_box(vec![0u8; 16 * 1024]);
-    b.iter(|| {
-        copy_zip(&source, &mut dst)
-    })
-}
-
-#[bench]
-fn bench_zip_add(b: &mut Bencher) {
-    let source = vec![1.; 16 * 1024];
-    let mut dst = vec![0.; 16 * 1024];
-    b.iter(|| {
-        add_zip(&source, &mut dst)
-    });
-}
diff --git a/src/libcore/bench/lib.rs b/src/libcore/bench/lib.rs
deleted file mode 100644 (file)
index d2db329..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#![deny(warnings)]
-
-#![feature(flt2dec)]
-#![feature(slice_patterns)]
-#![feature(test)]
-
-extern crate core;
-extern crate test;
-
-mod any;
-mod hash;
-mod iter;
-mod mem;
-mod num;
-mod ops;
diff --git a/src/libcore/bench/mem.rs b/src/libcore/bench/mem.rs
deleted file mode 100644 (file)
index 8e541d9..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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 test::Bencher;
-
-// FIXME #13642 (these benchmarks should be in another place)
-// Completely miscellaneous language-construct benchmarks.
-// Static/dynamic method dispatch
-
-struct Struct {
-    field: isize
-}
-
-trait Trait {
-    fn method(&self) -> isize;
-}
-
-impl Trait for Struct {
-    fn method(&self) -> isize {
-        self.field
-    }
-}
-
-#[bench]
-fn trait_vtable_method_call(b: &mut Bencher) {
-    let s = Struct { field: 10 };
-    let t = &s as &Trait;
-    b.iter(|| {
-        t.method()
-    });
-}
-
-#[bench]
-fn trait_static_method_call(b: &mut Bencher) {
-    let s = Struct { field: 10 };
-    b.iter(|| {
-        s.method()
-    });
-}
-
-// Overhead of various match forms
-
-#[bench]
-fn match_option_some(b: &mut Bencher) {
-    let x = Some(10);
-    b.iter(|| {
-        match x {
-            Some(y) => y,
-            None => 11
-        }
-    });
-}
-
-#[bench]
-fn match_vec_pattern(b: &mut Bencher) {
-    let x = [1,2,3,4,5,6];
-    b.iter(|| {
-        match x {
-            [1,2,3,..] => 10,
-            _ => 11,
-        }
-    });
-}
diff --git a/src/libcore/bench/num/dec2flt/mod.rs b/src/libcore/bench/num/dec2flt/mod.rs
deleted file mode 100644 (file)
index 562866e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 std::f64;
-use test::Bencher;
-
-#[bench]
-fn bench_0(b: &mut Bencher) {
-    b.iter(|| "0.0".parse::<f64>());
-}
-
-#[bench]
-fn bench_42(b: &mut Bencher) {
-    b.iter(|| "42".parse::<f64>());
-}
-
-#[bench]
-fn bench_huge_int(b: &mut Bencher) {
-    // 2^128 - 1
-    b.iter(|| "170141183460469231731687303715884105727".parse::<f64>());
-}
-
-#[bench]
-fn bench_short_decimal(b: &mut Bencher) {
-    b.iter(|| "1234.5678".parse::<f64>());
-}
-
-#[bench]
-fn bench_pi_long(b: &mut Bencher) {
-    b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>());
-}
-
-#[bench]
-fn bench_pi_short(b: &mut Bencher) {
-    b.iter(|| "3.141592653589793".parse::<f64>())
-}
-
-#[bench]
-fn bench_1e150(b: &mut Bencher) {
-    b.iter(|| "1e150".parse::<f64>());
-}
-
-#[bench]
-fn bench_long_decimal_and_exp(b: &mut Bencher) {
-    b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>());
-}
-
-#[bench]
-fn bench_min_subnormal(b: &mut Bencher) {
-    b.iter(|| "5e-324".parse::<f64>());
-}
-
-#[bench]
-fn bench_min_normal(b: &mut Bencher) {
-    b.iter(|| "2.2250738585072014e-308".parse::<f64>());
-}
-
-#[bench]
-fn bench_max(b: &mut Bencher) {
-    b.iter(|| "1.7976931348623157e308".parse::<f64>());
-}
diff --git a/src/libcore/bench/num/flt2dec/mod.rs b/src/libcore/bench/num/flt2dec/mod.rs
deleted file mode 100644 (file)
index 1de2bf4..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-mod strategy {
-    mod dragon;
-    mod grisu;
-}
-
-use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
-use core::num::flt2dec::MAX_SIG_DIGITS;
-
-pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
-    match decode(v).1 {
-        FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
-    }
-}
diff --git a/src/libcore/bench/num/flt2dec/strategy/dragon.rs b/src/libcore/bench/num/flt2dec/strategy/dragon.rs
deleted file mode 100644 (file)
index 6824cf4..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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 std::{i16, f64};
-use super::super::*;
-use core::num::flt2dec::strategy::dragon::*;
-use test::Bencher;
-
-#[bench]
-fn bench_small_shortest(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; MAX_SIG_DIGITS];
-    b.iter(|| format_shortest(&decoded, &mut buf));
-}
-
-#[bench]
-fn bench_big_shortest(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; MAX_SIG_DIGITS];
-    b.iter(|| format_shortest(&decoded, &mut buf));
-}
-
-#[bench]
-fn bench_small_exact_3(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 3];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_3(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 3];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_small_exact_12(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 12];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_12(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 12];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_small_exact_inf(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 1024];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_inf(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 1024];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
diff --git a/src/libcore/bench/num/flt2dec/strategy/grisu.rs b/src/libcore/bench/num/flt2dec/strategy/grisu.rs
deleted file mode 100644 (file)
index 82e1a85..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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 std::{i16, f64};
-use super::super::*;
-use core::num::flt2dec::strategy::grisu::*;
-use test::Bencher;
-
-pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
-    match decode(v).1 {
-        FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
-    }
-}
-
-#[bench]
-fn bench_small_shortest(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; MAX_SIG_DIGITS];
-    b.iter(|| format_shortest(&decoded, &mut buf));
-}
-
-#[bench]
-fn bench_big_shortest(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; MAX_SIG_DIGITS];
-    b.iter(|| format_shortest(&decoded, &mut buf));
-}
-
-#[bench]
-fn bench_small_exact_3(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 3];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_3(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 3];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_small_exact_12(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 12];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_12(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 12];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_small_exact_inf(b: &mut Bencher) {
-    let decoded = decode_finite(3.141592f64);
-    let mut buf = [0; 1024];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
-
-#[bench]
-fn bench_big_exact_inf(b: &mut Bencher) {
-    let decoded = decode_finite(f64::MAX);
-    let mut buf = [0; 1024];
-    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
-}
diff --git a/src/libcore/bench/num/mod.rs b/src/libcore/bench/num/mod.rs
deleted file mode 100644 (file)
index 55f0bdb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-
-mod flt2dec;
-mod dec2flt;
diff --git a/src/libcore/bench/ops.rs b/src/libcore/bench/ops.rs
deleted file mode 100644 (file)
index 7f36a4b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 core::ops::*;
-use test::Bencher;
-
-// Overhead of dtors
-
-struct HasDtor {
-    _x: isize
-}
-
-impl Drop for HasDtor {
-    fn drop(&mut self) {
-    }
-}
-
-#[bench]
-fn alloc_obj_with_dtor(b: &mut Bencher) {
-    b.iter(|| {
-        HasDtor { _x : 10 };
-    })
-}
diff --git a/src/libcore/benches/any.rs b/src/libcore/benches/any.rs
new file mode 100644 (file)
index 0000000..67e02cf
--- /dev/null
@@ -0,0 +1,22 @@
+// 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 core::any::*;
+use test::{Bencher, black_box};
+
+#[bench]
+fn bench_downcast_ref(b: &mut Bencher) {
+    b.iter(|| {
+        let mut x = 0;
+        let mut y = &mut x as &mut Any;
+        black_box(&mut y);
+        black_box(y.downcast_ref::<isize>() == Some(&0));
+    });
+}
diff --git a/src/libcore/benches/hash/mod.rs b/src/libcore/benches/hash/mod.rs
new file mode 100644 (file)
index 0000000..55d9e3e
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+mod sip;
diff --git a/src/libcore/benches/hash/sip.rs b/src/libcore/benches/hash/sip.rs
new file mode 100644 (file)
index 0000000..3379c85
--- /dev/null
@@ -0,0 +1,151 @@
+// 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.
+
+#![allow(deprecated)]
+
+use core::hash::*;
+use test::{Bencher, black_box};
+
+fn hash_bytes<H: Hasher>(mut s: H, x: &[u8]) -> u64 {
+    Hasher::write(&mut s, x);
+    s.finish()
+}
+
+fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
+    x.hash(&mut st);
+    st.finish()
+}
+
+fn hash<T: Hash>(x: &T) -> u64 {
+    hash_with(SipHasher::new(), x)
+}
+
+#[bench]
+fn bench_str_under_8_bytes(b: &mut Bencher) {
+    let s = "foo";
+    b.iter(|| {
+        assert_eq!(hash(&s), 16262950014981195938);
+    })
+}
+
+#[bench]
+fn bench_str_of_8_bytes(b: &mut Bencher) {
+    let s = "foobar78";
+    b.iter(|| {
+        assert_eq!(hash(&s), 4898293253460910787);
+    })
+}
+
+#[bench]
+fn bench_str_over_8_bytes(b: &mut Bencher) {
+    let s = "foobarbaz0";
+    b.iter(|| {
+        assert_eq!(hash(&s), 10581415515220175264);
+    })
+}
+
+#[bench]
+fn bench_long_str(b: &mut Bencher) {
+    let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
+incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
+exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
+irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
+pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
+officia deserunt mollit anim id est laborum.";
+    b.iter(|| {
+        assert_eq!(hash(&s), 17717065544121360093);
+    })
+}
+
+#[bench]
+fn bench_u32(b: &mut Bencher) {
+    let u = 162629500u32;
+    let u = black_box(u);
+    b.iter(|| {
+        hash(&u)
+    });
+    b.bytes = 8;
+}
+
+#[bench]
+fn bench_u32_keyed(b: &mut Bencher) {
+    let u = 162629500u32;
+    let u = black_box(u);
+    let k1 = black_box(0x1);
+    let k2 = black_box(0x2);
+    b.iter(|| {
+        hash_with(SipHasher::new_with_keys(k1, k2), &u)
+    });
+    b.bytes = 8;
+}
+
+#[bench]
+fn bench_u64(b: &mut Bencher) {
+    let u = 16262950014981195938u64;
+    let u = black_box(u);
+    b.iter(|| {
+        hash(&u)
+    });
+    b.bytes = 8;
+}
+
+#[bench]
+fn bench_bytes_4(b: &mut Bencher) {
+    let data = black_box([b' '; 4]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 4;
+}
+
+#[bench]
+fn bench_bytes_7(b: &mut Bencher) {
+    let data = black_box([b' '; 7]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 7;
+}
+
+#[bench]
+fn bench_bytes_8(b: &mut Bencher) {
+    let data = black_box([b' '; 8]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 8;
+}
+
+#[bench]
+fn bench_bytes_a_16(b: &mut Bencher) {
+    let data = black_box([b' '; 16]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 16;
+}
+
+#[bench]
+fn bench_bytes_b_32(b: &mut Bencher) {
+    let data = black_box([b' '; 32]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 32;
+}
+
+#[bench]
+fn bench_bytes_c_128(b: &mut Bencher) {
+    let data = black_box([b' '; 128]);
+    b.iter(|| {
+        hash_bytes(SipHasher::default(), &data)
+    });
+    b.bytes = 128;
+}
diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs
new file mode 100644 (file)
index 0000000..93d38a5
--- /dev/null
@@ -0,0 +1,101 @@
+// 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 core::iter::*;
+use test::{Bencher, black_box};
+
+#[bench]
+fn bench_rposition(b: &mut Bencher) {
+    let it: Vec<usize> = (0..300).collect();
+    b.iter(|| {
+        it.iter().rposition(|&x| x <= 150);
+    });
+}
+
+#[bench]
+fn bench_skip_while(b: &mut Bencher) {
+    b.iter(|| {
+        let it = 0..100;
+        let mut sum = 0;
+        it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true);
+    });
+}
+
+#[bench]
+fn bench_multiple_take(b: &mut Bencher) {
+    let mut it = (0..42).cycle();
+    b.iter(|| {
+        let n = it.next().unwrap();
+        for _ in 0..n {
+            it.clone().take(it.next().unwrap()).all(|_| true);
+        }
+    });
+}
+
+fn scatter(x: i32) -> i32 { (x * 31) % 127 }
+
+#[bench]
+fn bench_max_by_key(b: &mut Bencher) {
+    b.iter(|| {
+        let it = 0..100;
+        it.max_by_key(|&x| scatter(x))
+    })
+}
+
+// http://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/
+#[bench]
+fn bench_max_by_key2(b: &mut Bencher) {
+    fn max_index_iter(array: &[i32]) -> usize {
+        array.iter().enumerate().max_by_key(|&(_, item)| item).unwrap().0
+    }
+
+    let mut data = vec![0; 1638];
+    data[514] = 9999;
+
+    b.iter(|| max_index_iter(&data));
+}
+
+#[bench]
+fn bench_max(b: &mut Bencher) {
+    b.iter(|| {
+        let it = 0..100;
+        it.map(scatter).max()
+    })
+}
+
+pub fn copy_zip(xs: &[u8], ys: &mut [u8]) {
+    for (a, b) in ys.iter_mut().zip(xs) {
+        *a = *b;
+    }
+}
+
+pub fn add_zip(xs: &[f32], ys: &mut [f32]) {
+    for (a, b) in ys.iter_mut().zip(xs) {
+        *a += *b;
+    }
+}
+
+#[bench]
+fn bench_zip_copy(b: &mut Bencher) {
+    let source = vec![0u8; 16 * 1024];
+    let mut dst = black_box(vec![0u8; 16 * 1024]);
+    b.iter(|| {
+        copy_zip(&source, &mut dst)
+    })
+}
+
+#[bench]
+fn bench_zip_add(b: &mut Bencher) {
+    let source = vec![1.; 16 * 1024];
+    let mut dst = vec![0.; 16 * 1024];
+    b.iter(|| {
+        add_zip(&source, &mut dst)
+    });
+}
diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs
new file mode 100644 (file)
index 0000000..d2db329
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+#![deny(warnings)]
+
+#![feature(flt2dec)]
+#![feature(slice_patterns)]
+#![feature(test)]
+
+extern crate core;
+extern crate test;
+
+mod any;
+mod hash;
+mod iter;
+mod mem;
+mod num;
+mod ops;
diff --git a/src/libcore/benches/mem.rs b/src/libcore/benches/mem.rs
new file mode 100644 (file)
index 0000000..8e541d9
--- /dev/null
@@ -0,0 +1,70 @@
+// 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 test::Bencher;
+
+// FIXME #13642 (these benchmarks should be in another place)
+// Completely miscellaneous language-construct benchmarks.
+// Static/dynamic method dispatch
+
+struct Struct {
+    field: isize
+}
+
+trait Trait {
+    fn method(&self) -> isize;
+}
+
+impl Trait for Struct {
+    fn method(&self) -> isize {
+        self.field
+    }
+}
+
+#[bench]
+fn trait_vtable_method_call(b: &mut Bencher) {
+    let s = Struct { field: 10 };
+    let t = &s as &Trait;
+    b.iter(|| {
+        t.method()
+    });
+}
+
+#[bench]
+fn trait_static_method_call(b: &mut Bencher) {
+    let s = Struct { field: 10 };
+    b.iter(|| {
+        s.method()
+    });
+}
+
+// Overhead of various match forms
+
+#[bench]
+fn match_option_some(b: &mut Bencher) {
+    let x = Some(10);
+    b.iter(|| {
+        match x {
+            Some(y) => y,
+            None => 11
+        }
+    });
+}
+
+#[bench]
+fn match_vec_pattern(b: &mut Bencher) {
+    let x = [1,2,3,4,5,6];
+    b.iter(|| {
+        match x {
+            [1,2,3,..] => 10,
+            _ => 11,
+        }
+    });
+}
diff --git a/src/libcore/benches/num/dec2flt/mod.rs b/src/libcore/benches/num/dec2flt/mod.rs
new file mode 100644 (file)
index 0000000..562866e
--- /dev/null
@@ -0,0 +1,68 @@
+// 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 std::f64;
+use test::Bencher;
+
+#[bench]
+fn bench_0(b: &mut Bencher) {
+    b.iter(|| "0.0".parse::<f64>());
+}
+
+#[bench]
+fn bench_42(b: &mut Bencher) {
+    b.iter(|| "42".parse::<f64>());
+}
+
+#[bench]
+fn bench_huge_int(b: &mut Bencher) {
+    // 2^128 - 1
+    b.iter(|| "170141183460469231731687303715884105727".parse::<f64>());
+}
+
+#[bench]
+fn bench_short_decimal(b: &mut Bencher) {
+    b.iter(|| "1234.5678".parse::<f64>());
+}
+
+#[bench]
+fn bench_pi_long(b: &mut Bencher) {
+    b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>());
+}
+
+#[bench]
+fn bench_pi_short(b: &mut Bencher) {
+    b.iter(|| "3.141592653589793".parse::<f64>())
+}
+
+#[bench]
+fn bench_1e150(b: &mut Bencher) {
+    b.iter(|| "1e150".parse::<f64>());
+}
+
+#[bench]
+fn bench_long_decimal_and_exp(b: &mut Bencher) {
+    b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>());
+}
+
+#[bench]
+fn bench_min_subnormal(b: &mut Bencher) {
+    b.iter(|| "5e-324".parse::<f64>());
+}
+
+#[bench]
+fn bench_min_normal(b: &mut Bencher) {
+    b.iter(|| "2.2250738585072014e-308".parse::<f64>());
+}
+
+#[bench]
+fn bench_max(b: &mut Bencher) {
+    b.iter(|| "1.7976931348623157e308".parse::<f64>());
+}
diff --git a/src/libcore/benches/num/flt2dec/mod.rs b/src/libcore/benches/num/flt2dec/mod.rs
new file mode 100644 (file)
index 0000000..1de2bf4
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+mod strategy {
+    mod dragon;
+    mod grisu;
+}
+
+use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
+use core::num::flt2dec::MAX_SIG_DIGITS;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+    match decode(v).1 {
+        FullDecoded::Finite(decoded) => decoded,
+        full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+    }
+}
diff --git a/src/libcore/benches/num/flt2dec/strategy/dragon.rs b/src/libcore/benches/num/flt2dec/strategy/dragon.rs
new file mode 100644 (file)
index 0000000..6824cf4
--- /dev/null
@@ -0,0 +1,70 @@
+// 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 std::{i16, f64};
+use super::super::*;
+use core::num::flt2dec::strategy::dragon::*;
+use test::Bencher;
+
+#[bench]
+fn bench_small_shortest(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; MAX_SIG_DIGITS];
+    b.iter(|| format_shortest(&decoded, &mut buf));
+}
+
+#[bench]
+fn bench_big_shortest(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; MAX_SIG_DIGITS];
+    b.iter(|| format_shortest(&decoded, &mut buf));
+}
+
+#[bench]
+fn bench_small_exact_3(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 3];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_3(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 3];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_small_exact_12(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 12];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_12(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 12];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_small_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 1024];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 1024];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
diff --git a/src/libcore/benches/num/flt2dec/strategy/grisu.rs b/src/libcore/benches/num/flt2dec/strategy/grisu.rs
new file mode 100644 (file)
index 0000000..82e1a85
--- /dev/null
@@ -0,0 +1,77 @@
+// 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 std::{i16, f64};
+use super::super::*;
+use core::num::flt2dec::strategy::grisu::*;
+use test::Bencher;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+    match decode(v).1 {
+        FullDecoded::Finite(decoded) => decoded,
+        full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+    }
+}
+
+#[bench]
+fn bench_small_shortest(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; MAX_SIG_DIGITS];
+    b.iter(|| format_shortest(&decoded, &mut buf));
+}
+
+#[bench]
+fn bench_big_shortest(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; MAX_SIG_DIGITS];
+    b.iter(|| format_shortest(&decoded, &mut buf));
+}
+
+#[bench]
+fn bench_small_exact_3(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 3];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_3(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 3];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_small_exact_12(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 12];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_12(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 12];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_small_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(3.141592f64);
+    let mut buf = [0; 1024];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
+
+#[bench]
+fn bench_big_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(f64::MAX);
+    let mut buf = [0; 1024];
+    b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
+}
diff --git a/src/libcore/benches/num/mod.rs b/src/libcore/benches/num/mod.rs
new file mode 100644 (file)
index 0000000..55f0bdb
--- /dev/null
@@ -0,0 +1,12 @@
+// 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.
+
+mod flt2dec;
+mod dec2flt;
diff --git a/src/libcore/benches/ops.rs b/src/libcore/benches/ops.rs
new file mode 100644 (file)
index 0000000..7f36a4b
--- /dev/null
@@ -0,0 +1,30 @@
+// 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 core::ops::*;
+use test::Bencher;
+
+// Overhead of dtors
+
+struct HasDtor {
+    _x: isize
+}
+
+impl Drop for HasDtor {
+    fn drop(&mut self) {
+    }
+}
+
+#[bench]
+fn alloc_obj_with_dtor(b: &mut Bencher) {
+    b.iter(|| {
+        HasDtor { _x : 10 };
+    })
+}
index 6537cc1adce001fa3c88522278c89c7524790da1..2d80fc32c469dc111f37eb8487811ea9940c24ba 100644 (file)
@@ -229,6 +229,7 @@ fn dylib_dependency_formats(&self, cnum: CrateNum)
     fn is_allocator(&self, cnum: CrateNum) -> bool;
     fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
     fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
+    fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool;
     fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy;
     fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>;
     /// The name of the crate as it is referred to in source code of the current
@@ -390,6 +391,7 @@ fn export_macros(&self, cnum: CrateNum) { bug!("export_macros") }
     fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
     fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
     fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }
+    fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { bug!("is_sanitizer_runtime") }
     fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
         bug!("panic_strategy")
     }
index d41c2ba93b93533a524e45f3be5b4028d5f29925..24615f2fa699213346c07cb91034d79e4a60161b 100644 (file)
@@ -51,6 +51,14 @@ pub struct Config {
     pub uint_type: UintTy,
 }
 
+#[derive(Clone)]
+pub enum Sanitizer {
+    Address,
+    Leak,
+    Memory,
+    Thread,
+}
+
 #[derive(Clone, Copy, PartialEq, Hash)]
 pub enum OptLevel {
     No, // -O0
@@ -626,11 +634,13 @@ mod $mod_desc {
             Some("a number");
         pub const parse_panic_strategy: Option<&'static str> =
             Some("either `panic` or `abort`");
+        pub const parse_sanitizer: Option<&'static str> =
+            Some("one of: `address`, `leak`, `memory` or `thread`");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses};
+        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
         use rustc_back::PanicStrategy;
 
         $(
@@ -751,6 +761,17 @@ fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bo
             }
             true
         }
+
+        fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
+            match v {
+                Some("address") => *slote = Some(Sanitizer::Address),
+                Some("leak") => *slote = Some(Sanitizer::Leak),
+                Some("memory") => *slote = Some(Sanitizer::Memory),
+                Some("thread") => *slote = Some(Sanitizer::Thread),
+                _ => return false,
+            }
+            true
+        }
     }
 ) }
 
@@ -949,6 +970,8 @@ fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bo
           "encode MIR of all functions into the crate metadata"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
           "pass `-install_name @rpath/...` to the OSX linker"),
+    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [UNTRACKED],
+                                   "Use a sanitizer"),
 }
 
 pub fn default_lib_output() -> CrateType {
diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml
new file mode 100644 (file)
index 0000000..2d4872b
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+authors = ["The Rust Project Developers"]
+build = "build.rs"
+name = "rustc_asan"
+version = "0.0.0"
+
+[lib]
+name = "rustc_asan"
+path = "lib.rs"
+
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+cmake = "0.1.18"
+
+[dependencies]
+alloc_system = { path = "../liballoc_system" }
+core = { path = "../libcore" }
diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs
new file mode 100644 (file)
index 0000000..015be14
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.
+
+extern crate build_helper;
+extern crate cmake;
+
+use std::path::PathBuf;
+use std::env;
+
+use cmake::Config;
+
+fn main() {
+    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
+        let dst = Config::new("../compiler-rt")
+            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
+            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
+            .define("COMPILER_RT_BUILD_XRAY", "OFF")
+            .define("LLVM_CONFIG_PATH", llvm_config)
+            .build_target("asan")
+            .build();
+
+        println!("cargo:rustc-link-search=native={}",
+                 dst.join("build/lib/linux").display());
+        println!("cargo:rustc-link-lib=static=clang_rt.asan-x86_64");
+
+        build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR")
+                .unwrap())
+            .join("../compiler-rt"));
+    }
+
+    println!("cargo:rerun-if-changed=build.rs");
+}
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
new file mode 100644 (file)
index 0000000..71a166b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
+#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![feature(alloc_system)]
+#![feature(staged_api)]
+#![no_std]
+#![unstable(feature = "sanitizer_runtime_lib",
+            reason = "internal implementation detail of sanitizers",
+            issue = "0")]
+
+extern crate alloc_system;
index b371ab6aa31bc1ac05080e4e52f4fb6c0758df1e..7724658a9d6fead0f25ec19c116c9b26fd0e654e 100644 (file)
@@ -176,46 +176,32 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Recreate the edges in the graph that are still clean.
     let mut clean_work_products = FxHashSet();
     let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output
+    let mut extra_edges = vec![];
     for (source, targets) in &edge_map {
         for target in targets {
-            // If the target is dirty, skip the edge. If this is an edge
-            // that targets a work-product, we can print the blame
-            // information now.
-            if let Some(blame) = dirty_raw_nodes.get(target) {
-                if let DepNode::WorkProduct(ref wp) = *target {
-                    if tcx.sess.opts.debugging_opts.incremental_info {
-                        if dirty_work_products.insert(wp.clone()) {
-                            // It'd be nice to pretty-print these paths better than just
-                            // using the `Debug` impls, but wev.
-                            println!("incremental: module {:?} is dirty because {:?} \
-                                      changed or was removed",
-                                     wp,
-                                     blame.map_def(|&index| {
-                                         Some(directory.def_path_string(tcx, index))
-                                     }).unwrap());
-                        }
-                    }
-                }
-                continue;
-            }
-
-            // If the source is dirty, the target will be dirty.
-            assert!(!dirty_raw_nodes.contains_key(source));
-
-            // Retrace the source -> target edges to def-ids and then
-            // create an edge in the graph. Retracing may yield none if
-            // some of the data happens to have been removed; this ought
-            // to be impossible unless it is dirty, so we can unwrap.
-            let source_node = retraced.map(source).unwrap();
-            let target_node = retraced.map(target).unwrap();
-            let _task = tcx.dep_graph.in_task(target_node);
-            tcx.dep_graph.read(source_node);
-            if let DepNode::WorkProduct(ref wp) = *target {
-                clean_work_products.insert(wp.clone());
-            }
+            process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes,
+                          &mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
         }
     }
 
+    // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
+    // This is pretty unusual but it arises in a scenario like this:
+    //
+    //     Hir(X) -> Foo(Y) -> Bar
+    //
+    // Note that the `Hir(Y)` is not an input to `Foo(Y)` -- this
+    // almost never happens, but can happen in some obscure
+    // scenarios. In that case, if `Y` is removed, then we can't
+    // recreate `Foo(Y)` (the def-id `Y` no longer exists); what we do
+    // then is to push the edge `Hir(X) -> Bar` onto `extra_edges`
+    // (along with any other targets of `Foo(Y)`). We will then add
+    // the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be
+    // recreated, to the targets of `Bar`).
+    while let Some((source, target)) = extra_edges.pop() {
+        process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes,
+                      &mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
+    }
+
     // Add in work-products that are still clean, and delete those that are
     // dirty.
     reconcile_work_products(tcx, work_products, &clean_work_products);
@@ -393,3 +379,66 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
            serialized_hashes.index_map.len());
 }
 
+fn process_edges<'a, 'tcx, 'edges>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    source: &'edges DepNode<DefPathIndex>,
+    target: &'edges DepNode<DefPathIndex>,
+    edges: &'edges FxHashMap<DepNode<DefPathIndex>, Vec<DepNode<DefPathIndex>>>,
+    directory: &DefIdDirectory,
+    retraced: &RetracedDefIdDirectory,
+    dirty_raw_nodes: &DirtyNodes,
+    clean_work_products: &mut FxHashSet<Arc<WorkProductId>>,
+    dirty_work_products: &mut FxHashSet<Arc<WorkProductId>>,
+    extra_edges: &mut Vec<(&'edges DepNode<DefPathIndex>, &'edges DepNode<DefPathIndex>)>)
+{
+    // If the target is dirty, skip the edge. If this is an edge
+    // that targets a work-product, we can print the blame
+    // information now.
+    if let Some(blame) = dirty_raw_nodes.get(target) {
+        if let DepNode::WorkProduct(ref wp) = *target {
+            if tcx.sess.opts.debugging_opts.incremental_info {
+                if dirty_work_products.insert(wp.clone()) {
+                    // It'd be nice to pretty-print these paths better than just
+                    // using the `Debug` impls, but wev.
+                    println!("incremental: module {:?} is dirty because {:?} \
+                              changed or was removed",
+                             wp,
+                             blame.map_def(|&index| {
+                                 Some(directory.def_path_string(tcx, index))
+                             }).unwrap());
+                }
+            }
+        }
+        return;
+    }
+
+    // If the source is dirty, the target will be dirty.
+    assert!(!dirty_raw_nodes.contains_key(source));
+
+    // Retrace the source -> target edges to def-ids and then create
+    // an edge in the graph. Retracing may yield none if some of the
+    // data happens to have been removed.
+    if let Some(source_node) = retraced.map(source) {
+        if let Some(target_node) = retraced.map(target) {
+            let _task = tcx.dep_graph.in_task(target_node);
+            tcx.dep_graph.read(source_node);
+            if let DepNode::WorkProduct(ref wp) = *target {
+                clean_work_products.insert(wp.clone());
+            }
+        } else {
+            // As discussed in `decode_dep_graph` above, sometimes the
+            // target cannot be recreated again, in which case we add
+            // edges to go from `source` to the targets of `target`.
+            extra_edges.extend(
+                edges[target].iter().map(|t| (source, t)));
+        }
+    } else {
+        // It's also possible that the source can't be created! But we
+        // can ignore such cases, because (a) if `source` is a HIR
+        // node, it would be considered dirty; and (b) in other cases,
+        // there must be some input to this node that is clean, and so
+        // we'll re-create the edges over in the case where target is
+        // undefined.
+    }
+}
+
index e42e038ea4d6c5a53779943ccb140522a9e3f442..8feb07953db81b4df59b70fcc0d677136d0b8432 100644 (file)
@@ -339,6 +339,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
 
 enum FfiResult {
     FfiSafe,
+    FfiPhantom,
     FfiUnsafe(&'static str),
     FfiBadStruct(DefId, &'static str),
     FfiBadUnion(DefId, &'static str),
@@ -383,8 +384,11 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
-    fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
+    fn check_type_for_ffi(&self,
+                          cache: &mut FxHashSet<Ty<'tcx>>,
+                          ty: Ty<'tcx>) -> FfiResult {
         use self::FfiResult::*;
+
         let cx = self.cx.tcx;
 
         // Protect against infinite recursion, for example
@@ -397,6 +401,9 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
 
         match ty.sty {
             ty::TyAdt(def, substs) => {
+                if def.is_phantom_data() {
+                    return FfiPhantom;
+                }
                 match def.adt_kind() {
                     AdtKind::Struct => {
                         if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
@@ -405,18 +412,22 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                                               consider adding a #[repr(C)] attribute to the type");
                         }
 
-                        // We can't completely trust repr(C) markings; make sure the
-                        // fields are actually safe.
                         if def.struct_variant().fields.is_empty() {
                             return FfiUnsafe("found zero-size struct in foreign module, consider \
                                               adding a member to this struct");
                         }
 
+                        // We can't completely trust repr(C) markings; make sure the
+                        // fields are actually safe.
+                        let mut all_phantom = true;
                         for field in &def.struct_variant().fields {
                             let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
                             let r = self.check_type_for_ffi(cache, field_ty);
                             match r {
-                                FfiSafe => {}
+                                FfiSafe => {
+                                    all_phantom = false;
+                                }
+                                FfiPhantom => {}
                                 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
                                     return r;
                                 }
@@ -425,7 +436,8 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                                 }
                             }
                         }
-                        FfiSafe
+
+                        if all_phantom { FfiPhantom } else { FfiSafe }
                     }
                     AdtKind::Union => {
                         if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
@@ -434,11 +446,20 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                                               consider adding a #[repr(C)] attribute to the type");
                         }
 
+                        if def.struct_variant().fields.is_empty() {
+                            return FfiUnsafe("found zero-size union in foreign module, consider \
+                                              adding a member to this union");
+                        }
+
+                        let mut all_phantom = true;
                         for field in &def.struct_variant().fields {
                             let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
                             let r = self.check_type_for_ffi(cache, field_ty);
                             match r {
-                                FfiSafe => {}
+                                FfiSafe => {
+                                    all_phantom = false;
+                                }
+                                FfiPhantom => {}
                                 FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
                                     return r;
                                 }
@@ -447,7 +468,8 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                                 }
                             }
                         }
-                        FfiSafe
+
+                        if all_phantom { FfiPhantom } else { FfiSafe }
                     }
                     AdtKind::Enum => {
                         if def.variants.is_empty() {
@@ -498,6 +520,10 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                                     FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
                                         return r;
                                     }
+                                    FfiPhantom => {
+                                        return FfiBadEnum(def.did,
+                                                          "Found phantom data in enum variant");
+                                    }
                                     FfiUnsafe(s) => {
                                         return FfiBadEnum(def.did, s);
                                     }
@@ -591,6 +617,12 @@ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
 
         match self.check_type_for_ffi(&mut FxHashSet(), ty) {
             FfiResult::FfiSafe => {}
+            FfiResult::FfiPhantom => {
+                self.cx.span_lint(IMPROPER_CTYPES,
+                                  sp,
+                                  &format!("found zero-sized type composed only \
+                                            of phantom-data in a foreign-function."));
+            }
             FfiResult::FfiUnsafe(s) => {
                 self.cx.span_lint(IMPROPER_CTYPES, sp, s);
             }
index 8510b9f523cb5eb34af3910c2372a5511e8ae227..949e949f673a2b39dd084162d20d8c4606bb3d56 100644 (file)
@@ -126,6 +126,9 @@ pub enum Attribute {
     UWTable         = 17,
     ZExt            = 18,
     InReg           = 19,
+    SanitizeThread  = 20,
+    SanitizeAddress = 21,
+    SanitizeMemory  = 22,
 }
 
 /// LLVMIntPredicate
@@ -1369,14 +1372,14 @@ pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef,
     pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef,
                                             Name: *const c_char,
                                             SizeInBits: u64,
-                                            AlignInBits: u64,
+                                            AlignInBits: u32,
                                             Encoding: c_uint)
                                             -> DIBasicType;
 
     pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef,
                                               PointeeTy: DIType,
                                               SizeInBits: u64,
-                                              AlignInBits: u64,
+                                              AlignInBits: u32,
                                               Name: *const c_char)
                                               -> DIDerivedType;
 
@@ -1386,7 +1389,7 @@ pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef,
                                              File: DIFile,
                                              LineNumber: c_uint,
                                              SizeInBits: u64,
-                                             AlignInBits: u64,
+                                             AlignInBits: u32,
                                              Flags: DIFlags,
                                              DerivedFrom: DIType,
                                              Elements: DIArray,
@@ -1401,7 +1404,7 @@ pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef,
                                              File: DIFile,
                                              LineNo: c_uint,
                                              SizeInBits: u64,
-                                             AlignInBits: u64,
+                                             AlignInBits: u32,
                                              OffsetInBits: u64,
                                              Flags: DIFlags,
                                              Ty: DIType)
@@ -1429,7 +1432,7 @@ pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef,
                                                  isLocalToUnit: bool,
                                                  Val: ValueRef,
                                                  Decl: DIDescriptor,
-                                                 AlignInBits: u64)
+                                                 AlignInBits: u32)
                                                  -> DIGlobalVariable;
 
     pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef,
@@ -1442,19 +1445,19 @@ pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef,
                                            AlwaysPreserve: bool,
                                            Flags: DIFlags,
                                            ArgNo: c_uint,
-                                           AlignInBits: u64)
+                                           AlignInBits: u32)
                                            -> DIVariable;
 
     pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef,
                                             Size: u64,
-                                            AlignInBits: u64,
+                                            AlignInBits: u32,
                                             Ty: DIType,
                                             Subscripts: DIArray)
                                             -> DIType;
 
     pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef,
                                              Size: u64,
-                                             AlignInBits: u64,
+                                             AlignInBits: u32,
                                              Ty: DIType,
                                              Subscripts: DIArray)
                                              -> DIType;
@@ -1489,7 +1492,7 @@ pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef,
                                                   File: DIFile,
                                                   LineNumber: c_uint,
                                                   SizeInBits: u64,
-                                                  AlignInBits: u64,
+                                                  AlignInBits: u32,
                                                   Elements: DIArray,
                                                   ClassType: DIType)
                                                   -> DIType;
@@ -1500,7 +1503,7 @@ pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef,
                                             File: DIFile,
                                             LineNumber: c_uint,
                                             SizeInBits: u64,
-                                            AlignInBits: u64,
+                                            AlignInBits: u32,
                                             Flags: DIFlags,
                                             Elements: DIArray,
                                             RunTimeLang: c_uint,
diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml
new file mode 100644 (file)
index 0000000..bc1f2ea
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+authors = ["The Rust Project Developers"]
+build = "build.rs"
+name = "rustc_lsan"
+version = "0.0.0"
+
+[lib]
+name = "rustc_lsan"
+path = "lib.rs"
+
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+cmake = "0.1.18"
+
+[dependencies]
+alloc_system = { path = "../liballoc_system" }
+core = { path = "../libcore" }
diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs
new file mode 100644 (file)
index 0000000..5773777
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.
+
+extern crate build_helper;
+extern crate cmake;
+
+use std::path::PathBuf;
+use std::env;
+
+use cmake::Config;
+
+fn main() {
+    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
+        let dst = Config::new("../compiler-rt")
+            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
+            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
+            .define("COMPILER_RT_BUILD_XRAY", "OFF")
+            .define("LLVM_CONFIG_PATH", llvm_config)
+            .build_target("lsan")
+            .build();
+
+        println!("cargo:rustc-link-search=native={}",
+                 dst.join("build/lib/linux").display());
+        println!("cargo:rustc-link-lib=static=clang_rt.lsan-x86_64");
+
+        build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR")
+                .unwrap())
+            .join("../compiler-rt"));
+    }
+
+    println!("cargo:rerun-if-changed=build.rs");
+}
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
new file mode 100644 (file)
index 0000000..71a166b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
+#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![feature(alloc_system)]
+#![feature(staged_api)]
+#![no_std]
+#![unstable(feature = "sanitizer_runtime_lib",
+            reason = "internal implementation detail of sanitizers",
+            issue = "0")]
+
+extern crate alloc_system;
index 81a4f7c93b6e91abe2eec44da15ef705b8dbccb9..55dc5aa2876f6bab0002341acdaae62c6a48fdd4 100644 (file)
@@ -17,7 +17,8 @@
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::DepKind;
-use rustc::session::{config, Session};
+use rustc::session::Session;
+use rustc::session::config::{Sanitizer, self};
 use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
 use rustc::middle;
@@ -786,6 +787,64 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
                                   &|data| data.needs_panic_runtime());
     }
 
+    fn inject_sanitizer_runtime(&mut self) {
+        if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
+            // Sanitizers can only be used with x86_64 Linux executables linked
+            // to `std`
+            if self.sess.target.target.llvm_target != "x86_64-unknown-linux-gnu" {
+                self.sess.err(&format!("Sanitizers only work with the \
+                                        `x86_64-unknown-linux-gnu` target."));
+                return
+            }
+
+            if !self.sess.crate_types.borrow().iter().all(|ct| {
+                match *ct {
+                    // Link the runtime
+                    config::CrateTypeExecutable => true,
+                    // This crate will be compiled with the required
+                    // instrumentation pass
+                    config::CrateTypeRlib => false,
+                    _ => {
+                        self.sess.err(&format!("Only executables and rlibs can be \
+                                                compiled with `-Z sanitizer`"));
+                        false
+                    }
+                }
+            }) {
+                return
+            }
+
+            let mut uses_std = false;
+            self.cstore.iter_crate_data(|_, data| {
+                if data.name == "std" {
+                    uses_std = true;
+                }
+            });
+
+            if uses_std {
+                let name = match *sanitizer {
+                    Sanitizer::Address => "rustc_asan",
+                    Sanitizer::Leak => "rustc_lsan",
+                    Sanitizer::Memory => "rustc_msan",
+                    Sanitizer::Thread => "rustc_tsan",
+                };
+                info!("loading sanitizer: {}", name);
+
+                let symbol = Symbol::intern(name);
+                let dep_kind = DepKind::Implicit;
+                let (_, data) =
+                    self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
+                                       PathKind::Crate, dep_kind);
+
+                // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
+                if !data.is_sanitizer_runtime() {
+                    self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
+                                           name));
+                }
+            }
+        }
+    }
+
     fn inject_allocator_crate(&mut self) {
         // Make sure that we actually need an allocator, if none of our
         // dependencies need one then we definitely don't!
@@ -982,6 +1041,9 @@ fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod,
 
 impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
     fn postprocess(&mut self, krate: &ast::Crate) {
+        // inject the sanitizer runtime before the allocator runtime because all
+        // sanitizers force the use of the `alloc_system` allocator
+        self.inject_sanitizer_runtime();
         self.inject_allocator_crate();
         self.inject_panic_runtime(krate);
 
index beba5faf3d03407c67f3c8558317a6b7188b1d97..4709ca6101c7908f11e8ce5ef7e9cd5a96d090ec 100644 (file)
@@ -297,6 +297,11 @@ pub fn is_compiler_builtins(&self) -> bool {
         attr::contains_name(&attrs, "compiler_builtins")
     }
 
+    pub fn is_sanitizer_runtime(&self) -> bool {
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
+        attr::contains_name(&attrs, "sanitizer_runtime")
+    }
+
     pub fn is_no_builtins(&self) -> bool {
         let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "no_builtins")
index 39581a46960887069faecd871888335f49a89c95..7b0177bfd23ed966a2b4fef4a5e6195770e7edb5 100644 (file)
@@ -297,6 +297,10 @@ fn is_compiler_builtins(&self, cnum: CrateNum) -> bool {
         self.get_crate_data(cnum).is_compiler_builtins()
     }
 
+    fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool {
+        self.get_crate_data(cnum).is_sanitizer_runtime()
+    }
+
     fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
         self.get_crate_data(cnum).panic_strategy()
     }
diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml
new file mode 100644 (file)
index 0000000..45cc6b9
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+authors = ["The Rust Project Developers"]
+build = "build.rs"
+name = "rustc_msan"
+version = "0.0.0"
+
+[lib]
+name = "rustc_msan"
+path = "lib.rs"
+
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+cmake = "0.1.18"
+
+[dependencies]
+alloc_system = { path = "../liballoc_system" }
+core = { path = "../libcore" }
diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs
new file mode 100644 (file)
index 0000000..7a4c8f7
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.
+
+extern crate build_helper;
+extern crate cmake;
+
+use std::path::PathBuf;
+use std::env;
+
+use cmake::Config;
+
+fn main() {
+    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
+        let dst = Config::new("../compiler-rt")
+            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
+            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
+            .define("COMPILER_RT_BUILD_XRAY", "OFF")
+            .define("LLVM_CONFIG_PATH", llvm_config)
+            .build_target("msan")
+            .build();
+
+        println!("cargo:rustc-link-search=native={}",
+                 dst.join("build/lib/linux").display());
+        println!("cargo:rustc-link-lib=static=clang_rt.msan-x86_64");
+
+        build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR")
+                .unwrap())
+            .join("../compiler-rt"));
+    }
+
+    println!("cargo:rerun-if-changed=build.rs");
+}
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
new file mode 100644 (file)
index 0000000..71a166b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
+#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![feature(alloc_system)]
+#![feature(staged_api)]
+#![no_std]
+#![unstable(feature = "sanitizer_runtime_lib",
+            reason = "internal implementation detail of sanitizers",
+            issue = "0")]
+
+extern crate alloc_system;
index bc1e07e708c248e5dc051b450ec4fa6d5230ff85..59f2104ec146471a05aaa0f7ce98100a7b1a8c52 100644 (file)
@@ -56,6 +56,8 @@
 use type_::Type;
 use type_of;
 
+use mir::lvalue::Alignment;
+
 /// Given an enum, struct, closure, or tuple, extracts fields.
 /// Treats closures as a struct with one variant.
 /// `empty_if_no_variants` is a switch to deal with empty enums.
@@ -279,6 +281,7 @@ pub fn trans_get_discr<'a, 'tcx>(
     bcx: &Builder<'a, 'tcx>,
     t: Ty<'tcx>,
     scrutinee: ValueRef,
+    alignment: Alignment,
     cast_to: Option<Type>,
     range_assert: bool
 ) -> ValueRef {
@@ -292,11 +295,12 @@ pub fn trans_get_discr<'a, 'tcx>(
 
     let val = match *l {
         layout::CEnum { discr, min, max, .. } => {
-            load_discr(bcx, discr, scrutinee, min, max, range_assert)
+            load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert)
         }
         layout::General { discr, .. } => {
             let ptr = bcx.struct_gep(scrutinee, 0);
-            load_discr(bcx, discr, ptr, 0, def.variants.len() as u64 - 1,
+            load_discr(bcx, discr, ptr, alignment,
+                       0, def.variants.len() as u64 - 1,
                        range_assert)
         }
         layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
@@ -305,10 +309,10 @@ pub fn trans_get_discr<'a, 'tcx>(
             let llptrty = type_of::sizing_type_of(bcx.ccx,
                 monomorphize::field_ty(bcx.tcx(), substs,
                 &def.variants[nndiscr as usize].fields[0]));
-            bcx.icmp(cmp, bcx.load(scrutinee), C_null(llptrty))
+            bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty))
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
-            struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
+            struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment)
         },
         _ => bug!("{} is not an enum", t)
     };
@@ -322,17 +326,19 @@ fn struct_wrapped_nullable_bitdiscr(
     bcx: &Builder,
     nndiscr: u64,
     discrfield: &layout::FieldPath,
-    scrutinee: ValueRef
+    scrutinee: ValueRef,
+    alignment: Alignment,
 ) -> ValueRef {
     let llptrptr = bcx.gepi(scrutinee,
         &discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>()[..]);
-    let llptr = bcx.load(llptrptr);
+    let llptr = bcx.load(llptrptr, alignment.to_align());
     let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
     bcx.icmp(cmp, llptr, C_null(val_ty(llptr)))
 }
 
 /// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
+fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef,
+              alignment: Alignment, min: u64, max: u64,
               range_assert: bool)
     -> ValueRef {
     let llty = Type::from_integer(bcx.ccx, ity);
@@ -348,11 +354,12 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, min: u64, max:
         // rejected by the LLVM verifier (it would mean either an
         // empty set, which is impossible, or the entire range of the
         // type, which is pointless).
-        bcx.load(ptr)
+        bcx.load(ptr, alignment.to_align())
     } else {
         // llvm::ConstantRange can deal with ranges that wrap around,
         // so an overflow on (max + 1) is fine.
-        bcx.load_range_assert(ptr, min, max.wrapping_add(1), /* signed: */ True)
+        bcx.load_range_assert(ptr, min, max.wrapping_add(1), /* signed: */ True,
+                              alignment.to_align())
     }
 }
 
index c95d414701876ef6a4d4c9e19d57b12925db5bc5..12e4e57964f985e47c9ba31226693965c73b4dd7 100644 (file)
@@ -20,6 +20,8 @@
 use rustc::hir;
 use rustc::ty::Ty;
 
+use mir::lvalue::Alignment;
+
 use std::ffi::CString;
 use syntax::ast::AsmDialect;
 use libc::{c_uint, c_char};
@@ -38,7 +40,7 @@ pub fn trans_inline_asm<'a, 'tcx>(
     let mut indirect_outputs = vec![];
     for (i, (out, &(val, ty))) in ia.outputs.iter().zip(&outputs).enumerate() {
         let val = if out.is_rw || out.is_indirect {
-            Some(base::load_ty(bcx, val, ty))
+            Some(base::load_ty(bcx, val, Alignment::Packed, ty))
         } else {
             None
         };
index 4ddf8a883bc488781efd48a31d5758eefb7460b0..1cbfa26b705ac8190d6ba15e49477116d767c337 100644 (file)
@@ -1031,6 +1031,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
         // symbols from the dylib.
         let src = sess.cstore.used_crate_source(cnum);
         match data[cnum.as_usize() - 1] {
+            _ if sess.cstore.is_sanitizer_runtime(cnum) => {
+                link_sanitizer_runtime(cmd, sess, tmpdir, cnum);
+            }
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
             _ if sess.cstore.is_compiler_builtins(cnum) => {
@@ -1048,6 +1051,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
         }
     }
 
+    // compiler-builtins are always placed last to ensure that they're
+    // linked correctly.
     // We must always link the `compiler_builtins` crate statically. Even if it
     // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic`
     // is used)
@@ -1064,6 +1069,34 @@ fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
         }
     }
 
+    // We must link the sanitizer runtime using -Wl,--whole-archive but since
+    // it's packed in a .rlib, it contains stuff that are not objects that will
+    // make the linker error. So we must remove those bits from the .rlib before
+    // linking it.
+    fn link_sanitizer_runtime(cmd: &mut Linker,
+                              sess: &Session,
+                              tmpdir: &Path,
+                              cnum: CrateNum) {
+        let src = sess.cstore.used_crate_source(cnum);
+        let cratepath = &src.rlib.unwrap().0;
+        let dst = tmpdir.join(cratepath.file_name().unwrap());
+        let cfg = archive_config(sess, &dst, Some(cratepath));
+        let mut archive = ArchiveBuilder::new(cfg);
+        archive.update_symbols();
+
+        for f in archive.src_files() {
+            if f.ends_with("bytecode.deflate") ||
+                f == sess.cstore.metadata_filename() {
+                    archive.remove_file(&f);
+                    continue
+                }
+        }
+
+        archive.build();
+
+        cmd.link_whole_rlib(&dst);
+    }
+
     // Adds the static "rlib" versions of all crates to the command line.
     // There's a bit of magic which happens here specifically related to LTO and
     // dynamic libraries. Specifically:
index b3a2d66a07c112ef779128a1c5321e691a50e236..5c4a5a9a4423d3abdf4bd9a96b90cb1884d5417f 100644 (file)
@@ -12,7 +12,7 @@
 use back::link::{get_linker, remove};
 use back::symbol_export::ExportedSymbols;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses};
+use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses, Sanitizer};
 use session::Session;
 use session::config::{self, OutputType};
 use llvm;
@@ -27,6 +27,7 @@
 use syntax_pos::MultiSpan;
 use context::{is_pie_binary, get_reloc_model};
 
+use std::cmp;
 use std::ffi::CString;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -678,6 +679,22 @@ pub fn run_passes(sess: &Session,
     let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone());
     let mut metadata_config = ModuleConfig::new(tm, vec![]);
 
+    if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
+        match *sanitizer {
+            Sanitizer::Address => {
+                modules_config.passes.push("asan".to_owned());
+                modules_config.passes.push("asan-module".to_owned());
+            }
+            Sanitizer::Memory => {
+                modules_config.passes.push("msan".to_owned())
+            }
+            Sanitizer::Thread => {
+                modules_config.passes.push("tsan".to_owned())
+            }
+            _ => {}
+        }
+    }
+
     modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
     modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));
 
@@ -754,10 +771,13 @@ pub fn run_passes(sess: &Session,
     }
 
     // Process the work items, optionally using worker threads.
-    // NOTE: This code is not really adapted to incremental compilation where
-    //       the compiler decides the number of codegen units (and will
-    //       potentially create hundreds of them).
-    let num_workers = work_items.len() - 1;
+    // NOTE: We are hardcoding a limit of worker threads for now. With
+    //       incremental compilation we can run into situations where we would
+    //       open hundreds of threads otherwise -- which can make things slower
+    //       if things don't fit into memory anymore, or can cause the compiler
+    //       to crash because of too many open file handles. See #39280 for
+    //       some discussion on how to improve this in the future.
+    let num_workers = cmp::min(work_items.len() - 1, 32);
     if num_workers <= 1 {
         run_work_singlethreaded(sess, &trans.exported_symbols, work_items);
     } else {
index 9bd19d5bbb3e47f050d7ffcbd19495e55cdaa6fb..5312cc60b09167b82e3dbc607b9e3043816756bb 100644 (file)
@@ -90,6 +90,8 @@
 use rustc::ty::layout::{self, Layout};
 use syntax::ast;
 
+use mir::lvalue::Alignment;
+
 pub struct StatRecorder<'a, 'tcx: 'a> {
     ccx: &'a CrateContext<'a, 'tcx>,
     name: Option<String>,
@@ -250,25 +252,25 @@ pub fn unsize_thin_ptr<'a, 'tcx>(
 /// Coerce `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty` and store the result in `dst`
 pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
-                                     src: ValueRef,
-                                     src_ty: Ty<'tcx>,
-                                     dst: ValueRef,
-                                     dst_ty: Ty<'tcx>) {
+                                     src: &LvalueRef<'tcx>,
+                                     dst: &LvalueRef<'tcx>) {
+    let src_ty = src.ty.to_ty(bcx.tcx());
+    let dst_ty = dst.ty.to_ty(bcx.tcx());
     let coerce_ptr = || {
         let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) {
             // fat-ptr to fat-ptr unsize preserves the vtable
             // i.e. &'a fmt::Debug+Send => &'a fmt::Debug
             // So we need to pointercast the base to ensure
             // the types match up.
-            let (base, info) = load_fat_ptr(bcx, src, src_ty);
+            let (base, info) = load_fat_ptr(bcx, src.llval, src.alignment, src_ty);
             let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty);
             let base = bcx.pointercast(base, llcast_ty);
             (base, info)
         } else {
-            let base = load_ty(bcx, src, src_ty);
+            let base = load_ty(bcx, src.llval, src.alignment, src_ty);
             unsize_thin_ptr(bcx, base, src_ty, dst_ty)
         };
-        store_fat_ptr(bcx, base, info, dst, dst_ty);
+        store_fat_ptr(bcx, base, info, dst.llval, dst.alignment, dst_ty);
     };
     match (&src_ty.sty, &dst_ty.sty) {
         (&ty::TyRef(..), &ty::TyRef(..)) |
@@ -290,21 +292,22 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 monomorphize::field_ty(bcx.tcx(), substs_b, f)
             });
 
-            let src = LvalueRef::new_sized_ty(src, src_ty);
-            let dst = LvalueRef::new_sized_ty(dst, dst_ty);
-
             let iter = src_fields.zip(dst_fields).enumerate();
             for (i, (src_fty, dst_fty)) in iter {
                 if type_is_zero_size(bcx.ccx, dst_fty) {
                     continue;
                 }
 
-                let src_f = src.trans_field_ptr(bcx, i);
-                let dst_f = dst.trans_field_ptr(bcx, i);
+                let (src_f, src_f_align) = src.trans_field_ptr(bcx, i);
+                let (dst_f, dst_f_align) = dst.trans_field_ptr(bcx, i);
                 if src_fty == dst_fty {
                     memcpy_ty(bcx, dst_f, src_f, src_fty, None);
                 } else {
-                    coerce_unsized_into(bcx, src_f, src_fty, dst_f, dst_fty);
+                    coerce_unsized_into(
+                        bcx,
+                        &LvalueRef::new_sized_ty(src_f, src_fty, src_f_align),
+                        &LvalueRef::new_sized_ty(dst_f, dst_fty, dst_f_align)
+                    );
                 }
             }
         }
@@ -399,7 +402,8 @@ pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
 /// Helper for loading values from memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values. Also handles various special cases where the type
 /// gives us better information about what we are loading.
-pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
+pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef,
+                         alignment: Alignment, t: Ty<'tcx>) -> ValueRef {
     let ccx = b.ccx;
     if type_is_zero_size(ccx, t) {
         return C_undef(type_of::type_of(ccx, t));
@@ -419,29 +423,31 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> V
     }
 
     if t.is_bool() {
-        b.trunc(b.load_range_assert(ptr, 0, 2, llvm::False), Type::i1(ccx))
+        b.trunc(b.load_range_assert(ptr, 0, 2, llvm::False, alignment.to_align()),
+                Type::i1(ccx))
     } else if t.is_char() {
         // a char is a Unicode codepoint, and so takes values from 0
         // to 0x10FFFF inclusive only.
-        b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False)
+        b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False, alignment.to_align())
     } else if (t.is_region_ptr() || t.is_box()) && !common::type_is_fat_ptr(ccx, t) {
-        b.load_nonnull(ptr)
+        b.load_nonnull(ptr, alignment.to_align())
     } else {
-        b.load(ptr)
+        b.load(ptr, alignment.to_align())
     }
 }
 
 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values.
-pub fn store_ty<'a, 'tcx>(cx: &Builder<'a, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
+pub fn store_ty<'a, 'tcx>(cx: &Builder<'a, 'tcx>, v: ValueRef, dst: ValueRef,
+                          dst_align: Alignment, t: Ty<'tcx>) {
     debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
 
     if common::type_is_fat_ptr(cx.ccx, t) {
         let lladdr = cx.extract_value(v, abi::FAT_PTR_ADDR);
         let llextra = cx.extract_value(v, abi::FAT_PTR_EXTRA);
-        store_fat_ptr(cx, lladdr, llextra, dst, t);
+        store_fat_ptr(cx, lladdr, llextra, dst, dst_align, t);
     } else {
-        cx.store(from_immediate(cx, v), dst, None);
+        cx.store(from_immediate(cx, v), dst, dst_align.to_align());
     }
 }
 
@@ -449,24 +455,25 @@ pub fn store_fat_ptr<'a, 'tcx>(cx: &Builder<'a, 'tcx>,
                                data: ValueRef,
                                extra: ValueRef,
                                dst: ValueRef,
+                               dst_align: Alignment,
                                _ty: Ty<'tcx>) {
     // FIXME: emit metadata
-    cx.store(data, get_dataptr(cx, dst), None);
-    cx.store(extra, get_meta(cx, dst), None);
+    cx.store(data, get_dataptr(cx, dst), dst_align.to_align());
+    cx.store(extra, get_meta(cx, dst), dst_align.to_align());
 }
 
 pub fn load_fat_ptr<'a, 'tcx>(
-    b: &Builder<'a, 'tcx>, src: ValueRef, t: Ty<'tcx>
+    b: &Builder<'a, 'tcx>, src: ValueRef, alignment: Alignment, t: Ty<'tcx>
 ) -> (ValueRef, ValueRef) {
     let ptr = get_dataptr(b, src);
     let ptr = if t.is_region_ptr() || t.is_box() {
-        b.load_nonnull(ptr)
+        b.load_nonnull(ptr, alignment.to_align())
     } else {
-        b.load(ptr)
+        b.load(ptr, alignment.to_align())
     };
 
     // FIXME: emit metadata on `meta`.
-    let meta = b.load(get_meta(b, src));
+    let meta = b.load(get_meta(b, src), alignment.to_align());
 
     (ptr, meta)
 }
@@ -633,7 +640,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
         };
         // Can return unsized value
-        let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output());
+        let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output(), Alignment::AbiAligned);
         dest_val.ty = LvalueTy::Downcast {
             adt_def: sig.output().ty_adt_def().unwrap(),
             substs: substs,
@@ -642,7 +649,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
         let mut arg_idx = 0;
         for (i, arg_ty) in sig.inputs().iter().enumerate() {
-            let lldestptr = dest_val.trans_field_ptr(&bcx, i);
+            let (lldestptr, _) = dest_val.trans_field_ptr(&bcx, i);
             let arg = &fn_ty.args[arg_idx];
             arg_idx += 1;
             if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
@@ -662,14 +669,12 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
 
         if let Some(cast_ty) = fn_ty.ret.cast {
-            let load = bcx.load(bcx.pointercast(dest, cast_ty.ptr_to()));
-            let llalign = llalign_of_min(ccx, fn_ty.ret.ty);
-            unsafe {
-                llvm::LLVMSetAlignment(load, llalign);
-            }
-            bcx.ret(load)
+            bcx.ret(bcx.load(
+                bcx.pointercast(dest, cast_ty.ptr_to()),
+                Some(llalign_of_min(ccx, fn_ty.ret.ty))
+            ));
         } else {
-            bcx.ret(bcx.load(dest))
+            bcx.ret(bcx.load(dest, None))
         }
     } else {
         bcx.ret_void();
index c113716ca5c74295339868d95bda27492dbcc0d3..89aaa8b66306ffeafd653259e73d723e74aba242 100644 (file)
@@ -19,9 +19,8 @@
 use type_::Type;
 use value::Value;
 use libc::{c_uint, c_char};
-use rustc::ty::{Ty, TyCtxt, TypeFoldable};
+use rustc::ty::TyCtxt;
 use rustc::session::Session;
-use type_of;
 
 use std::borrow::Cow;
 use std::ffi::CString;
@@ -486,11 +485,6 @@ pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
         builder.dynamic_alloca(ty, name)
     }
 
-    pub fn alloca_ty(&self, ty: Ty<'tcx>, name: &str) -> ValueRef {
-        assert!(!ty.has_param_types());
-        self.alloca(type_of::type_of(self.ccx, ty), name)
-    }
-
     pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
         self.count_insn("alloca");
         unsafe {
@@ -511,10 +505,14 @@ pub fn free(&self, ptr: ValueRef) {
         }
     }
 
-    pub fn load(&self, ptr: ValueRef) -> ValueRef {
+    pub fn load(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
         self.count_insn("load");
         unsafe {
-            llvm::LLVMBuildLoad(self.llbuilder, ptr, noname())
+            let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
+            if let Some(align) = align {
+                llvm::LLVMSetAlignment(load, align as c_uint);
+            }
+            load
         }
     }
 
@@ -539,8 +537,9 @@ pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
 
 
     pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
-                             hi: u64, signed: llvm::Bool) -> ValueRef {
-        let value = self.load(ptr);
+                             hi: u64, signed: llvm::Bool,
+                             align: Option<u32>) -> ValueRef {
+        let value = self.load(ptr, align);
 
         unsafe {
             let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
@@ -558,8 +557,8 @@ pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
         value
     }
 
-    pub fn load_nonnull(&self, ptr: ValueRef) -> ValueRef {
-        let value = self.load(ptr);
+    pub fn load_nonnull(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
+        let value = self.load(ptr, align);
         unsafe {
             llvm::LLVMSetMetadata(value, llvm::MD_nonnull as c_uint,
                                   llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));
index c6b86c6ba48deed1ee9f5a775409b5e0c8f6fbb2..4a8658dd2e308a86d2bec71d3c0a890102c6979a 100644 (file)
@@ -41,6 +41,8 @@
 
 use syntax_pos::DUMMY_SP;
 
+use mir::lvalue::Alignment;
+
 #[derive(Debug)]
 pub enum CalleeData {
     /// Constructor for enum variant/tuple-like-struct.
@@ -358,29 +360,27 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
     let self_idx = fn_ty.ret.is_indirect() as usize;
     let env_arg = &orig_fn_ty.args[0];
-    let llenv = if env_arg.is_indirect() {
-        llargs[self_idx]
+    let env = if env_arg.is_indirect() {
+        LvalueRef::new_sized_ty(llargs[self_idx], closure_ty, Alignment::AbiAligned)
     } else {
-        let scratch = bcx.alloca_ty(closure_ty, "self");
+        let scratch = LvalueRef::alloca(&bcx, closure_ty, "self");
         let mut llarg_idx = self_idx;
-        env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch);
+        env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch.llval);
         scratch
     };
 
-    debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
+    debug!("trans_fn_once_adapter_shim: env={:?}", env);
     // Adjust llargs such that llargs[self_idx..] has the call arguments.
     // For zero-sized closures that means sneaking in a new argument.
     if env_arg.is_ignore() {
-        llargs.insert(self_idx, llenv);
+        llargs.insert(self_idx, env.llval);
     } else {
-        llargs[self_idx] = llenv;
+        llargs[self_idx] = env.llval;
     }
 
     // Call the by-ref closure body with `self` in a cleanup scope,
     // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = CleanupScope::schedule_drop_mem(
-        &bcx, LvalueRef::new_sized_ty(llenv, closure_ty)
-    );
+    let self_scope = CleanupScope::schedule_drop_mem(&bcx, env);
 
     let llfn = callee.reify(bcx.ccx);
     let llret;
@@ -512,7 +512,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
     let llfnpointer = llfnpointer.unwrap_or_else(|| {
         // the first argument (`self`) will be ptr to the fn pointer
         if is_by_ref {
-            bcx.load(self_arg)
+            bcx.load(self_arg, None)
         } else {
             self_arg
         }
index c83e2f4854bf5cda8cbfd195df2b58d6462b0a84..7578cc74dbf34bf990436ef8a412daaf56c8e99f 100644 (file)
@@ -1783,7 +1783,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
                                                     is_local_to_unit,
                                                     global,
                                                     ptr::null_mut(),
-                                                    global_align as u64,
+                                                    global_align,
         );
     }
 }
index 501f891befa8dafa279002972a0610e9571ac39d..729eae15ad696ae85693f1f7c43d47d3cffa7064 100644 (file)
@@ -464,7 +464,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                     cx.sess().opts.optimize != config::OptLevel::No,
                     DIFlags::FlagZero,
                     argument_index,
-                    align as u64,
+                    align,
                 )
             };
             source_loc::set_debug_location(bcx,
index 8d634c0e292ad7f35e5cfab404c75c89c88ecfc1..15a1c990aadc6aa674f83abde74b3cd8da235673 100644 (file)
@@ -24,6 +24,8 @@
 use syntax_pos::{self, Span};
 use syntax::ast;
 
+use std::ops;
+
 pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
 {
     // The is_local_to_unit flag indicates whether a function is local to the
@@ -49,12 +51,13 @@ pub fn span_start(cx: &CrateContext, span: Span) -> syntax_pos::Loc {
     cx.sess().codemap().lookup_char_pos(span.lo)
 }
 
-pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
-    (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type) as u64)
+pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u32) {
+    (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
 }
 
-pub fn bytes_to_bits(bytes: u64) -> u64 {
-    bytes * 8
+pub fn bytes_to_bits<T>(bytes: T) -> T
+    where T: ops::Mul<Output=T> + From<u8> {
+    bytes * 8u8.into()
 }
 
 #[inline]
index bf7a02eb0f196c7fdc6306f6a8a2c35fd3014afd..7ac482459ee39f5846a3dd4ec807bbde27cb8405 100644 (file)
@@ -23,6 +23,7 @@
 use llvm::{self, ValueRef};
 use llvm::AttributePlace::Function;
 use rustc::ty;
+use rustc::session::config::Sanitizer;
 use abi::{Abi, FnType};
 use attributes;
 use context::CrateContext;
@@ -72,6 +73,21 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
         llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
     }
 
+    if let Some(ref sanitizer) = ccx.tcx().sess.opts.debugging_opts.sanitizer {
+        match *sanitizer {
+            Sanitizer::Address => {
+                llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
+            },
+            Sanitizer::Memory => {
+                llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
+            },
+            Sanitizer::Thread => {
+                llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
+            },
+            _ => {}
+        }
+    }
+
     // If we're compiling the compiler-builtins crate, e.g. the equivalent of
     // compiler-rt, then we want to implicitly compile everything with hidden
     // visibility as we're going to link this object all over the place but
index fdefd37549ced1251245822615473da33c8f46ab..d66ea4d650f7b4638c226adc826d2316a086c9be 100644 (file)
@@ -13,7 +13,6 @@
 // Code relating to drop glue.
 
 use std;
-use std::ptr;
 use std::iter;
 
 use llvm;
@@ -41,6 +40,7 @@
 use builder::Builder;
 
 use syntax_pos::DUMMY_SP;
+use mir::lvalue::Alignment;
 
 pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<'tcx>) {
     let content_ty = ptr.ty.to_ty(bcx.tcx());
@@ -199,9 +199,9 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
 
     let value = get_param(llfn, 0);
     let ptr = if ccx.shared().type_is_sized(t) {
-        LvalueRef::new_sized_ty(value, t)
+        LvalueRef::new_sized_ty(value, t, Alignment::AbiAligned)
     } else {
-        LvalueRef::new_unsized_ty(value, get_param(llfn, 1), t)
+        LvalueRef::new_unsized_ty(value, get_param(llfn, 1), t, Alignment::AbiAligned)
     };
 
     let skip_dtor = match g {
@@ -216,11 +216,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             assert!(!skip_dtor);
             let content_ty = t.boxed_ty();
             let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) {
-                let llbox = bcx.load(get_dataptr(&bcx, ptr.llval));
-                let info = bcx.load(get_meta(&bcx, ptr.llval));
-                LvalueRef::new_unsized_ty(llbox, info, content_ty)
+                let llbox = bcx.load(get_dataptr(&bcx, ptr.llval), None);
+                let info = bcx.load(get_meta(&bcx, ptr.llval), None);
+                LvalueRef::new_unsized_ty(llbox, info, content_ty, Alignment::AbiAligned)
             } else {
-                LvalueRef::new_sized_ty(bcx.load(ptr.llval), content_ty)
+                LvalueRef::new_sized_ty(
+                    bcx.load(ptr.llval, None),
+                    content_ty, Alignment::AbiAligned)
             };
             drop_ty(&bcx, ptr);
             trans_exchange_free_ty(&bcx, ptr);
@@ -231,7 +233,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             // versus without calling Drop::drop. Assert caller is
             // okay with always calling the Drop impl, if any.
             assert!(!skip_dtor);
-            let dtor = bcx.load(ptr.llextra);
+            let dtor = bcx.load(ptr.llextra, None);
             bcx.call(dtor, &[ptr.llval], None);
             bcx
         }
@@ -384,7 +386,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             let info = bcx.pointercast(info, Type::int(bcx.ccx).ptr_to());
             let size_ptr = bcx.gepi(info, &[1]);
             let align_ptr = bcx.gepi(info, &[2]);
-            (bcx.load(size_ptr), bcx.load(align_ptr))
+            (bcx.load(size_ptr, None), bcx.load(align_ptr, None))
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(bcx.tcx());
@@ -416,8 +418,8 @@ fn iter_variant_fields<'a, 'tcx>(
         let tcx = cx.tcx();
         for (i, field) in variant.fields.iter().enumerate() {
             let arg = monomorphize::field_ty(tcx, substs, field);
-            let field_ptr = av.trans_field_ptr(&cx, i);
-            drop_ty(&cx, LvalueRef::new_sized_ty(field_ptr, arg));
+            let (field_ptr, align) = av.trans_field_ptr(&cx, i);
+            drop_ty(&cx, LvalueRef::new_sized_ty(field_ptr, arg, align));
         }
     }
 
@@ -426,8 +428,8 @@ fn iter_variant_fields<'a, 'tcx>(
     match t.sty {
         ty::TyClosure(def_id, substs) => {
             for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() {
-                let llupvar = ptr.trans_field_ptr(&cx, i);
-                drop_ty(&cx, LvalueRef::new_sized_ty(llupvar, upvar_ty));
+                let (llupvar, align) = ptr.trans_field_ptr(&cx, i);
+                drop_ty(&cx, LvalueRef::new_sized_ty(llupvar, upvar_ty, align));
             }
         }
         ty::TyArray(_, n) => {
@@ -435,29 +437,29 @@ fn iter_variant_fields<'a, 'tcx>(
             let len = C_uint(cx.ccx, n);
             let unit_ty = t.sequence_element_type(cx.tcx());
             cx = tvec::slice_for_each(&cx, base, unit_ty, len,
-                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
+                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty, ptr.alignment)));
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(cx.tcx());
             cx = tvec::slice_for_each(&cx, ptr.llval, unit_ty, ptr.llextra,
-                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
+                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty, ptr.alignment)));
         }
         ty::TyTuple(ref args, _) => {
             for (i, arg) in args.iter().enumerate() {
-                let llfld_a = ptr.trans_field_ptr(&cx, i);
-                drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg));
+                let (llfld_a, align) = ptr.trans_field_ptr(&cx, i);
+                drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg, align));
             }
         }
         ty::TyAdt(adt, substs) => match adt.adt_kind() {
             AdtKind::Struct => {
                 for (i, field) in adt.variants[0].fields.iter().enumerate() {
                     let field_ty = monomorphize::field_ty(cx.tcx(), substs, field);
-                    let mut field_ptr = ptr.clone();
-                    field_ptr.llval = ptr.trans_field_ptr(&cx, i);
-                    field_ptr.ty = LvalueTy::from_ty(field_ty);
-                    if cx.ccx.shared().type_is_sized(field_ty) {
-                        field_ptr.llextra = ptr::null_mut();
-                    }
+                    let (llval, align) = ptr.trans_field_ptr(&cx, i);
+                    let field_ptr = if cx.ccx.shared().type_is_sized(field_ty) {
+                        LvalueRef::new_sized_ty(llval, field_ty, align)
+                    } else {
+                        LvalueRef::new_unsized_ty(llval, ptr.llextra, field_ty, align)
+                    };
                     drop_ty(&cx, field_ptr);
                 }
             }
@@ -490,9 +492,8 @@ fn iter_variant_fields<'a, 'tcx>(
                     layout::General { .. } |
                     layout::RawNullablePointer { .. } |
                     layout::StructWrappedNullablePointer { .. } => {
-                        let lldiscrim_a = adt::trans_get_discr(&cx, t, ptr.llval, None, false);
-                        let tcx = cx.tcx();
-                        drop_ty(&cx, LvalueRef::new_sized_ty(lldiscrim_a, tcx.types.isize));
+                        let lldiscrim_a = adt::trans_get_discr(
+                            &cx, t, ptr.llval, ptr.alignment, None, false);
 
                         // Create a fall-through basic block for the "else" case of
                         // the switch instruction we're about to generate. Note that
index 37f63e7499689f1cee16ccc3324584bffbd962a0..333a0802ee6ff664c75ebdb4d3a4f8d4ae57c735 100644 (file)
@@ -36,6 +36,8 @@
 use std::cmp::Ordering;
 use std::iter;
 
+use mir::lvalue::Alignment;
+
 fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     let llvm_name = match name {
         "sqrtf32" => "llvm.sqrt.f32",
@@ -243,7 +245,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 bcx.volatile_store(llargs[2], get_meta(bcx, llargs[0]));
             } else {
                 let val = if fn_ty.args[1].is_indirect() {
-                    bcx.load(llargs[1])
+                    bcx.load(llargs[1], None)
                 } else {
                     from_immediate(bcx, llargs[1])
                 };
@@ -348,7 +350,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             let val_ty = substs.type_at(0);
             match val_ty.sty {
                 ty::TyAdt(adt, ..) if adt.is_enum() => {
-                    adt::trans_get_discr(bcx, val_ty, llargs[0],
+                    adt::trans_get_discr(bcx, val_ty, llargs[0], Alignment::AbiAligned,
                                          Some(llret_ty), true)
                 }
                 _ => C_null(llret_ty)
@@ -547,8 +549,11 @@ fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                         // destructors, and the contents are SIMD
                         // etc.
                         assert!(!bcx.ccx.shared().type_needs_drop(arg_type));
-                        let arg = LvalueRef::new_sized_ty(llarg, arg_type);
-                        (0..contents.len()).map(|i| bcx.load(arg.trans_field_ptr(bcx, i))).collect()
+                        let arg = LvalueRef::new_sized_ty(llarg, arg_type, Alignment::AbiAligned);
+                        (0..contents.len()).map(|i| {
+                            let (ptr, align) = arg.trans_field_ptr(bcx, i);
+                            bcx.load(ptr, align.to_align())
+                        }).collect()
                     }
                     intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => {
                         let llvm_elem = one(ty_to_type(bcx.ccx, llvm_elem, &mut false));
@@ -624,7 +629,7 @@ fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             let ptr = bcx.pointercast(llresult, ty.ptr_to());
             bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
         } else {
-            store_ty(bcx, llval, llresult, ret_ty);
+            store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty);
         }
     }
 }
@@ -780,10 +785,10 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             None => bug!("msvc_try_filter not defined"),
         };
         let tok = catchpad.catch_pad(cs, &[tydesc, C_i32(ccx, 0), slot]);
-        let addr = catchpad.load(slot);
-        let arg1 = catchpad.load(addr);
+        let addr = catchpad.load(slot, None);
+        let arg1 = catchpad.load(addr, None);
         let val1 = C_i32(ccx, 1);
-        let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]));
+        let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]), None);
         let local_ptr = catchpad.bitcast(local_ptr, i64p);
         catchpad.store(arg1, local_ptr, None);
         catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), None);
index aecba2f57e52cd156d0324f80fbf9f6c275d325e..3033ae61d20c80ded2e4101210084e57e825e862 100644 (file)
@@ -36,7 +36,7 @@ pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     debug!("get_virtual_method(vtable_index={}, llvtable={:?})",
            vtable_index, Value(llvtable));
 
-    bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]))
+    bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None)
 }
 
 /// Generate a shim function that allows an object type like `SomeTrait` to
index 027779aca63e4e03f1432873278301674aedebc2..f04f7ab9ed1a2e1cda4910ca08f0d74eb5e6aee4 100644 (file)
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef, BasicBlockRef};
 use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
-use rustc::ty::{self, layout};
+use rustc::ty::{self, layout, TypeFoldable};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
 use adt;
@@ -37,7 +37,7 @@
 use super::{MirContext, LocalRef};
 use super::analyze::CleanupKind;
 use super::constant::Const;
-use super::lvalue::LvalueRef;
+use super::lvalue::{Alignment, LvalueRef};
 use super::operand::OperandRef;
 use super::operand::OperandValue::{Pair, Ref, Immediate};
 
@@ -120,7 +120,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     bcx.cleanup_ret(cleanup_pad, None);
                 } else {
                     let ps = self.get_personality_slot(&bcx);
-                    let lp = bcx.load(ps);
+                    let lp = bcx.load(ps, None);
                     Lifetime::End.call(&bcx, ps);
                     if !bcx.sess().target.target.options.custom_unwind_resume {
                         bcx.resume(lp);
@@ -147,7 +147,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
             mir::TerminatorKind::Switch { ref discr, ref adt_def, ref targets } => {
                 let discr_lvalue = self.trans_lvalue(&bcx, discr);
                 let ty = discr_lvalue.ty.to_ty(bcx.tcx());
-                let discr = adt::trans_get_discr(&bcx, ty, discr_lvalue.llval, None, true);
+                let discr = adt::trans_get_discr(
+                    &bcx, ty, discr_lvalue.llval, discr_lvalue.alignment,
+                    None, true);
 
                 let mut bb_hist = FxHashMap();
                 for target in targets {
@@ -179,7 +181,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
 
             mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
                 let (otherwise, targets) = targets.split_last().unwrap();
-                let discr = bcx.load(self.trans_lvalue(&bcx, discr).llval);
+                let lv = self.trans_lvalue(&bcx, discr);
+                let discr = bcx.load(lv.llval, lv.alignment.to_align());
                 let discr = base::to_immediate(&bcx, discr, switch_ty);
                 let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
                 for (value, target) in values.iter().zip(targets) {
@@ -202,7 +205,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                         LocalRef::Operand(None) => bug!("use of return before def"),
                         LocalRef::Lvalue(tr_lvalue) => {
                             OperandRef {
-                                val: Ref(tr_lvalue.llval),
+                                val: Ref(tr_lvalue.llval, tr_lvalue.alignment),
                                 ty: tr_lvalue.ty.to_ty(bcx.tcx())
                             }
                         }
@@ -210,21 +213,23 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     let llslot = match op.val {
                         Immediate(_) | Pair(..) => {
                             let llscratch = bcx.alloca(ret.original_ty, "ret");
-                            self.store_operand(&bcx, llscratch, op, None);
+                            self.store_operand(&bcx, llscratch, None, op);
                             llscratch
                         }
-                        Ref(llval) => llval
+                        Ref(llval, align) => {
+                            assert_eq!(align, Alignment::AbiAligned,
+                                       "return pointer is unaligned!");
+                            llval
+                        }
                     };
-                    let load = bcx.load(bcx.pointercast(llslot, cast_ty.ptr_to()));
-                    let llalign = llalign_of_min(bcx.ccx, ret.ty);
-                    unsafe {
-                        llvm::LLVMSetAlignment(load, llalign);
-                    }
+                    let load = bcx.load(
+                        bcx.pointercast(llslot, cast_ty.ptr_to()),
+                        Some(llalign_of_min(bcx.ccx, ret.ty)));
                     load
                 } else {
                     let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
-                    if let Ref(llval) = op.val {
-                        base::load_ty(&bcx, llval, op.ty)
+                    if let Ref(llval, align) = op.val {
+                        base::load_ty(&bcx, llval, align, op.ty)
                     } else {
                         op.pack_if_pair(&bcx).immediate()
                     }
@@ -425,17 +430,14 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     // The first argument is a thin destination pointer.
                     let llptr = self.trans_operand(&bcx, &args[0]).immediate();
                     let val = self.trans_operand(&bcx, &args[1]);
-                    self.store_operand(&bcx, llptr, val, None);
+                    self.store_operand(&bcx, llptr, None, val);
                     funclet_br(self, bcx, target);
                     return;
                 }
 
                 if intrinsic == Some("transmute") {
                     let &(ref dest, target) = destination.as_ref().unwrap();
-                    self.with_lvalue_ref(&bcx, dest, |this, dest| {
-                        this.trans_transmute(&bcx, &args[0], dest);
-                    });
-
+                    self.trans_transmute(&bcx, &args[0], dest);
                     funclet_br(self, bcx, target);
                     return;
                 }
@@ -550,7 +552,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                         if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
                             // Make a fake operand for store_return
                             let op = OperandRef {
-                                val: Ref(dst),
+                                val: Ref(dst, Alignment::AbiAligned),
                                 ty: sig.output(),
                             };
                             self.store_return(&bcx, ret_dest, fn_ty.ret, op);
@@ -652,33 +654,39 @@ fn trans_argument(&mut self,
         }
 
         // Force by-ref if we have to load through a cast pointer.
-        let (mut llval, by_ref) = match op.val {
+        let (mut llval, align, by_ref) = match op.val {
             Immediate(_) | Pair(..) => {
                 if arg.is_indirect() || arg.cast.is_some() {
                     let llscratch = bcx.alloca(arg.original_ty, "arg");
-                    self.store_operand(bcx, llscratch, op, None);
-                    (llscratch, true)
+                    self.store_operand(bcx, llscratch, None, op);
+                    (llscratch, Alignment::AbiAligned, true)
                 } else {
-                    (op.pack_if_pair(bcx).immediate(), false)
+                    (op.pack_if_pair(bcx).immediate(), Alignment::AbiAligned, false)
                 }
             }
-            Ref(llval) => (llval, true)
+            Ref(llval, Alignment::Packed) if arg.is_indirect() => {
+                // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I
+                // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
+                // have scary latent bugs around.
+
+                let llscratch = bcx.alloca(arg.original_ty, "arg");
+                base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
+                (llscratch, Alignment::AbiAligned, true)
+            }
+            Ref(llval, align) => (llval, align, true)
         };
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
             if arg.original_ty == Type::i1(bcx.ccx) {
                 // We store bools as i8 so we need to truncate to i1.
-                llval = bcx.load_range_assert(llval, 0, 2, llvm::False);
+                llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
                 llval = bcx.trunc(llval, arg.original_ty);
             } else if let Some(ty) = arg.cast {
-                llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()));
-                let llalign = llalign_of_min(bcx.ccx, arg.ty);
-                unsafe {
-                    llvm::LLVMSetAlignment(llval, llalign);
-                }
+                llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()),
+                                 align.min_with(llalign_of_min(bcx.ccx, arg.ty)));
             } else {
-                llval = bcx.load(llval);
+                llval = bcx.load(llval, align.to_align());
             }
         }
 
@@ -702,16 +710,16 @@ fn trans_arguments_untupled(&mut self,
 
         // Handle both by-ref and immediate tuples.
         match tuple.val {
-            Ref(llval) => {
+            Ref(llval, align) => {
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let ptr = LvalueRef::new_sized_ty(llval, tuple.ty);
-                    let ptr = ptr.trans_field_ptr(bcx, n);
+                    let ptr = LvalueRef::new_sized_ty(llval, tuple.ty, align);
+                    let (ptr, align) = ptr.trans_field_ptr(bcx, n);
                     let val = if common::type_is_fat_ptr(bcx.ccx, ty) {
-                        let (lldata, llextra) = base::load_fat_ptr(bcx, ptr, ty);
+                        let (lldata, llextra) = base::load_fat_ptr(bcx, ptr, align, ty);
                         Pair(lldata, llextra)
                     } else {
                         // trans_argument will load this if it needs to
-                        Ref(ptr)
+                        Ref(ptr, align)
                     };
                     let op = OperandRef {
                         val: val,
@@ -839,15 +847,15 @@ fn make_return_dest(&mut self, bcx: &Builder<'a, 'tcx>,
                     return if fn_ret_ty.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = bcx.alloca_ty(ret_ty, "tmp_ret");
-                        llargs.push(tmp);
-                        ReturnDest::IndirectOperand(tmp, index)
+                        let tmp = LvalueRef::alloca(bcx, ret_ty, "tmp_ret");
+                        llargs.push(tmp.llval);
+                        ReturnDest::IndirectOperand(tmp.llval, index)
                     } else if is_intrinsic {
                         // Currently, intrinsics always need a location to store
                         // the result. so we create a temporary alloca for the
                         // result
-                        let tmp = bcx.alloca_ty(ret_ty, "tmp_ret");
-                        ReturnDest::IndirectOperand(tmp, index)
+                        let tmp = LvalueRef::alloca(bcx, ret_ty, "tmp_ret");
+                        ReturnDest::IndirectOperand(tmp.llval, index)
                     } else {
                         ReturnDest::DirectOperand(index)
                     };
@@ -868,7 +876,34 @@ fn make_return_dest(&mut self, bcx: &Builder<'a, 'tcx>,
     }
 
     fn trans_transmute(&mut self, bcx: &Builder<'a, 'tcx>,
-                       src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) {
+                       src: &mir::Operand<'tcx>,
+                       dst: &mir::Lvalue<'tcx>) {
+        if let mir::Lvalue::Local(index) = *dst {
+            match self.locals[index] {
+                LocalRef::Lvalue(lvalue) => self.trans_transmute_into(bcx, src, &lvalue),
+                LocalRef::Operand(None) => {
+                    let lvalue_ty = self.monomorphized_lvalue_ty(dst);
+                    assert!(!lvalue_ty.has_erasable_regions());
+                    let lvalue = LvalueRef::alloca(bcx, lvalue_ty, "transmute_temp");
+                    self.trans_transmute_into(bcx, src, &lvalue);
+                    let op = self.trans_load(bcx, lvalue.llval, lvalue.alignment, lvalue_ty);
+                    self.locals[index] = LocalRef::Operand(Some(op));
+                }
+                LocalRef::Operand(Some(_)) => {
+                    let ty = self.monomorphized_lvalue_ty(dst);
+                    assert!(common::type_is_zero_size(bcx.ccx, ty),
+                            "assigning to initialized SSAtemp");
+                }
+            }
+        } else {
+            let dst = self.trans_lvalue(bcx, dst);
+            self.trans_transmute_into(bcx, src, &dst);
+        }
+    }
+
+    fn trans_transmute_into(&mut self, bcx: &Builder<'a, 'tcx>,
+                            src: &mir::Operand<'tcx>,
+                            dst: &LvalueRef<'tcx>) {
         let mut val = self.trans_operand(bcx, src);
         if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
             let llouttype = type_of::type_of(bcx.ccx, dst.ty.to_ty(bcx.tcx()));
@@ -892,7 +927,7 @@ fn trans_transmute(&mut self, bcx: &Builder<'a, 'tcx>,
         let in_type = val.ty;
         let out_type = dst.ty.to_ty(bcx.tcx());;
         let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
-        self.store_operand(bcx, cast_ptr, val, Some(llalign));
+        self.store_operand(bcx, cast_ptr, Some(llalign), val);
     }
 
 
@@ -908,15 +943,15 @@ fn store_return(&mut self,
             Nothing => (),
             Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
             IndirectOperand(tmp, index) => {
-                let op = self.trans_load(bcx, tmp, op.ty);
+                let op = self.trans_load(bcx, tmp, Alignment::AbiAligned, op.ty);
                 self.locals[index] = LocalRef::Operand(Some(op));
             }
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if ret_ty.cast.is_some() {
-                    let tmp = bcx.alloca_ty(op.ty, "tmp_ret");
-                    ret_ty.store(bcx, op.immediate(), tmp);
-                    self.trans_load(bcx, tmp, op.ty)
+                    let tmp = LvalueRef::alloca(bcx, op.ty, "tmp_ret");
+                    ret_ty.store(bcx, op.immediate(), tmp.llval);
+                    self.trans_load(bcx, tmp.llval, tmp.alignment, op.ty)
                 } else {
                     op.unpack_if_pair(bcx)
                 };
index f92faaa0508a653ee035e2a6d8f3961273c122a8..11668e792e3f98faa503c0c88f1bc44837d54096 100644 (file)
@@ -40,6 +40,7 @@
 use std::fmt;
 use std::ptr;
 
+use super::lvalue::Alignment;
 use super::operand::{OperandRef, OperandValue};
 use super::MirContext;
 
@@ -140,7 +141,7 @@ pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
             // a constant LLVM global and cast its address if necessary.
             let align = type_of::align_of(ccx, self.ty);
             let ptr = consts::addr_of(ccx, self.llval, align, "const");
-            OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()))
+            OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned)
         };
 
         OperandRef {
index bd6e70639bba540e4396742fdd5187ea5fc0bedf..2538f32031fdb2e9f719bcee93f9c4ac34d6e41e 100644 (file)
 use rustc_data_structures::indexed_vec::Idx;
 use adt;
 use builder::Builder;
-use common::{self, CrateContext, C_uint, C_undef};
+use common::{self, CrateContext, C_uint};
 use consts;
 use machine;
-use type_of::type_of;
 use type_of;
 use type_::Type;
 use value::Value;
 use glue;
 
 use std::ptr;
+use std::ops;
 
 use super::{MirContext, LocalRef};
 use super::operand::OperandValue;
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Alignment {
+    Packed,
+    AbiAligned,
+}
+
+impl ops::BitOr for Alignment {
+    type Output = Self;
+
+    fn bitor(self, rhs: Self) -> Self {
+        match (self, rhs) {
+            (Alignment::Packed, _) => Alignment::Packed,
+            (Alignment::AbiAligned, a) => a,
+        }
+    }
+}
+
+impl Alignment {
+    pub fn from_packed(packed: bool) -> Self {
+        if packed {
+            Alignment::Packed
+        } else {
+            Alignment::AbiAligned
+        }
+    }
+
+    pub fn to_align(self) -> Option<u32> {
+        match self {
+            Alignment::Packed => Some(1),
+            Alignment::AbiAligned => None,
+        }
+    }
+
+    pub fn min_with(self, align: u32) -> Option<u32> {
+        match self {
+            Alignment::Packed => Some(1),
+            Alignment::AbiAligned => Some(align),
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub struct LvalueRef<'tcx> {
     /// Pointer to the contents of the lvalue
@@ -39,25 +80,38 @@ pub struct LvalueRef<'tcx> {
 
     /// Monomorphized type of this lvalue, including variant information
     pub ty: LvalueTy<'tcx>,
+
+    /// Whether this lvalue is known to be aligned according to its layout
+    pub alignment: Alignment,
 }
 
 impl<'a, 'tcx> LvalueRef<'tcx> {
-    pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
-        LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
+    pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>,
+                     alignment: Alignment) -> LvalueRef<'tcx> {
+        LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty, alignment: alignment }
     }
 
-    pub fn new_sized_ty(llval: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
-        LvalueRef::new_sized(llval, LvalueTy::from_ty(ty))
+    pub fn new_sized_ty(llval: ValueRef, ty: Ty<'tcx>, alignment: Alignment) -> LvalueRef<'tcx> {
+        LvalueRef::new_sized(llval, LvalueTy::from_ty(ty), alignment)
     }
 
-    pub fn new_unsized_ty(llval: ValueRef, llextra: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
+    pub fn new_unsized_ty(llval: ValueRef, llextra: ValueRef, ty: Ty<'tcx>, alignment: Alignment)
+                          -> LvalueRef<'tcx> {
         LvalueRef {
             llval: llval,
             llextra: llextra,
             ty: LvalueTy::from_ty(ty),
+            alignment: alignment,
         }
     }
 
+    pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> {
+        debug!("alloca({:?}: {:?})", name, ty);
+        let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name);
+        assert!(!ty.has_param_types());
+        Self::new_sized_ty(tmp, ty, Alignment::AbiAligned)
+    }
+
     pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         let ty = self.ty.to_ty(ccx.tcx());
         match ty.sty {
@@ -81,10 +135,12 @@ fn struct_field_ptr(
         fields: &Vec<Ty<'tcx>>,
         ix: usize,
         needs_cast: bool
-    ) -> ValueRef {
+    ) -> (ValueRef, Alignment) {
         let fty = fields[ix];
         let ccx = bcx.ccx;
 
+        let alignment = self.alignment | Alignment::from_packed(st.packed);
+
         let ptr_val = if needs_cast {
             let fields = st.field_index_by_increasing_offset().map(|i| {
                 type_of::in_memory_type_of(ccx, fields[i])
@@ -101,14 +157,14 @@ fn struct_field_ptr(
         //   * Field is sized - pointer is properly aligned already
         if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
             bcx.ccx.shared().type_is_sized(fty) {
-                return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
+                return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
             }
 
         // If the type of the last field is [T] or str, then we don't need to do
         // any adjusments
         match fty.sty {
             ty::TySlice(..) | ty::TyStr => {
-                return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
+                return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
             }
             _ => ()
         }
@@ -117,7 +173,7 @@ fn struct_field_ptr(
         if !self.has_extra() {
             debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
                 ix, Value(ptr_val));
-            return bcx.struct_gep(ptr_val, ix);
+            return (bcx.struct_gep(ptr_val, ix), alignment);
         }
 
         // We need to get the pointer manually now.
@@ -163,11 +219,11 @@ fn struct_field_ptr(
         // Finally, cast back to the type expected
         let ll_fty = type_of::in_memory_type_of(bcx.ccx, fty);
         debug!("struct_field_ptr: Field type is {:?}", ll_fty);
-        bcx.pointercast(byte_ptr, ll_fty.ptr_to())
+        (bcx.pointercast(byte_ptr, ll_fty.ptr_to()), alignment)
     }
 
     /// Access a field, at a point when the value's case is known.
-    pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> ValueRef {
+    pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> (ValueRef, Alignment) {
         let discr = match self.ty {
             LvalueTy::Ty { .. } => 0,
             LvalueTy::Downcast { variant_index, .. } => variant_index,
@@ -186,17 +242,18 @@ pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> ValueRef {
             layout::Vector { count, .. } => {
                 assert_eq!(discr, 0);
                 assert!((ix as u64) < count);
-                bcx.struct_gep(self.llval, ix)
+                (bcx.struct_gep(self.llval, ix), self.alignment)
             }
             layout::General { discr: d, ref variants, .. } => {
                 let mut fields = adt::compute_fields(bcx.ccx, t, discr, false);
                 fields.insert(0, d.to_ty(&bcx.tcx(), false));
                 self.struct_field_ptr(bcx, &variants[discr], &fields, ix + 1, true)
             }
-            layout::UntaggedUnion { .. } => {
+            layout::UntaggedUnion { ref variants } => {
                 let fields = adt::compute_fields(bcx.ccx, t, 0, false);
                 let ty = type_of::in_memory_type_of(bcx.ccx, fields[ix]);
-                bcx.pointercast(self.llval, ty.ptr_to())
+                (bcx.pointercast(self.llval, ty.ptr_to()),
+                 self.alignment | Alignment::from_packed(variants.packed))
             }
             layout::RawNullablePointer { nndiscr, .. } |
             layout::StructWrappedNullablePointer { nndiscr,  .. } if discr as u64 != nndiscr => {
@@ -205,19 +262,19 @@ pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> ValueRef {
                 // (e.d., Result of Either with (), as one side.)
                 let ty = type_of::type_of(bcx.ccx, nullfields[ix]);
                 assert_eq!(machine::llsize_of_alloc(bcx.ccx, ty), 0);
-                bcx.pointercast(self.llval, ty.ptr_to())
+                (bcx.pointercast(self.llval, ty.ptr_to()), Alignment::Packed)
             }
             layout::RawNullablePointer { nndiscr, .. } => {
                 let nnty = adt::compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
                 assert_eq!(ix, 0);
                 assert_eq!(discr as u64, nndiscr);
                 let ty = type_of::type_of(bcx.ccx, nnty);
-                bcx.pointercast(self.llval, ty.ptr_to())
+                (bcx.pointercast(self.llval, ty.ptr_to()), self.alignment)
             }
             layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
                 assert_eq!(discr as u64, nndiscr);
                 self.struct_field_ptr(bcx, &nonnull,
-                    &adt::compute_fields(bcx.ccx, t, discr, false), ix, false)
+                     &adt::compute_fields(bcx.ccx, t, discr, false), ix, false)
             }
             _ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
         }
@@ -250,7 +307,8 @@ pub fn trans_lvalue(&mut self,
             mir::Lvalue::Static(def_id) => {
                 let const_ty = self.monomorphized_lvalue_ty(lvalue);
                 LvalueRef::new_sized(consts::get_static(ccx, def_id),
-                                     LvalueTy::from_ty(const_ty))
+                                     LvalueTy::from_ty(const_ty),
+                                     Alignment::AbiAligned)
             },
             mir::Lvalue::Projection(box mir::Projection {
                 ref base,
@@ -264,18 +322,20 @@ pub fn trans_lvalue(&mut self,
                 let (llptr, llextra) = match ptr.val {
                     OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
                     OperandValue::Pair(llptr, llextra) => (llptr, llextra),
-                    OperandValue::Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
+                    OperandValue::Ref(..) => bug!("Deref of by-Ref type {:?}", ptr.ty)
                 };
                 LvalueRef {
                     llval: llptr,
                     llextra: llextra,
                     ty: projected_ty,
+                    alignment: Alignment::AbiAligned,
                 }
             }
             mir::Lvalue::Projection(ref projection) => {
                 let tr_base = self.trans_lvalue(bcx, &projection.base);
                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
                 let projected_ty = self.monomorphize(&projected_ty);
+                let align = tr_base.alignment;
 
                 let project_index = |llindex| {
                     let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty {
@@ -285,10 +345,10 @@ pub fn trans_lvalue(&mut self,
                         let zero = common::C_uint(bcx.ccx, 0u64);
                         bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
                     };
-                    element
+                    (element, align)
                 };
 
-                let (llprojected, llextra) = match projection.elem {
+                let ((llprojected, align), llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
                         let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) {
@@ -318,7 +378,7 @@ pub fn trans_lvalue(&mut self,
                     }
                     mir::ProjectionElem::Subslice { from, to } => {
                         let llindex = C_uint(bcx.ccx, from);
-                        let llbase = project_index(llindex);
+                        let (llbase, align) = project_index(llindex);
 
                         let base_ty = tr_base.ty.to_ty(bcx.tcx());
                         match base_ty.sty {
@@ -328,25 +388,26 @@ pub fn trans_lvalue(&mut self,
                                 let base_ty = self.monomorphized_lvalue_ty(lvalue);
                                 let llbasety = type_of::type_of(bcx.ccx, base_ty).ptr_to();
                                 let llbase = bcx.pointercast(llbase, llbasety);
-                                (llbase, ptr::null_mut())
+                                ((llbase, align), ptr::null_mut())
                             }
                             ty::TySlice(..) => {
                                 assert!(tr_base.llextra != ptr::null_mut());
                                 let lllen = bcx.sub(tr_base.llextra,
                                                     C_uint(bcx.ccx, from+to));
-                                (llbase, lllen)
+                                ((llbase, align), lllen)
                             }
                             _ => bug!("unexpected type {:?} in Subslice", base_ty)
                         }
                     }
                     mir::ProjectionElem::Downcast(..) => {
-                        (tr_base.llval, tr_base.llextra)
+                        ((tr_base.llval, align), tr_base.llextra)
                     }
                 };
                 LvalueRef {
                     llval: llprojected,
                     llextra: llextra,
                     ty: projected_ty,
+                    alignment: align,
                 }
             }
         };
@@ -354,45 +415,6 @@ pub fn trans_lvalue(&mut self,
         result
     }
 
-    // Perform an action using the given Lvalue.
-    // If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
-    // is created first, then used as an operand to update the Lvalue.
-    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &Builder<'a, 'tcx>,
-                                 lvalue: &mir::Lvalue<'tcx>, f: F) -> U
-    where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
-    {
-        if let mir::Lvalue::Local(index) = *lvalue {
-            match self.locals[index] {
-                LocalRef::Lvalue(lvalue) => f(self, lvalue),
-                LocalRef::Operand(None) => {
-                    let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
-                    assert!(!lvalue_ty.has_erasable_regions());
-                    let lltemp = bcx.alloca_ty(lvalue_ty, "lvalue_temp");
-                    let lvalue = LvalueRef::new_sized(lltemp, LvalueTy::from_ty(lvalue_ty));
-                    let ret = f(self, lvalue);
-                    let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
-                    self.locals[index] = LocalRef::Operand(Some(op));
-                    ret
-                }
-                LocalRef::Operand(Some(_)) => {
-                    // See comments in LocalRef::new_operand as to why
-                    // we always have Some in a ZST LocalRef::Operand.
-                    let ty = self.monomorphized_lvalue_ty(lvalue);
-                    if common::type_is_zero_size(bcx.ccx, ty) {
-                        // Pass an undef pointer as no stores can actually occur.
-                        let llptr = C_undef(type_of(bcx.ccx, ty).ptr_to());
-                        f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
-                    } else {
-                        bug!("Lvalue local already set");
-                    }
-                }
-            }
-        } else {
-            let lvalue = self.trans_lvalue(bcx, lvalue);
-            f(self, lvalue)
-        }
-    }
-
     /// Adjust the bitwidth of an index since LLVM is less forgiving
     /// than we are.
     ///
index 8a0a97a56343955c8fd258b09097da0b76912171..e017c8f2532e4a98591f8d74c6248a0461e6361f 100644 (file)
@@ -38,7 +38,7 @@
 pub use self::constant::trans_static_initializer;
 
 use self::analyze::CleanupKind;
-use self::lvalue::LvalueRef;
+use self::lvalue::{Alignment, LvalueRef};
 use rustc::mir::traversal;
 
 use self::operand::{OperandRef, OperandValue};
@@ -269,8 +269,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
 
                 debug!("alloc: {:?} ({}) -> lvalue", local, name);
                 assert!(!ty.has_erasable_regions());
-                let lltemp = bcx.alloca_ty(ty, &name.as_str());
-                let lvalue = LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty));
+                let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
                 if dbg {
                     let (scope, span) = mircx.debug_loc(source_info);
                     declare_local(&bcx, &mircx.debug_context, name, ty, scope,
@@ -283,12 +282,12 @@ pub fn trans_mir<'a, 'tcx: 'a>(
                 if local == mir::RETURN_POINTER && mircx.fn_ty.ret.is_indirect() {
                     debug!("alloc: {:?} (return pointer) -> lvalue", local);
                     let llretptr = llvm::get_param(llfn, 0);
-                    LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
+                    LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty),
+                                                          Alignment::AbiAligned))
                 } else if lvalue_locals.contains(local.index()) {
                     debug!("alloc: {:?} -> lvalue", local);
                     assert!(!ty.has_erasable_regions());
-                    let lltemp = bcx.alloca_ty(ty, &format!("{:?}", local));
-                    LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty)))
+                    LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty,  &format!("{:?}", local)))
                 } else {
                     // If this is an immediate local, we do not create an
                     // alloca in advance. Instead we wait until we see the
@@ -388,9 +387,9 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let lltemp = bcx.alloca_ty(arg_ty, &format!("arg{}", arg_index));
+            let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index));
             for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
-                let dst = bcx.struct_gep(lltemp, i);
+                let dst = bcx.struct_gep(lvalue.llval, i);
                 let arg = &mircx.fn_ty.args[idx];
                 idx += 1;
                 if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
@@ -409,7 +408,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             // we can create one debuginfo entry for the argument.
             arg_scope.map(|scope| {
                 let variable_access = VariableAccess::DirectVariable {
-                    alloca: lltemp
+                    alloca: lvalue.llval
                 };
                 declare_local(
                     bcx,
@@ -422,7 +421,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 );
             });
 
-            return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
+            return LocalRef::Lvalue(lvalue);
         }
 
         let arg = &mircx.fn_ty.args[idx];
@@ -469,21 +468,21 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             };
             return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
         } else {
-            let lltemp = bcx.alloca_ty(arg_ty, &format!("arg{}", arg_index));
+            let lltemp = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index));
             if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
                 // we pass fat pointers as two words, but we want to
                 // represent them internally as a pointer to two words,
                 // so make an alloca to store them in.
                 let meta = &mircx.fn_ty.args[idx];
                 idx += 1;
-                arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, lltemp));
-                meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, lltemp));
+                arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, lltemp.llval));
+                meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, lltemp.llval));
             } else  {
                 // otherwise, arg is passed by value, so make a
                 // temporary and store it there
-                arg.store_fn_arg(bcx, &mut llarg_idx, lltemp);
+                arg.store_fn_arg(bcx, &mut llarg_idx, lltemp.llval);
             }
-            lltemp
+            lltemp.llval
         };
         arg_scope.map(|scope| {
             // Is this a regular argument?
@@ -573,7 +572,8 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 );
             }
         });
-        LocalRef::Lvalue(LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty)))
+        LocalRef::Lvalue(LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty),
+                                              Alignment::AbiAligned))
     }).collect()
 }
 
index 28a247ee612a9078b6ba32322613439e40abb8b4..cb77fcbbff85dbea7f015394b73f77cc494d202f 100644 (file)
@@ -10,6 +10,7 @@
 
 use llvm::ValueRef;
 use rustc::ty::Ty;
+use rustc::ty::layout::Layout;
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -23,6 +24,7 @@
 use std::fmt;
 
 use super::{MirContext, LocalRef};
+use super::lvalue::Alignment;
 
 /// The representation of a Rust value. The enum variant is in fact
 /// uniquely determined by the value's type, but is kept as a
@@ -31,7 +33,7 @@
 pub enum OperandValue {
     /// A reference to the actual operand. The data is guaranteed
     /// to be valid for the operand's lifetime.
-    Ref(ValueRef),
+    Ref(ValueRef, Alignment),
     /// A single LLVM value.
     Immediate(ValueRef),
     /// A pair of immediate LLVM values. Used by fat pointers too.
@@ -58,9 +60,9 @@ pub struct OperandRef<'tcx> {
 impl<'tcx> fmt::Debug for OperandRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.val {
-            OperandValue::Ref(r) => {
-                write!(f, "OperandRef(Ref({:?}) @ {:?})",
-                       Value(r), self.ty)
+            OperandValue::Ref(r, align) => {
+                write!(f, "OperandRef(Ref({:?}, {:?}) @ {:?})",
+                       Value(r), align, self.ty)
             }
             OperandValue::Immediate(i) => {
                 write!(f, "OperandRef(Immediate({:?}) @ {:?})",
@@ -137,27 +139,33 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_load(&mut self,
                       bcx: &Builder<'a, 'tcx>,
                       llval: ValueRef,
+                      align: Alignment,
                       ty: Ty<'tcx>)
                       -> OperandRef<'tcx>
     {
         debug!("trans_load: {:?} @ {:?}", Value(llval), ty);
 
         let val = if common::type_is_fat_ptr(bcx.ccx, ty) {
-            let (lldata, llextra) = base::load_fat_ptr(bcx, llval, ty);
+            let (lldata, llextra) = base::load_fat_ptr(bcx, llval, align, ty);
             OperandValue::Pair(lldata, llextra)
         } else if common::type_is_imm_pair(bcx.ccx, ty) {
+            let f_align = match *bcx.ccx.layout_of(ty) {
+                Layout::Univariant { ref variant, .. } =>
+                    Alignment::from_packed(variant.packed) | align,
+                _ => align
+            };
             let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap();
             let a_ptr = bcx.struct_gep(llval, 0);
             let b_ptr = bcx.struct_gep(llval, 1);
 
             OperandValue::Pair(
-                base::load_ty(bcx, a_ptr, a_ty),
-                base::load_ty(bcx, b_ptr, b_ty)
+                base::load_ty(bcx, a_ptr, f_align, a_ty),
+                base::load_ty(bcx, b_ptr, f_align, b_ty)
             )
         } else if common::type_is_immediate(bcx.ccx, ty) {
-            OperandValue::Immediate(base::load_ty(bcx, llval, ty))
+            OperandValue::Immediate(base::load_ty(bcx, llval, align, ty))
         } else {
-            OperandValue::Ref(llval)
+            OperandValue::Ref(llval, align)
         };
 
         OperandRef { val: val, ty: ty }
@@ -212,7 +220,7 @@ pub fn trans_consume(&mut self,
         // out from their home
         let tr_lvalue = self.trans_lvalue(bcx, lvalue);
         let ty = tr_lvalue.ty.to_ty(bcx.tcx());
-        self.trans_load(bcx, tr_lvalue.llval, ty)
+        self.trans_load(bcx, tr_lvalue.llval, tr_lvalue.alignment, ty)
     }
 
     pub fn trans_operand(&mut self,
@@ -230,9 +238,9 @@ pub fn trans_operand(&mut self,
             mir::Operand::Constant(ref constant) => {
                 let val = self.trans_constant(bcx, constant);
                 let operand = val.to_operand(bcx.ccx);
-                if let OperandValue::Ref(ptr) = operand.val {
+                if let OperandValue::Ref(ptr, align) = operand.val {
                     // If this is a OperandValue::Ref to an immediate constant, load it.
-                    self.trans_load(bcx, ptr, operand.ty)
+                    self.trans_load(bcx, ptr, align, operand.ty)
                 } else {
                     operand
                 }
@@ -243,8 +251,8 @@ pub fn trans_operand(&mut self,
     pub fn store_operand(&mut self,
                          bcx: &Builder<'a, 'tcx>,
                          lldest: ValueRef,
-                         operand: OperandRef<'tcx>,
-                         align: Option<u32>) {
+                         align: Option<u32>,
+                         operand: OperandRef<'tcx>) {
         debug!("store_operand: operand={:?}, align={:?}", operand, align);
         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
         // value is through `undef`, and store itself is useless.
@@ -252,7 +260,10 @@ pub fn store_operand(&mut self,
             return;
         }
         match operand.val {
-            OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty, align),
+            OperandValue::Ref(r, Alignment::Packed) =>
+                base::memcpy_ty(bcx, lldest, r, operand.ty, Some(1)),
+            OperandValue::Ref(r, Alignment::AbiAligned) =>
+                base::memcpy_ty(bcx, lldest, r, operand.ty, align),
             OperandValue::Immediate(s) => {
                 bcx.store(base::from_immediate(bcx, s), lldest, align);
             }
index 81b241b4851756a2441c572254900f3a1331afd3..0a8e676b07812f41f475c11f35263f48d1f7d7ff 100644 (file)
@@ -33,7 +33,7 @@
 use super::MirContext;
 use super::constant::const_scalar_checked_binop;
 use super::operand::{OperandRef, OperandValue};
-use super::lvalue::{LvalueRef};
+use super::lvalue::LvalueRef;
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_rvalue(&mut self,
@@ -50,7 +50,7 @@ pub fn trans_rvalue(&mut self,
                let tr_operand = self.trans_operand(&bcx, operand);
                // FIXME: consider not copying constants through stack. (fixable by translating
                // constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
-               self.store_operand(&bcx, dest.llval, tr_operand, None);
+               self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), tr_operand);
                bcx
            }
 
@@ -61,7 +61,7 @@ pub fn trans_rvalue(&mut self,
                     // into-coerce of a thin pointer to a fat pointer - just
                     // use the operand path.
                     let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
-                    self.store_operand(&bcx, dest.llval, temp, None);
+                    self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp);
                     return bcx;
                 }
 
@@ -81,13 +81,15 @@ pub fn trans_rvalue(&mut self,
                         // index into the struct, and this case isn't
                         // important enough for it.
                         debug!("trans_rvalue: creating ugly alloca");
-                        let lltemp = bcx.alloca_ty(operand.ty, "__unsize_temp");
-                        base::store_ty(&bcx, llval, lltemp, operand.ty);
-                        lltemp
+                        let scratch = LvalueRef::alloca(&bcx, operand.ty, "__unsize_temp");
+                        base::store_ty(&bcx, llval, scratch.llval, scratch.alignment, operand.ty);
+                        scratch
+                    }
+                    OperandValue::Ref(llref, align) => {
+                        LvalueRef::new_sized_ty(llref, operand.ty, align)
                     }
-                    OperandValue::Ref(llref) => llref
                 };
-                base::coerce_unsized_into(&bcx, llref, operand.ty, dest.llval, cast_ty);
+                base::coerce_unsized_into(&bcx, &llref, &dest);
                 bcx
             }
 
@@ -97,7 +99,7 @@ pub fn trans_rvalue(&mut self,
                 let size = C_uint(bcx.ccx, size);
                 let base = base::get_dataptr(&bcx, dest.llval);
                 tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| {
-                    self.store_operand(bcx, llslot, tr_elem, None);
+                    self.store_operand(bcx, llslot, dest.alignment.to_align(), tr_elem);
                 })
             }
 
@@ -111,15 +113,16 @@ pub fn trans_rvalue(&mut self,
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
                             if !common::type_is_zero_size(bcx.ccx, op.ty) {
-                                let mut val = LvalueRef::new_sized(dest.llval, dest.ty);
+                                let mut val = LvalueRef::new_sized(
+                                    dest.llval, dest.ty, dest.alignment);
                                 let field_index = active_field_index.unwrap_or(i);
                                 val.ty = LvalueTy::Downcast {
                                     adt_def: adt_def,
                                     substs: self.monomorphize(&substs),
                                     variant_index: disr.0 as usize,
                                 };
-                                let lldest_i = val.trans_field_ptr(&bcx, field_index);
-                                self.store_operand(&bcx, lldest_i, op, None);
+                                let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index);
+                                self.store_operand(&bcx, lldest_i, align.to_align(), op);
                             }
                         }
                     },
@@ -131,6 +134,7 @@ pub fn trans_rvalue(&mut self,
                         } else {
                             None
                         };
+                        let alignment = dest.alignment;
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
@@ -144,7 +148,7 @@ pub fn trans_rvalue(&mut self,
                                     i
                                 };
                                 let dest = bcx.gepi(dest.llval, &[0, i]);
-                                self.store_operand(&bcx, dest, op, None);
+                                self.store_operand(&bcx, dest, alignment.to_align(), op);
                             }
                         }
                     }
@@ -169,7 +173,7 @@ pub fn trans_rvalue(&mut self,
             _ => {
                 assert!(rvalue_creates_operand(rvalue));
                 let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
-                self.store_operand(&bcx, dest.llval, temp, None);
+                self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp);
                 bcx
             }
         }
@@ -228,7 +232,7 @@ pub fn trans_rvalue_operand(&mut self,
                                     operand.ty, cast_ty);
                                 OperandValue::Pair(lldata, llextra)
                             }
-                            OperandValue::Ref(_) => {
+                            OperandValue::Ref(..) => {
                                 bug!("by-ref operand {:?} in trans_rvalue_operand",
                                      operand);
                             }
diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml
new file mode 100644 (file)
index 0000000..66d6236
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+authors = ["The Rust Project Developers"]
+build = "build.rs"
+name = "rustc_tsan"
+version = "0.0.0"
+
+[lib]
+name = "rustc_tsan"
+path = "lib.rs"
+
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+cmake = "0.1.18"
+
+[dependencies]
+alloc_system = { path = "../liballoc_system" }
+core = { path = "../libcore" }
diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs
new file mode 100644 (file)
index 0000000..84326ae
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.
+
+extern crate build_helper;
+extern crate cmake;
+
+use std::path::PathBuf;
+use std::env;
+
+use cmake::Config;
+
+fn main() {
+    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
+        let dst = Config::new("../compiler-rt")
+            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
+            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
+            .define("COMPILER_RT_BUILD_XRAY", "OFF")
+            .define("LLVM_CONFIG_PATH", llvm_config)
+            .build_target("tsan")
+            .build();
+
+        println!("cargo:rustc-link-search=native={}",
+                 dst.join("build/lib/linux").display());
+        println!("cargo:rustc-link-lib=static=clang_rt.tsan-x86_64");
+
+        build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR")
+                .unwrap())
+            .join("../compiler-rt"));
+    }
+
+    println!("cargo:rerun-if-changed=build.rs");
+}
diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs
new file mode 100644 (file)
index 0000000..71a166b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+#![cfg_attr(not(stage0), feature(sanitizer_runtime))]
+#![cfg_attr(not(stage0), sanitizer_runtime)]
+#![feature(alloc_system)]
+#![feature(staged_api)]
+#![no_std]
+#![unstable(feature = "sanitizer_runtime_lib",
+            reason = "internal implementation detail of sanitizers",
+            issue = "0")]
+
+extern crate alloc_system;
index 60dae19d876c98a765d9b9e1cfa6a5d94f8c2af4..c591c09bf20e2701b221f806ad659249bf899d3b 100644 (file)
@@ -671,9 +671,11 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                 }
                 _ => {
                     if f.alternate() {
-                        write!(f, "&{}{}{:#}", lt, m, **ty)
+                        write!(f, "&{}{}", lt, m)?;
+                        fmt_type(&ty, f, use_absolute)
                     } else {
-                        write!(f, "&amp;{}{}{}", lt, m, **ty)
+                        write!(f, "&amp;{}{}", lt, m)?;
+                        fmt_type(&ty, f, use_absolute)
                     }
                 }
             }
index a0f4a3a87434845c7f464723bea9f47f4842c985..c7c5aabab97ae8002ce57b674d6623068c5090dd 100644 (file)
@@ -35,6 +35,7 @@
 use std::slice;
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
+use syntax::codemap::Span;
 
 use html::render::derive_id;
 use html::toc::TocBuilder;
@@ -424,7 +425,7 @@ fn dont_escape(c: u8) -> bool {
     }
 }
 
-pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: usize) {
+pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
     extern fn block(_ob: *mut hoedown_buffer,
                     text: *const hoedown_buffer,
                     lang: *const hoedown_buffer,
@@ -449,11 +450,12 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line:
             });
             let text = lines.collect::<Vec<&str>>().join("\n");
             let line = tests.get_line() + line;
+            let filename = tests.get_filename();
             tests.add_test(text.to_owned(),
                            block_info.should_panic, block_info.no_run,
                            block_info.ignore, block_info.test_harness,
                            block_info.compile_fail, block_info.error_codes,
-                           line);
+                           line, filename);
         }
     }
 
@@ -474,7 +476,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line:
         }
     }
 
-    tests.set_line(start_line);
+    tests.set_position(position);
     unsafe {
         let ob = hoedown_buffer_new(DEF_OUNIT);
         let renderer = hoedown_html_renderer_new(0, 0);
index 40eb7e5ab78c3df024e83346641c41979913fc76..6234d89024441b946e3d3aba0ba0503b6d9d2385 100644 (file)
@@ -2132,10 +2132,23 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
         <ul class='item-list' id='implementors-list'>
     ")?;
     if let Some(implementors) = cache.implementors.get(&it.def_id) {
-        let mut implementor_count: FxHashMap<&str, usize> = FxHashMap();
+        // The DefId is for the first Type found with that name. The bool is
+        // if any Types with the same name but different DefId have been found.
+        let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap();
         for implementor in implementors {
-            if let clean::Type::ResolvedPath {ref path, ..} = implementor.impl_.for_ {
-                *implementor_count.entry(path.last_name()).or_insert(0) += 1;
+            match implementor.impl_.for_ {
+                clean::ResolvedPath { ref path, did, is_generic: false, .. } |
+                clean::BorrowedRef {
+                    type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. },
+                    ..
+                } => {
+                    let &mut (prev_did, ref mut has_duplicates) =
+                        implementor_dups.entry(path.last_name()).or_insert((did, false));
+                    if prev_did != did {
+                        *has_duplicates = true;
+                    }
+                }
+                _ => {}
             }
         }
 
@@ -2143,12 +2156,13 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
             write!(w, "<li><code>")?;
             // If there's already another implementor that has the same abbridged name, use the
             // full path, for example in `std::iter::ExactSizeIterator`
-            let use_absolute = if let clean::Type::ResolvedPath {
-                ref path, ..
-            } = implementor.impl_.for_ {
-                implementor_count[path.last_name()] > 1
-            } else {
-                false
+            let use_absolute = match implementor.impl_.for_ {
+                clean::ResolvedPath { ref path, is_generic: false, .. } |
+                clean::BorrowedRef {
+                    type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
+                    ..
+                } => implementor_dups[path.last_name()].1,
+                _ => false,
             };
             fmt_impl_for_trait_page(&implementor.impl_, w, use_absolute)?;
             writeln!(w, "</code></li>")?;
index 49497957be980734fe03a7e29713a4022b4dd319..70ef7c597e4d7ba55f3c81a5f46e477f3db2ea35 100644 (file)
@@ -18,6 +18,7 @@
 use testing;
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::Externs;
+use syntax::codemap::DUMMY_SP;
 
 use externalfiles::{ExternalHtml, LoadStringError, load_string};
 
@@ -154,9 +155,8 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     let mut opts = TestOptions::default();
     opts.no_crate_inject = true;
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
-                                       true, opts, maybe_sysroot, "input".to_string(),
-                                       None);
-    find_testable_code(&input_str, &mut collector, 0);
+                                       true, opts, maybe_sysroot, None);
+    find_testable_code(&input_str, &mut collector, DUMMY_SP);
     test_args.insert(0, "rustdoctest".to_string());
     testing::test_main(&test_args, collector.tests);
     0
index 6f38da4f24b0d5a2196fa96d19c8a6883e1b04d9..930cf401e74501b202a0f49b404c07301b34cf7e 100644 (file)
@@ -37,7 +37,7 @@
 use syntax::ast;
 use syntax::codemap::CodeMap;
 use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::{BytePos, DUMMY_SP, Pos};
+use syntax_pos::{BytePos, DUMMY_SP, Pos, Span};
 use errors;
 use errors::emitter::ColorConfig;
 
@@ -97,7 +97,6 @@ pub fn run(input: &str,
         link::find_crate_name(None, &hir_forest.krate().attrs, &input)
     });
     let opts = scrape_test_config(hir_forest.krate());
-    let filename = input_path.to_str().unwrap_or("").to_owned();
     let mut collector = Collector::new(crate_name,
                                        cfgs,
                                        libs,
@@ -105,7 +104,6 @@ pub fn run(input: &str,
                                        false,
                                        opts,
                                        maybe_sysroot,
-                                       filename,
                                        Some(codemap));
 
     {
@@ -391,15 +389,14 @@ pub struct Collector {
     cratename: String,
     opts: TestOptions,
     maybe_sysroot: Option<PathBuf>,
-    filename: String,
-    start_line: usize,
+    position: Span,
     codemap: Option<Rc<CodeMap>>,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
                use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
-               filename: String, codemap: Option<Rc<CodeMap>>) -> Collector {
+               codemap: Option<Rc<CodeMap>>) -> Collector {
         Collector {
             tests: Vec::new(),
             names: Vec::new(),
@@ -412,8 +409,7 @@ pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Ext
             cratename: cratename,
             opts: opts,
             maybe_sysroot: maybe_sysroot,
-            filename: filename,
-            start_line: 0,
+            position: DUMMY_SP,
             codemap: codemap,
         }
     }
@@ -421,8 +417,8 @@ pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Ext
     pub fn add_test(&mut self, test: String,
                     should_panic: bool, no_run: bool, should_ignore: bool,
                     as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
-                    line: usize) {
-        let name = format!("{} - line {}", self.filename, line);
+                    line: usize, filename: String) {
+        let name = format!("{} - line {}", filename, line);
         self.cnt += 1;
         let cfgs = self.cfgs.clone();
         let libs = self.libs.clone();
@@ -467,16 +463,25 @@ pub fn add_test(&mut self, test: String,
     }
 
     pub fn get_line(&self) -> usize {
-        if let Some(ref codemap) = self.codemap{
-            let line = codemap.lookup_char_pos(BytePos(self.start_line as u32)).line;
+        if let Some(ref codemap) = self.codemap {
+            let line = self.position.lo.to_usize();
+            let line = codemap.lookup_char_pos(BytePos(line as u32)).line;
             if line > 0 { line - 1 } else { line }
         } else {
-            self.start_line
+            0
         }
     }
 
-    pub fn set_line(&mut self, start_line: usize) {
-        self.start_line = start_line;
+    pub fn set_position(&mut self, position: Span) {
+        self.position = position;
+    }
+
+    pub fn get_filename(&self) -> String {
+        if let Some(ref codemap) = self.codemap {
+            codemap.span_to_filename(self.position)
+        } else {
+            "<input>".to_owned()
+        }
     }
 
     pub fn register_header(&mut self, name: &str, level: u32) {
@@ -520,7 +525,7 @@ fn visit_testable<F: FnOnce(&mut Self)>(&mut self,
         if let Some(doc) = attrs.doc_value() {
             self.collector.cnt = 0;
             markdown::find_testable_code(doc, self.collector,
-                                         attrs.span.unwrap_or(DUMMY_SP).lo.to_usize());
+                                         attrs.span.unwrap_or(DUMMY_SP));
         }
 
         nested(self);
index 8146e7fb1edaf4a5b0a413d781a06dbd7d7b943b..2ba7517d3d2023761a0cc24838d184fe2c95d2f4 100644 (file)
@@ -23,13 +23,23 @@ compiler_builtins = { path = "../libcompiler_builtins" }
 std_unicode = { path = "../libstd_unicode" }
 unwind = { path = "../libunwind" }
 
+[target.x86_64-unknown-linux-gnu.dependencies]
+rustc_asan = { path = "../librustc_asan", optional = true }
+rustc_lsan = { path = "../librustc_lsan", optional = true }
+rustc_msan = { path = "../librustc_msan", optional = true }
+rustc_tsan = { path = "../librustc_tsan", optional = true }
+
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 gcc = "0.3.27"
 
 [features]
+asan = ["rustc_asan"]
 backtrace = []
 debug-jemalloc = ["alloc_jemalloc/debug"]
 jemalloc = ["alloc_jemalloc"]
 force_alloc_system = []
+lsan = ["rustc_lsan"]
+msan = ["rustc_msan"]
 panic-unwind = ["panic_unwind"]
+tsan = ["rustc_tsan"]
index e26415392949175499c870fd6d2143c7e91b2415..1ef2cb4ed153c2e5d4e78eba2531e86031ecc29d 100644 (file)
@@ -400,15 +400,19 @@ pub struct JoinPathsError {
     inner: os_imp::JoinPathsError
 }
 
-/// Joins a collection of `Path`s appropriately for the `PATH`
+/// Joins a collection of [`Path`]s appropriately for the `PATH`
 /// environment variable.
 ///
-/// Returns an `OsString` on success.
+/// Returns an [`OsString`] on success.
 ///
-/// Returns an `Err` (containing an error message) if one of the input
-/// `Path`s contains an invalid character for constructing the `PATH`
+/// Returns an [`Err`][err] (containing an error message) if one of the input
+/// [`Path`]s contains an invalid character for constructing the `PATH`
 /// variable (a double quote on Windows or a colon on Unix).
 ///
+/// [`Path`]: ../../std/path/struct.Path.html
+/// [`OsString`]: ../../std/ffi/struct.OsString.html
+/// [err]: ../../std/result/enum.Result.html#variant.Err
+///
 /// # Examples
 ///
 /// ```
index c16b97ebda5e3c2bd4a1d4a4ca055c6101077c50..4ff35738b50fbd085657154c517563fbab6e991c 100644 (file)
@@ -844,9 +844,9 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// guaranteed to repeatedly return a successful exit status so long as the
     /// child has already exited.
     ///
-    /// If the child has exited, then `Ok(status)` is returned. If the exit
-    /// status is not available at this time then an error is returned with the
-    /// error kind `WouldBlock`. If an error occurs, then that error is returned.
+    /// If the child has exited, then `Ok(Some(status))` is returned. If the
+    /// exit status is not available at this time then `Ok(None)` is returned.
+    /// If an error occurs, then that error is returned.
     ///
     /// Note that unlike `wait`, this function will not attempt to drop stdin.
     ///
@@ -857,14 +857,13 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// ```no_run
     /// #![feature(process_try_wait)]
     ///
-    /// use std::io;
     /// use std::process::Command;
     ///
     /// let mut child = Command::new("ls").spawn().unwrap();
     ///
     /// match child.try_wait() {
-    ///     Ok(status) => println!("exited with: {}", status),
-    ///     Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+    ///     Ok(Some(status)) => println!("exited with: {}", status),
+    ///     Ok(None) => {
     ///         println!("status not ready yet, let's really wait");
     ///         let res = child.wait();
     ///         println!("result: {:?}", res);
@@ -873,8 +872,8 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// }
     /// ```
     #[unstable(feature = "process_try_wait", issue = "38903")]
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
-        self.handle.try_wait().map(ExitStatus)
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        Ok(self.handle.try_wait()?.map(ExitStatus))
     }
 
     /// Simultaneously waits for the child to exit and collect all remaining
index 50dcd44b42e92d3836267ff050e00278042c5912..60dc03fcf47e2aa7b5f0fed92d54aa493cc2d4e5 100644 (file)
@@ -502,17 +502,17 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus(status as i32))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         if let Some(status) = self.status {
-            return Ok(status)
+            return Ok(Some(status))
         }
         let mut status = 0;
         let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
         if pid == 0 {
-            Err(io::Error::from_raw_os_error(syscall::EWOULDBLOCK))
+            Ok(None)
         } else {
             self.status = Some(ExitStatus(status as i32));
-            Ok(ExitStatus(status as i32))
+            Ok(Some(ExitStatus(status as i32)))
         }
     }
 }
index 87acb0ed9b977e4fe1dc9c7da72e27e0e8d1b2d7..0bb2e0c1a83d4469a534469b83ef8c363a08d901 100644 (file)
@@ -165,7 +165,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus::new(proc_info.rec.return_code))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         use default::Default;
         use sys::process::magenta::*;
 
@@ -179,7 +179,7 @@ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
             match status {
                 0 => { }, // Success
                 x if x == ERR_TIMED_OUT => {
-                    return Err(io::Error::from(io::ErrorKind::WouldBlock));
+                    return Ok(None);
                 },
                 _ => { panic!("Failed to wait on process handle: {}", status); },
             }
@@ -192,7 +192,7 @@ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
             return Err(io::Error::new(io::ErrorKind::InvalidData,
                                       "Failed to get exit status of process"));
         }
-        Ok(ExitStatus::new(proc_info.rec.return_code))
+        Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
     }
 }
 
index 0dc1739c1a15aef50a5e7d956ddff298a7c56b85..bbc987209e300edf7c9ebde5a1cbf2f02f13b211 100644 (file)
@@ -249,19 +249,19 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus::new(status))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         if let Some(status) = self.status {
-            return Ok(status)
+            return Ok(Some(status))
         }
         let mut status = 0 as c_int;
         let pid = cvt(unsafe {
             libc::waitpid(self.pid, &mut status, libc::WNOHANG)
         })?;
         if pid == 0 {
-            Err(io::Error::from_raw_os_error(libc::EWOULDBLOCK))
+            Ok(None)
         } else {
             self.status = Some(ExitStatus::new(status));
-            Ok(ExitStatus::new(status))
+            Ok(Some(ExitStatus::new(status)))
         }
     }
 }
index d2ad81023e7feefcd7cb34da5684bc1c2c19e965..1afb3728c9d72e7d00d20a153631a312b72302e6 100644 (file)
@@ -340,18 +340,18 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         }
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         unsafe {
             match c::WaitForSingleObject(self.handle.raw(), 0) {
                 c::WAIT_OBJECT_0 => {}
                 c::WAIT_TIMEOUT => {
-                    return Err(io::Error::from_raw_os_error(c::WSAEWOULDBLOCK))
+                    return Ok(None);
                 }
                 _ => return Err(io::Error::last_os_error()),
             }
             let mut status = 0;
             cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
-            Ok(ExitStatus(status))
+            Ok(Some(ExitStatus(status)))
         }
     }
 
index 77846b69829c8606d5e6d7b4e3f0cb2aa9a650a7..a7c86bf8e06bae014aa2b2c8ed08c2ffe10e6e79 100644 (file)
@@ -325,6 +325,10 @@ pub fn new() -> Features {
 
     // `extern "msp430-interrupt" fn()`
     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
+
+    // Used to identify crates that contain sanitizer runtimes
+    // rustc internal
+    (active, sanitizer_runtime, "1.17.0", None),
 );
 
 declare_features! (
@@ -646,6 +650,12 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                               contains compiler-rt intrinsics and will never be \
                                               stable",
                                           cfg_fn!(compiler_builtins))),
+    ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
+                                             "sanitizer_runtime",
+                                             "the `#[sanitizer_runtime]` attribute is used to \
+                                              identify crates that contain the runtime of a \
+                                              sanitizer and will never be stable",
+                                             cfg_fn!(sanitizer_runtime))),
 
     ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
                                               "allow_internal_unstable",
index 792239e7219326d6b233efae7e08dea801491b38..1d67c2a2c2b74023c8f1fa1c7c5e4dc4ca8d9e6b 100644 (file)
 //! by two zero-length breaks. The algorithm will try its best to fit it on a
 //! line (which it can't) and so naturally place the content on its own line to
 //! avoid combining it with other lines and making matters even worse.
+//!
+//! # Explanation
+//!
+//! In case you do not have the paper, here is an explanation of what's going
+//! on.
+//!
+//! There is a stream of input tokens flowing through this printer.
+//!
+//! The printer buffers up to 3N tokens inside itself, where N is linewidth.
+//! Yes, linewidth is chars and tokens are multi-char, but in the worst
+//! case every token worth buffering is 1 char long, so it's ok.
+//!
+//! Tokens are String, Break, and Begin/End to delimit blocks.
+//!
+//! Begin tokens can carry an offset, saying "how far to indent when you break
+//! inside here", as well as a flag indicating "consistent" or "inconsistent"
+//! breaking. Consistent breaking means that after the first break, no attempt
+//! will be made to flow subsequent breaks together onto lines. Inconsistent
+//! is the opposite. Inconsistent breaking example would be, say:
+//!
+//! ```
+//! foo(hello, there, good, friends)
+//! ```
+//!
+//! breaking inconsistently to become
+//!
+//! ```
+//! foo(hello, there
+//!     good, friends);
+//! ```
+//!
+//! whereas a consistent breaking would yield:
+//!
+//! ```
+//! foo(hello,
+//!     there
+//!     good,
+//!     friends);
+//! ```
+//!
+//! That is, in the consistent-break blocks we value vertical alignment
+//! more than the ability to cram stuff onto a line. But in all cases if it
+//! can make a block a one-liner, it'll do so.
+//!
+//! Carrying on with high-level logic:
+//!
+//! The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
+//! 'right' indices denote the active portion of the ring buffer as well as
+//! describing hypothetical points-in-the-infinite-stream at most 3N tokens
+//! apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch
+//! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
+//! and point-in-infinite-stream senses freely.
+//!
+//! There is a parallel ring buffer, 'size', that holds the calculated size of
+//! each token. Why calculated? Because for Begin/End pairs, the "size"
+//! includes everything between the pair. That is, the "size" of Begin is
+//! actually the sum of the sizes of everything between Begin and the paired
+//! End that follows. Since that is arbitrarily far in the future, 'size' is
+//! being rewritten regularly while the printer runs; in fact most of the
+//! machinery is here to work out 'size' entries on the fly (and give up when
+//! they're so obviously over-long that "infinity" is a good enough
+//! approximation for purposes of line breaking).
+//!
+//! The "input side" of the printer is managed as an abstract process called
+//! SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in
+//! other words, the process of calculating 'size' entries.
+//!
+//! The "output side" of the printer is managed by an abstract process called
+//! PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to
+//! do with each token/size pair it consumes as it goes. It's trying to consume
+//! the entire buffered window, but can't output anything until the size is >=
+//! 0 (sizes are set to negative while they're pending calculation).
+//!
+//! So SCAN takes input and buffers tokens and pending calculations, while
+//! PRINT gobbles up completed calculations and tokens from the buffer. The
+//! theory is that the two can never get more than 3N tokens apart, because
+//! once there's "obviously" too much data to fit on a line, in a size
+//! calculation, SCAN will write "infinity" to the size and let PRINT consume
+//! it.
+//!
+//! In this implementation (following the paper, again) the SCAN process is
+//! the method called `Printer::pretty_print`, and the 'PRINT' process is the method
+//! called `Printer::print`.
 
 use std::collections::VecDeque;
 use std::fmt;
 use std::io;
 
+/// How to break. Described in more detail in the module docs.
 #[derive(Clone, Copy, PartialEq)]
 pub enum Breaks {
     Consistent,
@@ -177,81 +261,6 @@ pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> {
     }
 }
 
-
-/// In case you do not have the paper, here is an explanation of what's going
-/// on.
-///
-/// There is a stream of input tokens flowing through this printer.
-///
-/// The printer buffers up to 3N tokens inside itself, where N is linewidth.
-/// Yes, linewidth is chars and tokens are multi-char, but in the worst
-/// case every token worth buffering is 1 char long, so it's ok.
-///
-/// Tokens are String, Break, and Begin/End to delimit blocks.
-///
-/// Begin tokens can carry an offset, saying "how far to indent when you break
-/// inside here", as well as a flag indicating "consistent" or "inconsistent"
-/// breaking. Consistent breaking means that after the first break, no attempt
-/// will be made to flow subsequent breaks together onto lines. Inconsistent
-/// is the opposite. Inconsistent breaking example would be, say:
-///
-///  foo(hello, there, good, friends)
-///
-/// breaking inconsistently to become
-///
-///  foo(hello, there
-///      good, friends);
-///
-/// whereas a consistent breaking would yield:
-///
-///  foo(hello,
-///      there
-///      good,
-///      friends);
-///
-/// That is, in the consistent-break blocks we value vertical alignment
-/// more than the ability to cram stuff onto a line. But in all cases if it
-/// can make a block a one-liner, it'll do so.
-///
-/// Carrying on with high-level logic:
-///
-/// The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
-/// 'right' indices denote the active portion of the ring buffer as well as
-/// describing hypothetical points-in-the-infinite-stream at most 3N tokens
-/// apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch
-/// between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
-/// and point-in-infinite-stream senses freely.
-///
-/// There is a parallel ring buffer, 'size', that holds the calculated size of
-/// each token. Why calculated? Because for Begin/End pairs, the "size"
-/// includes everything between the pair. That is, the "size" of Begin is
-/// actually the sum of the sizes of everything between Begin and the paired
-/// End that follows. Since that is arbitrarily far in the future, 'size' is
-/// being rewritten regularly while the printer runs; in fact most of the
-/// machinery is here to work out 'size' entries on the fly (and give up when
-/// they're so obviously over-long that "infinity" is a good enough
-/// approximation for purposes of line breaking).
-///
-/// The "input side" of the printer is managed as an abstract process called
-/// SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in
-/// other words, the process of calculating 'size' entries.
-///
-/// The "output side" of the printer is managed by an abstract process called
-/// PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to
-/// do with each token/size pair it consumes as it goes. It's trying to consume
-/// the entire buffered window, but can't output anything until the size is >=
-/// 0 (sizes are set to negative while they're pending calculation).
-///
-/// So SCAN takes input and buffers tokens and pending calculations, while
-/// PRINT gobbles up completed calculations and tokens from the buffer. The
-/// theory is that the two can never get more than 3N tokens apart, because
-/// once there's "obviously" too much data to fit on a line, in a size
-/// calculation, SCAN will write "infinity" to the size and let PRINT consume
-/// it.
-///
-/// In this implementation (following the paper, again) the SCAN process is
-/// the method called 'pretty_print', and the 'PRINT' process is the method
-/// called 'print'.
 pub struct Printer<'a> {
     pub out: Box<io::Write+'a>,
     buf_len: usize,
@@ -292,7 +301,7 @@ impl<'a> Printer<'a> {
     pub fn last_token(&mut self) -> Token {
         self.buf[self.right].token.clone()
     }
-    // be very careful with this!
+    /// be very careful with this!
     pub fn replace_last_token(&mut self, t: Token) {
         self.buf[self.right].token = t;
     }
@@ -571,8 +580,8 @@ pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> {
 }
 
 // Convenience functions to talk to the printer.
-//
-// "raw box"
+
+/// "raw box"
 pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> {
     p.pretty_print(Token::Begin(BeginToken {
         offset: indent as isize,
@@ -580,10 +589,12 @@ pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> {
     }))
 }
 
+/// Inconsistent breaking box
 pub fn ibox(p: &mut Printer, indent: usize) -> io::Result<()> {
     rbox(p, indent, Breaks::Inconsistent)
 }
 
+/// Consistent breaking box
 pub fn cbox(p: &mut Printer, indent: usize) -> io::Result<()> {
     rbox(p, indent, Breaks::Consistent)
 }
index 14c9c5544b188561d41302d3a22ac5a6dcbc32ee..db96079d3e916e1fb789fe88bdab6a39a90de3cb 100644 (file)
@@ -35,8 +35,12 @@ core = { path = "../../libcore" }
 
 # Reexport features from std
 [features]
+asan = ["std/asan"]
 backtrace = ["std/backtrace"]
 debug-jemalloc = ["std/debug-jemalloc"]
 jemalloc = ["std/jemalloc"]
 force_alloc_system = ["std/force_alloc_system"]
+lsan = ["std/lsan"]
+msan = ["std/msan"]
 panic-unwind = ["std/panic-unwind"]
+tsan = ["std/tsan"]
index c7bcd2558186e6f94ef24a4e82d14bbedd9326bf..f3b52b71b99c12655dfcdbc9fa86294e7af5551e 100644 (file)
@@ -148,6 +148,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::ZExt;
   case InReg:
     return Attribute::InReg;
+  case SanitizeThread:
+    return Attribute::SanitizeThread;
+  case SanitizeAddress:
+    return Attribute::SanitizeAddress;
+  case SanitizeMemory:
+    return Attribute::SanitizeMemory;
   }
   llvm_unreachable("bad AttributeKind");
 }
@@ -513,7 +519,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction(
 
 extern "C" LLVMRustMetadataRef
 LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name,
-                                 uint64_t SizeInBits, uint64_t AlignInBits,
+                                 uint64_t SizeInBits, uint32_t AlignInBits,
                                  unsigned Encoding) {
   return wrap(Builder->createBasicType(Name, SizeInBits,
 #if LLVM_VERSION_LE(3, 9)
@@ -524,7 +530,7 @@ LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name,
 
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef PointeeTy,
-    uint64_t SizeInBits, uint64_t AlignInBits, const char *Name) {
+    uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) {
   return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy),
                                          SizeInBits, AlignInBits, Name));
 }
@@ -532,7 +538,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType(
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name,
     LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
-    uint64_t AlignInBits, LLVMRustDIFlags Flags,
+    uint32_t AlignInBits, LLVMRustDIFlags Flags,
     LLVMRustMetadataRef DerivedFrom, LLVMRustMetadataRef Elements,
     unsigned RunTimeLang, LLVMRustMetadataRef VTableHolder,
     const char *UniqueId) {
@@ -546,7 +552,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType(
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name,
     LLVMRustMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
-    uint64_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags,
+    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags,
     LLVMRustMetadataRef Ty) {
   return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), Name,
                                         unwrapDI<DIFile>(File), LineNo,
@@ -573,7 +579,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Context, const char *Name,
     const char *LinkageName, LLVMRustMetadataRef File, unsigned LineNo,
     LLVMRustMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V,
-    LLVMRustMetadataRef Decl = nullptr, uint64_t AlignInBits = 0) {
+    LLVMRustMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) {
   Constant *InitVal = cast<Constant>(unwrap(V));
 
 #if LLVM_VERSION_GE(4, 0)
@@ -612,7 +618,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
     LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMRustMetadataRef Scope,
     const char *Name, LLVMRustMetadataRef File, unsigned LineNo,
     LLVMRustMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags,
-    unsigned ArgNo, uint64_t AlignInBits) {
+    unsigned ArgNo, uint32_t AlignInBits) {
 #if LLVM_VERSION_GE(3, 8)
   if (Tag == 0x100) { // DW_TAG_auto_variable
     return wrap(Builder->createAutoVariable(
@@ -637,7 +643,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
 
 extern "C" LLVMRustMetadataRef
 LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size,
-                                 uint64_t AlignInBits, LLVMRustMetadataRef Ty,
+                                 uint32_t AlignInBits, LLVMRustMetadataRef Ty,
                                  LLVMRustMetadataRef Subscripts) {
   return wrap(
       Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty),
@@ -646,7 +652,7 @@ LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size,
 
 extern "C" LLVMRustMetadataRef
 LLVMRustDIBuilderCreateVectorType(LLVMRustDIBuilderRef Builder, uint64_t Size,
-                                  uint64_t AlignInBits, LLVMRustMetadataRef Ty,
+                                  uint32_t AlignInBits, LLVMRustMetadataRef Ty,
                                   LLVMRustMetadataRef Subscripts) {
   return wrap(
       Builder->createVectorType(Size, AlignInBits, unwrapDI<DIType>(Ty),
@@ -687,7 +693,7 @@ LLVMRustDIBuilderCreateEnumerator(LLVMRustDIBuilderRef Builder,
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name,
     LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
-    uint64_t AlignInBits, LLVMRustMetadataRef Elements,
+    uint32_t AlignInBits, LLVMRustMetadataRef Elements,
     LLVMRustMetadataRef ClassTy) {
   return wrap(Builder->createEnumerationType(
       unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
@@ -698,7 +704,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType(
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType(
     LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name,
     LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
-    uint64_t AlignInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef Elements,
+    uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef Elements,
     unsigned RunTimeLang, const char *UniqueId) {
   return wrap(Builder->createUnionType(
       unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
index a30fa3133e2825b1403d0afa0dda7343846f9acc..0baf5528e9356574397864719da3747f44ed98a8 100644 (file)
@@ -98,6 +98,9 @@ enum LLVMRustAttribute {
   UWTable = 17,
   ZExt = 18,
   InReg = 19,
+  SanitizeThread = 20,
+  SanitizeAddress = 21,
+  SanitizeMemory = 22,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs
new file mode 100644 (file)
index 0000000..db2cd3b
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#[repr(packed)]
+pub struct Packed {
+    dealign: u8,
+    data: u32
+}
+
+// CHECK-LABEL: @write_pkd
+#[no_mangle]
+pub fn write_pkd(pkd: &mut Packed) -> u32 {
+// CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 1
+// CHECK: store i32 42, i32* %{{.*}}, align 1
+    let result = pkd.data;
+    pkd.data = 42;
+    result
+}
diff --git a/src/test/compile-fail/feature-gate-sanitizer-runtime.rs b/src/test/compile-fail/feature-gate-sanitizer-runtime.rs
new file mode 100644 (file)
index 0000000..a18641d
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+#![sanitizer_runtime] //~ ERROR the `#[sanitizer_runtime]` attribute is
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-27433.rs b/src/test/compile-fail/issue-27433.rs
new file mode 100644 (file)
index 0000000..78d9639
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+fn main() {
+    let foo = 42u32;
+    const FOO : u32 = foo;
+                   //~^ ERROR attempt to use a non-constant value in a constant
+}
index ccc25b58228bd66941036a5555072f2865cae0b1..608b1eb0872ad8243f502781da1fd75496474fa7 100644 (file)
@@ -29,6 +29,9 @@ pub struct StructWithProjectionAndLifetime<'a>(
 pub type CVoidRet = ();
 pub struct Foo;
 
+#[repr(C)]
+pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
+
 extern {
     pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without
     pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without
@@ -40,6 +43,9 @@ pub struct StructWithProjectionAndLifetime<'a>(
     pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
     pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
     pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
+    pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type
+    pub fn zero_size_phantom_toplevel()
+        -> ::std::marker::PhantomData<bool>; //~ ERROR: found zero-sized type
     pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
     pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
     pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without
diff --git a/src/test/incremental/issue-39569.rs b/src/test/incremental/issue-39569.rs
new file mode 100644 (file)
index 0000000..5b53e94
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 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.
+
+// Regression test for a weird corner case in our dep-graph reduction
+// code. When we solve `CoerceUnsized<Foo>`, we find no impls, so we
+// don't end up with an edge to any HIR nodes, but it still gets
+// preserved in the dep graph.
+
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+
+use std::sync::Arc;
+
+#[cfg(rpass1)]
+struct Foo { x: usize }
+
+#[cfg(rpass1)]
+fn main() {
+    let x: Arc<Foo> = Arc::new(Foo { x: 22 });
+    let y: Arc<Foo> = x;
+}
+
+#[cfg(rpass2)]
+struct FooX { x: usize }
+
+#[cfg(rpass2)]
+fn main() {
+    let x: Arc<FooX> = Arc::new(FooX { x: 22 });
+    let y: Arc<FooX> = x;
+}
+
diff --git a/src/test/run-make/sanitizer-address/Makefile b/src/test/run-make/sanitizer-address/Makefile
new file mode 100644 (file)
index 0000000..5931145
--- /dev/null
@@ -0,0 +1,11 @@
+-include ../tools.mk
+
+# NOTE the address sanitizer only supports x86_64 linux
+ifdef SANITIZER_SUPPORT
+all:
+       $(RUSTC) -g -Z sanitizer=address -Z print-link-args overflow.rs | grep -q librustc_asan
+       $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow
+else
+all:
+
+endif
diff --git a/src/test/run-make/sanitizer-address/overflow.rs b/src/test/run-make/sanitizer-address/overflow.rs
new file mode 100644 (file)
index 0000000..e35c387
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+fn main() {
+    let xs = [0, 1, 2, 3];
+    let y = unsafe { *xs.as_ptr().offset(4) };
+}
diff --git a/src/test/run-make/sanitizer-dylib/Makefile b/src/test/run-make/sanitizer-dylib/Makefile
new file mode 100644 (file)
index 0000000..835d5b0
--- /dev/null
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+all:
+       $(RUSTC) -Z sanitizer=leak --crate-type dylib --target $(TARGET) hello.rs 2>&1 | grep -q 'Only executables and rlibs can be compiled with `-Z sanitizer`'
+else
+all:
+endif
diff --git a/src/test/run-make/sanitizer-dylib/hello.rs b/src/test/run-make/sanitizer-dylib/hello.rs
new file mode 100644 (file)
index 0000000..4178285
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/run-make/sanitizer-invalid-target/Makefile b/src/test/run-make/sanitizer-invalid-target/Makefile
new file mode 100644 (file)
index 0000000..6a1ce8b
--- /dev/null
@@ -0,0 +1,4 @@
+-include ../tools.mk
+
+all:
+       $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'Sanitizers only work with the `x86_64-unknown-linux-gnu` target'
diff --git a/src/test/run-make/sanitizer-invalid-target/hello.rs b/src/test/run-make/sanitizer-invalid-target/hello.rs
new file mode 100644 (file)
index 0000000..e9e46b7
--- /dev/null
@@ -0,0 +1,13 @@
+// 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(no_core)]
+#![no_core]
+#![no_main]
diff --git a/src/test/run-make/sanitizer-leak/Makefile b/src/test/run-make/sanitizer-leak/Makefile
new file mode 100644 (file)
index 0000000..f02d948
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../tools.mk
+
+ifdef SANITIZER_SUPPORT
+all:
+       $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan
+       $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks'
+else
+all:
+
+endif
diff --git a/src/test/run-make/sanitizer-leak/leak.rs b/src/test/run-make/sanitizer-leak/leak.rs
new file mode 100644 (file)
index 0000000..279da6a
--- /dev/null
@@ -0,0 +1,16 @@
+// 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 std::mem;
+
+fn main() {
+    let xs = vec![1, 2, 3, 4];
+    mem::forget(xs);
+}
diff --git a/src/test/run-make/sanitizer-memory/Makefile b/src/test/run-make/sanitizer-memory/Makefile
new file mode 100644 (file)
index 0000000..08682e5
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../tools.mk
+
+ifdef SANITIZER_SUPPORT
+all:
+       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | grep -q librustc_msan
+       $(TMPDIR)/uninit 2>&1 | grep -q use-of-uninitialized-value
+else
+all:
+
+endif
diff --git a/src/test/run-make/sanitizer-memory/uninit.rs b/src/test/run-make/sanitizer-memory/uninit.rs
new file mode 100644 (file)
index 0000000..8350c7d
--- /dev/null
@@ -0,0 +1,16 @@
+// 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 std::mem;
+
+fn main() {
+    let xs: [u8; 4] = unsafe { mem::uninitialized() };
+    let y = xs[0] + xs[1];
+}
diff --git a/src/test/run-make/sanitizer-thread/Makefile b/src/test/run-make/sanitizer-thread/Makefile
new file mode 100644 (file)
index 0000000..8bb89a2
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../tools.mk
+
+ifdef SANITIZER_SUPPORT
+all:
+       $(RUSTC) -g -Z sanitizer=thread -Z print-link-args racy.rs | grep -q librustc_tsan
+       $(TMPDIR)/racy 2>&1 | grep -q 'data race'
+else
+all:
+
+endif
diff --git a/src/test/run-make/sanitizer-thread/racy.rs b/src/test/run-make/sanitizer-thread/racy.rs
new file mode 100644 (file)
index 0000000..dc929e0
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 std::thread;
+
+static mut ANSWER: i32 = 0;
+
+fn main() {
+    let t1 = thread::spawn(|| unsafe { ANSWER = 42 });
+    unsafe {
+        ANSWER = 24;
+    }
+    t1.join().ok();
+}
diff --git a/src/test/run-pass/issue-34798.rs b/src/test/run-pass/issue-34798.rs
new file mode 100644 (file)
index 0000000..e217d07
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+#![forbid(improper_ctypes)]
+#![allow(dead_code)]
+
+#[repr(C)]
+pub struct Foo {
+    size: u8,
+    __value: ::std::marker::PhantomData<i32>,
+}
+
+#[repr(C)]
+pub struct ZeroSizeWithPhantomData<T>(::std::marker::PhantomData<T>);
+
+#[repr(C)]
+pub struct Bar {
+    size: u8,
+    baz: ZeroSizeWithPhantomData<i32>,
+}
+
+extern "C" {
+    pub fn bar(_: *mut Foo, _: *mut Bar);
+}
+
+fn main() {
+}
index d9826373cceb00803a2525ca120793b4da747e6e..be87b7b3c87e42fbd50cd4905bc39d9bd9af7a3a 100644 (file)
@@ -13,7 +13,6 @@
 #![feature(process_try_wait)]
 
 use std::env;
-use std::io;
 use std::process::Command;
 use std::thread;
 use std::time::Duration;
@@ -32,17 +31,17 @@ fn main() {
                          .arg("sleep")
                          .spawn()
                          .unwrap();
-    let err = me.try_wait().unwrap_err();
-    assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
-    let err = me.try_wait().unwrap_err();
-    assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
 
     me.kill().unwrap();
     me.wait().unwrap();
 
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(!status.success());
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(!status.success());
 
     let mut me = Command::new(env::current_exe().unwrap())
@@ -51,17 +50,17 @@ fn main() {
                          .unwrap();
     loop {
         match me.try_wait() {
-            Ok(res) => {
+            Ok(Some(res)) => {
                 assert!(res.success());
                 break
             }
-            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+            Ok(None) => {
                 thread::sleep(Duration::from_millis(1));
             }
             Err(e) => panic!("error in try_wait: {}", e),
         }
     }
 
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(status.success());
 }
diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs
new file mode 100644 (file)
index 0000000..afe1daf
--- /dev/null
@@ -0,0 +1,40 @@
+// 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.
+
+#![crate_name = "foo"]
+
+pub trait Foo {}
+
+pub struct Bar<T> { field: T }
+
+// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+//     "impl Foo for Bar<u8>"
+impl Foo for Bar<u8> {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+//     "impl Foo for Bar<u16>"
+impl Foo for Bar<u16> {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+//     "impl<'a> Foo for &'a Bar<u8>"
+impl<'a> Foo for &'a Bar<u8> {}
+
+pub mod mod1 {
+    pub struct Baz {}
+}
+
+pub mod mod2 {
+    pub enum Baz {}
+}
+
+// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+//     "impl Foo for foo::mod1::Baz"
+impl Foo for mod1::Baz {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+//     "impl<'a> Foo for &'a foo::mod2::Baz"
+impl<'a> Foo for &'a mod2::Baz {}
diff --git a/src/test/rustdoc/test_option_check/bar.rs b/src/test/rustdoc/test_option_check/bar.rs
new file mode 100644 (file)
index 0000000..51daa80
--- /dev/null
@@ -0,0 +1,19 @@
+// 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: --test
+// check-test-line-numbers-match
+
+/// This looks like another awesome test!
+///
+/// ```
+/// println!("foo?");
+/// ```
+pub fn foooo() {}
index b2afe43204d41d811c28f679d97226c495bb9a8f..a9578c5f434a23e0ecb291cc0d989699cadd7be2 100644 (file)
@@ -11,6 +11,8 @@
 // compile-flags: --test
 // check-test-line-numbers-match
 
+pub mod bar;
+
 /// This is a Foo;
 ///
 /// ```
index 8c15a6630a33c9139787177ed56a99b74cbc6449..0aefe703c9ca7de3e540801f1ded23012dab2987 100644 (file)
@@ -11,7 +11,7 @@
 extern crate toml;
 extern crate rustc_serialize;
 
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
 use std::env;
 use std::fs::File;
 use std::io::{self, Read, Write};
@@ -95,7 +95,6 @@
     "x86_64-pc-windows-gnu",
 ];
 
-#[derive(RustcEncodable)]
 struct Manifest {
     manifest_version: String,
     date: String,
@@ -171,8 +170,18 @@ fn build(&mut self) {
         self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");
 
         self.digest_and_sign();
-        let manifest = self.build_manifest();
-        let manifest = toml::encode(&manifest).to_string();
+        let Manifest { manifest_version, date, pkg } = self.build_manifest();
+
+        // Unfortunately we can't use derive(RustcEncodable) here because the
+        // version field is called `manifest-version`, not `manifest_version`.
+        // In lieu of that just create the table directly here with a `BTreeMap`
+        // and wrap it up in a `Value::Table`.
+        let mut manifest = BTreeMap::new();
+        manifest.insert("manifest-version".to_string(),
+                        toml::encode(&manifest_version));
+        manifest.insert("date".to_string(), toml::encode(&date));
+        manifest.insert("pkg".to_string(), toml::encode(&pkg));
+        let manifest = toml::Value::Table(manifest).to_string();
 
         let filename = format!("channel-rust-{}.toml", self.channel);
         self.write_manifest(&manifest, &filename);
@@ -317,6 +326,8 @@ fn url(&self, component: &str, target: &str) -> String {
     fn filename(&self, component: &str, target: &str) -> String {
         if component == "rust-src" {
             format!("rust-src-{}.tar.gz", self.channel)
+        } else if component == "cargo" {
+            format!("cargo-nightly-{}.tar.gz", target)
         } else {
             format!("{}-{}-{}.tar.gz", component, self.channel, target)
         }
index bcec1f63bc089df560acffeb839d7ca69a2c4c85..1a3d7a190be366bb1d655a1da9d88fc768252a5f 100644 (file)
@@ -30,6 +30,7 @@
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output, ExitStatus};
 use std::str;
+use std::collections::HashMap;
 
 use extract_gdb_version;
 
@@ -1942,17 +1943,28 @@ fn run_rustdoc_test(&self) {
         }
     }
 
-    fn check_rustdoc_test_option(&self, res: ProcRes) {
-        let mut file = fs::File::open(&self.testpaths.file)
+    fn get_lines<P: AsRef<Path>>(&self, path: &P,
+                                 mut other_files: Option<&mut Vec<String>>) -> Vec<usize> {
+        let mut file = fs::File::open(path)
                                 .expect("markdown_test_output_check_entry File::open failed");
         let mut content = String::new();
         file.read_to_string(&mut content)
             .expect("markdown_test_output_check_entry read_to_string failed");
         let mut ignore = false;
-        let mut v: Vec<usize> =
-            content.lines()
-                   .enumerate()
-                   .filter_map(|(line_nb, line)| {
+        content.lines()
+               .enumerate()
+               .filter_map(|(line_nb, line)| {
+                   if (line.trim_left().starts_with("pub mod ") ||
+                       line.trim_left().starts_with("mod ")) &&
+                      line.ends_with(";") {
+                       if let Some(ref mut other_files) = other_files {
+                           other_files.push(line.rsplit("mod ")
+                                      .next()
+                                      .unwrap()
+                                      .replace(";", ""));
+                       }
+                       None
+                   } else {
                        let sline = line.split("///").last().unwrap_or("");
                        let line = sline.trim_left();
                        if line.starts_with("```") {
@@ -1966,8 +1978,21 @@ fn check_rustdoc_test_option(&self, res: ProcRes) {
                        } else {
                            None
                        }
-                   })
-                   .collect();
+                   }
+               })
+               .collect()
+    }
+
+    fn check_rustdoc_test_option(&self, res: ProcRes) {
+        let mut other_files = Vec::new();
+        let mut files: HashMap<String, Vec<usize>> = HashMap::new();
+        files.insert(self.testpaths.file.to_str().unwrap().to_owned(),
+                     self.get_lines(&self.testpaths.file, Some(&mut other_files)));
+        for other_file in other_files {
+            let mut path = self.testpaths.file.clone();
+            path.set_file_name(&format!("{}.rs", other_file));
+            files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None));
+        }
 
         let mut tested = 0;
         for _ in res.stdout.split("\n")
@@ -1975,27 +2000,35 @@ fn check_rustdoc_test_option(&self, res: ProcRes) {
                            .inspect(|s| {
                                let tmp: Vec<&str> = s.split(" - line ").collect();
                                if tmp.len() == 2 {
-                                   tested += 1;
-                                   let line = tmp[1].split(" ...")
-                                                    .next()
-                                                    .unwrap_or("0")
-                                                    .parse()
-                                                    .unwrap_or(0);
-                                   if let Ok(pos) = v.binary_search(&line) {
-                                       v.remove(pos);
-                                   } else {
-                                       self.fatal_proc_rec(
-                                           &format!("Not found doc test: \"{}\" in {:?}", s, v),
-                                           &res);
+                                   let path = tmp[0].rsplit("test ").next().unwrap();
+                                   if let Some(ref mut v) = files.get_mut(path) {
+                                       tested += 1;
+                                       let line = tmp[1].split(" ...")
+                                                        .next()
+                                                        .unwrap_or("0")
+                                                        .parse()
+                                                        .unwrap_or(0);
+                                       if let Ok(pos) = v.binary_search(&line) {
+                                           v.remove(pos);
+                                       } else {
+                                           self.fatal_proc_rec(
+                                               &format!("Not found doc test: \"{}\" in \"{}\":{:?}",
+                                                        s, path, v),
+                                               &res);
+                                       }
                                    }
                                }
                            }) {}
         if tested == 0 {
-            self.fatal_proc_rec("No test has been found", &res);
-        } else if v.len() != 0 {
-            self.fatal_proc_rec(&format!("Not found test at line{} {:?}",
-                                         if v.len() > 1 { "s" } else { "" }, v),
-                                &res);
+            self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res);
+        } else {
+            for (entry, v) in &files {
+                if v.len() != 0 {
+                    self.fatal_proc_rec(&format!("Not found test at line{} \"{}\":{:?}",
+                                                 if v.len() > 1 { "s" } else { "" }, entry, v),
+                                        &res);
+                }
+            }
         }
     }
 
index e85f4b2181357350e038b5142d739f400349c923..69e2a953a176d45606baf48182ad85c5c2529e8c 100644 (file)
@@ -1 +1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"675ffe583db77282d010306f29e6d81e5070ab081deddd0300137dfbd2cb83de","Cargo.toml":"19bb617b74de761515ef5d087fd0e30912fda1d7c22fd04fa211236dab99a509","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ecb2d93f4c81edbd48d8742ff7887dc0a4530a5890967839090bbc972d49bebe","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"11edfe1fc6f932bd42ffffda5145833302bc163e0b87dc0d54f4bd0997ad4708","src/lib.rs":"7e7c60beccfdd145e876da81bb07dd09c5248dab0b26d93190bab4242799d51a","src/registry.rs":"3e2a42581ebb82e325dd5600c6571cef937b35003b2927dc618967f5238a2058","src/windows_registry.rs":"1f4211caec5a192b5f05c8a47efb27aa6a0ab976c659b9318a0cf603a28d6746","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"f4dad5a8133c3dd6678d9a3de057b82e624ef547b9b3e4ac9508a48962fc387b","tests/test.rs":"164220f11be2eebc20315826513999970660a82feff8cc4b15b4e9d73d98324e"},"package":"872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"4cc6445feac7e9a1f8f1e1c51cc3afd0cf7bb931e3c5a6f18c41258401652702",".travis.yml":"e68f9d10a8e367890cf734239c39952ee480cf0e8da9520b377df4a2b8ccc9e8","Cargo.toml":"4c5eb683d4c57fff819ebf564a8db93b5c87284993def6bc066ba1e311d5b090","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"b1a639560fd536f2c3ab708a8e1066b675edd4d018dfa4e5e18d0d7327d81c15","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/lib.rs":"eb4ca086dd2ffa5e30f022f556d0def6d1142160da392afb328393b3f435e8f7","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/windows_registry.rs":"36c6a7f8322407faff2dcfd4789d0876d034885944bc0340ac7c1f7cbfc307f1","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"56bcfd1e2ff5ae8e581c71229444a3d96094bf689808808dd80e315bd6632083","tests/test.rs":"b63e74d571e7d585edc53693bcf0caae88fc040613ace91e32437d4a62cddb6a"},"package":"c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"}
\ No newline at end of file
index a9d37c560c6ab8d4afbf47eda643e8c42e857716..3b874ca574de0550d0ee2608988aeb9655940377 100644 (file)
@@ -1,2 +1,4 @@
 target
 Cargo.lock
+.idea
+*.iml
index bf55f49173dcc894eae82fa48fc7f4ade5a2f513..10d3d13d876bcee206e5c1171d5038537bf0dd22 100644 (file)
@@ -3,6 +3,13 @@ rust:
   - stable
   - beta
   - nightly
+matrix:
+  include:
+    # Minimum version supported
+    - rust: 1.6.0
+      install:
+      script: cargo build
+
 sudo: false
 install:
   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
index 7efdbf9b4b3808ef6ce3593deced1e07e7cdf22e..9fee7788cefc85ef8c593130cc080729563efda4 100644 (file)
@@ -1,11 +1,11 @@
 [package]
 
 name = "gcc"
-version = "0.3.40"
+version = "0.3.43"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/alexcrichton/gcc-rs"
-documentation = "http://alexcrichton.com/gcc-rs"
+documentation = "https://docs.rs/gcc"
 description = """
 A build-time dependency for Cargo build scripts to assist in invoking the native
 C compiler to compile native C code into a static archive to be linked into Rust
@@ -13,8 +13,12 @@ code.
 """
 keywords = ["build-dependencies"]
 
+[badges]
+travis-ci = { repository = "alexcrichton/gcc-rs" }
+appveyor = { repository = "alexcrichton/gcc-rs" }
+
 [dependencies]
-rayon = { version = "0.4", optional = true }
+rayon = { version = "0.6", optional = true }
 
 [features]
 parallel = ["rayon"]
index ecc79c6735266dbfc64b510ecbcfb10e5bc3dd58..2d3e5ed7387549a5fb81b5caea6c0b3931866f1a 100644 (file)
@@ -5,7 +5,7 @@ A library to compile C/C++ code into a Rust library/application.
 [![Build Status](https://travis-ci.org/alexcrichton/gcc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/gcc-rs)
 [![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/gcc-rs)
 
-[Documentation](http://alexcrichton.com/gcc-rs)
+[Documentation](https://docs.rs/gcc)
 
 A simple library meant to be used as a build dependency with Cargo packages in
 order to build a set of C/C++ files into a static archive. Note that while this
@@ -106,7 +106,9 @@ gcc = { version = "0.3", features = ["parallel"] }
 ```
 
 By default gcc-rs will limit parallelism to `$NUM_JOBS`, or if not present it
-will limit it to the number of cpus on the machine.
+will limit it to the number of cpus on the machine. If you are using cargo,
+use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS`
+is supplied by cargo.
 
 ## Compile-time Requirements
 
index 43fd811d3615b6728937c202df53e17307ff08d8..7fd0ea8fa84b72bbf8da4aeb92d4a91021f46514 100644 (file)
@@ -10,7 +10,7 @@ fn main() {
     for i in 0.. {
         let candidate = out_dir.join(format!("out{}", i));
         if candidate.exists() {
-            continue
+            continue;
         }
         let mut f = File::create(candidate).unwrap();
         for arg in env::args().skip(1) {
@@ -18,6 +18,6 @@ fn main() {
         }
 
         File::create(out_dir.join("libfoo.a")).unwrap();
-        break
+        break;
     }
 }
index 43cc371117f018564c6d124564156d5e3feed388..f2d9da7f694218d8016fdb0787c4b8510e99887f 100644 (file)
@@ -42,7 +42,7 @@
 //! }
 //! ```
 
-#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")]
+#![doc(html_root_url = "https://docs.rs/gcc/0.3")]
 #![cfg_attr(test, deny(warnings))]
 #![deny(missing_docs)]
 
 use std::env;
 use std::ffi::{OsString, OsStr};
 use std::fs;
-use std::io;
 use std::path::{PathBuf, Path};
 use std::process::{Command, Stdio};
-use std::io::{BufReader, BufRead, Write};
+use std::io::{self, BufReader, BufRead, Read, Write};
+use std::thread;
 
 #[cfg(windows)]
 mod registry;
@@ -94,6 +94,52 @@ pub struct Tool {
     path: PathBuf,
     args: Vec<OsString>,
     env: Vec<(OsString, OsString)>,
+    family: ToolFamily
+}
+
+/// Represents the family of tools this tool belongs to.
+///
+/// Each family of tools differs in how and what arguments they accept.
+///
+/// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
+#[derive(Copy, Clone, Debug)]
+enum ToolFamily {
+    /// Tool is GNU Compiler Collection-like.
+    Gnu,
+    /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
+    /// and its cross-compilation approach is different.
+    Clang,
+    /// Tool is the MSVC cl.exe.
+    Msvc,
+}
+
+impl ToolFamily {
+    /// What the flag to request debug info for this family of tools look like
+    fn debug_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/Z7",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-g",
+        }
+    }
+
+    /// What the flag to include directories into header search path looks like
+    fn include_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/I",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-I",
+        }
+    }
+
+    /// What the flag to request macro-expanded source output looks like
+    fn expand_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/E",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-E",
+        }
+    }
 }
 
 /// Compile a library from the given set of input C files.
@@ -114,7 +160,7 @@ pub fn compile_library(output: &str, files: &[&str]) {
     for f in files.iter() {
         c.file(*f);
     }
-    c.compile(output)
+    c.compile(output);
 }
 
 impl Config {
@@ -194,8 +240,7 @@ pub fn cpp(&mut self, cpp: bool) -> &mut Config {
     /// otherwise cargo will link against the specified library.
     ///
     /// The given library name must not contain the `lib` prefix.
-    pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>)
-                           -> &mut Config {
+    pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) -> &mut Config {
         self.cpp_link_stdlib = Some(cpp_link_stdlib.map(|s| s.into()));
         self
     }
@@ -220,8 +265,7 @@ pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>)
     /// be used, otherwise `-stdlib` is added to the compile invocation.
     ///
     /// The given library name must not contain the `lib` prefix.
-    pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>)
-                          -> &mut Config {
+    pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) -> &mut Config {
         self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into());
         self.cpp_link_stdlib(cpp_set_stdlib);
         self
@@ -322,7 +366,8 @@ pub fn pic(&mut self, pic: bool) -> &mut Config {
 
     #[doc(hidden)]
     pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Config
-        where A: AsRef<OsStr>, B: AsRef<OsStr>
+        where A: AsRef<OsStr>,
+              B: AsRef<OsStr>
     {
         self.env.push((a.as_ref().to_owned(), b.as_ref().to_owned()));
         self
@@ -355,18 +400,18 @@ pub fn compile(&self, output: &str) {
 
         if self.get_target().contains("msvc") {
             let compiler = self.get_base_compiler();
-            let atlmfc_lib = compiler.env().iter().find(|&&(ref var, _)| {
-                var == OsStr::new("LIB")
-            }).and_then(|&(_, ref lib_paths)| {
-                env::split_paths(lib_paths).find(|path| {
-                    let sub = Path::new("atlmfc/lib");
-                    path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub))
-                })
-            });
+            let atlmfc_lib = compiler.env()
+                .iter()
+                .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB"))
+                .and_then(|&(_, ref lib_paths)| {
+                    env::split_paths(lib_paths).find(|path| {
+                        let sub = Path::new("atlmfc/lib");
+                        path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub))
+                    })
+                });
 
             if let Some(atlmfc_lib) = atlmfc_lib {
-                self.print(&format!("cargo:rustc-link-search=native={}",
-                                    atlmfc_lib.display()));
+                self.print(&format!("cargo:rustc-link-search=native={}", atlmfc_lib.display()));
             }
         }
 
@@ -394,9 +439,7 @@ fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) {
         }
         drop(rayon::initialize(cfg));
 
-        objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| {
-            self.compile_object(src, dst)
-        })
+        objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| self.compile_object(src, dst));
     }
 
     #[cfg(not(feature = "parallel"))]
@@ -417,8 +460,12 @@ fn compile_object(&self, file: &Path, dst: &Path) {
             for &(ref a, ref b) in self.env.iter() {
                 cmd.env(a, b);
             }
-            (cmd, compiler.path.file_name().unwrap()
-                          .to_string_lossy().into_owned())
+            (cmd,
+             compiler.path
+                 .file_name()
+                 .unwrap()
+                 .to_string_lossy()
+                 .into_owned())
         };
         if msvc && is_asm {
             cmd.arg("/Fo").arg(dst);
@@ -429,12 +476,35 @@ fn compile_object(&self, file: &Path, dst: &Path) {
         } else {
             cmd.arg("-o").arg(&dst);
         }
-        cmd.arg(if msvc {"/c"} else {"-c"});
+        cmd.arg(if msvc { "/c" } else { "-c" });
         cmd.arg(file);
 
         run(&mut cmd, &name);
     }
 
+    /// Run the compiler, returning the macro-expanded version of the input files.
+    ///
+    /// This is only relevant for C and C++ files.
+    pub fn expand(&self) -> Vec<u8> {
+        let compiler = self.get_compiler();
+        let mut cmd = compiler.to_command();
+        for &(ref a, ref b) in self.env.iter() {
+            cmd.env(a, b);
+        }
+        cmd.arg(compiler.family.expand_flag());
+        for file in self.files.iter() {
+            cmd.arg(file);
+        }
+
+        let name = compiler.path
+            .file_name()
+            .unwrap()
+            .to_string_lossy()
+            .into_owned();
+
+        run(&mut cmd, &name)
+    }
+
     /// Get the compiler that's in use for this configuration.
     ///
     /// This function will return a `Tool` which represents the culmination
@@ -451,136 +521,159 @@ fn compile_object(&self, file: &Path, dst: &Path) {
     /// falling back to the default configuration.
     pub fn get_compiler(&self) -> Tool {
         let opt_level = self.get_opt_level();
-        let debug = self.get_debug();
         let target = self.get_target();
-        let msvc = target.contains("msvc");
-        self.print(&format!("debug={} opt-level={}", debug, opt_level));
 
         let mut cmd = self.get_base_compiler();
-        let nvcc = cmd.path.to_str()
-            .map(|path| path.contains("nvcc"))
+        let nvcc = cmd.path.file_name()
+            .and_then(|p| p.to_str()).map(|p| p.contains("nvcc"))
             .unwrap_or(false);
 
-        if msvc {
-            cmd.args.push("/nologo".into());
-            let features = env::var("CARGO_CFG_TARGET_FEATURE")
-                              .unwrap_or(String::new());
-            if features.contains("crt-static") {
-                cmd.args.push("/MT".into());
-            } else {
-                cmd.args.push("/MD".into());
-            }
-            match &opt_level[..] {
-                "z" | "s" => cmd.args.push("/Os".into()),
-                "2" => cmd.args.push("/O2".into()),
-                "1" => cmd.args.push("/O1".into()),
-                _ => {}
+        // Non-target flags
+        // If the flag is not conditioned on target variable, it belongs here :)
+        match cmd.family {
+            ToolFamily::Msvc => {
+                cmd.args.push("/nologo".into());
+                let features = env::var("CARGO_CFG_TARGET_FEATURE")
+                                  .unwrap_or(String::new());
+                if features.contains("crt-static") {
+                    cmd.args.push("/MT".into());
+                } else {
+                    cmd.args.push("/MD".into());
+                }
+                match &opt_level[..] {
+                    "z" | "s" => cmd.args.push("/Os".into()),
+                    "1" => cmd.args.push("/O1".into()),
+                    // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2.
+                    "2" | "3" => cmd.args.push("/O2".into()),
+                    _ => {}
+                }
             }
-            if target.contains("i586") {
-                cmd.args.push("/ARCH:IA32".into());
+            ToolFamily::Gnu |
+            ToolFamily::Clang => {
+                cmd.args.push(format!("-O{}", opt_level).into());
+                if !nvcc {
+                    cmd.args.push("-ffunction-sections".into());
+                    cmd.args.push("-fdata-sections".into());
+                    if self.pic.unwrap_or(!target.contains("windows-gnu")) {
+                        cmd.args.push("-fPIC".into());
+                    }
+                } else if self.pic.unwrap_or(false) {
+                    cmd.args.push("-Xcompiler".into());
+                    cmd.args.push("\'-fPIC\'".into());
+                }
             }
-        } else if nvcc {
-            cmd.args.push(format!("-O{}", opt_level).into());
-        } else {
-            cmd.args.push(format!("-O{}", opt_level).into());
-            cmd.args.push("-ffunction-sections".into());
-            cmd.args.push("-fdata-sections".into());
         }
         for arg in self.envflags(if self.cpp {"CXXFLAGS"} else {"CFLAGS"}) {
             cmd.args.push(arg.into());
         }
 
-        if debug {
-            cmd.args.push(if msvc {"/Z7"} else {"-g"}.into());
+        if self.get_debug() {
+            cmd.args.push(cmd.family.debug_flag().into());
         }
 
-        if target.contains("-ios") {
-            self.ios_flags(&mut cmd);
-        } else if !msvc {
-            if target.contains("i686") || target.contains("i586") {
-                cmd.args.push("-m32".into());
-            } else if target.contains("x86_64") || target.contains("powerpc64") {
-                cmd.args.push("-m64".into());
+        // Target flags
+        match cmd.family {
+            ToolFamily::Clang => {
+                cmd.args.push(format!("--target={}", target).into());
             }
-
-            if !nvcc && self.pic.unwrap_or(!target.contains("i686") && !target.contains("windows-gnu")) {
-                cmd.args.push("-fPIC".into());
-            } else if nvcc && self.pic.unwrap_or(false) {
-                cmd.args.push("-Xcompiler".into());
-                cmd.args.push("\'-fPIC\'".into());
+            ToolFamily::Msvc => {
+                if target.contains("i586") {
+                    cmd.args.push("/ARCH:IA32".into());
+                }
             }
+            ToolFamily::Gnu => {
+                if target.contains("i686") || target.contains("i586") {
+                    cmd.args.push("-m32".into());
+                } else if target.contains("x86_64") || target.contains("powerpc64") {
+                    cmd.args.push("-m64".into());
+                }
 
-            if target.contains("musl") {
-                cmd.args.push("-static".into());
-            }
+                if target.contains("musl") {
+                    cmd.args.push("-static".into());
+                }
 
-            // armv7 targets get to use armv7 instructions
-            if target.starts_with("armv7-unknown-linux-") {
-                cmd.args.push("-march=armv7-a".into());
-            }
+                // armv7 targets get to use armv7 instructions
+                if target.starts_with("armv7-unknown-linux-") {
+                    cmd.args.push("-march=armv7-a".into());
+                }
 
-            // On android we can guarantee some extra float instructions
-            // (specified in the android spec online)
-            if target.starts_with("armv7-linux-androideabi") {
-                cmd.args.push("-march=armv7-a".into());
-                cmd.args.push("-mfpu=vfpv3-d16".into());
-            }
+                // On android we can guarantee some extra float instructions
+                // (specified in the android spec online)
+                if target.starts_with("armv7-linux-androideabi") {
+                    cmd.args.push("-march=armv7-a".into());
+                    cmd.args.push("-mfpu=vfpv3-d16".into());
+                }
 
-            // For us arm == armv6 by default
-            if target.starts_with("arm-unknown-linux-") {
-                cmd.args.push("-march=armv6".into());
-                cmd.args.push("-marm".into());
-            }
+                // For us arm == armv6 by default
+                if target.starts_with("arm-unknown-linux-") {
+                    cmd.args.push("-march=armv6".into());
+                    cmd.args.push("-marm".into());
+                }
 
-            // Turn codegen down on i586 to avoid some instructions.
-            if target.starts_with("i586-unknown-linux-") {
-                cmd.args.push("-march=pentium".into());
-            }
+                // Turn codegen down on i586 to avoid some instructions.
+                if target.starts_with("i586-unknown-linux-") {
+                    cmd.args.push("-march=pentium".into());
+                }
 
-            // Set codegen level for i686 correctly
-            if target.starts_with("i686-unknown-linux-") {
-                cmd.args.push("-march=i686".into());
-            }
+                // Set codegen level for i686 correctly
+                if target.starts_with("i686-unknown-linux-") {
+                    cmd.args.push("-march=i686".into());
+                }
 
-            // Looks like `musl-gcc` makes is hard for `-m32` to make its way
-            // all the way to the linker, so we need to actually instruct the
-            // linker that we're generating 32-bit executables as well. This'll
-            // typically only be used for build scripts which transitively use
-            // these flags that try to compile executables.
-            if target == "i686-unknown-linux-musl" {
-                cmd.args.push("-Wl,-melf_i386".into());
-            }
+                // Looks like `musl-gcc` makes is hard for `-m32` to make its way
+                // all the way to the linker, so we need to actually instruct the
+                // linker that we're generating 32-bit executables as well. This'll
+                // typically only be used for build scripts which transitively use
+                // these flags that try to compile executables.
+                if target == "i686-unknown-linux-musl" {
+                    cmd.args.push("-Wl,-melf_i386".into());
+                }
 
-            if target.starts_with("thumb") {
-                cmd.args.push("-mthumb".into());
+                if target.starts_with("thumb") {
+                    cmd.args.push("-mthumb".into());
 
-                if target.ends_with("eabihf") {
-                    cmd.args.push("-mfloat-abi=hard".into())
+                    if target.ends_with("eabihf") {
+                        cmd.args.push("-mfloat-abi=hard".into())
+                    }
                 }
-            }
-            if target.starts_with("thumbv6m") {
-                cmd.args.push("-march=armv6s-m".into());
-            }
-            if target.starts_with("thumbv7em") {
-                cmd.args.push("-march=armv7e-m".into());
+                if target.starts_with("thumbv6m") {
+                    cmd.args.push("-march=armv6s-m".into());
+                }
+                if target.starts_with("thumbv7em") {
+                    cmd.args.push("-march=armv7e-m".into());
 
-                if target.ends_with("eabihf") {
-                    cmd.args.push("-mfpu=fpv4-sp-d16".into())
+                    if target.ends_with("eabihf") {
+                        cmd.args.push("-mfpu=fpv4-sp-d16".into())
+                    }
+                }
+                if target.starts_with("thumbv7m") {
+                    cmd.args.push("-march=armv7-m".into());
                 }
             }
-            if target.starts_with("thumbv7m") {
-                cmd.args.push("-march=armv7-m".into());
-            }
         }
 
-        if self.cpp && !msvc {
-            if let Some(ref stdlib) = self.cpp_set_stdlib {
-                cmd.args.push(format!("-stdlib=lib{}", stdlib).into());
+        if target.contains("-ios") {
+            // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be
+            // detected instead.
+            self.ios_flags(&mut cmd);
+        }
+
+        if self.cpp {
+            match (self.cpp_set_stdlib.as_ref(), cmd.family) {
+                (None, _) => { }
+                (Some(stdlib), ToolFamily::Gnu) |
+                (Some(stdlib), ToolFamily::Clang) => {
+                    cmd.args.push(format!("-stdlib=lib{}", stdlib).into());
+                }
+                _ => {
+                    println!("cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \
+                              does not support this option, ignored", cmd.family);
+                }
             }
         }
 
         for directory in self.include_directories.iter() {
-            cmd.args.push(if msvc {"/I"} else {"-I"}.into());
+            cmd.args.push(cmd.family.include_flag().into());
             cmd.args.push(directory.into());
         }
 
@@ -589,7 +682,7 @@ pub fn get_compiler(&self) -> Tool {
         }
 
         for &(ref key, ref value) in self.definitions.iter() {
-            let lead = if msvc {"/"} else {"-"};
+            let lead = if let ToolFamily::Msvc = cmd.family {"/"} else {"-"};
             if let &Some(ref value) = value {
                 cmd.args.push(format!("{}D{}={}", lead, key, value).into());
             } else {
@@ -601,10 +694,12 @@ pub fn get_compiler(&self) -> Tool {
 
     fn msvc_macro_assembler(&self) -> (Command, String) {
         let target = self.get_target();
-        let tool = if target.contains("x86_64") {"ml64.exe"} else {"ml.exe"};
-        let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| {
-            self.cmd(tool)
-        });
+        let tool = if target.contains("x86_64") {
+            "ml64.exe"
+        } else {
+            "ml.exe"
+        };
+        let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool));
         for directory in self.include_directories.iter() {
             cmd.arg("/I").arg(directory);
         }
@@ -635,31 +730,37 @@ fn assemble(&self, lib_name: &str, dst: &Path, objects: &[PathBuf]) {
         if target.contains("msvc") {
             let mut cmd = match self.archiver {
                 Some(ref s) => self.cmd(s),
-                None => windows_registry::find(&target, "lib.exe")
-                                         .unwrap_or(self.cmd("lib.exe")),
+                None => windows_registry::find(&target, "lib.exe").unwrap_or(self.cmd("lib.exe")),
             };
             let mut out = OsString::from("/OUT:");
             out.push(dst);
-            run(cmd.arg(out).arg("/nologo")
-                   .args(objects)
-                   .args(&self.objects), "lib.exe");
+            run(cmd.arg(out)
+                    .arg("/nologo")
+                    .args(objects)
+                    .args(&self.objects),
+                "lib.exe");
 
             // The Rust compiler will look for libfoo.a and foo.lib, but the
             // MSVC linker will also be passed foo.lib, so be sure that both
             // exist for now.
             let lib_dst = dst.with_file_name(format!("{}.lib", lib_name));
             let _ = fs::remove_file(&lib_dst);
-            fs::hard_link(&dst, &lib_dst).or_else(|_| {
-                //if hard-link fails, just copy (ignoring the number of bytes written)
-                fs::copy(&dst, &lib_dst).map(|_| ())
-            }).ok().expect("Copying from {:?} to {:?} failed.");;
+            fs::hard_link(&dst, &lib_dst)
+                .or_else(|_| {
+                    // if hard-link fails, just copy (ignoring the number of bytes written)
+                    fs::copy(&dst, &lib_dst).map(|_| ())
+                })
+                .ok()
+                .expect("Copying from {:?} to {:?} failed.");;
         } else {
             let ar = self.get_ar();
             let cmd = ar.file_name().unwrap().to_string_lossy();
-            run(self.cmd(&ar).arg("crs")
-                                 .arg(dst)
-                                 .args(objects)
-                                 .args(&self.objects), &cmd);
+            run(self.cmd(&ar)
+                    .arg("crs")
+                    .arg(dst)
+                    .args(objects)
+                    .args(&self.objects),
+                &cmd);
         }
     }
 
@@ -677,7 +778,7 @@ enum ArchSpec {
             "arm64" | "aarch64" => ArchSpec::Device("arm64"),
             "i386" | "i686" => ArchSpec::Simulator("-m32"),
             "x86_64" => ArchSpec::Simulator("-m64"),
-            _ => fail("Unknown arch for iOS target")
+            _ => fail("Unknown arch for iOS target"),
         };
 
         let sdk = match arch {
@@ -686,7 +787,7 @@ enum ArchSpec {
                 cmd.args.push(arch.into());
                 cmd.args.push("-miphoneos-version-min=7.0".into());
                 "iphoneos"
-            },
+            }
             ArchSpec::Simulator(arch) => {
                 cmd.args.push(arch.into());
                 cmd.args.push("-mios-simulator-version-min=7.0".into());
@@ -715,12 +816,12 @@ fn cmd<P: AsRef<OsStr>>(&self, prog: P) -> Command {
         for &(ref a, ref b) in self.env.iter() {
             cmd.env(a, b);
         }
-        return cmd
+        return cmd;
     }
 
     fn get_base_compiler(&self) -> Tool {
         if let Some(ref c) = self.compiler {
-            return Tool::new(c.clone())
+            return Tool::new(c.clone());
         }
         let host = self.get_host();
         let target = self.get_target();
@@ -729,87 +830,88 @@ fn get_base_compiler(&self) -> Tool {
         } else {
             ("CC", "cl.exe", "gcc", "cc")
         };
-        self.env_tool(env).map(|(tool, args)| {
-            let mut t = Tool::new(PathBuf::from(tool));
-            for arg in args {
-                t.args.push(arg.into());
-            }
-            return t
-        }).or_else(|| {
-            if target.contains("emscripten") {
-                if self.cpp {
-                    Some(Tool::new(PathBuf::from("em++")))
-                } else {
-                    Some(Tool::new(PathBuf::from("emcc")))
+        self.env_tool(env)
+            .map(|(tool, args)| {
+                let mut t = Tool::new(PathBuf::from(tool));
+                for arg in args {
+                    t.args.push(arg.into());
                 }
-            } else {
-                None
-            }
-        }).or_else(|| {
-            windows_registry::find_tool(&target, "cl.exe")
-        }).unwrap_or_else(|| {
-            let compiler = if host.contains("windows") &&
-                              target.contains("windows") {
-                if target.contains("msvc") {
-                    msvc.to_string()
+                return t;
+            })
+            .or_else(|| {
+                if target.contains("emscripten") {
+                    if self.cpp {
+                        Some(Tool::new(PathBuf::from("em++")))
+                    } else {
+                        Some(Tool::new(PathBuf::from("emcc")))
+                    }
                 } else {
-                    format!("{}.exe", gnu)
+                    None
                 }
-            } else if target.contains("android") {
-                format!("{}-{}", target, gnu)
-            } else if self.get_host() != target {
-                // CROSS_COMPILE is of the form: "arm-linux-gnueabi-"
-                let cc_env = self.getenv("CROSS_COMPILE");
-                let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-'));
-                let prefix = cross_compile.or(match &target[..] {
-                    "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"),
-                    "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
-                    "arm-unknown-linux-gnueabihf"  => Some("arm-linux-gnueabihf"),
-                    "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"),
-                    "arm-unknown-linux-musleabihf"  => Some("arm-linux-musleabihf"),
-                    "arm-unknown-netbsdelf-eabi" => Some("arm--netbsdelf-eabi"),
-                    "armv6-unknown-netbsdelf-eabihf" => Some("armv6--netbsdelf-eabihf"),
-                    "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
-                    "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
-                    "armv7-unknown-netbsdelf-eabihf" => Some("armv7--netbsdelf-eabihf"),
-                    "i686-pc-windows-gnu" => Some("i686-w64-mingw32"),
-                    "i686-unknown-linux-musl" => Some("musl"),
-                    "i686-unknown-netbsdelf" => Some("i486--netbsdelf"),
-                    "mips-unknown-linux-gnu" => Some("mips-linux-gnu"),
-                    "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"),
-                    "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"),
-                    "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"),
-                    "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
-                    "powerpc-unknown-netbsd" => Some("powerpc--netbsd"),
-                    "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
-                    "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"),
-                    "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"),
-                    "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
-                    "thumbv6m-none-eabi" => Some("arm-none-eabi"),
-                    "thumbv7em-none-eabi" => Some("arm-none-eabi"),
-                    "thumbv7em-none-eabihf" => Some("arm-none-eabi"),
-                    "thumbv7m-none-eabi" => Some("arm-none-eabi"),
-                    "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"),
-                    "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"),
-                    "x86_64-unknown-linux-musl" => Some("musl"),
-                    "x86_64-unknown-netbsd" => Some("x86_64--netbsd"),
-                    _ => None,
-                });
-                match prefix {
-                    Some(prefix) => format!("{}-{}", prefix, gnu),
-                    None => default.to_string(),
-                }
-            } else {
-                default.to_string()
-            };
-            Tool::new(PathBuf::from(compiler))
-        })
+            })
+            .or_else(|| windows_registry::find_tool(&target, "cl.exe"))
+            .unwrap_or_else(|| {
+                let compiler = if host.contains("windows") && target.contains("windows") {
+                    if target.contains("msvc") {
+                        msvc.to_string()
+                    } else {
+                        format!("{}.exe", gnu)
+                    }
+                } else if target.contains("android") {
+                    format!("{}-{}", target.replace("armv7", "arm"), gnu)
+                } else if self.get_host() != target {
+                    // CROSS_COMPILE is of the form: "arm-linux-gnueabi-"
+                    let cc_env = self.getenv("CROSS_COMPILE");
+                    let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-'));
+                    let prefix = cross_compile.or(match &target[..] {
+                        "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"),
+                        "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
+                        "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"),
+                        "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "arm-unknown-netbsdelf-eabi" => Some("arm--netbsdelf-eabi"),
+                        "armv6-unknown-netbsdelf-eabihf" => Some("armv6--netbsdelf-eabihf"),
+                        "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "armv7-unknown-netbsdelf-eabihf" => Some("armv7--netbsdelf-eabihf"),
+                        "i686-pc-windows-gnu" => Some("i686-w64-mingw32"),
+                        "i686-unknown-linux-musl" => Some("musl"),
+                        "i686-unknown-netbsdelf" => Some("i486--netbsdelf"),
+                        "mips-unknown-linux-gnu" => Some("mips-linux-gnu"),
+                        "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"),
+                        "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"),
+                        "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"),
+                        "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
+                        "powerpc-unknown-netbsd" => Some("powerpc--netbsd"),
+                        "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
+                        "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"),
+                        "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"),
+                        "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
+                        "thumbv6m-none-eabi" => Some("arm-none-eabi"),
+                        "thumbv7em-none-eabi" => Some("arm-none-eabi"),
+                        "thumbv7em-none-eabihf" => Some("arm-none-eabi"),
+                        "thumbv7m-none-eabi" => Some("arm-none-eabi"),
+                        "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"),
+                        "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"),
+                        "x86_64-unknown-linux-musl" => Some("musl"),
+                        "x86_64-unknown-netbsd" => Some("x86_64--netbsd"),
+                        _ => None,
+                    });
+                    match prefix {
+                        Some(prefix) => format!("{}-{}", prefix, gnu),
+                        None => default.to_string(),
+                    }
+                } else {
+                    default.to_string()
+                };
+                Tool::new(PathBuf::from(compiler))
+            })
     }
 
     fn get_var(&self, var_base: &str) -> Result<String, String> {
         let target = self.get_target();
         let host = self.get_host();
-        let kind = if host == target {"HOST"} else {"TARGET"};
+        let kind = if host == target { "HOST" } else { "TARGET" };
         let target_u = target.replace("-", "_");
         let res = self.getenv(&format!("{}_{}", var_base, target))
             .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u)))
@@ -823,8 +925,10 @@ fn get_var(&self, var_base: &str) -> Result<String, String> {
     }
 
     fn envflags(&self, name: &str) -> Vec<String> {
-        self.get_var(name).unwrap_or(String::new())
-            .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
+        self.get_var(name)
+            .unwrap_or(String::new())
+            .split(|c: char| c.is_whitespace())
+            .filter(|s| !s.is_empty())
             .map(|s| s.to_string())
             .collect()
     }
@@ -834,8 +938,7 @@ fn env_tool(&self, name: &str) -> Option<(String, Vec<String>)> {
             let whitelist = ["ccache", "distcc"];
             for t in whitelist.iter() {
                 if tool.starts_with(t) && tool[t.len()..].starts_with(" ") {
-                    return (t.to_string(),
-                            vec![tool[t.len()..].trim_left().to_string()])
+                    return (t.to_string(), vec![tool[t.len()..].trim_left().to_string()]);
                 }
             }
             (tool, Vec::new())
@@ -860,17 +963,18 @@ fn get_cpp_link_stdlib(&self) -> Option<String> {
     }
 
     fn get_ar(&self) -> PathBuf {
-        self.archiver.clone().or_else(|| {
-            self.get_var("AR").map(PathBuf::from).ok()
-        }).unwrap_or_else(|| {
-            if self.get_target().contains("android") {
-                PathBuf::from(format!("{}-ar", self.get_target()))
-            } else if self.get_target().contains("emscripten") {
-                PathBuf::from("emar")
-            } else {
-                PathBuf::from("ar")
-            }
-        })
+        self.archiver
+            .clone()
+            .or_else(|| self.get_var("AR").map(PathBuf::from).ok())
+            .unwrap_or_else(|| {
+                if self.get_target().contains("android") {
+                    PathBuf::from(format!("{}-ar", self.get_target().replace("armv7", "arm")))
+                } else if self.get_target().contains("emscripten") {
+                    PathBuf::from("emar")
+                } else {
+                    PathBuf::from("ar")
+                }
+            })
     }
 
     fn get_target(&self) -> String {
@@ -882,9 +986,7 @@ fn get_host(&self) -> String {
     }
 
     fn get_opt_level(&self) -> String {
-        self.opt_level.as_ref().cloned().unwrap_or_else(|| {
-            self.getenv_unwrap("OPT_LEVEL")
-        })
+        self.opt_level.as_ref().cloned().unwrap_or_else(|| self.getenv_unwrap("OPT_LEVEL"))
     }
 
     fn get_debug(&self) -> bool {
@@ -892,9 +994,7 @@ fn get_debug(&self) -> bool {
     }
 
     fn get_out_dir(&self) -> PathBuf {
-        self.out_dir.clone().unwrap_or_else(|| {
-            env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
-        })
+        self.out_dir.clone().unwrap_or_else(|| env::var_os("OUT_DIR").map(PathBuf::from).unwrap())
     }
 
     fn getenv(&self, v: &str) -> Option<String> {
@@ -919,10 +1019,23 @@ fn print(&self, s: &str) {
 
 impl Tool {
     fn new(path: PathBuf) -> Tool {
+        // Try to detect family of the tool from its name, falling back to Gnu.
+        let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
+            if fname.contains("clang") {
+                ToolFamily::Clang
+            } else if fname.contains("cl") {
+                ToolFamily::Msvc
+            } else {
+                ToolFamily::Gnu
+            }
+        } else {
+            ToolFamily::Gnu
+        };
         Tool {
             path: path,
             args: Vec::new(),
             env: Vec::new(),
+            family: family
         }
     }
 
@@ -937,7 +1050,7 @@ pub fn to_command(&self) -> Command {
         for &(ref k, ref v) in self.env.iter() {
             cmd.env(k, v);
         }
-        return cmd
+        cmd
     }
 
     /// Returns the path for this compiler.
@@ -963,23 +1076,27 @@ pub fn env(&self) -> &[(OsString, OsString)] {
     }
 }
 
-fn run(cmd: &mut Command, program: &str) {
+fn run(cmd: &mut Command, program: &str) -> Vec<u8> {
     println!("running: {:?}", cmd);
     // Capture the standard error coming from these programs, and write it out
     // with cargo:warning= prefixes. Note that this is a bit wonky to avoid
     // requiring the output to be UTF-8, we instead just ship bytes from one
     // location to another.
-    let spawn_result = match cmd.stderr(Stdio::piped()).spawn() {
+    let (spawn_result, stdout) = match cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
         Ok(mut child) => {
             let stderr = BufReader::new(child.stderr.take().unwrap());
-            for line in stderr.split(b'\n').filter_map(|l| l.ok()) {
-                print!("cargo:warning=");
-                std::io::stdout().write_all(&line).unwrap();
-                println!("");
-            }
-            child.wait()
+            thread::spawn(move || {
+                for line in stderr.split(b'\n').filter_map(|l| l.ok()) {
+                    print!("cargo:warning=");
+                    std::io::stdout().write_all(&line).unwrap();
+                    println!("");
+                }
+            });
+            let mut stdout = vec![];
+            child.stdout.take().unwrap().read_to_end(&mut stdout).unwrap();
+            (child.wait(), stdout)
         }
-        Err(e) => Err(e),
+        Err(e) => (Err(e), vec![]),
     };
     let status = match spawn_result {
         Ok(status) => status,
@@ -991,7 +1108,10 @@ fn run(cmd: &mut Command, program: &str) {
                 ""
             };
             fail(&format!("failed to execute command: {}\nIs `{}` \
-                           not installed?{}", e, program, extra));
+                           not installed?{}",
+                          e,
+                          program,
+                          extra));
         }
         Err(e) => fail(&format!("failed to execute command: {}", e)),
     };
@@ -999,6 +1119,7 @@ fn run(cmd: &mut Command, program: &str) {
     if !status.success() {
         fail(&format!("command did not execute successfully, got: {}", status));
     }
+    stdout
 }
 
 fn fail(s: &str) -> ! {
index d871cd21f3c06d69e40a3c332e91fd97323b1d8b..a45272344db403c87e1005a7315e14a755f47804 100644 (file)
@@ -40,7 +40,8 @@ fn RegOpenKeyExW(key: HKEY,
                      lpSubKey: LPCWSTR,
                      ulOptions: DWORD,
                      samDesired: REGSAM,
-                     phkResult: PHKEY) -> LONG;
+                     phkResult: PHKEY)
+                     -> LONG;
     fn RegEnumKeyExW(key: HKEY,
                      dwIndex: DWORD,
                      lpName: LPWSTR,
@@ -48,13 +49,15 @@ fn RegEnumKeyExW(key: HKEY,
                      lpReserved: LPDWORD,
                      lpClass: LPWSTR,
                      lpcClass: LPDWORD,
-                     lpftLastWriteTime: PFILETIME) -> LONG;
+                     lpftLastWriteTime: PFILETIME)
+                     -> LONG;
     fn RegQueryValueExW(hKey: HKEY,
                         lpValueName: LPCWSTR,
                         lpReserved: LPDWORD,
                         lpType: LPDWORD,
                         lpData: LPBYTE,
-                        lpcbData: LPDWORD) -> LONG;
+                        lpcbData: LPDWORD)
+                        -> LONG;
     fn RegCloseKey(hKey: HKEY) -> LONG;
 }
 
@@ -73,8 +76,7 @@ pub struct Iter<'a> {
 unsafe impl Sync for Repr {}
 unsafe impl Send for Repr {}
 
-pub static LOCAL_MACHINE: RegistryKey =
-    RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
+pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
 
 impl RegistryKey {
     fn raw(&self) -> HKEY {
@@ -88,8 +90,11 @@ pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
         let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
         let mut ret = 0 as *mut _;
         let err = unsafe {
-            RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
-                          KEY_READ | KEY_WOW64_32KEY, &mut ret)
+            RegOpenKeyExW(self.raw(),
+                          key.as_ptr(),
+                          0,
+                          KEY_READ | KEY_WOW64_32KEY,
+                          &mut ret)
         };
         if err == ERROR_SUCCESS as LONG {
             Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
@@ -99,7 +104,10 @@ pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
     }
 
     pub fn iter(&self) -> Iter {
-        Iter { idx: 0.., key: self }
+        Iter {
+            idx: 0..,
+            key: self,
+        }
     }
 
     pub fn query_str(&self, name: &str) -> io::Result<OsString> {
@@ -108,25 +116,31 @@ pub fn query_str(&self, name: &str) -> io::Result<OsString> {
         let mut len = 0;
         let mut kind = 0;
         unsafe {
-            let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _,
-                                       &mut kind, 0 as *mut _, &mut len);
+            let err = RegQueryValueExW(self.raw(),
+                                       name.as_ptr(),
+                                       0 as *mut _,
+                                       &mut kind,
+                                       0 as *mut _,
+                                       &mut len);
             if err != ERROR_SUCCESS as LONG {
-                return Err(io::Error::from_raw_os_error(err as i32))
+                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"))
+                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(), 0 as *mut _,
-                                       0 as *mut _, v.as_mut_ptr() as *mut _,
+            let err = RegQueryValueExW(self.raw(),
+                                       name.as_ptr(),
+                                       0 as *mut _,
+                                       0 as *mut _,
+                                       v.as_mut_ptr() as *mut _,
                                        &mut len);
             if err != ERROR_SUCCESS as LONG {
-                return Err(io::Error::from_raw_os_error(err as i32))
+                return Err(io::Error::from_raw_os_error(err as i32));
             }
             v.set_len(len as usize / 2);
 
@@ -142,7 +156,9 @@ pub fn query_str(&self, name: &str) -> io::Result<OsString> {
 
 impl Drop for OwnedKey {
     fn drop(&mut self) {
-        unsafe { RegCloseKey(self.0); }
+        unsafe {
+            RegCloseKey(self.0);
+        }
     }
 }
 
@@ -153,8 +169,13 @@ fn next(&mut self) -> Option<io::Result<OsString>> {
         self.idx.next().and_then(|i| unsafe {
             let mut v = Vec::with_capacity(256);
             let mut len = v.capacity() as DWORD;
-            let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len,
-                                    0 as *mut _, 0 as *mut _, 0 as *mut _,
+            let ret = RegEnumKeyExW(self.key.raw(),
+                                    i,
+                                    v.as_mut_ptr(),
+                                    &mut len,
+                                    0 as *mut _,
+                                    0 as *mut _,
+                                    0 as *mut _,
                                     0 as *mut _);
             if ret == ERROR_NO_MORE_ITEMS as LONG {
                 None
index e16a33f24647884b6559990a1ab73d4fc7328b87..08b1df5f9b24af3926861ae5f2b05cb97c2e3204 100644 (file)
@@ -78,31 +78,29 @@ fn into_tool(self) -> Tool {
             add_env(&mut tool, "LIB", libs);
             add_env(&mut tool, "PATH", path);
             add_env(&mut tool, "INCLUDE", include);
-            return tool
+            tool
         }
     }
 
     // This logic is all tailored for MSVC, if we're not that then bail out
     // early.
     if !target.contains("msvc") {
-        return None
+        return None;
     }
 
     // Looks like msbuild isn't located in the same location as other tools like
     // cl.exe and lib.exe. To handle this we probe for it manually with
     // dedicated registry keys.
     if tool.contains("msbuild") {
-        return find_msbuild(target)
+        return find_msbuild(target);
     }
 
     // If VCINSTALLDIR is set, then someone's probably already run vcvars and we
     // should just find whatever that indicates.
     if env::var_os("VCINSTALLDIR").is_some() {
-        return env::var_os("PATH").and_then(|path| {
-            env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists())
-        }).map(|path| {
-            Tool::new(path.into())
-        })
+        return env::var_os("PATH")
+            .and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
+            .map(|path| Tool::new(path.into()));
     }
 
     // Ok, if we're here, now comes the fun part of the probing. Default shells
@@ -112,13 +110,10 @@ fn into_tool(self) -> Tool {
     // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
     // the tool is actually usable.
 
-    return find_msvc_latest(tool, target, "15.0").or_else(|| {
-        find_msvc_latest(tool, target, "14.0")
-    }).or_else(|| {
-        find_msvc_12(tool, target)
-    }).or_else(|| {
-        find_msvc_11(tool, target)
-    });
+    return find_msvc_latest(tool, target, "15.0")
+        .or_else(|| find_msvc_latest(tool, target, "14.0"))
+        .or_else(|| find_msvc_12(tool, target))
+        .or_else(|| find_msvc_11(tool, target));
 
     // 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.
@@ -151,7 +146,7 @@ fn find_msvc_latest(tool: &str, target: &str, ver: &str) -> Option<Tool> {
             tool.include.push(sdk_include.join("winrt"));
             tool.include.push(sdk_include.join("shared"));
         } else {
-            return None
+            return None;
         }
         Some(tool.into_tool())
     }
@@ -198,26 +193,27 @@ fn add_env(tool: &mut Tool, env: &str, paths: Vec<PathBuf>) {
     // Given a possible MSVC installation directory, we look for the linker and
     // then add the MSVC library path.
     fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> {
-        bin_subdir(target).into_iter().map(|(sub, host)| {
-            (path.join("bin").join(sub).join(tool),
-             path.join("bin").join(host))
-        }).filter(|&(ref path, _)| {
-            path.is_file()
-        }).map(|(path, host)| {
-            let mut tool = MsvcTool::new(path);
-            tool.path.push(host);
-            tool
-        }).filter_map(|mut tool| {
-            let sub = otry!(vc_lib_subdir(target));
-            tool.libs.push(path.join("lib").join(sub));
-            tool.include.push(path.join("include"));
-            let atlmfc_path = path.join("atlmfc");
-            if atlmfc_path.exists() {
-                tool.libs.push(atlmfc_path.join("lib").join(sub));
-                tool.include.push(atlmfc_path.join("include"));
-            }
-            Some(tool)
-        }).next()
+        bin_subdir(target)
+            .into_iter()
+            .map(|(sub, host)| (path.join("bin").join(sub).join(tool), path.join("bin").join(host)))
+            .filter(|&(ref path, _)| path.is_file())
+            .map(|(path, host)| {
+                let mut tool = MsvcTool::new(path);
+                tool.path.push(host);
+                tool
+            })
+            .filter_map(|mut tool| {
+                let sub = otry!(vc_lib_subdir(target));
+                tool.libs.push(path.join("lib").join(sub));
+                tool.include.push(path.join("include"));
+                let atlmfc_path = path.join("atlmfc");
+                if atlmfc_path.exists() {
+                    tool.libs.push(atlmfc_path.join("lib").join(sub));
+                    tool.include.push(atlmfc_path.join("include"));
+                }
+                Some(tool)
+            })
+            .next()
     }
 
     // To find MSVC we look in a specific registry key for the version we are
@@ -240,17 +236,16 @@ fn get_ucrt_dir() -> Option<(PathBuf, String)> {
         let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
         let root = otry!(key.query_str("KitsRoot10").ok());
         let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
-        let max_libdir = otry!(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());
+        let max_libdir = otry!(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());
         let version = max_libdir.components().last().unwrap();
         let version = version.as_os_str().to_str().unwrap().to_string();
         Some((root.into(), version))
@@ -270,12 +265,13 @@ fn get_sdk10_dir() -> Option<(PathBuf, String)> {
         let root = otry!(key.query_str("InstallationFolder").ok());
         let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
         let mut dirs = readdir.filter_map(|dir| dir.ok())
-                              .map(|dir| dir.path())
-                              .collect::<Vec<_>>();
+            .map(|dir| dir.path())
+            .collect::<Vec<_>>();
         dirs.sort();
-        let dir = otry!(dirs.into_iter().rev().filter(|dir| {
-            dir.join("um").join("x64").join("kernel32.lib").is_file()
-        }).next());
+        let dir = otry!(dirs.into_iter()
+            .rev()
+            .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
+            .next());
         let version = dir.components().last().unwrap();
         let version = version.as_os_str().to_str().unwrap().to_string();
         Some((root.into(), version))
@@ -319,10 +315,8 @@ fn get_sdk8_dir() -> Option<PathBuf> {
     fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> {
         let arch = target.split('-').next().unwrap();
         match (arch, host_arch()) {
-            ("i586", X86) |
-            ("i686", X86) => vec![("", "")],
-            ("i586", X86_64) |
-            ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
+            ("i586", X86) | ("i686", X86) => vec![("", "")],
+            ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
             ("x86_64", X86) => vec![("x86_amd64", "")],
             ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
             ("arm", X86) => vec![("x86_arm", "")],
@@ -393,9 +387,8 @@ fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
         let mut max_vers = 0;
         let mut max_key = None;
         for subkey in key.iter().filter_map(|k| k.ok()) {
-            let val = subkey.to_str().and_then(|s| {
-                s.trim_left_matches("v").replace(".", "").parse().ok()
-            });
+            let val = subkey.to_str()
+                .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
             let val = match val {
                 Some(s) => s,
                 None => continue,
@@ -407,24 +400,25 @@ fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
                 }
             }
         }
-        return max_key
+        max_key
     }
 
     // see http://stackoverflow.com/questions/328017/path-to-msbuild
     fn find_msbuild(target: &str) -> Option<Tool> {
         let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
-        LOCAL_MACHINE.open(key.as_ref()).ok().and_then(|key| {
-            max_version(&key).and_then(|(_vers, key)| {
-                key.query_str("MSBuildToolsPath").ok()
+        LOCAL_MACHINE.open(key.as_ref())
+            .ok()
+            .and_then(|key| {
+                max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok())
+            })
+            .map(|path| {
+                let mut path = PathBuf::from(path);
+                path.push("MSBuild.exe");
+                let mut tool = Tool::new(path);
+                if target.contains("x86_64") {
+                    tool.env.push(("Platform".into(), "X64".into()));
+                }
+                tool
             })
-        }).map(|path| {
-            let mut path = PathBuf::from(path);
-            path.push("MSBuild.exe");
-            let mut tool = Tool::new(path);
-            if target.contains("x86_64") {
-                tool.env.push(("Platform".into(), "X64".into()));
-            }
-            tool
-        })
     }
 }
index 5c40984eb6a0999f27ba3195f7827324620957b4..135a6635b5935ae206759a2c8dcd49e77829b1fe 100644 (file)
@@ -37,28 +37,27 @@ pub fn new() -> Test {
     pub fn gnu() -> Test {
         let t = Test::new();
         t.shim("cc").shim("ar");
-        return t
+        t
     }
 
     pub fn msvc() -> Test {
         let mut t = Test::new();
         t.shim("cl").shim("lib.exe");
         t.msvc = true;
-        return t
+        t
     }
 
     pub fn shim(&self, name: &str) -> &Test {
         let fname = format!("{}{}", name, env::consts::EXE_SUFFIX);
-        fs::hard_link(&self.gcc, self.td.path().join(&fname)).or_else(|_| {
-            fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ())
-        }).unwrap();
+        fs::hard_link(&self.gcc, self.td.path().join(&fname))
+            .or_else(|_| fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ()))
+            .unwrap();
         self
     }
 
     pub fn gcc(&self) -> gcc::Config {
         let mut cfg = gcc::Config::new();
-        let mut path = env::split_paths(&env::var_os("PATH").unwrap())
-                           .collect::<Vec<_>>();
+        let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::<Vec<_>>();
         path.insert(0, self.td.path().to_owned());
         let target = if self.msvc {
             "x86_64-pc-windows-msvc"
@@ -66,26 +65,27 @@ pub fn gcc(&self) -> gcc::Config {
             "x86_64-unknown-linux-gnu"
         };
 
-        cfg.target(target).host(target)
-           .opt_level(2)
-           .debug(false)
-           .out_dir(self.td.path())
-           .__set_env("PATH", env::join_paths(path).unwrap())
-           .__set_env("GCCTEST_OUT_DIR", self.td.path());
+        cfg.target(target)
+            .host(target)
+            .opt_level(2)
+            .debug(false)
+            .out_dir(self.td.path())
+            .__set_env("PATH", env::join_paths(path).unwrap())
+            .__set_env("GCCTEST_OUT_DIR", self.td.path());
         if self.msvc {
             cfg.compiler(self.td.path().join("cl"));
             cfg.archiver(self.td.path().join("lib.exe"));
         }
-        return cfg
+        cfg
     }
 
     pub fn cmd(&self, i: u32) -> Execution {
         let mut s = String::new();
-        File::open(self.td.path().join(format!("out{}", i))).unwrap()
-             .read_to_string(&mut s).unwrap();
-        Execution {
-            args: s.lines().map(|s| s.to_string()).collect(),
-        }
+        File::open(self.td.path().join(format!("out{}", i)))
+            .unwrap()
+            .read_to_string(&mut s)
+            .unwrap();
+        Execution { args: s.lines().map(|s| s.to_string()).collect() }
     }
 }
 
@@ -107,8 +107,6 @@ pub fn must_not_have<P: AsRef<OsStr>>(&self, p: P) -> &Execution {
     }
 
     pub fn has(&self, p: &OsStr) -> bool {
-        self.args.iter().any(|arg| {
-            OsStr::new(arg) == p
-        })
+        self.args.iter().any(|arg| OsStr::new(arg) == p)
     }
 }
index 1b6a0bd0d10a6b92cfc8c68f0dac89724d19ee90..5a034ff347b240de930e3a28ab5cb60bfa5d211a 100644 (file)
@@ -9,14 +9,16 @@
 fn gnu_smoke() {
     let test = Test::gnu();
     test.gcc()
-        .file("foo.c").compile("libfoo.a");
-
-    test.cmd(0).must_have("-O2")
-               .must_have("foo.c")
-               .must_not_have("-g")
-               .must_have("-c")
-               .must_have("-ffunction-sections")
-               .must_have("-fdata-sections");
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("-O2")
+        .must_have("foo.c")
+        .must_not_have("-g")
+        .must_have("-c")
+        .must_have("-ffunction-sections")
+        .must_have("-fdata-sections");
     test.cmd(1).must_have(test.td.path().join("foo.o"));
 }
 
@@ -25,10 +27,12 @@ fn gnu_opt_level_1() {
     let test = Test::gnu();
     test.gcc()
         .opt_level(1)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
-    test.cmd(0).must_have("-O1")
-               .must_not_have("-O2");
+    test.cmd(0)
+        .must_have("-O1")
+        .must_not_have("-O2");
 }
 
 #[test]
@@ -36,13 +40,15 @@ fn gnu_opt_level_s() {
     let test = Test::gnu();
     test.gcc()
         .opt_level_str("s")
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
-    test.cmd(0).must_have("-Os")
-               .must_not_have("-O1")
-               .must_not_have("-O2")
-               .must_not_have("-O3")
-               .must_not_have("-Oz");
+    test.cmd(0)
+        .must_have("-Os")
+        .must_not_have("-O1")
+        .must_not_have("-O2")
+        .must_not_have("-O3")
+        .must_not_have("-Oz");
 }
 
 #[test]
@@ -50,7 +56,8 @@ fn gnu_debug() {
     let test = Test::gnu();
     test.gcc()
         .debug(true)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
     test.cmd(0).must_have("-g");
 }
 
@@ -62,10 +69,12 @@ fn gnu_x86_64() {
         test.gcc()
             .target(&target)
             .host(&target)
-            .file("foo.c").compile("libfoo.a");
+            .file("foo.c")
+            .compile("libfoo.a");
 
-        test.cmd(0).must_have("-fPIC")
-                   .must_have("-m64");
+        test.cmd(0)
+            .must_have("-fPIC")
+            .must_have("-m64");
     }
 }
 
@@ -78,7 +87,8 @@ fn gnu_x86_64_no_pic() {
             .pic(false)
             .target(&target)
             .host(&target)
-            .file("foo.c").compile("libfoo.a");
+            .file("foo.c")
+            .compile("libfoo.a");
 
         test.cmd(0).must_not_have("-fPIC");
     }
@@ -92,10 +102,12 @@ fn gnu_i686() {
         test.gcc()
             .target(&target)
             .host(&target)
-            .file("foo.c").compile("libfoo.a");
+            .file("foo.c")
+            .compile("libfoo.a");
 
-        test.cmd(0).must_not_have("-fPIC")
-                   .must_have("-m32");
+        test.cmd(0)
+            .must_not_have("-fPIC")
+            .must_have("-m32");
     }
 }
 
@@ -108,7 +120,8 @@ fn gnu_i686_pic() {
             .pic(true)
             .target(&target)
             .host(&target)
-            .file("foo.c").compile("libfoo.a");
+            .file("foo.c")
+            .compile("libfoo.a");
 
         test.cmd(0).must_have("-fPIC");
     }
@@ -119,7 +132,8 @@ fn gnu_set_stdlib() {
     let test = Test::gnu();
     test.gcc()
         .cpp_set_stdlib(Some("foo"))
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_not_have("-stdlib=foo");
 }
@@ -129,7 +143,8 @@ fn gnu_include() {
     let test = Test::gnu();
     test.gcc()
         .include("foo/bar")
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_have("-I").must_have("foo/bar");
 }
@@ -140,7 +155,8 @@ fn gnu_define() {
     test.gcc()
         .define("FOO", Some("bar"))
         .define("BAR", None)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
 }
@@ -149,7 +165,8 @@ fn gnu_define() {
 fn gnu_compile_assembly() {
     let test = Test::gnu();
     test.gcc()
-        .file("foo.S").compile("libfoo.a");
+        .file("foo.S")
+        .compile("libfoo.a");
     test.cmd(0).must_have("foo.S");
 }
 
@@ -157,12 +174,14 @@ fn gnu_compile_assembly() {
 fn msvc_smoke() {
     let test = Test::msvc();
     test.gcc()
-        .file("foo.c").compile("libfoo.a");
-
-    test.cmd(0).must_have("/O2")
-               .must_have("foo.c")
-               .must_not_have("/Z7")
-               .must_have("/c");
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("/O2")
+        .must_have("foo.c")
+        .must_not_have("/Z7")
+        .must_have("/c");
     test.cmd(1).must_have(test.td.path().join("foo.o"));
 }
 
@@ -171,7 +190,8 @@ fn msvc_opt_level_0() {
     let test = Test::msvc();
     test.gcc()
         .opt_level(0)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_not_have("/O2");
 }
@@ -181,7 +201,8 @@ fn msvc_debug() {
     let test = Test::msvc();
     test.gcc()
         .debug(true)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
     test.cmd(0).must_have("/Z7");
 }
 
@@ -190,7 +211,8 @@ fn msvc_include() {
     let test = Test::msvc();
     test.gcc()
         .include("foo/bar")
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_have("/I").must_have("foo/bar");
 }
@@ -201,7 +223,8 @@ fn msvc_define() {
     test.gcc()
         .define("FOO", Some("bar"))
         .define("BAR", None)
-        .file("foo.c").compile("libfoo.a");
+        .file("foo.c")
+        .compile("libfoo.a");
 
     test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR");
 }