-Version 1.15.1 (2017-02-07)
+Version 1.15.1 (2017-02-08)
===========================
* [Fix IntoIter::as_mut_slice's signature][39466]
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"
+++ /dev/null
-# rustbuild-only target
+++ /dev/null
-# rustbuild-only target
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",
]
"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)",
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]]
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]]
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]]
[[package]]
name = "gcc"
-version = "0.3.40"
+version = "0.3.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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"
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"
"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"
"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"
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",
"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",
]
"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"
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") {
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() {
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"));
pub target_config: HashMap<String, Target>,
pub full_bootstrap: bool,
pub extended: bool,
+ pub sanitizers: bool,
// llvm codegen options
pub llvm_assertions: bool,
python: Option<String>,
full_bootstrap: Option<bool>,
extended: Option<bool>,
+ sanitizers: Option<bool>,
}
/// TOML representation of various global install decisions.
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);
("VENDOR", self.vendor),
("FULL_BOOTSTRAP", self.full_bootstrap),
("EXTENDED", self.extended),
+ ("SANITIZERS", self.sanitizers),
}
match key {
# disabled by default.
#extended = false
+# Build the sanitizer runtimes
+#sanitizers = false
+
# =============================================================================
# General install configuration options
# =============================================================================
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(),
};
/// 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");
}
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
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
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
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
--- /dev/null
+#!/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
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
-Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
+Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
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;
};
```
+
+
### Static items
A *static item* is similar to a *constant*, except that it represents a precise
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;
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
### 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
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
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"
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use 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);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod map;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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);
+ })
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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());
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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())
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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)
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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);
+ })
+}
+++ /dev/null
-// 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);
- })
- }
- )
-}
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);
- }
-}
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;
use std::collections::LinkedList;
-use test;
-
#[test]
fn test_basic() {
let mut m = LinkedList::<Box<_>>::new();
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();
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;
- }
-}
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());
-}
// 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>;
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())
-}
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,
}
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)
-}
use std::fmt::Debug;
use std::collections::vec_deque::Drain;
-use test;
-
use self::Taggy::*;
use self::Taggypar::*;
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),
path = "../libcoretest/lib.rs"
[[bench]]
-name = "corebench"
-path = "../libcore/bench/lib.rs"
+name = "corebenches"
+path = "../libcore/benches/lib.rs"
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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));
- });
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-mod sip;
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![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;
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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)
- });
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![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;
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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,
- }
- });
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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>());
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-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)
- }
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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));
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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));
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-mod flt2dec;
-mod dec2flt;
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use 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 };
- })
-}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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));
+ });
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod sip;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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)
+ });
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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,
+ }
+ });
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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>());
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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)
+ }
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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));
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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));
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod flt2dec;
+mod dec2flt;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use 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 };
+ })
+}
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
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")
}
pub uint_type: UintTy,
}
+#[derive(Clone)]
+pub enum Sanitizer {
+ Address,
+ Leak,
+ Memory,
+ Thread,
+}
+
#[derive(Clone, Copy, PartialEq, Hash)]
pub enum OptLevel {
No, // -O0
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;
$(
}
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
+ }
}
) }
"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 {
--- /dev/null
+[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" }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
// 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);
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.
+ }
+}
+
enum FfiResult {
FfiSafe,
+ FfiPhantom,
FfiUnsafe(&'static str),
FfiBadStruct(DefId, &'static str),
FfiBadUnion(DefId, &'static str),
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
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) {
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;
}
}
}
}
- FfiSafe
+
+ if all_phantom { FfiPhantom } else { FfiSafe }
}
AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
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;
}
}
}
}
- FfiSafe
+
+ if all_phantom { FfiPhantom } else { FfiSafe }
}
AdtKind::Enum => {
if def.variants.is_empty() {
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
+ FfiPhantom => {
+ return FfiBadEnum(def.did,
+ "Found phantom data in enum variant");
+ }
FfiUnsafe(s) => {
return FfiBadEnum(def.did, s);
}
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);
}
UWTable = 17,
ZExt = 18,
InReg = 19,
+ SanitizeThread = 20,
+ SanitizeAddress = 21,
+ SanitizeMemory = 22,
}
/// LLVMIntPredicate
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;
File: DIFile,
LineNumber: c_uint,
SizeInBits: u64,
- AlignInBits: u64,
+ AlignInBits: u32,
Flags: DIFlags,
DerivedFrom: DIType,
Elements: DIArray,
File: DIFile,
LineNo: c_uint,
SizeInBits: u64,
- AlignInBits: u64,
+ AlignInBits: u32,
OffsetInBits: u64,
Flags: DIFlags,
Ty: DIType)
isLocalToUnit: bool,
Val: ValueRef,
Decl: DIDescriptor,
- AlignInBits: u64)
+ AlignInBits: u32)
-> DIGlobalVariable;
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;
File: DIFile,
LineNumber: c_uint,
SizeInBits: u64,
- AlignInBits: u64,
+ AlignInBits: u32,
Elements: DIArray,
ClassType: DIType)
-> DIType;
File: DIFile,
LineNumber: c_uint,
SizeInBits: u64,
- AlignInBits: u64,
+ AlignInBits: u32,
Flags: DIFlags,
Elements: DIArray,
RunTimeLang: c_uint,
--- /dev/null
+[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" }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
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;
&|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!
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);
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")
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()
}
--- /dev/null
+[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" }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
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.
bcx: &Builder<'a, 'tcx>,
t: Ty<'tcx>,
scrutinee: ValueRef,
+ alignment: Alignment,
cast_to: Option<Type>,
range_assert: bool
) -> ValueRef {
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),
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)
};
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);
// 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())
}
}
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};
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
};
// 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) => {
}
}
+ // 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)
}
}
+ // 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:
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;
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};
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));
}
// 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 {
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>,
/// 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(..)) |
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)
+ );
}
}
}
/// 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));
}
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());
}
}
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)
}
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,
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) {
}
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();
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;
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 {
}
}
- 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
}
}
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));
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));
use syntax_pos::DUMMY_SP;
+use mir::lvalue::Alignment;
+
#[derive(Debug)]
pub enum CalleeData {
/// Constructor for enum variant/tuple-like-struct.
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;
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
}
is_local_to_unit,
global,
ptr::null_mut(),
- global_align as u64,
+ global_align,
);
}
}
cx.sess().opts.optimize != config::OptLevel::No,
DIFlags::FlagZero,
argument_index,
- align as u64,
+ align,
)
};
source_loc::set_debug_location(bcx,
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
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]
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;
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
// Code relating to drop glue.
use std;
-use std::ptr;
use std::iter;
use llvm;
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());
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 {
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);
// 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
}
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());
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));
}
}
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) => {
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);
}
}
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
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",
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])
};
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)
// 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));
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);
}
}
}
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);
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
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;
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};
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);
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 {
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) {
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())
}
}
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()
}
// 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;
}
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);
}
// 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());
}
}
// 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,
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)
};
}
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()));
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);
}
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)
};
use std::fmt;
use std::ptr;
+use super::lvalue::Alignment;
use super::operand::{OperandRef, OperandValue};
use super::MirContext;
// 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 {
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
/// 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 {
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])
// * 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);
}
_ => ()
}
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.
// 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,
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 => {
// (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)
}
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,
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 {
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)) {
}
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 {
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,
}
}
};
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.
///
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};
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,
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
_ => 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) {
// 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,
);
});
- return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
+ return LocalRef::Lvalue(lvalue);
}
let arg = &mircx.fn_ty.args[idx];
};
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?
);
}
});
- 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()
}
use llvm::ValueRef;
use rustc::ty::Ty;
+use rustc::ty::layout::Layout;
use rustc::mir;
use rustc_data_structures::indexed_vec::Idx;
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
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.
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({:?}) @ {:?})",
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 }
// 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,
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
}
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.
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);
}
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,
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
}
// 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;
}
// 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
}
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);
})
}
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);
}
}
},
} 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.
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);
}
}
}
_ => {
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
}
}
operand.ty, cast_ty);
OperandValue::Pair(lldata, llextra)
}
- OperandValue::Ref(_) => {
+ OperandValue::Ref(..) => {
bug!("by-ref operand {:?} in trans_rvalue_operand",
operand);
}
--- /dev/null
+[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" }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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;
}
_ => {
if f.alternate() {
- write!(f, "&{}{}{:#}", lt, m, **ty)
+ write!(f, "&{}{}", lt, m)?;
+ fmt_type(&ty, f, use_absolute)
} else {
- write!(f, "&{}{}{}", lt, m, **ty)
+ write!(f, "&{}{}", lt, m)?;
+ fmt_type(&ty, f, use_absolute)
}
}
}
use std::slice;
use std::str;
use syntax::feature_gate::UnstableFeatures;
+use syntax::codemap::Span;
use html::render::derive_id;
use html::toc::TocBuilder;
}
}
-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,
});
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);
}
}
}
}
- 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);
<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;
+ }
+ }
+ _ => {}
}
}
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>")?;
use testing;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
+use syntax::codemap::DUMMY_SP;
use externalfiles::{ExternalHtml, LoadStringError, load_string};
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
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;
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,
false,
opts,
maybe_sysroot,
- filename,
Some(codemap));
{
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(),
cratename: cratename,
opts: opts,
maybe_sysroot: maybe_sysroot,
- filename: filename,
- start_line: 0,
+ position: DUMMY_SP,
codemap: codemap,
}
}
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();
}
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) {
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);
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"]
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
///
/// ```
/// 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.
///
/// ```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);
/// }
/// ```
#[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
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)))
}
}
}
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::*;
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); },
}
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)))
}
}
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)))
}
}
}
}
}
- 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)))
}
}
// `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! (
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",
//! 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,
}
}
-
-/// 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,
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;
}
}
// 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,
}))
}
+/// 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)
}
# 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"]
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");
}
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)
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));
}
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) {
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,
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)
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(
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),
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),
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,
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,
UWTable = 17,
ZExt = 18,
InReg = 19,
+ SanitizeThread = 20,
+ SanitizeAddress = 21,
+ SanitizeMemory = 22,
};
typedef struct OpaqueRustString *RustStringRef;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![sanitizer_runtime] //~ ERROR the `#[sanitizer_runtime]` attribute is
+
+fn main() {}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let foo = 42u32;
+ const FOO : u32 = foo;
+ //~^ ERROR attempt to use a non-constant value in a constant
+}
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
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
--- /dev/null
+// 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;
+}
+
--- /dev/null
+-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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let xs = [0, 1, 2, 3];
+ let y = unsafe { *xs.as_ptr().offset(4) };
+}
--- /dev/null
+-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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+-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'
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
--- /dev/null
+-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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+fn main() {
+ let xs = vec![1, 2, 3, 4];
+ mem::forget(xs);
+}
--- /dev/null
+-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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+fn main() {
+ let xs: [u8; 4] = unsafe { mem::uninitialized() };
+ let y = xs[0] + xs[1];
+}
--- /dev/null
+-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
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::thread;
+
+static mut ANSWER: i32 = 0;
+
+fn main() {
+ let t1 = thread::spawn(|| unsafe { ANSWER = 42 });
+ unsafe {
+ ANSWER = 24;
+ }
+ t1.join().ok();
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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() {
+}
#![feature(process_try_wait)]
use std::env;
-use std::io;
use std::process::Command;
use std::thread;
use std::time::Duration;
.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())
.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());
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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 {}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --test
+// check-test-line-numbers-match
+
+/// This looks like another awesome test!
+///
+/// ```
+/// println!("foo?");
+/// ```
+pub fn foooo() {}
// compile-flags: --test
// check-test-line-numbers-match
+pub mod bar;
+
/// This is a Foo;
///
/// ```
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};
"x86_64-pc-windows-gnu",
];
-#[derive(RustcEncodable)]
struct Manifest {
manifest_version: String,
date: String,
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);
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)
}
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::str;
+use std::collections::HashMap;
use extract_gdb_version;
}
}
- 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("```") {
} 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")
.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);
+ }
+ }
}
}
-{"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
target
Cargo.lock
+.idea
+*.iml
- 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
[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
"""
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"]
[![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
```
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
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) {
}
File::create(out_dir.join("libfoo.a")).unwrap();
- break
+ break;
}
}
//! }
//! ```
-#![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;
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.
for f in files.iter() {
c.file(*f);
}
- c.compile(output)
+ c.compile(output);
}
impl 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
}
/// 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
#[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
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()));
}
}
}
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"))]
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);
} 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
/// 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());
}
}
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 {
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);
}
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);
}
}
"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 {
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());
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();
} 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)))
}
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()
}
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())
}
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 {
}
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 {
}
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> {
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
}
}
for &(ref k, ref v) in self.env.iter() {
cmd.env(k, v);
}
- return cmd
+ cmd
}
/// Returns the path for this compiler.
}
}
-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,
""
};
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)),
};
if !status.success() {
fail(&format!("command did not execute successfully, got: {}", status));
}
+ stdout
}
fn fail(s: &str) -> ! {
lpSubKey: LPCWSTR,
ulOptions: DWORD,
samDesired: REGSAM,
- phkResult: PHKEY) -> LONG;
+ phkResult: PHKEY)
+ -> LONG;
fn RegEnumKeyExW(key: HKEY,
dwIndex: DWORD,
lpName: LPWSTR,
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;
}
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 {
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))))
}
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> {
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);
impl Drop for OwnedKey {
fn drop(&mut self) {
- unsafe { RegCloseKey(self.0); }
+ unsafe {
+ RegCloseKey(self.0);
+ }
}
}
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
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
// 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.
tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared"));
} else {
- return None
+ return None;
}
Some(tool.into_tool())
}
// 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
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))
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))
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", "")],
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,
}
}
}
- 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
- })
}
}
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"
"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() }
}
}
}
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)
}
}
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"));
}
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]
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]
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");
}
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");
}
}
.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");
}
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");
}
}
.pic(true)
.target(&target)
.host(&target)
- .file("foo.c").compile("libfoo.a");
+ .file("foo.c")
+ .compile("libfoo.a");
test.cmd(0).must_have("-fPIC");
}
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");
}
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");
}
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");
}
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");
}
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"));
}
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");
}
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");
}
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");
}
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");
}