Most common editors supporting Rust have been updated to work with it. It was
previously described [on the Rust blog]
(https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html).
-* [In error descriptions, references are now described in plain english,
+* [In error descriptions, references are now described in plain English,
instead of as "&-ptr"]
(https://github.com/rust-lang/rust/pull/35611)
* [In error type descriptions, unknown numeric types are named `{integer}` or
(https://github.com/rust-lang/rust/pull/34946)
* [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry`
implement `Debug`]
- (https://github.com/rust-lang/rust/pull/34946)
+ (https://github.com/rust-lang/rust/pull/34937)
* [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry`
implement `Debug`]
(https://github.com/rust-lang/rust/pull/34885)
Performance
-----------
-* [The time complexity of comparing variables for equivalence during type
+* [The time complexity of comparing variables for equivalence during type
unification is reduced from _O_(_n_!) to _O_(_n_)][1.9tu]. This leads
to major compilation time improvement in some scenarios.
* [`ToString` is specialized for `str`, giving it the same performance
--- /dev/null
+# wasm32-unknown-emscripten configuration
+CC_wasm32-unknown-emscripten=emcc
+CXX_wasm32-unknown-emscripten=em++
+CPP_wasm32-unknown-emscripten=$(CPP)
+AR_wasm32-unknown-emscripten=emar
+CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
+CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
+CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
+CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
+CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
+CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
+CFG_INSTALL_NAME_wasm32-unknown-emscripten =
+CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
+CFG_WINDOWSY_wasm32-unknown-emscripten :=
+CFG_UNIXY_wasm32-unknown-emscripten := 1
+CFG_LDPATH_wasm32-unknown-emscripten :=
+CFG_RUN_wasm32-unknown-emscripten=$(2)
+CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
+CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
+CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1
# LLVM macros
######################################################################
-LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
+LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
interpreter instrumentation
"build_helper 0.1.0",
"cmake 0.1.17 (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.31 (git+https://github.com/alexcrichton/gcc-rs)",
+ "gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
-version = "0.3.31"
-source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
+version = "0.3.35"
+source = "git+https://github.com/alexcrichton/gcc-rs#8ff5360b6e0dc4f3c9d3f71036f1ff403c68469d"
[[package]]
name = "gcc"
-version = "0.3.31"
+version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
-version = "0.2.10"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
-version = "0.2.11"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "toml"
-version = "0.1.28"
+version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "winapi"
-version = "0.2.6"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
-"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
-"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
+"checksum gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
+"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
+"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
-"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
+"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
-"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
+"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
-"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
+"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
cmd.arg("--host").arg(compiler.host);
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
+ if let Some(nodejs) = build.config.nodejs.as_ref() {
+ cmd.arg("--nodejs").arg(nodejs);
+ }
+
let mut flags = vec!["-Crpath".to_string()];
if build.config.rust_optimize_tests {
flags.push("-O".to_string());
if target.contains("android") {
build.run(cargo.arg("--no-run"));
krate_android(build, compiler, target, mode);
+ } else if target.contains("emscripten") {
+ build.run(cargo.arg("--no-run"));
+ krate_emscripten(build, compiler, target, mode);
} else {
cargo.args(&build.flags.args);
build.run(&mut cargo);
}
}
+fn krate_emscripten(build: &Build,
+ compiler: &Compiler,
+ target: &str,
+ mode: Mode) {
+ let mut tests = Vec::new();
+ let out_dir = build.cargo_out(compiler, mode, target);
+ find_tests(&out_dir, target, &mut tests);
+ find_tests(&out_dir.join("deps"), target, &mut tests);
+
+ for test in tests {
+ let test_file_name = test.to_string_lossy().into_owned();
+ println!("running {}", test_file_name);
+ let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
+ let status = Command::new(nodejs)
+ .arg(&test_file_name)
+ .stderr(::std::process::Stdio::inherit())
+ .status();
+ match status {
+ Ok(status) => {
+ if !status.success() {
+ panic!("some tests failed");
+ }
+ }
+ Err(e) => panic!(format!("failed to execute command: {}", e)),
+ };
+ }
+ }
+
+
fn find_tests(dir: &Path,
target: &str,
dst: &mut Vec<PathBuf>) {
}
let filename = e.file_name().into_string().unwrap();
if (target.contains("windows") && filename.ends_with(".exe")) ||
- (!target.contains("windows") && !filename.contains(".")) {
+ (!target.contains("windows") && !filename.contains(".")) ||
+ (target.contains("emscripten") && filename.contains(".js")){
dst.push(e.path());
}
}
continue
}
- if !submodule.path.exists() {
- t!(fs::create_dir_all(&submodule.path));
- }
+ // `submodule.path` is the relative path to a submodule (from the repository root)
+ // `submodule_path` is the path to a submodule from the cwd
+
+ // use `submodule.path` when e.g. executing a submodule specific command from the
+ // repository root
+ // use `submodule_path` when e.g. executing a normal git command for the submodule
+ // (set via `current_dir`)
+ let submodule_path = self.src.join(submodule.path);
match submodule.state {
State::MaybeDirty => {
// drop staged changes
- self.run(git().current_dir(submodule.path)
+ self.run(git().current_dir(&submodule_path)
.args(&["reset", "--hard"]));
// drops unstaged changes
- self.run(git().current_dir(submodule.path)
+ self.run(git().current_dir(&submodule_path)
.args(&["clean", "-fdx"]));
},
State::NotInitialized => {
State::OutOfSync => {
// drops submodule commits that weren't reported to the (outer) git repository
self.run(git_submodule().arg("update").arg(submodule.path));
- self.run(git().current_dir(submodule.path)
+ self.run(git().current_dir(&submodule_path)
.args(&["reset", "--hard"]));
- self.run(git().current_dir(submodule.path)
+ self.run(git().current_dir(&submodule_path)
.args(&["clean", "-fdx"]));
},
}
// than an entry here.
let mut base = Vec::new();
- if target != self.config.build && !target.contains("msvc") {
+ if target != self.config.build && !target.contains("msvc") &&
+ !target.contains("emscripten") {
base.push(format!("-Clinker={}", self.cc(target).display()));
}
return base
.out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.define("LLVM_ENABLE_ASSERTIONS", assertions)
- .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
+ .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
+ // On emscripten we don't actually need the C compiler to just
+ // build the target artifacts, only for testing. For the sake
+ // of easier bot configuration, just skip detection.
+ if target.contains("emscripten") {
+ continue;
+ }
+
need_cmd(build.cc(target).as_ref());
if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref());
need_cmd(build.cxx(host).as_ref());
}
+ // The msvc hosts don't use jemalloc, turn it off globally to
+ // avoid packaging the dummy liballoc_jemalloc on that platform.
+ for host in build.config.host.iter() {
+ if host.contains("msvc") {
+ build.config.use_jemalloc = false;
+ }
+ }
+
// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
}
for target in build.config.target.iter() {
- // Either can't build or don't want to run jemalloc on these targets
- if target.contains("rumprun") ||
- target.contains("bitrig") ||
- target.contains("openbsd") ||
- target.contains("msvc") ||
- target.contains("emscripten") {
- build.config.use_jemalloc = false;
- }
-
// Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
self.check_crate_std(compiler),
self.check_crate_test(compiler),
self.check_debuginfo(compiler),
- self.dist(stage),
];
// If we're testing the build triple, then we know we can
// misc
self.check_linkcheck(stage),
self.check_tidy(stage),
+
+ // can we make the distributables?
+ self.dist(stage),
]);
}
return base
-Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89
+Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356
return v.iter().fold(0, |a, &b| a + b);
}
// Borrow two vectors and sum them.
- // This kind of borrowing does not allow mutation to the borrowed.
+ // This kind of borrowing does not allow mutation through the borrowed reference.
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
let s1 = sum_vec(v1);
found, `.deref()` is called and the compiler continues to search for the method
implementation in the returned type `U`.
+## The `Send` trait
+
+The `Send` trait indicates that a value of this type is safe to send from one
+thread to another.
+
+## The 'Sync' trait
+
+The 'Sync' trait indicates that a value of this type is safe to share between
+multiple threads.
+
# Memory model
A Rust program's memory consists of a static set of *items* and a *heap*.
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);
/// the destructor of `T` and free the allocated memory. Since the
/// way `Box` allocates and releases memory is unspecified, the
/// only valid pointer to pass to this function is the one taken
- /// from another `Box` via the `Box::into_raw` function.
+ /// from another `Box` via the [`Box::into_raw`] function.
///
/// This function is unsafe because improper use may lead to
/// memory problems. For example, a double-free may occur if the
/// function is called twice on the same raw pointer.
///
+ /// [`Box::into_raw`]: struct.Box.html#method.into_raw
+ ///
/// # Examples
///
/// ```
/// memory previously managed by the `Box`. In particular, the
/// caller should properly destroy `T` and release the memory. The
/// proper way to do so is to convert the raw pointer back into a
- /// `Box` with the `Box::from_raw` function.
+ /// `Box` with the [`Box::from_raw`] function.
///
/// Note: this is an associated function, which means that you have
/// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
/// is so that there is no conflict with a method on the inner type.
///
+ /// [`Box::from_raw`]: struct.Box.html#method.from_raw
+ ///
/// # Examples
///
/// ```
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let src_dir = env::current_dir().unwrap();
+ // FIXME: This is a hack to support building targets that don't
+ // support jemalloc alongside hosts that do. The jemalloc build is
+ // controlled by a feature of the std crate, and if that feature
+ // changes between targets, it invalidates the fingerprint of
+ // std's build script (this is a cargo bug); so we must ensure
+ // that the feature set used by std is the same across all
+ // targets, which means we have to build the alloc_jemalloc crate
+ // for targets like emscripten, even if we don't use it.
+ if target.contains("rumprun") ||
+ target.contains("bitrig") ||
+ target.contains("openbsd") ||
+ target.contains("msvc") ||
+ target.contains("emscripten")
+ {
+ println!("cargo:rustc-cfg=dummy_jemalloc");
+ return;
+ }
+
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
let jemalloc = PathBuf::from(jemalloc);
println!("cargo:rustc-link-search=native={}",
extern crate libc;
-use libc::{c_int, c_void, size_t};
+pub use imp::*;
-// Linkage directives to pull in jemalloc and its dependencies.
-//
-// On some platforms we need to be sure to link in `pthread` which jemalloc
-// depends on, and specifically on android we need to also link to libgcc.
-// Currently jemalloc is compiled with gcc which will generate calls to
-// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
-// libcompiler-rt), so link that in to get that support.
-#[link(name = "jemalloc", kind = "static")]
-#[cfg_attr(target_os = "android", link(name = "gcc"))]
-#[cfg_attr(all(not(windows),
- not(target_os = "android"),
- not(target_env = "musl")),
- link(name = "pthread"))]
-#[cfg(not(cargobuild))]
-extern "C" {}
-
-// Note that the symbols here are prefixed by default on OSX and Windows (we
-// don't explicitly request it), and on Android and DragonFly we explicitly
-// request it as unprefixing cause segfaults (mismatches in allocators).
-extern "C" {
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
- link_name = "je_mallocx")]
- fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
- link_name = "je_rallocx")]
- fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
- link_name = "je_xallocx")]
- fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
- link_name = "je_sdallocx")]
- fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
- link_name = "je_nallocx")]
- fn nallocx(size: size_t, flags: c_int) -> size_t;
-}
+// See comments in build.rs for why we sometimes build a crate that does nothing
+#[cfg(not(dummy_jemalloc))]
+mod imp {
+ use libc::{c_int, c_void, size_t};
-// The minimum alignment guaranteed by the architecture. This value is used to
-// add fast paths for low alignment values. In practice, the alignment is a
-// constant at the call site and the branch will be optimized out.
-#[cfg(all(any(target_arch = "arm",
- target_arch = "mips",
- target_arch = "powerpc")))]
-const MIN_ALIGN: usize = 8;
-#[cfg(all(any(target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "aarch64",
- target_arch = "powerpc64",
- target_arch = "mips64",
- target_arch = "s390x")))]
-const MIN_ALIGN: usize = 16;
-
-// MALLOCX_ALIGN(a) macro
-fn mallocx_align(a: usize) -> c_int {
- a.trailing_zeros() as c_int
-}
+ // Linkage directives to pull in jemalloc and its dependencies.
+ //
+ // On some platforms we need to be sure to link in `pthread` which jemalloc
+ // depends on, and specifically on android we need to also link to libgcc.
+ // Currently jemalloc is compiled with gcc which will generate calls to
+ // intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
+ // libcompiler-rt), so link that in to get that support.
+ #[link(name = "jemalloc", kind = "static")]
+ #[cfg_attr(target_os = "android", link(name = "gcc"))]
+ #[cfg_attr(all(not(windows),
+ not(target_os = "android"),
+ not(target_env = "musl")),
+ link(name = "pthread"))]
+ #[cfg(not(cargobuild))]
+ extern "C" {}
+
+ // Note that the symbols here are prefixed by default on OSX and Windows (we
+ // don't explicitly request it), and on Android and DragonFly we explicitly
+ // request it as unprefixing cause segfaults (mismatches in allocators).
+ extern "C" {
+ #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+ target_os = "dragonfly", target_os = "windows"),
+ link_name = "je_mallocx")]
+ fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
+ #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+ target_os = "dragonfly", target_os = "windows"),
+ link_name = "je_rallocx")]
+ fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
+ #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+ target_os = "dragonfly", target_os = "windows"),
+ link_name = "je_xallocx")]
+ fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
+ #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+ target_os = "dragonfly", target_os = "windows"),
+ link_name = "je_sdallocx")]
+ fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
+ #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+ target_os = "dragonfly", target_os = "windows"),
+ link_name = "je_nallocx")]
+ fn nallocx(size: size_t, flags: c_int) -> size_t;
+ }
+
+ // The minimum alignment guaranteed by the architecture. This value is used to
+ // add fast paths for low alignment values. In practice, the alignment is a
+ // constant at the call site and the branch will be optimized out.
+ #[cfg(all(any(target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "powerpc")))]
+ const MIN_ALIGN: usize = 8;
+ #[cfg(all(any(target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "powerpc64",
+ target_arch = "mips64",
+ target_arch = "s390x")))]
+ const MIN_ALIGN: usize = 16;
+
+ // MALLOCX_ALIGN(a) macro
+ fn mallocx_align(a: usize) -> c_int {
+ a.trailing_zeros() as c_int
+ }
+
+ fn align_to_flags(align: usize) -> c_int {
+ if align <= MIN_ALIGN {
+ 0
+ } else {
+ mallocx_align(align)
+ }
+ }
+
+ #[no_mangle]
+ pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+ let flags = align_to_flags(align);
+ unsafe { mallocx(size as size_t, flags) as *mut u8 }
+ }
+
+ #[no_mangle]
+ pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> *mut u8 {
+ let flags = align_to_flags(align);
+ unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
+ }
+
+ #[no_mangle]
+ pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
+ let flags = align_to_flags(align);
+ unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
+ }
-fn align_to_flags(align: usize) -> c_int {
- if align <= MIN_ALIGN {
+ #[no_mangle]
+ pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+ let flags = align_to_flags(align);
+ unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
+ }
+
+ #[no_mangle]
+ pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
+ let flags = align_to_flags(align);
+ unsafe { nallocx(size as size_t, flags) as usize }
+ }
+
+ // These symbols are used by jemalloc on android but the really old android
+ // we're building on doesn't have them defined, so just make sure the symbols
+ // are available.
+ #[no_mangle]
+ #[cfg(target_os = "android")]
+ pub extern "C" fn pthread_atfork(_prefork: *mut u8,
+ _postfork_parent: *mut u8,
+ _postfork_child: *mut u8)
+ -> i32 {
0
- } else {
- mallocx_align(align)
}
}
-#[no_mangle]
-pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
- let flags = align_to_flags(align);
- unsafe { mallocx(size as size_t, flags) as *mut u8 }
-}
+#[cfg(dummy_jemalloc)]
+mod imp {
+ fn bogus() -> ! {
+ panic!("jemalloc is not implemented for this platform");
+ }
-#[no_mangle]
-pub extern "C" fn __rust_reallocate(ptr: *mut u8,
- _old_size: usize,
- size: usize,
- align: usize)
- -> *mut u8 {
- let flags = align_to_flags(align);
- unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
-}
+ #[no_mangle]
+ pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
+ bogus()
+ }
-#[no_mangle]
-pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
- _old_size: usize,
- size: usize,
- align: usize)
- -> usize {
- let flags = align_to_flags(align);
- unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
-}
+ #[no_mangle]
+ pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
+ _old_size: usize,
+ _size: usize,
+ _align: usize)
+ -> *mut u8 {
+ bogus()
+ }
-#[no_mangle]
-pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
- let flags = align_to_flags(align);
- unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
-}
+ #[no_mangle]
+ pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
+ _old_size: usize,
+ _size: usize,
+ _align: usize)
+ -> usize {
+ bogus()
+ }
-#[no_mangle]
-pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
- let flags = align_to_flags(align);
- unsafe { nallocx(size as size_t, flags) as usize }
-}
+ #[no_mangle]
+ pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
+ bogus()
+ }
-// These symbols are used by jemalloc on android but the really old android
-// we're building on doesn't have them defined, so just make sure the symbols
-// are available.
-#[no_mangle]
-#[cfg(target_os = "android")]
-pub extern "C" fn pthread_atfork(_prefork: *mut u8,
- _postfork_parent: *mut u8,
- _postfork_child: *mut u8)
- -> i32 {
- 0
+ #[no_mangle]
+ pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
+ bogus()
+ }
}
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
- target_arch = "asmjs")))]
+ target_arch = "asmjs",
+ target_arch = "wasm32")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
-use core::ops::Deref;
+use core::ops::{Add, AddAssign, Deref};
use fmt;
self
}
}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> Add<&'a str> for Cow<'a, str> {
+ type Output = Cow<'a, str>;
+
+ fn add(self, rhs: &'a str) -> Self {
+ if self == "" {
+ Cow::Borrowed(rhs)
+ } else if rhs == "" {
+ self
+ } else {
+ Cow::Owned(self.into_owned() + rhs)
+ }
+ }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
+ type Output = Cow<'a, str>;
+
+ fn add(self, rhs: Cow<'a, str>) -> Self {
+ if self == "" {
+ rhs
+ } else if rhs == "" {
+ self
+ } else {
+ Cow::Owned(self.into_owned() + rhs.borrow())
+ }
+ }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> AddAssign<&'a str> for Cow<'a, str> {
+ fn add_assign(&mut self, rhs: &'a str) {
+ if rhs == "" { return; }
+ self.to_mut().push_str(rhs);
+ }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
+ fn add_assign(&mut self, rhs: Cow<'a, str>) {
+ if rhs == "" { return; }
+ self.to_mut().push_str(rhs.borrow());
+ }
+}
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
core_slice::SliceExt::len(self)
}
- /// Returns true if the slice has a length of 0
+ /// Returns true if the slice has a length of 0.
///
/// # Example
///
core_slice::SliceExt::get_unchecked_mut(self, index)
}
- /// Returns an raw pointer to the slice's buffer
+ /// Returns an raw pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let mut v = ["a", "b", "c", "d"];
/// v.swap(1, 3);
/// assert!(v == ["a", "d", "c", "b"]);
///
/// # Example
///
- /// ```rust
+ /// ```
/// let mut v = [1, 2, 3];
/// v.reverse();
/// assert!(v == [3, 2, 1]);
}
/// Returns an iterator over `size` elements of the slice at a
- /// time. The chunks are slices and do not overlap. If `size` does not divide the
- /// length of the slice, then the last chunk will not have length
- /// `size`.
+ /// time. The chunks are slices and do not overlap. If `size` does
+ /// not divide the length of the slice, then the last chunk will
+ /// not have length `size`.
///
/// # Panics
///
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let mut v = [1, 2, 3, 4, 5, 6];
///
/// // scoped to restrict the lifetime of the borrows
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
+ /// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
/// The last element returned, if any, will contain the remainder of the
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
+ /// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
/// The last element returned, if any, will contain the remainder of the
/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
+ /// the slice and works backwards. The matched element is not contained in
/// the subslices.
///
/// The last element returned, if any, will contain the remainder of the
///
/// Looks up a series of four elements. The first is found, with a
/// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1,4]`.
+ /// found; the fourth could match any position in `[1, 4]`.
///
- /// ```rust
+ /// ```
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
///
/// assert_eq!(s.binary_search(&13), Ok(9));
///
/// Looks up a series of four elements. The first is found, with a
/// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1,4]`.
+ /// found; the fourth could match any position in `[1, 4]`.
///
- /// ```rust
+ /// ```
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
///
/// let seek = 13;
/// Binary search a sorted slice with a key extraction function.
///
/// Assumes that the slice is sorted by the key, for instance with
- /// `sort_by_key` using the same key extraction function.
+ /// [`sort_by_key`] using the same key extraction function.
///
/// If a matching value is found then returns `Ok`, containing the
/// index for the matched element; if no match is found then `Err`
/// is returned, containing the index where a matching element could
/// be inserted while maintaining sorted order.
///
+ /// [`sort_by_key`]: #method.sort_by_key
+ ///
/// # Examples
///
/// Looks up a series of four elements in a slice of pairs sorted by
/// their second elements. The first is found, with a uniquely
/// determined position; the second and third are not found; the
- /// fourth could match any position in `[1,4]`.
+ /// fourth could match any position in `[1, 4]`.
///
- /// ```rust
+ /// ```
/// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
/// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
/// (1, 21), (2, 34), (4, 55)];
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let mut v = [-5, 4, 1, -3, 2];
///
/// v.sort();
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let mut v = [-5i32, 4, 1, -3, 2];
///
/// v.sort_by_key(|k| k.abs());
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let mut v = [5, 4, 1, 3, 2];
/// v.sort_by(|a, b| a.cmp(b));
/// assert!(v == [1, 2, 3, 4, 5]);
///
/// # Example
///
- /// ```rust
+ /// ```
/// let mut dst = [0, 0, 0];
/// let src = [1, 2, 3];
///
///
/// # Example
///
- /// ```rust
+ /// ```
/// let mut dst = [0, 0, 0];
/// let src = [1, 2, 3];
///
///
/// Basic usage:
///
- /// ```rust
+ /// ```
/// let bananas = "bananas";
///
/// assert!(bananas.ends_with("anas"));
///
/// It does _not_ give you:
///
- /// ```rust,ignore
+ /// ```,ignore
/// assert_eq!(d, &["a", "b", "c"]);
/// ```
///
//!
//! There are multiple ways to create a new `String` from a string literal:
//!
-//! ```rust
+//! ```
//! let s = "Hello".to_string();
//!
//! let s = String::from("world");
//! You can create a new `String` from an existing one by concatenating with
//! `+`:
//!
-//! ```rust
+//! ```
//! let s = "Hello".to_string();
//!
//! let message = s + " world!";
//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of
//! it. You can do the reverse too.
//!
-//! ```rust
+//! ```
//! let sparkle_heart = vec![240, 159, 146, 150];
//!
//! // We know these bytes are valid, so we'll use `unwrap()`.
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8),
- _ => self.vec.extend_from_slice(ch.encode_utf8().as_slice()),
+ _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
}
}
let len = self.len();
assert!(idx <= len);
assert!(self.is_char_boundary(idx));
- let bits = ch.encode_utf8();
+ let mut bits = [0; 4];
+ let bits = ch.encode_utf8(&mut bits).as_bytes();
unsafe {
- self.insert_bytes(idx, bits.as_slice());
+ self.insert_bytes(idx, bits);
}
}
///
/// # Examples
///
- /// ```rust
+ /// ```
/// # #![feature(vec_into_iter_as_slice)]
/// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter();
///
/// # Examples
///
- /// ```rust
+ /// ```
/// # #![feature(vec_into_iter_as_slice)]
/// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter();
--- /dev/null
+// Copyright 2012-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.
+
+use std::borrow::Cow;
+
+// check that Cow<'a, str> implements addition
+#[test]
+fn check_cow_add() {
+ borrowed1 = Cow::Borrowed("Hello, ");
+ borrowed2 = Cow::Borrowed("World!");
+ borrow_empty = Cow::Borrowed("");
+
+ owned1 = Cow::Owned("Hi, ".into());
+ owned2 = Cow::Owned("Rustaceans!".into());
+ owned_empty = Cow::Owned("".into());
+
+ assert_eq!("Hello, World!", borrowed1 + borrowed2);
+ assert_eq!("Hello, Rustaceans!", borrowed1 + owned2);
+
+ assert_eq!("Hello, World!", owned1 + borrowed2);
+ assert_eq!("Hello, Rustaceans!", owned1 + owned2);
+
+ if let Cow::Owned(_) = borrowed1 + borrow_empty {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = borrow_empty + borrowed1 {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = borrowed1 + owned_empty {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = owned_empty + borrowed1 {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+}
+
+fn check_cow_add_assign() {
+ borrowed1 = Cow::Borrowed("Hello, ");
+ borrowed2 = Cow::Borrowed("World!");
+ borrow_empty = Cow::Borrowed("");
+
+ owned1 = Cow::Owned("Hi, ".into());
+ owned2 = Cow::Owned("Rustaceans!".into());
+ owned_empty = Cow::Owned("".into());
+
+ let borrowed1clone = borrowed1.clone();
+ borrowed1clone += borrow_empty;
+ assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
+
+ borrowed1clone += owned_empty;
+ assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
+
+ owned1 += borrowed2;
+ borrowed1 += owned2;
+
+ assert_eq!("Hello, World!", owned1);
+ assert_eq!("Hello, Rustaceans!", borrowed1);
+}
}
#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
fn test_box_slice_clone_panics() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[test]
fn test_chars_decoding() {
+ let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(::std::char::from_u32) {
- let bytes = c.encode_utf8();
- let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
+ let s = c.encode_utf8(&mut bytes);
if Some(c) != s.chars().next() {
panic!("character {:x}={} does not decode correctly", c as u32, c);
}
#[test]
fn test_chars_rev_decoding() {
+ let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(::std::char::from_u32) {
- let bytes = c.encode_utf8();
- let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
+ let s = c.encode_utf8(&mut bytes);
if Some(c) != s.chars().rev().next() {
panic!("character {:x}={} does not decode correctly", c as u32, c);
}
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
+
+ // Emscripten's runtime includes all the builtins
+ if target.contains("emscripten") {
+ return;
+ }
+
let cfg = &mut gcc::Config::new();
if target.contains("msvc") {
use char_private::is_printable;
use convert::TryFrom;
use fmt;
+use slice;
use iter::FusedIterator;
use mem::transmute;
#[stable(feature = "core", since = "1.6.0")]
fn len_utf16(self) -> usize;
#[unstable(feature = "unicode", issue = "27784")]
- fn encode_utf8(self) -> EncodeUtf8;
+ fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
#[unstable(feature = "unicode", issue = "27784")]
- fn encode_utf16(self) -> EncodeUtf16;
+ fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
}
#[stable(feature = "core", since = "1.6.0")]
}
#[inline]
- fn encode_utf8(self) -> EncodeUtf8 {
+ fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
let code = self as u32;
- let mut buf = [0; 4];
- let pos = if code < MAX_ONE_B {
- buf[3] = code as u8;
- 3
- } else if code < MAX_TWO_B {
- buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
- buf[3] = (code & 0x3F) as u8 | TAG_CONT;
- 2
- } else if code < MAX_THREE_B {
- buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
- buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
- buf[3] = (code & 0x3F) as u8 | TAG_CONT;
- 1
- } else {
- buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
- buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
- buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
- buf[3] = (code & 0x3F) as u8 | TAG_CONT;
- 0
- };
- EncodeUtf8 { buf: buf, pos: pos }
+ unsafe {
+ let len =
+ if code < MAX_ONE_B && !dst.is_empty() {
+ *dst.get_unchecked_mut(0) = code as u8;
+ 1
+ } else if code < MAX_TWO_B && dst.len() >= 2 {
+ *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
+ *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
+ 2
+ } else if code < MAX_THREE_B && dst.len() >= 3 {
+ *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
+ *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
+ *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
+ 3
+ } else if dst.len() >= 4 {
+ *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
+ *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
+ *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
+ *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
+ 4
+ } else {
+ panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
+ from_u32_unchecked(code).len_utf8(),
+ code,
+ dst.len())
+ };
+ transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
+ }
}
#[inline]
- fn encode_utf16(self) -> EncodeUtf16 {
- let mut buf = [0; 2];
+ fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
let mut code = self as u32;
- let pos = if (code & 0xFFFF) == code {
- // The BMP falls through (assuming non-surrogate, as it should)
- buf[1] = code as u16;
- 1
- } else {
- // Supplementary planes break into surrogates.
- code -= 0x1_0000;
- buf[0] = 0xD800 | ((code >> 10) as u16);
- buf[1] = 0xDC00 | ((code as u16) & 0x3FF);
- 0
- };
- EncodeUtf16 { buf: buf, pos: pos }
+ unsafe {
+ if (code & 0xFFFF) == code && !dst.is_empty() {
+ // The BMP falls through (assuming non-surrogate, as it should)
+ *dst.get_unchecked_mut(0) = code as u16;
+ slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
+ } else if dst.len() >= 2 {
+ // Supplementary planes break into surrogates.
+ code -= 0x1_0000;
+ *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
+ *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
+ slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
+ } else {
+ panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
+ from_u32_unchecked(code).len_utf16(),
+ code,
+ dst.len())
+ }
+ }
}
}
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDebug {}
-/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
-/// value.
-///
-/// Constructed via the `.encode_utf8()` method on `char`.
-#[unstable(feature = "unicode", issue = "27784")]
-#[derive(Debug)]
-pub struct EncodeUtf8 {
- buf: [u8; 4],
- pos: usize,
-}
-
-impl EncodeUtf8 {
- /// Returns the remaining bytes of this iterator as a slice.
- #[unstable(feature = "unicode", issue = "27784")]
- pub fn as_slice(&self) -> &[u8] {
- &self.buf[self.pos..]
- }
-}
-
-#[unstable(feature = "unicode", issue = "27784")]
-impl Iterator for EncodeUtf8 {
- type Item = u8;
-
- fn next(&mut self) -> Option<u8> {
- if self.pos == self.buf.len() {
- None
- } else {
- let ret = Some(self.buf[self.pos]);
- self.pos += 1;
- ret
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.as_slice().iter().size_hint()
- }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-impl FusedIterator for EncodeUtf8 {}
-
-/// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
-/// value.
-///
-/// Constructed via the `.encode_utf16()` method on `char`.
-#[unstable(feature = "unicode", issue = "27784")]
-#[derive(Debug)]
-pub struct EncodeUtf16 {
- buf: [u16; 2],
- pos: usize,
-}
-
-impl EncodeUtf16 {
- /// Returns the remaining bytes of this iterator as a slice.
- #[unstable(feature = "unicode", issue = "27784")]
- pub fn as_slice(&self) -> &[u16] {
- &self.buf[self.pos..]
- }
-}
-
-
-#[unstable(feature = "unicode", issue = "27784")]
-impl Iterator for EncodeUtf16 {
- type Item = u16;
-
- fn next(&mut self) -> Option<u16> {
- if self.pos == self.buf.len() {
- None
- } else {
- let ret = Some(self.buf[self.pos]);
- self.pos += 1;
- ret
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.as_slice().iter().size_hint()
- }
-}
-#[unstable(feature = "fused", issue = "35602")]
-impl FusedIterator for EncodeUtf16 {}
/// An iterator over an iterator of bytes of the characters the bytes represent
/// as UTF-8
//! Functionality for ordering and comparison.
//!
-//! This module defines both `PartialOrd` and `PartialEq` traits which are used
+//! This module defines both [`PartialOrd`] and [`PartialEq`] traits which are used
//! by the compiler to implement comparison operators. Rust programs may
-//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators,
-//! and may implement `PartialEq` to overload the `==` and `!=` operators.
+//! implement [`PartialOrd`] to overload the `<`, `<=`, `>`, and `>=` operators,
+//! and may implement [`PartialEq`] to overload the `==` and `!=` operators.
+//!
+//! [`PartialOrd`]: trait.PartialOrd.html
+//! [`PartialEq`]: trait.PartialEq.html
//!
//! # Examples
//!
/// This function will return an instance of `Error` on error.
#[stable(feature = "fmt_write_char", since = "1.1.0")]
fn write_char(&mut self, c: char) -> Result {
- self.write_str(unsafe {
- str::from_utf8_unchecked(c.encode_utf8().as_slice())
- })
+ self.write_str(c.encode_utf8(&mut [0; 4]))
}
/// Glue for usage of the `write!` macro with implementors of this trait.
/// assert_eq!(output, "Hello world!");
/// ```
///
-/// Please note that using [`write!`][write_macro] might be preferrable. Example:
+/// Please note that using [`write!`] might be preferrable. Example:
///
/// ```
/// use std::fmt::Write;
/// assert_eq!(output, "Hello world!");
/// ```
///
-/// [write_macro]: ../../std/macro.write!.html
+/// [`write!`]: ../../std/macro.write.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(output: &mut Write, args: Arguments) -> Result {
let mut formatter = Formatter {
// Writes the sign if it exists, and then the prefix if it was requested
let write_prefix = |f: &mut Formatter| {
if let Some(c) = sign {
- f.buf.write_str(unsafe {
- str::from_utf8_unchecked(c.encode_utf8().as_slice())
- })?;
+ f.buf.write_str(c.encode_utf8(&mut [0; 4]))?;
}
if prefixed { f.buf.write_str(prefix) }
else { Ok(()) }
rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
};
- let fill = self.fill.encode_utf8();
- let fill = unsafe {
- str::from_utf8_unchecked(fill.as_slice())
- };
+ let mut fill = [0; 4];
+ let fill = self.fill.encode_utf8(&mut fill);
for _ in 0..pre_pad {
self.buf.write_str(fill)?;
if f.width.is_none() && f.precision.is_none() {
f.write_char(*self)
} else {
- f.pad(unsafe {
- str::from_utf8_unchecked(self.encode_utf8().as_slice())
- })
+ f.pad(self.encode_utf8(&mut [0; 4]))
}
}
}
// Implementation of Display/Debug for various core types
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for *const T {
+impl<T: ?Sized> Debug for *const T {
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for *mut T {
+impl<T: ?Sized> Debug for *mut T {
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
}
#![stable(feature = "rust1", since = "1.0.0")]
+use clone;
+use cmp;
+use fmt;
+use hash;
use intrinsics;
+use marker::{Copy, PhantomData, Sized};
use ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
ptr::read(src as *const T as *const U)
}
+
+/// Opaque type representing the discriminant of an enum.
+///
+/// See the `discriminant` function in this module for more information.
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+pub struct Discriminant<T>(u64, PhantomData<*const T>);
+
+// N.B. These trait implementations cannot be derived because we don't want any bounds on T.
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> Copy for Discriminant<T> {}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> clone::Clone for Discriminant<T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> cmp::PartialEq for Discriminant<T> {
+ fn eq(&self, rhs: &Self) -> bool {
+ self.0 == rhs.0
+ }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> cmp::Eq for Discriminant<T> {}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> hash::Hash for Discriminant<T> {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.0.hash(state);
+ }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> fmt::Debug for Discriminant<T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_tuple("Discriminant")
+ .field(&self.0)
+ .finish()
+ }
+}
+
+/// Returns a value uniquely identifying the enum variant in `v`.
+///
+/// If `T` is not an enum, calling this function will not result in undefined behavior, but the
+/// return value is unspecified.
+///
+/// # Stability
+///
+/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
+/// of some variant will not change between compilations with the same compiler.
+///
+/// # Examples
+///
+/// This can be used to compare enums that carry data, while disregarding
+/// the actual data:
+///
+/// ```
+/// #![feature(discriminant_value)]
+/// use std::mem;
+///
+/// enum Foo { A(&'static str), B(i32), C(i32) }
+///
+/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz")));
+/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2)));
+/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3)));
+/// ```
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+pub fn discriminant<T>(v: &T) -> Discriminant<T> {
+ unsafe {
+ Discriminant(intrinsics::discriminant_value(v), PhantomData)
+ }
+}
+
//!
//! Some of these traits are imported by the prelude, so they are available in
//! every Rust program. Only operators backed by traits can be overloaded. For
-//! example, the addition operator (`+`) can be overloaded through the `Add`
+//! example, the addition operator (`+`) can be overloaded through the [`Add`]
//! trait, but since the assignment operator (`=`) has no backing trait, there
//! is no way of overloading its semantics. Additionally, this module does not
//! provide any mechanism to create new operators. If traitless overloading or
//! contexts involving built-in types, this is usually not a problem.
//! However, using these operators in generic code, requires some
//! attention if values have to be reused as opposed to letting the operators
-//! consume them. One option is to occasionally use `clone()`.
+//! consume them. One option is to occasionally use [`clone()`].
//! Another option is to rely on the types involved providing additional
//! operator implementations for references. For example, for a user-defined
//! type `T` which is supposed to support addition, it is probably a good
-//! idea to have both `T` and `&T` implement the traits `Add<T>` and `Add<&T>`
-//! so that generic code can be written without unnecessary cloning.
+//! idea to have both `T` and `&T` implement the traits [`Add<T>`][`Add`] and
+//! [`Add<&T>`][`Add`] so that generic code can be written without unnecessary
+//! cloning.
//!
//! # Examples
//!
-//! This example creates a `Point` struct that implements `Add` and `Sub`, and
-//! then demonstrates adding and subtracting two `Point`s.
+//! This example creates a `Point` struct that implements [`Add`] and [`Sub`],
+//! and then demonstrates adding and subtracting two `Point`s.
//!
//! ```rust
//! use std::ops::{Add, Sub};
//! See the documentation for each trait for an example implementation.
//!
//! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be
-//! invoked like functions. Note that `Fn` takes `&self`, `FnMut` takes `&mut
-//! self` and `FnOnce` takes `self`. These correspond to the three kinds of
+//! invoked like functions. Note that [`Fn`] takes `&self`, [`FnMut`] takes `&mut
+//! self` and [`FnOnce`] takes `self`. These correspond to the three kinds of
//! methods that can be invoked on an instance: call-by-reference,
//! call-by-mutable-reference, and call-by-value. The most common use of these
//! traits is to act as bounds to higher-level functions that take functions or
//! closures as arguments.
//!
-//! [`Fn`]: trait.Fn.html
-//! [`FnMut`]: trait.FnMut.html
-//! [`FnOnce`]: trait.FnOnce.html
-//!
-//! Taking a `Fn` as a parameter:
+//! Taking a [`Fn`] as a parameter:
//!
//! ```rust
//! fn call_with_one<F>(func: F) -> usize
//! assert_eq!(call_with_one(double), 2);
//! ```
//!
-//! Taking a `FnMut` as a parameter:
+//! Taking a [`FnMut`] as a parameter:
//!
//! ```rust
//! fn do_twice<F>(mut func: F)
//! assert_eq!(x, 5);
//! ```
//!
-//! Taking a `FnOnce` as a parameter:
+//! Taking a [`FnOnce`] as a parameter:
//!
//! ```rust
//! fn consume_with_relish<F>(func: F)
//!
//! // `consume_and_return_x` can no longer be invoked at this point
//! ```
+//!
+//! [`Fn`]: trait.Fn.html
+//! [`FnMut`]: trait.FnMut.html
+//! [`FnOnce`]: trait.FnOnce.html
+//! [`Add`]: trait.Add.html
+//! [`Sub`]: trait.Sub.html
+//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone
#![stable(feature = "rust1", since = "1.0.0")]
shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
/// The `Index` trait is used to specify the functionality of indexing operations
-/// like `arr[idx]` when used in an immutable context.
+/// like `container[index]` when used in an immutable context.
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
type Output: ?Sized;
- /// The method for the indexing (`Foo[Bar]`) operation
+ /// The method for the indexing (`container[index]`) operation
#[stable(feature = "rust1", since = "1.0.0")]
fn index(&self, index: Idx) -> &Self::Output;
}
/// The `IndexMut` trait is used to specify the functionality of indexing
-/// operations like `arr[idx]`, when used in a mutable context.
+/// operations like `container[index]`, when used in a mutable context.
///
/// # Examples
///
-/// A trivial implementation of `IndexMut`. When `Foo[Bar]` happens, it ends up
-/// calling `index_mut`, and therefore, `main` prints `Indexing!`.
+/// A trivial implementation of `IndexMut` for a type `Foo`. When `&mut Foo[2]`
+/// happens, it ends up calling `index_mut`, and therefore, `main` prints
+/// `Mutable indexing with 2!`.
///
/// ```
/// use std::ops::{Index, IndexMut};
///
/// #[derive(Copy, Clone)]
/// struct Foo;
-/// struct Bar;
///
-/// impl Index<Bar> for Foo {
+/// impl Index<usize> for Foo {
/// type Output = Foo;
///
-/// fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
+/// fn index(&self, _index: usize) -> &Foo {
/// self
/// }
/// }
///
-/// impl IndexMut<Bar> for Foo {
-/// fn index_mut<'a>(&'a mut self, _index: Bar) -> &'a mut Foo {
-/// println!("Indexing!");
+/// impl IndexMut<usize> for Foo {
+/// fn index_mut(&mut self, index: usize) -> &mut Foo {
+/// println!("Mutable indexing with {}!", index);
/// self
/// }
/// }
///
/// fn main() {
-/// &mut Foo[Bar];
+/// &mut Foo[2];
/// }
/// ```
#[lang = "index_mut"]
#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
- /// The method for the indexing (`Foo[Bar]`) operation
+ /// The method for the mutable indexing (`container[index]`) operation
#[stable(feature = "rust1", since = "1.0.0")]
fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::char;
+use std::{char,str};
use std::convert::TryFrom;
#[test]
#[test]
fn test_encode_utf8() {
fn check(input: char, expect: &[u8]) {
- assert_eq!(input.encode_utf8().as_slice(), expect);
- for (a, b) in input.encode_utf8().zip(expect) {
- assert_eq!(a, *b);
- }
+ let mut buf = [0; 4];
+ let ptr = buf.as_ptr();
+ let s = input.encode_utf8(&mut buf);
+ assert_eq!(s.as_ptr() as usize, ptr as usize);
+ assert!(str::from_utf8(s.as_bytes()).is_ok());
+ assert_eq!(s.as_bytes(), expect);
}
check('x', &[0x78]);
#[test]
fn test_encode_utf16() {
fn check(input: char, expect: &[u16]) {
- assert_eq!(input.encode_utf16().as_slice(), expect);
- for (a, b) in input.encode_utf16().zip(expect) {
- assert_eq!(a, *b);
- }
+ let mut buf = [0; 2];
+ let ptr = buf.as_mut_ptr();
+ let b = input.encode_utf16(&mut buf);
+ assert_eq!(b.as_mut_ptr() as usize, ptr as usize);
+ assert_eq!(b, expect);
}
check('x', &[0x0078]);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// FIXME https://github.com/kripken/emscripten/issues/4563
+// NB we have to actually not compile this test to avoid
+// an undefined symbol error
+#![cfg(not(target_os = "emscripten"))]
+
use core::num::flt2dec::estimator::*;
#[test]
-Subproject commit eb708c020826a8d792a5a5275be147aabe47fe24
+Subproject commit b474785561d58efbd27add9d22339dcabad742ad
"alloc 0.0.0",
"core 0.0.0",
"libc 0.0.0",
+ "unwind 0.0.0",
]
[[package]]
"core 0.0.0",
]
+[[package]]
+name = "unwind"
+version = "0.0.0"
+dependencies = [
+ "core 0.0.0",
+ "libc 0.0.0",
+]
+
--- /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.
+
+//! Unwinding for emscripten
+//!
+//! Whereas Rust's usual unwinding implementation for Unix platforms
+//! calls into the libunwind APIs directly, on emscripten we instead
+//! call into the C++ unwinding APIs. This is just an expedience since
+//! emscripten's runtime always implements those APIs and does not
+//! implement libunwind.
+
+#![allow(private_no_mangle_fns)]
+
+use core::any::Any;
+use core::ptr;
+use alloc::boxed::Box;
+use libc::{self, c_int};
+use unwind as uw;
+use core::mem;
+
+pub fn payload() -> *mut u8 {
+ ptr::null_mut()
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
+ assert!(!ptr.is_null());
+ let ex = ptr::read(ptr as *mut _);
+ __cxa_free_exception(ptr as *mut _);
+ ex
+}
+
+pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
+ let sz = mem::size_of_val(&data);
+ let exception = __cxa_allocate_exception(sz);
+ if exception == ptr::null_mut() {
+ return uw::_URC_FATAL_PHASE1_ERROR as u32;
+ }
+ let exception = exception as *mut Box<Any + Send>;
+ ptr::write(exception, data);
+ __cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());
+
+ unreachable!()
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+unsafe extern "C" fn rust_eh_personality(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ __gxx_personality_v0(version, actions,
+ exception_class,
+ exception_object,
+ context)
+}
+
+extern {
+ fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
+ fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
+ fn __cxa_throw(thrown_exception: *mut libc::c_void,
+ tinfo: *mut libc::c_void,
+ dest: *mut libc::c_void);
+ fn __gxx_personality_v0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+}
mod imp;
// i686-pc-windows-gnu and all others
-#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
+#[cfg(any(all(unix, not(target_os = "emscripten")),
+ all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"]
mod imp;
+// emscripten
+#[cfg(target_os = "emscripten")]
+#[path = "emcc.rs"]
+mod imp;
+
mod dwarf;
mod windows;
self.add_ast_node(pat.id, &[pats_exit])
}
- PatKind::Vec(ref pre, ref vec, ref post) => {
+ PatKind::Slice(ref pre, ref vec, ref post) => {
let pre_exit = self.pats_all(pre.iter(), pred);
let vec_exit = self.pats_all(vec.iter(), pre_exit);
let post_exit = self.pats_all(post.iter(), vec_exit);
self.add_unreachable_node()
}
- hir::ExprVec(ref elems) => {
+ hir::ExprArray(ref elems) => {
self.straightline(expr, pred, elems.iter().map(|e| &**e))
}
visitor.visit_id(typ.id);
match typ.node {
- TyVec(ref ty) => {
+ TySlice(ref ty) => {
visitor.visit_ty(ty)
}
TyPtr(ref mutable_type) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyFixedLengthVec(ref ty, ref expression) => {
+ TyArray(ref ty, ref expression) => {
visitor.visit_ty(ty);
visitor.visit_expr(expression)
}
visitor.visit_expr(upper_bound)
}
PatKind::Wild => (),
- PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+ PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
walk_list!(visitor, visit_pat, prepatterns);
walk_list!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
ExprBox(ref subexpression) => {
visitor.visit_expr(subexpression)
}
- ExprVec(ref subexpressions) => {
+ ExprArray(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprRepeat(ref element, ref count) => {
}
fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
- use syntax::ast::TyKind::*;
P(hir::Ty {
id: t.id,
node: match t.node {
- Infer | ImplicitSelf => hir::TyInfer,
- Vec(ref ty) => hir::TyVec(self.lower_ty(ty)),
- Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
- Rptr(ref region, ref mt) => {
+ TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
+ TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
+ TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
+ TyKind::Rptr(ref region, ref mt) => {
hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt))
}
- BareFn(ref f) => {
+ TyKind::BareFn(ref f) => {
hir::TyBareFn(P(hir::BareFnTy {
lifetimes: self.lower_lifetime_defs(&f.lifetimes),
unsafety: self.lower_unsafety(f.unsafety),
decl: self.lower_fn_decl(&f.decl),
}))
}
- Never => hir::TyNever,
- Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()),
- Paren(ref ty) => {
+ TyKind::Never => hir::TyNever,
+ TyKind::Tup(ref tys) => {
+ hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect())
+ }
+ TyKind::Paren(ref ty) => {
return self.lower_ty(ty);
}
- Path(ref qself, ref path) => {
+ TyKind::Path(ref qself, ref path) => {
let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
hir::QSelf {
ty: self.lower_ty(ty),
});
hir::TyPath(qself, self.lower_path(path))
}
- ObjectSum(ref ty, ref bounds) => {
+ TyKind::ObjectSum(ref ty, ref bounds) => {
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
- FixedLengthVec(ref ty, ref e) => {
- hir::TyFixedLengthVec(self.lower_ty(ty), self.lower_expr(e))
+ TyKind::Array(ref ty, ref e) => {
+ hir::TyArray(self.lower_ty(ty), self.lower_expr(e))
}
- Typeof(ref expr) => {
+ TyKind::Typeof(ref expr) => {
hir::TyTypeof(self.lower_expr(expr))
}
- PolyTraitRef(ref bounds) => {
+ TyKind::PolyTraitRef(ref bounds) => {
hir::TyPolyTraitRef(self.lower_bounds(bounds))
}
- ImplTrait(ref bounds) => {
+ TyKind::ImplTrait(ref bounds) => {
hir::TyImplTrait(self.lower_bounds(bounds))
}
- Mac(_) => panic!("TyMac should have been expanded by now."),
+ TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
},
span: t.span,
})
PatKind::Range(ref e1, ref e2) => {
hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2))
}
- PatKind::Vec(ref before, ref slice, ref after) => {
- hir::PatKind::Vec(before.iter().map(|x| self.lower_pat(x)).collect(),
+ PatKind::Slice(ref before, ref slice, ref after) => {
+ hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
slice.as_ref().map(|x| self.lower_pat(x)),
after.iter().map(|x| self.lower_pat(x)).collect())
}
}
ExprKind::Vec(ref exprs) => {
- hir::ExprVec(exprs.iter().map(|x| self.lower_expr(x)).collect())
+ hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = self.lower_expr(expr);
fn visit_ty(&mut self, ty: &Ty) {
match ty.node {
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
- TyKind::FixedLengthVec(_, ref length) => self.visit_ast_const_integer(length),
+ TyKind::Array(_, ref length) => self.visit_ast_const_integer(length),
TyKind::ImplTrait(..) => {
self.create_def(ty.id, DefPathData::ImplTrait);
}
}
fn visit_ty(&mut self, ty: &'ast hir::Ty) {
- if let hir::TyFixedLengthVec(_, ref length) = ty.node {
+ if let hir::TyArray(_, ref length) = ty.node {
self.visit_hir_const_integer(length);
}
if let hir::TyImplTrait(..) = ty.node {
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
s.walk_(it)
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
before.iter().all(|p| p.walk_(it)) &&
slice.iter().all(|p| p.walk_(it)) &&
after.iter().all(|p| p.walk_(it))
/// A range pattern, e.g. `1...2`
Range(P<Expr>, P<Expr>),
/// `[a, b, ..i, y, z]` is represented as:
- /// `PatKind::Vec(box [a, b], Some(i), box [y, z])`
- Vec(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
+ /// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
+ Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
/// A `box x` expression.
ExprBox(P<Expr>),
/// An array (`[a, b, c, d]`)
- ExprVec(HirVec<P<Expr>>),
+ ExprArray(HirVec<P<Expr>>),
/// A function call
///
/// The first field resolves to the function itself (usually an `ExprPath`),
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
/// The different kinds of types recognized by the compiler
pub enum Ty_ {
- /// A variable length array (`[T]`)
- TyVec(P<Ty>),
+ /// A variable length slice (`[T]`)
+ TySlice(P<Ty>),
/// A fixed length array (`[T; n]`)
- TyFixedLengthVec(P<Ty>, P<Expr>),
+ TyArray(P<Ty>, P<Expr>),
/// A raw pointer (`*const T` or `*mut T`)
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
_ => false
}
}
- PatKind::Vec(..) => true,
+ PatKind::Slice(..) => true,
_ => false
}
}
self.maybe_print_comment(ty.span.lo)?;
self.ibox(0)?;
match ty.node {
- hir::TyVec(ref ty) => {
+ hir::TySlice(ref ty) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
word(&mut self.s, "]")?;
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
}
- hir::TyFixedLengthVec(ref ty, ref v) => {
+ hir::TyArray(ref ty, ref v) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
word(&mut self.s, "; ")?;
self.word_space("box")?;
self.print_expr(expr)?;
}
- hir::ExprVec(ref exprs) => {
+ hir::ExprArray(ref exprs) => {
self.print_expr_vec(&exprs[..])?;
}
hir::ExprRepeat(ref element, ref count) => {
word(&mut self.s, "...")?;
self.print_expr(&end)?;
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
word(&mut self.s, "[")?;
self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?;
if let Some(ref p) = *slice {
hir::TyPtr(ref mut_ty) => {
ty_queue.push(&mut_ty.ty);
}
- hir::TyVec(ref ty) |
- hir::TyFixedLengthVec(ref ty, _) => {
+ hir::TySlice(ref ty) |
+ hir::TyArray(ref ty, _) => {
ty_queue.push(&ty);
}
hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
ty: build_to(mut_ty.ty, to),
})
}
- hir::TyVec(ty) => hir::TyVec(build_to(ty, to)),
- hir::TyFixedLengthVec(ty, e) => {
- hir::TyFixedLengthVec(build_to(ty, to), e)
+ hir::TySlice(ty) => hir::TySlice(build_to(ty, to)),
+ hir::TyArray(ty, e) => {
+ hir::TyArray(build_to(ty, to), e)
}
hir::TyTup(tys) => {
hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
}
}
- hir::ExprVec(ref exprs) => {
+ hir::ExprArray(ref exprs) => {
self.consume_exprs(exprs);
}
// otherwise, live nodes are not required:
hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
- hir::ExprVec(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
+ hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) |
hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(_) |
hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) |
// Uninteresting cases: just propagate in rev exec order
- hir::ExprVec(ref exprs) => {
+ hir::ExprArray(ref exprs) => {
self.propagate_through_exprs(&exprs[..], succ)
}
hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) |
hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) |
hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
- hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprBinary(..) |
+ hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) |
hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) |
hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) |
hir::ExprBlock(..) | hir::ExprAddrOf(..) |
hir::ExprClosure(..) | hir::ExprRet(..) |
hir::ExprUnary(..) |
hir::ExprMethodCall(..) | hir::ExprCast(..) |
- hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprIf(..) |
+ hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) |
hir::ExprBinary(..) | hir::ExprWhile(..) |
hir::ExprBlock(..) | hir::ExprLoop(..) | hir::ExprMatch(..) |
hir::ExprLit(..) | hir::ExprBreak(..) |
self.cat_pattern_(subcmt, &subpat, op)?;
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
let context = InteriorOffsetKind::Pattern;
let elt_cmt = self.cat_index(pat, cmt, context)?;
for before_pat in before {
field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
}
- PatKind::Vec(ref pats1, ref pats2, ref pats3) => {
+ PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
pats1.iter().any(|p| is_binding_pat(&p)) ||
pats2.iter().any(|p| is_binding_pat(&p)) ||
pats3.iter().any(|p| is_binding_pat(&p))
visitor, &field.expr, blk_id);
}
}
- hir::ExprVec(ref subexprs) |
+ hir::ExprArray(ref subexprs) |
hir::ExprTup(ref subexprs) => {
for subexpr in subexprs {
record_rvalue_scope_if_borrow_expr(
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum AggregateKind<'tcx> {
- Vec,
+ Array,
Tuple,
/// The second field is variant number (discriminant), it's equal to 0
/// for struct and union expressions. The fourth field is active field
}
Aggregate(ref kind, ref lvs) => {
- use self::AggregateKind::*;
-
fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
let mut tuple_fmt = fmt.debug_tuple("");
for lv in lvs {
}
match *kind {
- Vec => write!(fmt, "{:?}", lvs),
+ AggregateKind::Array => write!(fmt, "{:?}", lvs),
- Tuple => {
+ AggregateKind::Tuple => {
match lvs.len() {
0 => write!(fmt, "()"),
1 => write!(fmt, "({:?},)", lvs[0]),
}
}
- Adt(adt_def, variant, substs, _) => {
+ AggregateKind::Adt(adt_def, variant, substs, _) => {
let variant_def = &adt_def.variants[variant];
ppaux::parameterized(fmt, substs, variant_def.did,
}
}
- Closure(def_id, _) => ty::tls::with(|tcx| {
+ AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
let name = format!("[closure@{:?}]", tcx.map.span(node_id));
let mut struct_fmt = fmt.debug_struct(&name);
}
&Rvalue::Aggregate(ref ak, ref ops) => {
match *ak {
- AggregateKind::Vec => {
+ AggregateKind::Array => {
if let Some(operand) = ops.get(0) {
let ty = operand.ty(mir, tcx);
Some(tcx.mk_array(ty, ops.len()))
Rvalue::Aggregate(ref $($mutability)* kind,
ref $($mutability)* operands) => {
match *kind {
- AggregateKind::Vec => {
+ AggregateKind::Array => {
}
AggregateKind::Tuple => {
}
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
- BoxMutability,
- PtrMutability,
- RefMutability,
- VecMutability,
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<usize>),
- TyParamSize(ExpectedFound<usize>),
ArgCount,
RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
RegionsNotSame(&'tcx Region, &'tcx Region),
RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region),
RegionsOverlyPolymorphic(BoundRegion, &'tcx Region),
Sorts(ExpectedFound<Ty<'tcx>>),
- IntegerAsChar,
IntMismatch(ExpectedFound<ty::IntVarValue>),
FloatMismatch(ExpectedFound<ast::FloatTy>),
Traits(ExpectedFound<DefId>),
BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
VariadicMismatch(ExpectedFound<bool>),
CyclicTy,
- ConvergenceMismatch(ExpectedFound<bool>),
ProjectionNameMismatched(ExpectedFound<Name>),
ProjectionBoundsLength(ExpectedFound<usize>),
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
values.found)
}
Mutability => write!(f, "types differ in mutability"),
- BoxMutability => {
- write!(f, "boxed types differ in mutability")
- }
- VecMutability => write!(f, "vectors differ in mutability"),
- PtrMutability => write!(f, "pointers differ in mutability"),
- RefMutability => write!(f, "references differ in mutability"),
- TyParamSize(values) => {
- write!(f, "expected a type with {} type params, \
- found one with {} type params",
- values.expected,
- values.found)
- }
FixedArraySize(values) => {
write!(f, "expected an array with a fixed size of {} elements, \
found one with {} elements",
values.found)
}
}
- IntegerAsChar => {
- write!(f, "expected an integral type, found `char`")
- }
IntMismatch(ref values) => {
write!(f, "expected `{:?}`, found `{:?}`",
values.expected,
if values.expected { "variadic" } else { "non-variadic" },
if values.found { "variadic" } else { "non-variadic" })
}
- ConvergenceMismatch(ref values) => {
- write!(f, "expected {} fn, found {} function",
- if values.expected { "converging" } else { "diverging" },
- if values.found { "converging" } else { "diverging" })
- }
ProjectionNameMismatched(ref values) => {
write!(f, "expected {}, found {}",
values.expected,
FloatSimplifiedType(ast::FloatTy),
AdtSimplifiedType(DefId),
StrSimplifiedType,
- VecSimplifiedType,
+ ArraySimplifiedType,
PtrSimplifiedType,
NeverSimplifiedType,
TupleSimplifiedType(usize),
ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)),
ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)),
ty::TyStr => Some(StrSimplifiedType),
- ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType),
+ ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType),
ty::TyRawPtr(_) => Some(PtrSimplifiedType),
ty::TyTrait(ref trait_info) => {
Some(TraitSimplifiedType(trait_info.principal.def_id()))
/// If true, the size is exact, otherwise it's only a lower bound.
pub sized: bool,
- /// Offsets for the first byte after each field.
- /// That is, field_offset(i) = offset_after_field[i - 1] and the
- /// whole structure's size is the last offset, excluding padding.
- // FIXME(eddyb) use small vector optimization for the common case.
- pub offset_after_field: Vec<Size>
+ /// Offsets for the first byte of each field.
+ /// FIXME(eddyb) use small vector optimization for the common case.
+ pub offsets: Vec<Size>,
+
+ pub min_size: Size,
}
impl<'a, 'gcx, 'tcx> Struct {
align: if packed { dl.i8_align } else { dl.aggregate_align },
packed: packed,
sized: true,
- offset_after_field: vec![]
+ offsets: vec![],
+ min_size: Size::from_bytes(0),
}
}
scapegoat: Ty<'gcx>)
-> Result<(), LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
- self.offset_after_field.reserve(fields.size_hint().0);
+ self.offsets.reserve(fields.size_hint().0);
+
+ let mut offset = self.min_size;
for field in fields {
if !self.sized {
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
- self.offset_after_field.len(), scapegoat);
+ self.offsets.len(), scapegoat);
}
let field = field?;
}
// Invariant: offset < dl.obj_size_bound() <= 1<<61
- let mut offset = if !self.packed {
+ if !self.packed {
let align = field.align(dl);
self.align = self.align.max(align);
- self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {
- *last = last.abi_align(align);
- *last
- })
- } else {
- self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
- };
+ offset = offset.abi_align(align);
+ }
+
+ self.offsets.push(offset);
+
offset = offset.checked_add(field.size(dl), dl)
.map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
-
- self.offset_after_field.push(offset);
}
+ self.min_size = offset;
+
Ok(())
}
/// Get the size without trailing alignment padding.
- pub fn min_size(&self) -> Size {
- self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
- }
/// Get the size with trailing aligment padding.
pub fn stride(&self) -> Size {
- self.min_size().abi_align(self.align)
+ self.min_size.abi_align(self.align)
}
/// Determine whether a structure would be zero-sized, given its fields.
}
Ok(None)
}
-
- pub fn offset_of_field(&self, index: usize) -> Size {
- assert!(index < self.offset_after_field.len());
- if index == 0 {
- Size::from_bytes(0)
- } else {
- self.offset_after_field[index-1]
- }
- }
}
/// An untagged union.
});
let mut st = Struct::new(dl, false);
st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
- size = cmp::max(size, st.min_size());
+ size = cmp::max(size, st.min_size);
align = align.max(st.align);
Ok(st)
}).collect::<Result<Vec<_>, _>>()?;
let old_ity_size = Int(min_ity).size(dl);
let new_ity_size = Int(ity).size(dl);
for variant in &mut variants {
- for offset in &mut variant.offset_after_field {
+ for offset in &mut variant.offsets[1..] {
if *offset > old_ity_size {
break;
}
*offset = new_ity_size;
}
+ // We might be making the struct larger.
+ if variant.min_size <= old_ity_size {
+ variant.min_size = new_ity_size;
+ }
}
}
hir::ExprClosure(..) |
hir::ExprBlock(..) |
hir::ExprRepeat(..) |
- hir::ExprVec(..) |
+ hir::ExprArray(..) |
hir::ExprBreak(..) |
hir::ExprAgain(..) |
hir::ExprRet(..) |
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
- BoxMutability => BoxMutability,
- PtrMutability => PtrMutability,
- RefMutability => RefMutability,
- VecMutability => VecMutability,
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
- TyParamSize(x) => TyParamSize(x),
ArgCount => ArgCount,
RegionsDoesNotOutlive(a, b) => {
return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
RegionsOverlyPolymorphic(a, b) => {
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
}
- IntegerAsChar => IntegerAsChar,
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
Traits(x) => Traits(x),
BuiltinBoundsMismatch(x) => BuiltinBoundsMismatch(x),
VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy,
- ConvergenceMismatch(x) => ConvergenceMismatch(x),
ProjectionNameMismatched(x) => ProjectionNameMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
use hir::def_id::DefId;
use infer::InferCtxt;
+use hir::map as ast_map;
use hir::pat_util;
use traits::{self, Reveal};
use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
}
}
+// When hashing a type this ends up affecting properties like symbol names. We
+// want these symbol names to be calculated independent of other factors like
+// what architecture you're compiling *from*.
+//
+// The hashing just uses the standard `Hash` trait, but the implementations of
+// `Hash` for the `usize` and `isize` types are *not* architecture independent
+// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
+// `isize` completely when hashing. To ensure that these don't leak in we use a
+// custom hasher implementation here which inflates the size of these to a `u64`
+// and `i64`.
+struct WidenUsizeHasher<H> {
+ inner: H,
+}
+
+impl<H> WidenUsizeHasher<H> {
+ fn new(inner: H) -> WidenUsizeHasher<H> {
+ WidenUsizeHasher { inner: inner }
+ }
+}
+
+impl<H: Hasher> Hasher for WidenUsizeHasher<H> {
+ fn write(&mut self, bytes: &[u8]) {
+ self.inner.write(bytes)
+ }
+
+ fn finish(&self) -> u64 {
+ self.inner.finish()
+ }
+
+ fn write_u8(&mut self, i: u8) {
+ self.inner.write_u8(i)
+ }
+ fn write_u16(&mut self, i: u16) {
+ self.inner.write_u16(i)
+ }
+ fn write_u32(&mut self, i: u32) {
+ self.inner.write_u32(i)
+ }
+ fn write_u64(&mut self, i: u64) {
+ self.inner.write_u64(i)
+ }
+ fn write_usize(&mut self, i: usize) {
+ self.inner.write_u64(i as u64)
+ }
+ fn write_i8(&mut self, i: i8) {
+ self.inner.write_i8(i)
+ }
+ fn write_i16(&mut self, i: i16) {
+ self.inner.write_i16(i)
+ }
+ fn write_i32(&mut self, i: i32) {
+ self.inner.write_i32(i)
+ }
+ fn write_i64(&mut self, i: i64) {
+ self.inner.write_i64(i)
+ }
+ fn write_isize(&mut self, i: isize) {
+ self.inner.write_i64(i as i64)
+ }
+}
+
pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- state: H
+ state: WidenUsizeHasher<H>,
}
impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self {
TypeIdHasher {
tcx: tcx,
- state: state
+ state: WidenUsizeHasher::new(state),
}
}
fn def_id(&mut self, did: DefId) {
// Hash the DefPath corresponding to the DefId, which is independent
// of compiler internal state.
- let tcx = self.tcx;
- let def_path = tcx.def_path(did);
- def_path.deterministic_hash_to(tcx, &mut self.state);
+ let path = self.tcx.def_path(did);
+ self.def_path(&path)
+ }
+
+ pub fn def_path(&mut self, def_path: &ast_map::DefPath) {
+ def_path.deterministic_hash_to(self.tcx, &mut self.state);
}
}
TyInt(i) => self.hash(i),
TyUint(u) => self.hash(u),
TyFloat(f) => self.hash(f),
- TyArray(_, n) => self.hash(n as u64),
+ TyArray(_, n) => self.hash(n),
TyRawPtr(m) |
TyRef(_, m) => self.hash(m.mutbl),
TyClosure(def_id, _) |
self.hash(f.unsafety);
self.hash(f.abi);
self.hash(f.sig.variadic());
- self.hash(f.sig.inputs().skip_binder().len() as u64);
+ self.hash(f.sig.inputs().skip_binder().len());
}
TyTrait(ref data) => {
self.def_id(data.principal.def_id());
self.hash(data.builtin_bounds);
}
TyTuple(tys) => {
- self.hash(tys.len() as u64);
+ self.hash(tys.len());
}
TyParam(p) => {
self.hash(p.idx);
allow_asm: false,
obj_is_bitcode: true,
max_atomic_width: 32,
+ post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
.. Default::default()
};
Ok(Target {
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd),
- ("i686_unknown_haiku", i686_unknown_haiku),
- ("x86_64_unknown_haiku", x86_64_unknown_haiku),
+ ("i686-unknown-haiku", i686_unknown_haiku),
+ ("x86_64-unknown-haiku", x86_64_unknown_haiku),
("x86_64-apple-darwin", x86_64_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
("i586-pc-windows-msvc", i586_pc_windows_msvc),
("le32-unknown-nacl", le32_unknown_nacl),
- ("asmjs-unknown-emscripten", asmjs_unknown_emscripten)
+ ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
+ ("wasm32-unknown-emscripten", wasm32_unknown_emscripten)
}
/// Everything `rustc` knows about how to compile for a specific target.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{Target, TargetOptions};
+
+pub fn target() -> Result<Target, String> {
+ let opts = TargetOptions {
+ linker: "emcc".to_string(),
+ ar: "emar".to_string(),
+
+ dynamic_linking: false,
+ executables: true,
+ // Today emcc emits two files - a .js file to bootstrap and
+ // possibly interpret the wasm, and a .wasm file
+ exe_suffix: ".js".to_string(),
+ linker_is_gnu: true,
+ allow_asm: false,
+ obj_is_bitcode: true,
+ max_atomic_width: 32,
+ post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
+ "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+ .. Default::default()
+ };
+ Ok(Target {
+ llvm_target: "asmjs-unknown-emscripten".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_os: "emscripten".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
+ arch: "wasm32".to_string(),
+ options: opts,
+ })
+}
}
PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)),
PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl),
- PatKind::Vec(before, slice, after) => {
- PatKind::Vec(before.move_map(|x| self.fold_pat(x)),
- slice.map(|x| self.fold_pat(x)),
- after.move_map(|x| self.fold_pat(x)))
+ PatKind::Slice(before, slice, after) => {
+ PatKind::Slice(before.move_map(|x| self.fold_pat(x)),
+ slice.map(|x| self.fold_pat(x)),
+ after.move_map(|x| self.fold_pat(x)))
}
PatKind::Wild |
PatKind::Lit(_) |
ty::TySlice(_) => match ctor {
&Slice(n) => {
assert_eq!(pats_len, n);
- PatKind::Vec(pats.collect(), None, hir::HirVec::new())
+ PatKind::Slice(pats.collect(), None, hir::HirVec::new())
},
_ => unreachable!()
},
ty::TyArray(_, len) => {
assert_eq!(pats_len, len);
- PatKind::Vec(pats.collect(), None, hir::HirVec::new())
+ PatKind::Slice(pats.collect(), None, hir::HirVec::new())
}
_ => {
};
let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node {
- PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()),
+ PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
_ => None
}).max().map_or(0, |v| v + 1);
vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
PatKind::Range(ref lo, ref hi) =>
vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))],
- PatKind::Vec(ref before, ref slice, ref after) =>
+ PatKind::Slice(ref before, ref slice, ref after) =>
match left_ty.sty {
ty::TyArray(..) => vec![Single],
ty::TySlice(_) if slice.is_some() => {
}
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
let pat_len = before.len() + after.len();
match *constructor {
Single => {
PatKind::Struct(path.clone(), field_pats, false)
}
- hir::ExprVec(ref exprs) => {
+ hir::ExprArray(ref exprs) => {
let pats = exprs.iter()
.map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
.collect::<Result<_, _>>()?;
- PatKind::Vec(pats, None, hir::HirVec::new())
+ PatKind::Slice(pats, None, hir::HirVec::new())
}
hir::ExprPath(_, ref path) => {
Array(_, n) if idx >= n => {
signal!(e, IndexOutOfBounds { len: n, index: idx })
}
- Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+ Array(v, n) => if let hir::ExprArray(ref v) = tcx.map.expect_expr(v).node {
assert_eq!(n as usize as u64, n);
eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
} else {
_ => signal!(e, IndexedNonVec),
}
}
- hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
+ hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
hir::ExprRepeat(_, ref n) => {
let len_hint = ty_hint.checked_or(tcx.types.usize);
Repeat(
}
let thread = cfg.spawn(move || {
- io::set_panic(box err);
+ io::set_panic(Some(box err));
f()
});
// Panic so the process returns a failure code, but don't pollute the
// output with some unnecessary panic messages, we've already
// printed everything that we needed to.
- io::set_panic(box io::sink());
+ io::set_panic(Some(box io::sink()));
panic!();
}
SawExprAgain(Option<token::InternedString>),
SawExprBox,
- SawExprVec,
+ SawExprArray,
SawExprCall,
SawExprMethodCall,
SawExprTup,
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
match *node {
ExprBox(..) => SawExprBox,
- ExprVec(..) => SawExprVec,
+ ExprArray(..) => SawExprArray,
ExprCall(..) => SawExprCall,
ExprMethodCall(..) => SawExprMethodCall,
ExprTup(..) => SawExprTup,
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant
- let bytes = variant_layout.min_size().bytes()
+ let bytes = variant_layout.min_size.bytes()
.saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
let host = env::var("HOST").expect("HOST was not set");
let is_crossed = target != host;
- let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"];
+ let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz",
+ "jsbackend"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
LLVMInitializeSystemZTargetMC,
LLVMInitializeSystemZAsmPrinter,
LLVMInitializeSystemZAsmParser);
+ init_target!(llvm_component = "jsbackend",
+ LLVMInitializeJSBackendTargetInfo,
+ LLVMInitializeJSBackendTarget,
+ LLVMInitializeJSBackendTargetMC);
}
pub fn last_error() -> Option<String> {
let link_meta = self.link_meta;
let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro);
let root = self.lazy(&CrateRoot {
- rustc_version: RUSTC_VERSION.to_string(),
+ rustc_version: rustc_version(),
name: link_meta.crate_name.clone(),
triple: tcx.sess.opts.target_triple.clone(),
hash: link_meta.crate_hash,
//! metadata::loader or metadata::creader for all the juicy details!
use cstore::MetadataBlob;
-use schema::{METADATA_HEADER, RUSTC_VERSION};
+use schema::{METADATA_HEADER, rustc_version};
use rustc::hir::svh::Svh;
use rustc::session::Session;
}
if !self.rejected_via_version.is_empty() {
err.help(&format!("please recompile that crate using this compiler ({})",
- RUSTC_VERSION));
+ rustc_version()));
let mismatches = self.rejected_via_version.iter();
for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() {
err.note(&format!("crate `{}` path #{}: {} compiled by {:?}",
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
let root = metadata.get_root();
- if root.rustc_version != RUSTC_VERSION {
+ let rustc_version = rustc_version();
+ if root.rustc_version != rustc_version {
info!("Rejecting via version: expected {} got {}",
- RUSTC_VERSION, root.rustc_version);
+ rustc_version, root.rustc_version);
self.rejected_via_version.push(CrateMismatch {
path: libpath.to_path_buf(),
got: root.rustc_version
use std::marker::PhantomData;
-#[cfg(not(test))]
-pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION"));
-
-#[cfg(test)]
-pub const RUSTC_VERSION: &'static str = "rustc 0.0.0-unit-test";
+pub fn rustc_version() -> String {
+ format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version"))
+}
/// Metadata encoding version.
/// NB: increment this if you change the format of metadata such that
.map(|f| unpack!(block = this.as_operand(block, f)))
.collect();
- block.and(Rvalue::Aggregate(AggregateKind::Vec, fields))
+ block.and(Rvalue::Aggregate(AggregateKind::Array, fields))
}
ExprKind::Tuple { fields } => { // see (*) above
// first process the set of fields
value: value.to_ref(),
value_extents: cx.tcx.region_maps.node_extent(value.id)
},
- hir::ExprVec(ref fields) =>
+ hir::ExprArray(ref fields) =>
ExprKind::Vec { fields: fields.to_ref() },
hir::ExprTup(ref fields) =>
ExprKind::Tuple { fields: fields.to_ref() },
PatternKind::Deref { subpattern: self.to_pattern(subpattern) }
}
- PatKind::Vec(ref prefix, ref slice, ref suffix) => {
+ PatKind::Slice(ref prefix, ref slice, ref suffix) => {
let ty = self.cx.tcx.node_id_to_type(pat.id);
match ty.sty {
ty::TyRef(_, mt) =>
// Array lengths, i.e. [T; constant].
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyFixedLengthVec(_, ref length) = ty.node {
+ if let hir::TyArray(_, ref length) = ty.node {
self.build_const_integer(length);
}
intravisit::walk_ty(self, ty);
hir::ExprIndex(..) |
hir::ExprField(..) |
hir::ExprTupField(..) |
- hir::ExprVec(_) |
+ hir::ExprArray(_) |
hir::ExprType(..) |
hir::ExprTup(..) => {}
} else {
// danger, shouldn't be ident?
names.push(token::intern("<opaque>"));
- collect_mod(names, module);
+ collect_mod(names, module.parent.unwrap());
}
}
collect_mod(&mut names, module);
let mut def_collector = DefCollector::new(&mut self.definitions);
def_collector.visit_macro_invoc = Some(visit_macro_invoc);
- def_collector.with_parent(def_index, |def_collector| if !const_integer {
+ def_collector.with_parent(def_index, |def_collector| {
+ if const_integer {
+ if let Expansion::Expr(ref expr) = *expansion {
+ def_collector.visit_ast_const_integer(expr);
+ }
+ }
expansion.visit_with(def_collector)
- } else if let Expansion::Expr(ref expr) = *expansion {
- def_collector.visit_ast_const_integer(expr);
});
}
}
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
"s390x" => cabi_s390x::compute_abi_info(ccx, self),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
+ "wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}
let meta = val.meta;
- let offset = st.offset_of_field(ix).bytes();
+ let offset = st.offsets[ix].bytes();
let unaligned_offset = C_uint(bcx.ccx(), offset);
// Get the alignment of the field
let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
let mut vals_with_discr = vec![lldiscr];
vals_with_discr.extend_from_slice(vals);
- let mut contents = build_const_struct(ccx, &variant.offset_after_field[..],
- &vals_with_discr[..], variant.packed);
- let needed_padding = l.size(dl).bytes() - variant.min_size().bytes();
+ let mut contents = build_const_struct(ccx, &variant,
+ &vals_with_discr[..]);
+ let needed_padding = l.size(dl).bytes() - variant.min_size.bytes();
if needed_padding > 0 {
contents.push(padding(ccx, needed_padding));
}
layout::Univariant { ref variant, .. } => {
assert_eq!(discr, Disr(0));
let contents = build_const_struct(ccx,
- &variant.offset_after_field[..], vals, variant.packed);
+ &variant, vals);
C_struct(ccx, &contents[..], variant.packed)
}
layout::Vector { .. } => {
}
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
if discr.0 == nndiscr {
- C_struct(ccx, &build_const_struct(ccx,
- &nonnull.offset_after_field[..],
- vals, nonnull.packed),
+ C_struct(ccx, &build_const_struct(ccx, &nonnull, vals),
false)
} else {
let fields = compute_fields(ccx, t, nndiscr as usize, false);
// field; see #8506.
C_null(type_of::sizing_type_of(ccx, ty))
}).collect::<Vec<ValueRef>>();
- C_struct(ccx, &build_const_struct(ccx,
- &nonnull.offset_after_field[..],
- &vals[..],
- false),
+ C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]),
false)
}
}
/// a two-element struct will locate it at offset 4, and accesses to it
/// will read the wrong memory.
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- offset_after_field: &[layout::Size],
- vals: &[ValueRef],
- packed: bool)
+ st: &layout::Struct,
+ vals: &[ValueRef])
-> Vec<ValueRef> {
- assert_eq!(vals.len(), offset_after_field.len());
+ assert_eq!(vals.len(), st.offsets.len());
if vals.len() == 0 {
return Vec::new();
// offset of current value
let mut offset = 0;
let mut cfields = Vec::new();
- let target_offsets = offset_after_field.iter().map(|i| i.bytes());
- for (&val, target_offset) in vals.iter().zip(target_offsets) {
- assert!(!is_undef(val));
- cfields.push(val);
- offset += machine::llsize_of_alloc(ccx, val_ty(val));
- if !packed {
- let val_align = machine::llalign_of_min(ccx, val_ty(val));
- offset = roundup(offset, val_align);
- }
- if offset != target_offset {
+ let offsets = st.offsets.iter().map(|i| i.bytes());
+ for (&val, target_offset) in vals.iter().zip(offsets) {
+ if offset < target_offset {
cfields.push(padding(ccx, target_offset - offset));
offset = target_offset;
}
+ assert!(!is_undef(val));
+ cfields.push(val);
+ offset += machine::llsize_of_alloc(ccx, val_ty(val));
}
- let size = offset_after_field.last().unwrap();
- if offset < size.bytes() {
- cfields.push(padding(ccx, size.bytes() - offset));
+ if offset < st.min_size.bytes() {
+ cfields.push(padding(ccx, st.min_size.bytes() - offset));
}
cfields
let mut hash_state = scx.symbol_hasher().borrow_mut();
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
hash_state.reset();
- let mut hasher = Sha256Hasher(&mut hash_state);
+ let hasher = Sha256Hasher(&mut hash_state);
+ let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
// the main symbol name is not necessarily unique; hash in the
// compiler's internal def-path, guaranteeing each symbol has a
// truly unique path
- def_path.deterministic_hash_to(tcx, &mut hasher);
+ hasher.def_path(def_path);
// Include the main item-type. Note that, in this case, the
// assertions about `needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway.
- let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
assert!(!item_type.has_erasable_regions());
hasher.visit_ty(item_type);
Layout::FatPointer { .. } => true,
Layout::Univariant { ref variant, .. } => {
// There must be only 2 fields.
- if variant.offset_after_field.len() != 2 {
+ if variant.offsets.len() != 2 {
return false;
}
let layout = ccx.layout_of(t);
debug!("DST {} layout: {:?}", t, layout);
- // Returns size in bytes of all fields except the last one
- // (we will be recursing on the last one).
- fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 {
- let fields = variant.offset_after_field.len();
- if fields > 1 {
- variant.offset_after_field[fields - 2].bytes()
- } else {
- 0
- }
- }
-
let (sized_size, sized_align) = match *layout {
ty::layout::Layout::Univariant { ref variant, .. } => {
- (local_prefix_bytes(variant), variant.align.abi())
+ (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi())
}
_ => {
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
}
match *kind {
- mir::AggregateKind::Vec => {
+ mir::AggregateKind::Array => {
self.const_array(dest_ty, &fields)
}
mir::AggregateKind::Adt(..) |
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
{
if bounds.is_empty() {
- span_err!(self.tcx().sess, span, E0220,
+ struct_span_err!(self.tcx().sess, span, E0220,
"associated type `{}` not found for `{}`",
assoc_name,
- ty_param_name);
+ ty_param_name)
+ .span_label(span, &format!("associated type `{}` not found", assoc_name))
+ .emit();
return Err(ErrorReported);
}
}
let result_ty = match ast_ty.node {
- hir::TyVec(ref ty) => {
+ hir::TySlice(ref ty) => {
tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
}
hir::TyObjectSum(ref ty, ref bounds) => {
ty
}
- hir::TyFixedLengthVec(ref ty, ref e) => {
+ hir::TyArray(ref ty, ref e) => {
if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
} else {
tcx.types.err
}
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::TyArray(inner_ty, size) => {
expected: Expectation<'tcx>) -> Ty<'tcx>
{
let original_callee_ty = self.check_expr(callee_expr);
+ let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
- let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
+ let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
}).next();
if num_supplied_types > 0 && num_supplied_types != num_method_types {
if num_method_types == 0 {
- span_err!(self.tcx.sess, self.span, E0035,
- "does not take type parameters");
+ struct_span_err!(self.tcx.sess, self.span, E0035,
+ "does not take type parameters")
+ .span_label(self.span, &"called with unneeded type parameters")
+ .emit();
} else {
- span_err!(self.tcx.sess, self.span, E0036,
+ struct_span_err!(self.tcx.sess, self.span, E0036,
"incorrect number of type parameters given for this method: \
expected {}, found {}",
- num_method_types, num_supplied_types);
+ num_method_types, num_supplied_types)
+ .span_label(self.span,
+ &format!("Passed {} type argument{}, expected {}",
+ num_supplied_types,
+ if num_supplied_types != 1 {
+ "s"
+ } else {
+ ""
+ },
+ num_method_types))
+ .emit();
}
supplied_method_types = vec![self.tcx.types.err; num_method_types];
}
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
- hir::TyFixedLengthVec(_, ref expr) => {
+ hir::TyArray(_, ref expr) => {
check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
}
_ => {}
// need to record the type for that node
fn visit_ty(&mut self, t: &'gcx hir::Ty) {
match t.node {
- hir::TyFixedLengthVec(ref ty, ref count_expr) => {
+ hir::TyArray(ref ty, ref count_expr) => {
self.visit_ty(&ty);
self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
}
self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
}
hir::ExprCast(ref e, ref t) => {
- if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
+ if let hir::TyArray(_, ref count_expr) = t.node {
self.check_expr_with_hint(&count_expr, tcx.types.usize);
}
self.check_expr_eq_type(&e, typ);
typ
}
- hir::ExprVec(ref args) => {
+ hir::ExprArray(ref args) => {
let uty = expected.to_option(self).and_then(|uty| {
match uty.sty {
ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
fn visit_ty(&mut self, t: &hir::Ty) {
match t.node {
- hir::TyFixedLengthVec(ref ty, ref count_expr) => {
+ hir::TyArray(ref ty, ref count_expr) => {
self.visit_ty(&ty);
write_ty_to_tcx(self.fcx.ccx, count_expr.id, self.tcx().types.usize);
}
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
Some(disr)
} else {
- span_err!(tcx.sess, v.span, E0370,
- "enum discriminant overflowed on value after {}; \
- set explicitly via {} = {} if that is desired outcome",
- prev_disr.unwrap(), v.node.name, wrapped_disr);
+ struct_span_err!(tcx.sess, v.span, E0370,
+ "enum discriminant overflowed")
+ .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
+ .note(&format!("explicitly set `{} = {}` if that is desired outcome",
+ v.node.name, wrapped_disr))
+ .emit();
None
}.unwrap_or(wrapped_disr);
prev_disr = Some(disr);
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode};
+pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode};
// unstable reexports
#[unstable(feature = "try_from", issue = "33417")]
C::len_utf16(self)
}
- /// Returns an iterator over the bytes of this character as UTF-8.
+ /// Encodes this character as UTF-8 into the provided byte buffer,
+ /// and then returns the subslice of the buffer that contains the encoded character.
///
- /// The returned iterator also has an `as_slice()` method to view the
- /// encoded bytes as a byte slice.
+ /// # Panics
+ ///
+ /// Panics if the buffer is not large enough.
+ /// A buffer of length four is large enough to encode any `char`.
///
/// # Examples
///
+ /// In both of these examples, 'ß' takes two bytes to encode.
+ ///
/// ```
/// #![feature(unicode)]
///
- /// let iterator = 'ß'.encode_utf8();
- /// assert_eq!(iterator.as_slice(), [0xc3, 0x9f]);
+ /// let mut b = [0; 2];
///
- /// for (i, byte) in iterator.enumerate() {
- /// println!("byte {}: {:x}", i, byte);
- /// }
+ /// let result = 'ß'.encode_utf8(&mut b);
+ ///
+ /// assert_eq!(result, "ß");
+ ///
+ /// assert_eq!(result.len(), 2);
+ /// ```
+ ///
+ /// A buffer that's too small:
+ ///
+ /// ```
+ /// #![feature(unicode)]
+ /// use std::thread;
+ ///
+ /// let result = thread::spawn(|| {
+ /// let mut b = [0; 1];
+ ///
+ /// // this panics
+ /// 'ß'.encode_utf8(&mut b);
+ /// }).join();
+ ///
+ /// assert!(result.is_err());
/// ```
- #[unstable(feature = "unicode", issue = "27784")]
+ #[unstable(feature = "unicode",
+ reason = "pending decision about Iterator/Writer/Reader",
+ issue = "27784")]
#[inline]
- pub fn encode_utf8(self) -> EncodeUtf8 {
- C::encode_utf8(self)
+ pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
+ C::encode_utf8(self, dst)
}
- /// Returns an iterator over the `u16` entries of this character as UTF-16.
+ /// Encodes this character as UTF-16 into the provided `u16` buffer,
+ /// and then returns the subslice of the buffer that contains the encoded character.
///
- /// The returned iterator also has an `as_slice()` method to view the
- /// encoded form as a slice.
+ /// # Panics
+ ///
+ /// Panics if the buffer is not large enough.
+ /// A buffer of length 2 is large enough to encode any `char`.
///
/// # Examples
///
+ /// In both of these examples, '𝕊' takes two `u16`s to encode.
+ ///
/// ```
/// #![feature(unicode)]
///
- /// let iterator = '𝕊'.encode_utf16();
- /// assert_eq!(iterator.as_slice(), [0xd835, 0xdd4a]);
+ /// let mut b = [0; 2];
///
- /// for (i, val) in iterator.enumerate() {
- /// println!("entry {}: {:x}", i, val);
- /// }
+ /// let result = '𝕊'.encode_utf16(&mut b);
+ ///
+ /// assert_eq!(result.len(), 2);
/// ```
- #[unstable(feature = "unicode", issue = "27784")]
+ ///
+ /// A buffer that's too small:
+ ///
+ /// ```
+ /// #![feature(unicode)]
+ /// use std::thread;
+ ///
+ /// let result = thread::spawn(|| {
+ /// let mut b = [0; 1];
+ ///
+ /// // this panics
+ /// '𝕊'.encode_utf16(&mut b);
+ /// }).join();
+ ///
+ /// assert!(result.is_err());
+ /// ```
+ #[unstable(feature = "unicode",
+ reason = "pending decision about Iterator/Writer/Reader",
+ issue = "27784")]
#[inline]
- pub fn encode_utf16(self) -> EncodeUtf16 {
- C::encode_utf16(self)
+ pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
+ C::encode_utf16(self, dst)
}
/// Returns true if this `char` is an alphabetic code point, and false if not.
return Some(tmp);
}
+ let mut buf = [0; 2];
self.chars.next().map(|ch| {
- let n = CharExt::encode_utf16(ch);
- let n = n.as_slice();
- if n.len() == 2 {
- self.extra = n[1];
+ let n = CharExt::encode_utf16(ch, &mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
}
- n[0]
+ buf[0]
})
}
}
}
pub fn is_mod(&self) -> bool {
- ItemType::from(self) == ItemType::Module
+ self.type_() == ItemType::Module
}
pub fn is_trait(&self) -> bool {
- ItemType::from(self) == ItemType::Trait
+ self.type_() == ItemType::Trait
}
pub fn is_struct(&self) -> bool {
- ItemType::from(self) == ItemType::Struct
+ self.type_() == ItemType::Struct
}
pub fn is_enum(&self) -> bool {
- ItemType::from(self) == ItemType::Module
+ self.type_() == ItemType::Module
}
pub fn is_fn(&self) -> bool {
- ItemType::from(self) == ItemType::Function
+ self.type_() == ItemType::Function
}
pub fn is_associated_type(&self) -> bool {
- ItemType::from(self) == ItemType::AssociatedType
+ self.type_() == ItemType::AssociatedType
}
pub fn is_associated_const(&self) -> bool {
- ItemType::from(self) == ItemType::AssociatedConst
+ self.type_() == ItemType::AssociatedConst
}
pub fn is_method(&self) -> bool {
- ItemType::from(self) == ItemType::Method
+ self.type_() == ItemType::Method
}
pub fn is_ty_method(&self) -> bool {
- ItemType::from(self) == ItemType::TyMethod
+ self.type_() == ItemType::TyMethod
}
pub fn is_primitive(&self) -> bool {
- ItemType::from(self) == ItemType::Primitive
+ self.type_() == ItemType::Primitive
}
pub fn is_stripped(&self) -> bool {
match self.inner { StrippedItem(..) => true, _ => false }
pub fn stable_since(&self) -> Option<&str> {
self.stability.as_ref().map(|s| &s.since[..])
}
+
+ /// Returns a documentation-level item type from the item.
+ pub fn type_(&self) -> ItemType {
+ ItemType::from(self)
+ }
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
- TyVec(ref ty) => Vector(box ty.clean(cx)),
- TyFixedLengthVec(ref ty, ref e) => {
+ TySlice(ref ty) => Vector(box ty.clean(cx)),
+ TyArray(ref ty, ref e) => {
let n = if let Some(tcx) = cx.tcx_opt() {
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_const_eval::eval_const_expr;
},
PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
which is not allowed in function arguments"),
- PatKind::Vec(ref begin, ref mid, ref end) => {
+ PatKind::Slice(ref begin, ref mid, ref end) => {
let begin = begin.iter().map(|p| name_from_pat(&**p));
let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
let end = end.iter().map(|p| name_from_pat(&**p));
/// Current hierarchy of components leading down to what's currently being
/// rendered
pub current: Vec<String>,
- /// String representation of how to get back to the root path of the 'doc/'
- /// folder in terms of a relative URL.
- pub root_path: String,
/// The current destination folder of where HTML artifacts should be placed.
/// This changes as the context descends into the module hierarchy.
pub dst: PathBuf,
krate = render_sources(&dst, &mut scx, krate)?;
let cx = Context {
current: Vec::new(),
- root_path: String::new(),
dst: dst,
render_redirect_pages: false,
shared: Arc::new(scx),
for &(did, ref item) in orphan_impl_items {
if let Some(&(ref fqp, _)) = paths.get(&did) {
search_index.push(IndexItem {
- ty: item_type(item),
+ ty: item.type_(),
name: item.name.clone().unwrap(),
path: fqp[..fqp.len() - 1].join("::"),
desc: Escape(&shorter(item.doc_value())).to_string(),
}
}
-/// Returns a documentation-level item type from the item.
-fn item_type(item: &clean::Item) -> ItemType {
- ItemType::from(item)
-}
-
/// Takes a path to a source file and cleans the path to it. This canonicalizes
/// things like ".." to components which preserve the "top down" hierarchy of a
/// static HTML tree. Each component in the cleaned path will be passed as an
// inserted later on when serializing the search-index.
if item.def_id.index != CRATE_DEF_INDEX {
self.search_index.push(IndexItem {
- ty: item_type(&item),
+ ty: item.type_(),
name: s.to_string(),
path: path.join("::").to_string(),
desc: Escape(&shorter(item.doc_value())).to_string(),
self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
- (self.stack.clone(), item_type(&item)));
+ (self.stack.clone(), item.type_()));
}
}
// link variants to their parent enum because pages aren't emitted
clean::PrimitiveItem(..) if item.visibility.is_some() => {
self.paths.insert(item.def_id, (self.stack.clone(),
- item_type(&item)));
+ item.type_()));
}
_ => {}
}
impl Context {
+ /// String representation of how to get back to the root path of the 'doc/'
+ /// folder in terms of a relative URL.
+ fn root_path(&self) -> String {
+ repeat("../").take(self.current.len()).collect::<String>()
+ }
+
/// Recurse in the directory structure and change the "root path" to make
/// sure it always points to the top (relatively)
fn recurse<T, F>(&mut self, s: String, f: F) -> T where
}
let prev = self.dst.clone();
self.dst.push(&s);
- self.root_path.push_str("../");
self.current.push(s);
info!("Recursing into {}", self.dst.display());
// Go back to where we were at
self.dst = prev;
- let len = self.root_path.len();
- self.root_path.truncate(len - 3);
self.current.pop().unwrap();
return ret;
title.push_str(it.name.as_ref().unwrap());
}
title.push_str(" - Rust");
- let tyname = item_type(it).css_class();
+ let tyname = it.type_().css_class();
let desc = if it.is_crate() {
format!("API documentation for the Rust `{}` crate.",
self.shared.layout.krate)
let keywords = make_item_keywords(it);
let page = layout::Page {
css_class: tyname,
- root_path: &self.root_path,
+ root_path: &self.root_path(),
title: &title,
description: &desc,
keywords: &keywords,
&Item{ cx: self, item: it },
self.shared.css_file_extension.is_some())?;
} else {
- let mut url = repeat("../").take(self.current.len())
- .collect::<String>();
+ let mut url = self.root_path();
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
for name in &names[..names.len() - 1] {
url.push_str(name);
// buf will be empty if the item is stripped and there is no redirect for it
if !buf.is_empty() {
let name = item.name.as_ref().unwrap();
- let item_type = item_type(&item);
+ let item_type = item.type_();
let file_name = &item_path(item_type, name);
let joint_dst = self.dst.join(file_name);
try_err!(fs::create_dir_all(&self.dst), &self.dst);
for item in &m.items {
if maybe_ignore_item(item) { continue }
- let short = item_type(item).css_class();
+ let short = item.type_().css_class();
let myname = match item.name {
None => continue,
Some(ref s) => s.to_string(),
}).map(|l| &l.1);
let root = match root {
Some(&Remote(ref s)) => s.to_string(),
- Some(&Local) => self.cx.root_path.clone(),
+ Some(&Local) => self.cx.root_path(),
None | Some(&Unknown) => return None,
};
Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
let path = PathBuf::from(&self.item.source.filename);
self.cx.shared.local_sources.get(&path).map(|path| {
format!("{root}src/{krate}/{path}#{href}",
- root = self.cx.root_path,
+ root = self.cx.root_path(),
krate = self.cx.shared.layout.krate,
path = path,
href = href)
};
let mut path = match cache.extern_locations.get(&self.item.def_id.krate) {
Some(&(_, Remote(ref s))) => s.to_string(),
- Some(&(_, Local)) => self.cx.root_path.clone(),
+ Some(&(_, Local)) => self.cx.root_path(),
Some(&(_, Unknown)) => return None,
None => return None,
};
}
Some(format!("{path}{file}?gotosrc={goto}",
path = path,
- file = item_path(item_type(self.item), external_path.last().unwrap()),
+ file = item_path(self.item.type_(), external_path.last().unwrap()),
goto = self.item.def_id.index.as_usize()))
}
}
}
}
write!(fmt, "<a class='{}' href=''>{}</a>",
- item_type(self.item), self.item.name.as_ref().unwrap())?;
+ self.item.type_(), self.item.name.as_ref().unwrap())?;
write!(fmt, "</span>")?; // in-band
write!(fmt, "<span class='out-of-band'>")?;
}
fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
- let ty1 = item_type(i1);
- let ty2 = item_type(i2);
+ let ty1 = i1.type_();
+ let ty2 = i2.type_();
if ty1 != ty2 {
return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2))
}
continue;
}
- let myty = Some(item_type(myitem));
+ let myty = Some(myitem.type_());
if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
// Put `extern crate` and `use` re-exports in the same section.
curty = myty;
name = *myitem.name.as_ref().unwrap(),
stab_docs = stab_docs,
docs = shorter(Some(&Markdown(doc_value).to_string())),
- class = item_type(myitem),
+ class = myitem.type_(),
stab = myitem.stability_class(),
- href = item_path(item_type(myitem), myitem.name.as_ref().unwrap()),
+ href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()),
title = full_path(cx, myitem))?;
}
}
fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item)
-> fmt::Result {
let name = m.name.as_ref().unwrap();
- let item_type = item_type(m);
+ let item_type = m.type_();
let id = derive_id(format!("{}.{}", item_type, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h3 id='{id}' class='method stab {stab}'>\
let (ref path, _) = cache.external_paths[&it.def_id];
path[..path.len() - 1].join("/")
},
- ty = item_type(it).css_class(),
+ ty = it.type_().css_class(),
name = *it.name.as_ref().unwrap())?;
Ok(())
}
use html::item_type::ItemType::*;
let name = it.name.as_ref().unwrap();
- let ty = match item_type(it) {
+ let ty = match it.type_() {
Typedef | AssociatedType => AssociatedType,
s@_ => s,
};
link: AssocItemLink)
-> fmt::Result {
let name = meth.name.as_ref().unwrap();
- let anchor = format!("#{}.{}", item_type(meth), name);
+ let anchor = format!("#{}.{}", meth.type_(), name);
let href = match link {
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
AssocItemLink::Anchor(None) => anchor,
link: AssocItemLink, render_mode: RenderMode,
is_default_item: bool, outer_version: Option<&str>,
trait_: Option<&clean::Trait>) -> fmt::Result {
- let item_type = item_type(item);
+ let item_type = item.type_();
let name = item.name.as_ref().unwrap();
let render_method_item: bool = match render_mode {
write!(fmt, "::<wbr>")?;
}
write!(fmt, "<a href='{}index.html'>{}</a>",
- &cx.root_path[..(cx.current.len() - i - 1) * 3],
+ &cx.root_path()[..(cx.current.len() - i - 1) * 3],
*name)?;
}
write!(fmt, "</p>")?;
relpath: '{path}'\
}};</script>",
name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
- ty = item_type(it).css_class(),
+ ty = it.type_().css_class(),
path = relpath)?;
if parentlen == 0 {
// there is no sidebar-items.js beyond the crate root path
let codemap = Rc::new(CodeMap::new());
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
Some(codemap.clone()));
- let old = io::set_panic(box Sink(data.clone()));
+ let old = io::set_panic(Some(box Sink(data.clone())));
let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
// Compile the code
}
fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult {
- escape_str(writer, unsafe {
- str::from_utf8_unchecked(v.encode_utf8().as_slice())
- })
+ escape_str(writer, v.encode_utf8(&mut [0; 4]))
}
fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult {
//
// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md
-/// A hash map implementation which uses linear probing with Robin
-/// Hood bucket stealing.
+/// A hash map implementation which uses linear probing with Robin Hood bucket
+/// stealing.
///
-/// By default, HashMap uses a somewhat slow hashing algorithm which can provide resistance
-/// to DoS attacks. Rust makes a best attempt at acquiring random numbers without IO
-/// blocking from your system. Because of this HashMap is not guaranteed to provide
-/// DoS resistance since the numbers generated might not be truly random. If you do
-/// require this behavior you can create your own hashing function using
-/// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html).
+/// By default, `HashMap` uses a hashing algorithm selected to provide
+/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a
+/// reasonable best-effort is made to generate this seed from a high quality,
+/// secure source of randomness provided by the host without blocking the
+/// program. Because of this, the randomness of the seed is dependant on the
+/// quality of the system's random number generator at the time it is created.
+/// In particular, seeds generated when the system's entropy pool is abnormally
+/// low such as during system boot may be of a lower quality.
+///
+/// The default hashing algorithm is currently SipHash 1-3, though this is
+/// subject to change at any point in the future. While its performance is very
+/// competitive for medium sized keys, other hashing algorithms will outperform
+/// it for small keys such as integers as well as large keys such as long
+/// strings, though those algorithms will typically *not* protect against
+/// attacks such as HashDoS.
+///
+/// The hashing algorithm can be replaced on a per-`HashMap` basis using the
+/// `HashMap::default`, `HashMap::with_hasher`, and
+/// `HashMap::with_capacity_and_hasher` methods. Many alternative algorithms
+/// are available on crates.io, such as the `fnv` crate.
///
/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although
/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`.
use fmt;
use io;
use path::{Path, PathBuf};
+use sys;
use sys::os as os_imp;
/// Returns the current working directory as a `PathBuf`.
///
/// This structure is created through the `std::env::args_os` method.
#[stable(feature = "env", since = "1.0.0")]
-pub struct ArgsOs { inner: os_imp::Args }
+pub struct ArgsOs { inner: sys::args::Args }
/// Returns the arguments which this program was started with (normally passed
/// via the command line).
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn args_os() -> ArgsOs {
- ArgsOs { inner: os_imp::args() }
+ ArgsOs { inner: sys::args::args() }
}
#[stable(feature = "env", since = "1.0.0")]
/// Constants associated with the current target
#[stable(feature = "env", since = "1.0.0")]
pub mod consts {
+ use sys::env::os;
+
/// A string describing the architecture of the CPU that is currently
/// in use.
///
/// - unix
/// - windows
#[stable(feature = "env", since = "1.0.0")]
- pub const FAMILY: &'static str = super::os::FAMILY;
+ pub const FAMILY: &'static str = os::FAMILY;
/// A string describing the specific operating system in use.
/// Example value is `linux`.
/// - android
/// - windows
#[stable(feature = "env", since = "1.0.0")]
- pub const OS: &'static str = super::os::OS;
+ pub const OS: &'static str = os::OS;
/// Specifies the filename prefix used for shared libraries on this
/// platform. Example value is `lib`.
/// - lib
/// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
- pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
+ pub const DLL_PREFIX: &'static str = os::DLL_PREFIX;
/// Specifies the filename suffix used for shared libraries on this
/// platform. Example value is `.so`.
/// - .dylib
/// - .dll
#[stable(feature = "env", since = "1.0.0")]
- pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
+ pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX;
/// Specifies the file extension used for shared libraries on this
/// platform that goes after the dot. Example value is `so`.
/// - dylib
/// - dll
#[stable(feature = "env", since = "1.0.0")]
- pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
+ pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION;
/// Specifies the filename suffix used for executable binaries on this
/// platform. Example value is `.exe`.
/// - .pexe
/// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
- pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
+ pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX;
/// Specifies the file extension, if any, used for executable binaries
/// on this platform. Example value is `exe`.
/// - exe
/// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
- pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
-
-}
-
-#[cfg(target_os = "linux")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "linux";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "macos")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "macos";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".dylib";
- pub const DLL_EXTENSION: &'static str = "dylib";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "ios")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "ios";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".dylib";
- pub const DLL_EXTENSION: &'static str = "dylib";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "freebsd")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "freebsd";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "dragonfly")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "dragonfly";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "bitrig")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "bitrig";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "netbsd")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "netbsd";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "openbsd")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "openbsd";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "android")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "android";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "solaris")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "solaris";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "windows")]
-mod os {
- pub const FAMILY: &'static str = "windows";
- pub const OS: &'static str = "windows";
- pub const DLL_PREFIX: &'static str = "";
- pub const DLL_SUFFIX: &'static str = ".dll";
- pub const DLL_EXTENSION: &'static str = "dll";
- pub const EXE_SUFFIX: &'static str = ".exe";
- pub const EXE_EXTENSION: &'static str = "exe";
-}
-
-#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "nacl";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = ".nexe";
- pub const EXE_EXTENSION: &'static str = "nexe";
-}
-#[cfg(all(target_os = "nacl", target_arch = "le32"))]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "pnacl";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".pso";
- pub const DLL_EXTENSION: &'static str = "pso";
- pub const EXE_SUFFIX: &'static str = ".pexe";
- pub const EXE_EXTENSION: &'static str = "pexe";
-}
-
-#[cfg(target_os = "emscripten")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "emscripten";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = ".js";
- pub const EXE_EXTENSION: &'static str = "js";
-}
-
-#[cfg(target_os = "haiku")]
-mod os {
- pub const FAMILY: &'static str = "unix";
- pub const OS: &'static str = "haiku";
- pub const DLL_PREFIX: &'static str = "lib";
- pub const DLL_SUFFIX: &'static str = ".so";
- pub const DLL_EXTENSION: &'static str = "so";
- pub const EXE_SUFFIX: &'static str = "";
- pub const EXE_EXTENSION: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION;
}
#[cfg(target_arch = "x86")]
pub const ARCH: &'static str = "asmjs";
}
+#[cfg(target_arch = "wasm32")]
+mod arch {
+ pub const ARCH: &'static str = "wasm32";
+}
+
#[cfg(test)]
mod tests {
use super::*;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_var_big() {
let mut s = "".to_string();
let mut i = 0;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_self_exe_path() {
let path = current_exe();
assert!(path.is_ok());
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() {
let n = make_rand_name();
let s = repeat("x").take(10000).collect::<String>();
OsString { inner: Buf::from_string(String::new()) }
}
- #[cfg(unix)]
- fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
- use os::unix::ffi::OsStringExt;
- Some(OsString::from_vec(vec))
- }
-
- #[cfg(windows)]
- fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
- String::from_utf8(vec).ok().map(OsString::from)
- }
-
/// Converts to an `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &OsStr {
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::prelude::*;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0);
#[stable(feature = "rust1", since = "1.0.0")]
fn consume(&mut self, amt: usize);
- /// Read all bytes into `buf` until the delimiter `byte` is reached.
+ /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
///
/// This function will read bytes from the underlying stream until the
/// delimiter or EOF is found. Once found, all bytes up to, and including,
/// the delimiter (if found) will be appended to `buf`.
///
- /// If this reader is currently at EOF then this function will not modify
- /// `buf` and will return `Ok(n)` where `n` is the number of bytes which
- /// were read.
+ /// If successful, this function will return the total number of bytes read.
///
/// # Errors
///
/// up to, and including, the delimiter (if found) will be appended to
/// `buf`.
///
- /// If this reader is currently at EOF then this function will not modify
- /// `buf` and will return `Ok(n)` where `n` is the number of bytes which
- /// were read.
+ /// If successful, this function will return the total number of bytes read.
///
/// # Errors
///
use super::repeat;
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
}
#[bench]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
}
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
- #[cfg(windows)]
- const ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
- #[cfg(not(windows))]
- const ERR: i32 = ::libc::EBADF as i32;
+ use sys::stdio::EBADF_ERR;
match r {
- Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default),
+ Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
r => r
}
}
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
+pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use panicking::LOCAL_STDERR;
use mem;
LOCAL_STDERR.with(move |slot| {
- mem::replace(&mut *slot.borrow_mut(), Some(sink))
+ mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_print(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
+pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use mem;
LOCAL_STDOUT.with(move |slot| {
- mem::replace(&mut *slot.borrow_mut(), Some(sink))
+ mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
use super::*;
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
let _a = stdin();
#[macro_export]
macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
- /// Parse the current given file as an expression.
- ///
- /// This is generally a bad idea, because it's going to behave unhygienically.
+ /// Parse the file provided in the argument as an expression or an
+ /// item according to the context. This file is located relative
+ /// to the current file (similarly to how modules are found).
+ ///
+ /// Using this macro is often a bad idea, because if the file is
+ /// parsed as an expression, it is going to be placed in the
+ /// surrounding code unhygenically. This could result in variables
+ /// or functions being different from what the file expected if
+ /// there are variables or functions that have the same name in
+ /// the current file.
///
/// # Examples
///
// Original implementation taken from rust-memchr
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
-
-
/// A safe interface to `memchr`.
///
/// Returns the index corresponding to the first occurrence of `needle` in
/// let haystack = b"the quick brown fox";
/// assert_eq!(memchr(b'k', haystack), Some(8));
/// ```
+#[inline]
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
- // libc memchr
- #[cfg(not(target_os = "windows"))]
- fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- use libc;
-
- let p = unsafe {
- libc::memchr(
- haystack.as_ptr() as *const libc::c_void,
- needle as libc::c_int,
- haystack.len() as libc::size_t)
- };
- if p.is_null() {
- None
- } else {
- Some(p as usize - (haystack.as_ptr() as usize))
- }
- }
-
- // use fallback on windows, since it's faster
- #[cfg(target_os = "windows")]
- fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- fallback::memchr(needle, haystack)
- }
-
- memchr_specific(needle, haystack)
+ ::sys::memchr::memchr(needle, haystack)
}
/// A safe interface to `memrchr`.
/// let haystack = b"the quick brown fox";
/// assert_eq!(memrchr(b'o', haystack), Some(17));
/// ```
+#[inline]
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-
- #[cfg(target_os = "linux")]
- fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- use libc;
-
- // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
- if haystack.is_empty() {return None}
- let p = unsafe {
- libc::memrchr(
- haystack.as_ptr() as *const libc::c_void,
- needle as libc::c_int,
- haystack.len() as libc::size_t)
- };
- if p.is_null() {
- None
- } else {
- Some(p as usize - (haystack.as_ptr() as usize))
- }
- }
-
- #[cfg(not(target_os = "linux"))]
- fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- fallback::memrchr(needle, haystack)
- }
-
- memrchr_specific(needle, haystack)
-}
-
-#[allow(dead_code)]
-mod fallback {
- use cmp;
- use mem;
-
- const LO_U64: u64 = 0x0101010101010101;
- const HI_U64: u64 = 0x8080808080808080;
-
- // use truncation
- const LO_USIZE: usize = LO_U64 as usize;
- const HI_USIZE: usize = HI_U64 as usize;
-
- /// Return `true` if `x` contains any zero byte.
- ///
- /// From *Matters Computational*, J. Arndt
- ///
- /// "The idea is to subtract one from each of the bytes and then look for
- /// bytes where the borrow propagated all the way to the most significant
- /// bit."
- #[inline]
- fn contains_zero_byte(x: usize) -> bool {
- x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
- }
-
- #[cfg(target_pointer_width = "32")]
- #[inline]
- fn repeat_byte(b: u8) -> usize {
- let mut rep = (b as usize) << 8 | b as usize;
- rep = rep << 16 | rep;
- rep
- }
-
- #[cfg(target_pointer_width = "64")]
- #[inline]
- fn repeat_byte(b: u8) -> usize {
- let mut rep = (b as usize) << 8 | b as usize;
- rep = rep << 16 | rep;
- rep = rep << 32 | rep;
- rep
- }
-
- /// Return the first index matching the byte `a` in `text`.
- pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
- // Scan for a single byte value by reading two `usize` words at a time.
- //
- // Split `text` in three parts
- // - unaligned initial part, before the first word aligned address in text
- // - body, scan by 2 words at a time
- // - the last remaining part, < 2 word size
- let len = text.len();
- let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
-
- // search up to an aligned boundary
- let align = (ptr as usize) & (usize_bytes- 1);
- let mut offset;
- if align > 0 {
- offset = cmp::min(usize_bytes - align, len);
- if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
- return Some(index);
- }
- } else {
- offset = 0;
- }
-
- // search the body of the text
- let repeated_x = repeat_byte(x);
-
- if len >= 2 * usize_bytes {
- while offset <= len - 2 * usize_bytes {
- unsafe {
- let u = *(ptr.offset(offset as isize) as *const usize);
- let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
-
- // break if there is a matching byte
- let zu = contains_zero_byte(u ^ repeated_x);
- let zv = contains_zero_byte(v ^ repeated_x);
- if zu || zv {
- break;
- }
- }
- offset += usize_bytes * 2;
- }
- }
-
- // find the byte after the point the body loop stopped
- text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
- }
-
- /// Return the last index matching the byte `a` in `text`.
- pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
- // Scan for a single byte value by reading two `usize` words at a time.
- //
- // Split `text` in three parts
- // - unaligned tail, after the last word aligned address in text
- // - body, scan by 2 words at a time
- // - the first remaining bytes, < 2 word size
- let len = text.len();
- let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
-
- // search to an aligned boundary
- let end_align = (ptr as usize + len) & (usize_bytes - 1);
- let mut offset;
- if end_align > 0 {
- offset = if end_align >= len { 0 } else { len - end_align };
- if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
- return Some(offset + index);
- }
- } else {
- offset = len;
- }
-
- // search the body of the text
- let repeated_x = repeat_byte(x);
-
- while offset >= 2 * usize_bytes {
- unsafe {
- let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
- let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
-
- // break if there is a matching byte
- let zu = contains_zero_byte(u ^ repeated_x);
- let zv = contains_zero_byte(v ^ repeated_x);
- if zu || zv {
- break;
- }
- }
- offset -= 2 * usize_bytes;
- }
-
- // find the byte before the point the body loop stopped
- text[..offset].iter().rposition(|elt| *elt == x)
- }
-
- // test fallback implementations on all platforms
- #[test]
- fn matches_one() {
- assert_eq!(Some(0), memchr(b'a', b"a"));
- }
-
- #[test]
- fn matches_begin() {
- assert_eq!(Some(0), memchr(b'a', b"aaaa"));
- }
-
- #[test]
- fn matches_end() {
- assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
- }
-
- #[test]
- fn matches_nul() {
- assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
- }
-
- #[test]
- fn matches_past_nul() {
- assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
- }
-
- #[test]
- fn no_match_empty() {
- assert_eq!(None, memchr(b'a', b""));
- }
-
- #[test]
- fn no_match() {
- assert_eq!(None, memchr(b'a', b"xyz"));
- }
-
- #[test]
- fn matches_one_reversed() {
- assert_eq!(Some(0), memrchr(b'a', b"a"));
- }
-
- #[test]
- fn matches_begin_reversed() {
- assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
- }
-
- #[test]
- fn matches_end_reversed() {
- assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
- }
-
- #[test]
- fn matches_nul_reversed() {
- assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
- }
-
- #[test]
- fn matches_past_nul_reversed() {
- assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
- }
-
- #[test]
- fn no_match_empty_reversed() {
- assert_eq!(None, memrchr(b'a', b""));
- }
-
- #[test]
- fn no_match_reversed() {
- assert_eq!(None, memrchr(b'a', b"xyz"));
- }
-
- #[test]
- fn each_alignment_reversed() {
- let mut data = [1u8; 64];
- let needle = 2;
- let pos = 40;
- data[pos] = needle;
- for start in 0..16 {
- assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
- }
- }
+ ::sys::memchr::memrchr(needle, haystack)
}
#[cfg(test)]
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use net::*;
use net::test::{tsa, sa6, sa4};
}
// Tests for this module
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use net::*;
use net::Ipv6MulticastScope::*;
mod tcp;
mod udp;
mod parser;
-#[cfg(test)] mod test;
+#[cfg(test)]
+mod test;
/// Possible values which can be passed to the [`shutdown`] method of
/// [`TcpStream`].
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::ErrorKind;
use io::prelude::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_code)] // not used on emscripten
+
use env;
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use sync::atomic::{AtomicUsize, Ordering};
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::ErrorKind;
use net::*;
target_arch = "le32",
target_arch = "powerpc",
target_arch = "arm",
- target_arch = "asmjs"))]
+ target_arch = "asmjs",
+ target_arch = "wasm32"))]
mod arch {
use os::raw::{c_long, c_short, c_uint};
use ffi::{OsStr, OsString};
-use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
+use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
////////////////////////////////////////////////////////////////////////////////
// GENERAL NOTES
// OsStr APIs for parsing, but it will take a while for those to become
// available.
-////////////////////////////////////////////////////////////////////////////////
-// Platform-specific definitions
-////////////////////////////////////////////////////////////////////////////////
-
-// The following modules give the most basic tools for parsing paths on various
-// platforms. The bulk of the code is devoted to parsing prefixes on Windows.
-
-#[cfg(unix)]
-mod platform {
- use super::Prefix;
- use ffi::OsStr;
-
- #[inline]
- pub fn is_sep_byte(b: u8) -> bool {
- b == b'/'
- }
-
- #[inline]
- pub fn is_verbatim_sep(b: u8) -> bool {
- b == b'/'
- }
-
- pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
- None
- }
-
- pub const MAIN_SEP_STR: &'static str = "/";
- pub const MAIN_SEP: char = '/';
-}
-
-#[cfg(windows)]
-mod platform {
- use ascii::*;
-
- use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix};
- use ffi::OsStr;
-
- #[inline]
- pub fn is_sep_byte(b: u8) -> bool {
- b == b'/' || b == b'\\'
- }
-
- #[inline]
- pub fn is_verbatim_sep(b: u8) -> bool {
- b == b'\\'
- }
-
- pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
- use super::Prefix::*;
- unsafe {
- // The unsafety here stems from converting between &OsStr and &[u8]
- // and back. This is safe to do because (1) we only look at ASCII
- // contents of the encoding and (2) new &OsStr values are produced
- // only from ASCII-bounded slices of existing &OsStr values.
- let mut path = os_str_as_u8_slice(path);
-
- if path.starts_with(br"\\") {
- // \\
- path = &path[2..];
- if path.starts_with(br"?\") {
- // \\?\
- path = &path[2..];
- if path.starts_with(br"UNC\") {
- // \\?\UNC\server\share
- path = &path[4..];
- let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
- Some((server, share)) =>
- (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
- None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
- };
- return Some(VerbatimUNC(server, share));
- } else {
- // \\?\path
- let idx = path.iter().position(|&b| b == b'\\');
- if idx == Some(2) && path[1] == b':' {
- let c = path[0];
- if c.is_ascii() && (c as char).is_alphabetic() {
- // \\?\C:\ path
- return Some(VerbatimDisk(c.to_ascii_uppercase()));
- }
- }
- let slice = &path[..idx.unwrap_or(path.len())];
- return Some(Verbatim(u8_slice_as_os_str(slice)));
- }
- } else if path.starts_with(b".\\") {
- // \\.\path
- path = &path[2..];
- let pos = path.iter().position(|&b| b == b'\\');
- let slice = &path[..pos.unwrap_or(path.len())];
- return Some(DeviceNS(u8_slice_as_os_str(slice)));
- }
- match parse_two_comps(path, is_sep_byte) {
- Some((server, share)) if !server.is_empty() && !share.is_empty() => {
- // \\server\share
- return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
- }
- _ => (),
- }
- } else if path.get(1) == Some(& b':') {
- // C:
- let c = path[0];
- if c.is_ascii() && (c as char).is_alphabetic() {
- return Some(Disk(c.to_ascii_uppercase()));
- }
- }
- return None;
- }
-
- fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
- let first = match path.iter().position(|x| f(*x)) {
- None => return None,
- Some(x) => &path[..x],
- };
- path = &path[(first.len() + 1)..];
- let idx = path.iter().position(|x| f(*x));
- let second = &path[..idx.unwrap_or(path.len())];
- Some((first, second))
- }
- }
-
- pub const MAIN_SEP_STR: &'static str = "\\";
- pub const MAIN_SEP: char = '\\';
-}
-
////////////////////////////////////////////////////////////////////////////////
// Windows Prefixes
////////////////////////////////////////////////////////////////////////////////
/// The primary separator for the current platform
#[stable(feature = "rust1", since = "1.0.0")]
-pub const MAIN_SEPARATOR: char = platform::MAIN_SEP;
+pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP;
////////////////////////////////////////////////////////////////////////////////
// Misc helpers
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Working with processes.
+//! A module for working with processes.
+//!
+//! # Examples
+//!
+//! Basic usage where we try to execute the `cat` shell command:
+//!
+//! ```should_panic
+//! use std::process::Command;
+//!
+//! let mut child = Command::new("/bin/cat")
+//! .arg("file.txt")
+//! .spawn()
+//! .expect("failed to execute child");
+//!
+//! let ecode = child.wait()
+//! .expect("failed to wait on child");
+//!
+//! assert!(ecode.success());
+//! ```
#![stable(feature = "process", since = "1.0.0")]
::sys::os::exit(code)
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::prelude::*;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_os_rng_tasks() {
let mut txs = vec!();
thread_info::set(main_guard, thread);
// Store our args if necessary in a squirreled away location
- sys_common::args::init(argc, argv);
+ sys::args::init(argc, argv);
// Let's run some code!
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
use thread;
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn test_barrier() {
const N: usize = 10;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn notify_one() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn notify_all() {
const N: usize = 10;
}
#[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_ms() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
#[test]
#[should_panic]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn two_mutexes() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use env;
use super::*;
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod sync_tests {
use env;
use thread;
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::channel;
use super::{Queue, Data, Empty, Inconsistent};
}
}
-#[cfg(test)]
#[allow(unused_imports)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use thread;
use sync::mpsc::*;
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::Arc;
use super::Queue;
&guard.__lock.poison
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::channel;
use sync::{Arc, Mutex, Condvar};
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use panic;
use sync::mpsc::channel;
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
#![allow(deprecated)] // rand
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Global storage for command line arguments
-//!
-//! The current incarnation of the Rust runtime expects for
-//! the processes `argc` and `argv` arguments to be stored
-//! in a globally-accessible location for use by the `os` module.
-//!
-//! Only valid to call on Linux. Mac and Windows use syscalls to
-//! discover the command line arguments.
-//!
-//! FIXME #7756: Would be nice for this to not exist.
-
-#![allow(dead_code)] // different code on OSX/linux/etc
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() { imp::cleanup() }
-
-/// Make a clone of the global arguments.
-pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
-
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "solaris",
- target_os = "emscripten",
- target_os = "haiku"))]
-mod imp {
- use libc::c_char;
- use mem;
- use ffi::CStr;
-
- use sys_common::mutex::Mutex;
-
- static mut GLOBAL_ARGS_PTR: usize = 0;
- static LOCK: Mutex = Mutex::new();
-
- pub unsafe fn init(argc: isize, argv: *const *const u8) {
- let args = (0..argc).map(|i| {
- CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
- }).collect();
-
- LOCK.lock();
- let ptr = get_global_ptr();
- assert!((*ptr).is_none());
- (*ptr) = Some(box args);
- LOCK.unlock();
- }
-
- pub unsafe fn cleanup() {
- LOCK.lock();
- *get_global_ptr() = None;
- LOCK.unlock();
- }
-
- pub fn clone() -> Option<Vec<Vec<u8>>> {
- unsafe {
- LOCK.lock();
- let ptr = get_global_ptr();
- let ret = (*ptr).as_ref().map(|s| (**s).clone());
- LOCK.unlock();
- return ret
- }
- }
-
- fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
- unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
- }
-
-}
-
-#[cfg(any(target_os = "macos",
- target_os = "ios",
- target_os = "windows"))]
-mod imp {
- pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
- }
-
- pub fn cleanup() {
- }
-
- pub fn clone() -> Option<Vec<Vec<u8>>> {
- panic!()
- }
-}
}
#[cfg(test)]
+#[allow(dead_code)] // not used on emscripten
pub mod test {
use path::{Path, PathBuf};
use env;
}
#[bench]
+ #[cfg_attr(target_os = "emscripten", ignore)]
fn bench_uninitialized(b: &mut ::test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+#[allow(dead_code)]
+pub mod fallback {
+ use cmp;
+ use mem;
+
+ const LO_U64: u64 = 0x0101010101010101;
+ const HI_U64: u64 = 0x8080808080808080;
+
+ // use truncation
+ const LO_USIZE: usize = LO_U64 as usize;
+ const HI_USIZE: usize = HI_U64 as usize;
+
+ /// Return `true` if `x` contains any zero byte.
+ ///
+ /// From *Matters Computational*, J. Arndt
+ ///
+ /// "The idea is to subtract one from each of the bytes and then look for
+ /// bytes where the borrow propagated all the way to the most significant
+ /// bit."
+ #[inline]
+ fn contains_zero_byte(x: usize) -> bool {
+ x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ #[inline]
+ fn repeat_byte(b: u8) -> usize {
+ let mut rep = (b as usize) << 8 | b as usize;
+ rep = rep << 16 | rep;
+ rep
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ #[inline]
+ fn repeat_byte(b: u8) -> usize {
+ let mut rep = (b as usize) << 8 | b as usize;
+ rep = rep << 16 | rep;
+ rep = rep << 32 | rep;
+ rep
+ }
+
+ /// Return the first index matching the byte `a` in `text`.
+ pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
+ // Scan for a single byte value by reading two `usize` words at a time.
+ //
+ // Split `text` in three parts
+ // - unaligned initial part, before the first word aligned address in text
+ // - body, scan by 2 words at a time
+ // - the last remaining part, < 2 word size
+ let len = text.len();
+ let ptr = text.as_ptr();
+ let usize_bytes = mem::size_of::<usize>();
+
+ // search up to an aligned boundary
+ let align = (ptr as usize) & (usize_bytes- 1);
+ let mut offset;
+ if align > 0 {
+ offset = cmp::min(usize_bytes - align, len);
+ if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
+ return Some(index);
+ }
+ } else {
+ offset = 0;
+ }
+
+ // search the body of the text
+ let repeated_x = repeat_byte(x);
+
+ if len >= 2 * usize_bytes {
+ while offset <= len - 2 * usize_bytes {
+ unsafe {
+ let u = *(ptr.offset(offset as isize) as *const usize);
+ let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
+
+ // break if there is a matching byte
+ let zu = contains_zero_byte(u ^ repeated_x);
+ let zv = contains_zero_byte(v ^ repeated_x);
+ if zu || zv {
+ break;
+ }
+ }
+ offset += usize_bytes * 2;
+ }
+ }
+
+ // find the byte after the point the body loop stopped
+ text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
+ }
+
+ /// Return the last index matching the byte `a` in `text`.
+ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
+ // Scan for a single byte value by reading two `usize` words at a time.
+ //
+ // Split `text` in three parts
+ // - unaligned tail, after the last word aligned address in text
+ // - body, scan by 2 words at a time
+ // - the first remaining bytes, < 2 word size
+ let len = text.len();
+ let ptr = text.as_ptr();
+ let usize_bytes = mem::size_of::<usize>();
+
+ // search to an aligned boundary
+ let end_align = (ptr as usize + len) & (usize_bytes - 1);
+ let mut offset;
+ if end_align > 0 {
+ offset = if end_align >= len { 0 } else { len - end_align };
+ if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
+ return Some(offset + index);
+ }
+ } else {
+ offset = len;
+ }
+
+ // search the body of the text
+ let repeated_x = repeat_byte(x);
+
+ while offset >= 2 * usize_bytes {
+ unsafe {
+ let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
+ let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
+
+ // break if there is a matching byte
+ let zu = contains_zero_byte(u ^ repeated_x);
+ let zv = contains_zero_byte(v ^ repeated_x);
+ if zu || zv {
+ break;
+ }
+ }
+ offset -= 2 * usize_bytes;
+ }
+
+ // find the byte before the point the body loop stopped
+ text[..offset].iter().rposition(|elt| *elt == x)
+ }
+
+ // test fallback implementations on all platforms
+ #[test]
+ fn matches_one() {
+ assert_eq!(Some(0), memchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin() {
+ assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end() {
+ assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+ }
+
+ #[test]
+ fn matches_nul() {
+ assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul() {
+ assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+ }
+
+ #[test]
+ fn no_match_empty() {
+ assert_eq!(None, memchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match() {
+ assert_eq!(None, memchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn matches_one_reversed() {
+ assert_eq!(Some(0), memrchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin_reversed() {
+ assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+ }
+
+ #[test]
+ fn matches_nul_reversed() {
+ assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+ }
+
+ #[test]
+ fn no_match_empty_reversed() {
+ assert_eq!(None, memrchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match_reversed() {
+ assert_eq!(None, memrchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn each_alignment_reversed() {
+ let mut data = [1u8; 64];
+ let needle = 2;
+ let pos = 40;
+ data[pos] = needle;
+ for start in 0..16 {
+ assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+ }
+ }
+}
})
}
-pub mod args;
pub mod at_exit_imp;
#[cfg(any(not(cargobuild), feature = "backtrace"))]
pub mod backtrace;
pub mod condvar;
pub mod io;
+pub mod memchr;
pub mod mutex;
pub mod net;
pub mod poison;
pub fn cleanup() {
static CLEANUP: Once = Once::new();
CLEANUP.call_once(|| unsafe {
- args::cleanup();
+ sys::args::cleanup();
sys::stack_overflow::cleanup();
at_exit_imp::cleanup();
});
target_os = "solaris", target_os = "haiku")))]
use sys::net::netc::IPV6_DROP_MEMBERSHIP;
+#[cfg(target_os = "linux")]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(target_os = "linux"))]
+const MSG_NOSIGNAL: c_int = 0x0; // unused dummy value
+
////////////////////////////////////////////////////////////////////////////////
// sockaddr and misc bindings
////////////////////////////////////////////////////////////////////////////////
c::send(*self.inner.as_inner(),
buf.as_ptr() as *const c_void,
len,
- 0)
+ MSG_NOSIGNAL)
})?;
Ok(ret as usize)
}
let ret = cvt(unsafe {
c::sendto(*self.inner.as_inner(),
buf.as_ptr() as *const c_void, len,
- 0, dstp, dstlen)
+ MSG_NOSIGNAL, dstp, dstlen)
})?;
Ok(ret as usize)
}
c::send(*self.inner.as_inner(),
buf.as_ptr() as *const c_void,
len,
- 0)
+ MSG_NOSIGNAL)
})?;
Ok(ret as usize)
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use cell::RefCell;
/// Copied from String::push
/// This does **not** include the WTF-8 concatenation check.
fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
- let bytes = unsafe {
- char::from_u32_unchecked(code_point.value).encode_utf8()
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
};
- self.bytes.extend_from_slice(bytes.as_slice());
+ let mut bytes = [0; 4];
+ let bytes = c.encode_utf8(&mut bytes).as_bytes();
+ self.bytes.extend_from_slice(bytes)
}
#[inline]
return Some(tmp);
}
+ let mut buf = [0; 2];
self.code_points.next().map(|code_point| {
- let n = unsafe {
- char::from_u32_unchecked(code_point.value).encode_utf16()
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
};
- let n = n.as_slice();
- if n.len() == 2 {
- self.extra = n[1];
+ let n = c.encode_utf16(&mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
}
- n[0]
+ buf[0]
})
}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Global initialization and retreival of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ imp::args()
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+#[cfg(any(target_os = "linux",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "haiku"))]
+mod imp {
+ use os::unix::prelude::*;
+ use mem;
+ use ffi::{CStr, OsString};
+ use marker::PhantomData;
+ use libc;
+ use super::Args;
+
+ use sys_common::mutex::Mutex;
+
+ static mut GLOBAL_ARGS_PTR: usize = 0;
+ static LOCK: Mutex = Mutex::new();
+
+ pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ let args = (0..argc).map(|i| {
+ CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+ }).collect();
+
+ LOCK.lock();
+ let ptr = get_global_ptr();
+ assert!((*ptr).is_none());
+ (*ptr) = Some(box args);
+ LOCK.unlock();
+ }
+
+ pub unsafe fn cleanup() {
+ LOCK.lock();
+ *get_global_ptr() = None;
+ LOCK.unlock();
+ }
+
+ pub fn args() -> Args {
+ let bytes = clone().unwrap_or(Vec::new());
+ let v: Vec<OsString> = bytes.into_iter().map(|v| {
+ OsStringExt::from_vec(v)
+ }).collect();
+ Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+ }
+
+ fn clone() -> Option<Vec<Vec<u8>>> {
+ unsafe {
+ LOCK.lock();
+ let ptr = get_global_ptr();
+ let ret = (*ptr).as_ref().map(|s| (**s).clone());
+ LOCK.unlock();
+ return ret
+ }
+ }
+
+ fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+ unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+ }
+
+}
+
+#[cfg(any(target_os = "macos",
+ target_os = "ios"))]
+mod imp {
+ use ffi::CStr;
+ use marker::PhantomData;
+ use libc;
+ use super::Args;
+
+ pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+ }
+
+ pub fn cleanup() {
+ }
+
+ #[cfg(target_os = "macos")]
+ pub fn args() -> Args {
+ use os::unix::prelude::*;
+ extern {
+ // These functions are in crt_externs.h.
+ fn _NSGetArgc() -> *mut libc::c_int;
+ fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
+ }
+
+ let vec = unsafe {
+ let (argc, argv) = (*_NSGetArgc() as isize,
+ *_NSGetArgv() as *const *const libc::c_char);
+ (0.. argc as isize).map(|i| {
+ let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
+ OsStringExt::from_vec(bytes)
+ }).collect::<Vec<_>>()
+ };
+ Args {
+ iter: vec.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+ }
+
+ // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
+ // and use underscores in their names - they're most probably
+ // are considered private and therefore should be avoided
+ // Here is another way to get arguments using Objective C
+ // runtime
+ //
+ // In general it looks like:
+ // res = Vec::new()
+ // let args = [[NSProcessInfo processInfo] arguments]
+ // for i in (0..[args count])
+ // res.push([args objectAtIndex:i])
+ // res
+ #[cfg(target_os = "ios")]
+ pub fn args() -> Args {
+ use ffi::OsString;
+ use mem;
+ use str;
+
+ extern {
+ fn sel_registerName(name: *const libc::c_uchar) -> Sel;
+ fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+ fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
+ }
+
+ #[link(name = "Foundation", kind = "framework")]
+ #[link(name = "objc")]
+ #[cfg(not(cargobuild))]
+ extern {}
+
+ type Sel = *const libc::c_void;
+ type NsId = *const libc::c_void;
+
+ let mut res = Vec::new();
+
+ unsafe {
+ let process_info_sel = sel_registerName("processInfo\0".as_ptr());
+ let arguments_sel = sel_registerName("arguments\0".as_ptr());
+ let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
+ let count_sel = sel_registerName("count\0".as_ptr());
+ let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+ let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+ let info = objc_msgSend(klass, process_info_sel);
+ let args = objc_msgSend(info, arguments_sel);
+
+ let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
+ for i in 0..cnt {
+ let tmp = objc_msgSend(args, object_at_sel, i);
+ let utf_c_str: *const libc::c_char =
+ mem::transmute(objc_msgSend(tmp, utf8_sel));
+ let bytes = CStr::from_ptr(utf_c_str).to_bytes();
+ res.push(OsString::from(str::from_utf8(bytes).unwrap()))
+ }
+ }
+
+ Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
+ }
+}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(target_os = "linux")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "linux";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "macos")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "macos";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".dylib";
+ pub const DLL_EXTENSION: &'static str = "dylib";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "ios")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "ios";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".dylib";
+ pub const DLL_EXTENSION: &'static str = "dylib";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "freebsd")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "freebsd";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "dragonfly")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "dragonfly";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "bitrig")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "bitrig";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "netbsd")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "netbsd";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "openbsd")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "openbsd";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "android")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "android";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "solaris")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "solaris";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "nacl";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = ".nexe";
+ pub const EXE_EXTENSION: &'static str = "nexe";
+}
+#[cfg(all(target_os = "nacl", target_arch = "le32"))]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "pnacl";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".pso";
+ pub const DLL_EXTENSION: &'static str = "pso";
+ pub const EXE_SUFFIX: &'static str = ".pexe";
+ pub const EXE_EXTENSION: &'static str = "pexe";
+}
+
+#[cfg(target_os = "haiku")]
+mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "haiku";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
+mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "emscripten";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = ".js";
+ pub const EXE_EXTENSION: &'static str = "js";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
+mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "emscripten";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = ".js";
+ pub const EXE_EXTENSION: &'static str = "js";
+}
use sys::net::Socket;
use sys_common::{AsInner, FromInner, IntoInner};
+#[cfg(target_os = "linux")]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(target_os = "linux"))]
+const MSG_NOSIGNAL: libc::c_int = 0x0; // unused dummy value
+
fn sun_path_offset() -> usize {
unsafe {
// Work with an actual instance of the type since using a null pointer is UB
let count = cvt(libc::sendto(*d.0.as_inner(),
buf.as_ptr() as *const _,
buf.len(),
- 0,
+ MSG_NOSIGNAL,
&addr as *const _ as *const _,
len))?;
Ok(count as usize)
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod test {
use thread;
use io;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ use libc;
+
+ let p = unsafe {
+ libc::memchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len() as libc::size_t)
+ };
+ if p.is_null() {
+ None
+ } else {
+ Some(p as usize - (haystack.as_ptr() as usize))
+ }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+
+ #[cfg(target_os = "linux")]
+ fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+ use libc;
+
+ // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
+ if haystack.is_empty() {return None}
+ let p = unsafe {
+ libc::memrchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len() as libc::size_t)
+ };
+ if p.is_null() {
+ None
+ } else {
+ Some(p as usize - (haystack.as_ptr() as usize))
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+ ::sys_common::memchr::fallback::memrchr(needle, haystack)
+ }
+
+ memrchr_specific(needle, haystack)
+}
#[macro_use]
pub mod weak;
+pub mod args;
pub mod android;
#[cfg(any(not(cargobuild), feature = "backtrace"))]
pub mod backtrace;
pub mod condvar;
+pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
+pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
+pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
#[cfg(not(target_os = "linux"))]
const SOCK_CLOEXEC: c_int = 0;
+// Another conditional contant for name resolution: Macos et iOS use
+// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
+// Other platforms do otherwise.
+#[cfg(target_vendor = "apple")]
+use libc::SO_NOSIGPIPE;
+#[cfg(not(target_vendor = "apple"))]
+const SO_NOSIGPIPE: c_int = 0;
+
pub struct Socket(FileDesc);
pub fn init() {}
let fd = cvt(libc::socket(fam, ty, 0))?;
let fd = FileDesc::new(fd);
fd.set_cloexec()?;
- Ok(Socket(fd))
+ let socket = Socket(fd);
+ if cfg!(target_vendor = "apple") {
+ setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
+ }
+ Ok(socket)
}
}
}
}
-pub struct Args {
- iter: vec::IntoIter<OsString>,
- _dont_send_or_sync_me: PhantomData<*mut ()>,
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> { self.iter.next() }
- fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize { self.iter.len() }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
-}
-
-/// Returns the command line arguments
-///
-/// Returns a list of the command line arguments.
-#[cfg(target_os = "macos")]
-pub fn args() -> Args {
- extern {
- // These functions are in crt_externs.h.
- fn _NSGetArgc() -> *mut c_int;
- fn _NSGetArgv() -> *mut *mut *mut c_char;
- }
-
- let vec = unsafe {
- let (argc, argv) = (*_NSGetArgc() as isize,
- *_NSGetArgv() as *const *const c_char);
- (0.. argc as isize).map(|i| {
- let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
- OsStringExt::from_vec(bytes)
- }).collect::<Vec<_>>()
- };
- Args {
- iter: vec.into_iter(),
- _dont_send_or_sync_me: PhantomData,
- }
-}
-
-// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-// and use underscores in their names - they're most probably
-// are considered private and therefore should be avoided
-// Here is another way to get arguments using Objective C
-// runtime
-//
-// In general it looks like:
-// res = Vec::new()
-// let args = [[NSProcessInfo processInfo] arguments]
-// for i in (0..[args count])
-// res.push([args objectAtIndex:i])
-// res
-#[cfg(target_os = "ios")]
-pub fn args() -> Args {
- use mem;
-
- extern {
- fn sel_registerName(name: *const libc::c_uchar) -> Sel;
- fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
- fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
- }
-
- #[link(name = "Foundation", kind = "framework")]
- #[link(name = "objc")]
- #[cfg(not(cargobuild))]
- extern {}
-
- type Sel = *const libc::c_void;
- type NsId = *const libc::c_void;
-
- let mut res = Vec::new();
-
- unsafe {
- let process_info_sel = sel_registerName("processInfo\0".as_ptr());
- let arguments_sel = sel_registerName("arguments\0".as_ptr());
- let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
- let count_sel = sel_registerName("count\0".as_ptr());
- let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
-
- let klass = objc_getClass("NSProcessInfo\0".as_ptr());
- let info = objc_msgSend(klass, process_info_sel);
- let args = objc_msgSend(info, arguments_sel);
-
- let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
- for i in 0..cnt {
- let tmp = objc_msgSend(args, object_at_sel, i);
- let utf_c_str: *const libc::c_char =
- mem::transmute(objc_msgSend(tmp, utf8_sel));
- let bytes = CStr::from_ptr(utf_c_str).to_bytes();
- res.push(OsString::from(str::from_utf8(bytes).unwrap()))
- }
- }
-
- Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
-}
-
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "solaris",
- target_os = "nacl",
- target_os = "emscripten",
- target_os = "haiku"))]
-pub fn args() -> Args {
- use sys_common;
- let bytes = sys_common::args::clone().unwrap_or(Vec::new());
- let v: Vec<OsString> = bytes.into_iter().map(|v| {
- OsStringExt::from_vec(v)
- }).collect();
- Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
-}
-
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use path::Prefix;
+use ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+ None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
}
// NaCl has no signal support.
- if cfg!(not(target_os = "nacl")) {
+ if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
// Reset signal handling so the child process starts in a
// standardized state. libstd ignores SIGPIPE, and signal-handling
// libraries often set a mask. Child processes inherit ignored
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::*;
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
+
+pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
+// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
+// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
+#[cfg(not(target_os = "emscripten"))]
+unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
+ stack_size: libc::size_t) -> libc::c_int {
+ libc::pthread_attr_setstacksize(attr, stack_size)
+}
+
+#[cfg(target_os = "emscripten")]
+unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
+ _stack_size: libc::size_t) -> libc::c_int {
+ panic!()
+}
+
impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
-> io::Result<Thread> {
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
let stack_size = cmp::max(stack, min_stack_size(&attr));
- match libc::pthread_attr_setstacksize(&mut attr,
- stack_size as libc::size_t) {
+ match pthread_attr_setstacksize(&mut attr,
+ stack_size as libc::size_t) {
0 => {}
n => {
assert_eq!(n, libc::EINVAL);
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use os::windows::prelude::*;
+use sys::c;
+use slice;
+use ops::Range;
+use ffi::OsString;
+use libc::{c_int, c_void};
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }
+
+pub unsafe fn cleanup() { }
+
+pub fn args() -> Args {
+ unsafe {
+ let mut nArgs: c_int = 0;
+ let lpCmdLine = c::GetCommandLineW();
+ let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
+
+ // szArcList can be NULL if CommandLinToArgvW failed,
+ // but in that case nArgs is 0 so we won't actually
+ // try to read a null pointer
+ Args { cur: szArgList, range: 0..(nArgs as isize) }
+ }
+}
+
+pub struct Args {
+ range: Range<isize>,
+ cur: *mut *mut u16,
+}
+
+unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
+ let mut len = 0;
+ while *ptr.offset(len) != 0 { len += 1; }
+
+ // Push it onto the list.
+ let ptr = ptr as *const u16;
+ let buf = slice::from_raw_parts(ptr, len as usize);
+ OsStringExt::from_wide(buf)
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.range.len() }
+}
+
+impl Drop for Args {
+ fn drop(&mut self) {
+ // self.cur can be null if CommandLineToArgvW previously failed,
+ // but LocalFree ignores NULL pointers
+ unsafe { c::LocalFree(self.cur as *mut c_void); }
+ }
+}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod os {
+ pub const FAMILY: &'static str = "windows";
+ pub const OS: &'static str = "windows";
+ pub const DLL_PREFIX: &'static str = "";
+ pub const DLL_SUFFIX: &'static str = ".dll";
+ pub const DLL_EXTENSION: &'static str = "dll";
+ pub const EXE_SUFFIX: &'static str = ".exe";
+ pub const EXE_EXTENSION: &'static str = "exe";
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+// Fallback memchr is fastest on windows
+pub use sys_common::memchr::fallback::{memchr, memrchr};
#[macro_use] pub mod compat;
+pub mod args;
pub mod backtrace;
pub mod c;
pub mod condvar;
pub mod dynamic_lib;
+pub mod env;
pub mod ext;
pub mod fs;
pub mod handle;
+pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
+pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
use ffi::{OsString, OsStr};
use fmt;
use io;
-use libc::{c_int, c_void};
-use ops::Range;
use os::windows::ffi::EncodeWide;
use path::{self, PathBuf};
use ptr;
}).map(|_| ())
}
-pub struct Args {
- range: Range<isize>,
- cur: *mut *mut u16,
-}
-
-unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
- let mut len = 0;
- while *ptr.offset(len) != 0 { len += 1; }
-
- // Push it onto the list.
- let ptr = ptr as *const u16;
- let buf = slice::from_raw_parts(ptr, len as usize);
- OsStringExt::from_wide(buf)
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
- }
- fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize { self.range.len() }
-}
-
-impl Drop for Args {
- fn drop(&mut self) {
- // self.cur can be null if CommandLineToArgvW previously failed,
- // but LocalFree ignores NULL pointers
- unsafe { c::LocalFree(self.cur as *mut c_void); }
- }
-}
-
-pub fn args() -> Args {
- unsafe {
- let mut nArgs: c_int = 0;
- let lpCmdLine = c::GetCommandLineW();
- let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
-
- // szArcList can be NULL if CommandLinToArgvW failed,
- // but in that case nArgs is 0 so we won't actually
- // try to read a null pointer
- Args { cur: szArgList, range: 0..(nArgs as isize) }
- }
-}
-
pub fn temp_dir() -> PathBuf {
super::fill_utf16_buf(|buf, sz| unsafe {
c::GetTempPathW(sz, buf)
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ascii::*;
+
+use path::Prefix;
+use ffi::OsStr;
+use mem;
+
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+ unsafe { mem::transmute(s) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+ mem::transmute(s)
+}
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/' || b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'\\'
+}
+
+pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
+ use path::Prefix::*;
+ unsafe {
+ // The unsafety here stems from converting between &OsStr and &[u8]
+ // and back. This is safe to do because (1) we only look at ASCII
+ // contents of the encoding and (2) new &OsStr values are produced
+ // only from ASCII-bounded slices of existing &OsStr values.
+ let mut path = os_str_as_u8_slice(path);
+
+ if path.starts_with(br"\\") {
+ // \\
+ path = &path[2..];
+ if path.starts_with(br"?\") {
+ // \\?\
+ path = &path[2..];
+ if path.starts_with(br"UNC\") {
+ // \\?\UNC\server\share
+ path = &path[4..];
+ let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
+ Some((server, share)) =>
+ (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
+ None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
+ };
+ return Some(VerbatimUNC(server, share));
+ } else {
+ // \\?\path
+ let idx = path.iter().position(|&b| b == b'\\');
+ if idx == Some(2) && path[1] == b':' {
+ let c = path[0];
+ if c.is_ascii() && (c as char).is_alphabetic() {
+ // \\?\C:\ path
+ return Some(VerbatimDisk(c.to_ascii_uppercase()));
+ }
+ }
+ let slice = &path[..idx.unwrap_or(path.len())];
+ return Some(Verbatim(u8_slice_as_os_str(slice)));
+ }
+ } else if path.starts_with(b".\\") {
+ // \\.\path
+ path = &path[2..];
+ let pos = path.iter().position(|&b| b == b'\\');
+ let slice = &path[..pos.unwrap_or(path.len())];
+ return Some(DeviceNS(u8_slice_as_os_str(slice)));
+ }
+ match parse_two_comps(path, is_sep_byte) {
+ Some((server, share)) if !server.is_empty() && !share.is_empty() => {
+ // \\server\share
+ return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
+ }
+ _ => (),
+ }
+ } else if path.get(1) == Some(& b':') {
+ // C:
+ let c = path[0];
+ if c.is_ascii() && (c as char).is_alphabetic() {
+ return Some(Disk(c.to_ascii_uppercase()));
+ }
+ }
+ return None;
+ }
+
+ fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+ let first = match path.iter().position(|x| f(*x)) {
+ None => return None,
+ Some(x) => &path[..x],
+ };
+ path = &path[(first.len() + 1)..];
+ let idx = path.iter().position(|x| f(*x));
+ let second = &path[..idx.unwrap_or(path.len())];
+ Some((first, second))
+ }
+}
+
+pub const MAIN_SEP_STR: &'static str = "\\";
+pub const MAIN_SEP: char = '\\';
fn invalid_encoding() -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}
+
+pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
}
}
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::{channel, Sender};
use cell::{Cell, UnsafeCell};
//!
//! [`Cell`]: ../cell/struct.Cell.html
//! [`RefCell`]: ../cell/struct.RefCell.html
-//! [`thread_local!`]: ../macro.thread_local!.html
+//! [`thread_local!`]: ../macro.thread_local.html
//! [`with`]: struct.LocalKey.html#method.with
#![stable(feature = "rust1", since = "1.0.0")]
// Tests
////////////////////////////////////////////////////////////////////////////////
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use any::Any;
use sync::mpsc::{channel, Sender};
pub struct SystemTime(time::SystemTime);
/// An error returned from the `duration_since` method on `SystemTime`,
-/// used to learn about why how far in the opposite direction a timestamp lies.
+/// used to learn how far in the opposite direction a system time lies.
#[derive(Clone, Debug)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTimeError(Duration);
/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct LifetimeDef {
+ pub attrs: ThinVec<Attribute>,
pub lifetime: Lifetime,
pub bounds: Vec<Lifetime>
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TyParam {
+ pub attrs: ThinVec<Attribute>,
pub ident: Ident,
pub id: NodeId,
pub bounds: TyParamBounds,
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
s.walk(it)
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
before.iter().all(|p| p.walk(it)) &&
slice.iter().all(|p| p.walk(it)) &&
after.iter().all(|p| p.walk(it))
/// A range pattern, e.g. `1...2`
Range(P<Expr>, P<Expr>),
/// `[a, b, ..i, y, z]` is represented as:
- /// `PatKind::Vec(box [a, b], Some(i), box [y, z])`
- Vec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+ /// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
+ Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
/// A macro pattern; pre-expansion
Mac(Mac),
}
/// The different kinds of types recognized by the compiler
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TyKind {
- /// A variable-length array (`[T]`)
- Vec(P<Ty>),
+ /// A variable-length slice (`[T]`)
+ Slice(P<Ty>),
/// A fixed length array (`[T; n]`)
- FixedLengthVec(P<Ty>, P<Expr>),
+ Array(P<Ty>, P<Expr>),
/// A raw pointer (`*const T` or `*mut T`)
Ptr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
let ty = ecx.ty(
span,
- ast::TyKind::FixedLengthVec(
+ ast::TyKind::Array(
ecx.ty(
span,
ast::TyKind::Tup(vec![ty_str.clone(), ty_str])
fn typaram(&self,
span: Span,
id: ast::Ident,
+ attrs: Vec<ast::Attribute>,
bounds: ast::TyParamBounds,
default: Option<P<ast::Ty>>) -> ast::TyParam;
fn lifetime_def(&self,
span: Span,
name: ast::Name,
+ attrs: Vec<ast::Attribute>,
bounds: Vec<ast::Lifetime>)
-> ast::LifetimeDef;
ident: ast::Ident,
typ: P<ast::Ty>,
ex: P<ast::Expr>)
- -> P<ast::Stmt>;
+ -> ast::Stmt;
fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
fn typaram(&self,
span: Span,
id: ast::Ident,
+ attrs: Vec<ast::Attribute>,
bounds: ast::TyParamBounds,
default: Option<P<ast::Ty>>) -> ast::TyParam {
ast::TyParam {
ident: id,
id: ast::DUMMY_NODE_ID,
+ attrs: attrs.into(),
bounds: bounds,
default: default,
span: span
fn lifetime_def(&self,
span: Span,
name: ast::Name,
+ attrs: Vec<ast::Attribute>,
bounds: Vec<ast::Lifetime>)
-> ast::LifetimeDef {
ast::LifetimeDef {
+ attrs: attrs.into(),
lifetime: self.lifetime(span, name),
bounds: bounds
}
ident: ast::Ident,
typ: P<ast::Ty>,
ex: P<ast::Expr>)
- -> P<ast::Stmt> {
+ -> ast::Stmt {
let pat = if mutbl {
let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable);
self.pat_ident_binding_mode(sp, ident, binding_mode)
span: sp,
attrs: ast::ThinVec::new(),
});
- P(ast::Stmt {
+ ast::Stmt {
id: ast::DUMMY_NODE_ID,
node: ast::StmtKind::Local(local),
span: sp,
- })
+ }
}
// Generate `let _: Type;`, usually used for type assertions.
// Used to identify the `compiler_builtins` crate
// rustc internal
(active, compiler_builtins, "1.13.0", None),
+
+ // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
+ (active, generic_param_attrs, "1.11.0", Some(34761)),
);
declare_features! (
fn visit_pat(&mut self, pattern: &ast::Pat) {
match pattern.node {
- PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
+ PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
gate_feature_post!(&self, advanced_slice_patterns,
pattern.span,
"multiple-element slice matches anywhere \
but at the end of a slice (e.g. \
`[0, ..xs, 0]`) are experimental")
}
- PatKind::Vec(..) => {
+ PatKind::Slice(..) => {
gate_feature_post!(&self, slice_patterns,
pattern.span,
"slice pattern syntax is experimental");
visit::walk_vis(self, vis)
}
+
+ fn visit_generics(&mut self, g: &ast::Generics) {
+ for t in &g.ty_params {
+ if !t.attrs.is_empty() {
+ gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
+ "attributes on type parameter bindings are experimental");
+ }
+ }
+ visit::walk_generics(self, g)
+ }
+
+ fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
+ if !lifetime_def.attrs.is_empty() {
+ gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
+ "attributes on lifetime bindings are experimental");
+ }
+ visit::walk_lifetime_def(self, lifetime_def)
+ }
}
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
id: fld.new_id(id),
node: match node {
TyKind::Infer | TyKind::ImplicitSelf => node,
- TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)),
+ TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)),
TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)),
TyKind::Rptr(region, mt) => {
TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
TyKind::ObjectSum(fld.fold_ty(ty),
fld.fold_bounds(bounds))
}
- TyKind::FixedLengthVec(ty, e) => {
- TyKind::FixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
+ TyKind::Array(ty, e) => {
+ TyKind::Array(fld.fold_ty(ty), fld.fold_expr(e))
}
TyKind::Typeof(expr) => {
TyKind::Typeof(fld.fold_expr(expr))
}
pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
- let TyParam {id, ident, bounds, default, span} = tp;
+ let TyParam {attrs, id, ident, bounds, default, span} = tp;
+ let attrs: Vec<_> = attrs.into();
TyParam {
+ attrs: attrs.into_iter()
+ .flat_map(|x| fld.fold_attribute(x).into_iter())
+ .collect::<Vec<_>>()
+ .into(),
id: fld.new_id(id),
ident: ident,
bounds: fld.fold_bounds(bounds),
pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
-> LifetimeDef {
+ let attrs: Vec<_> = l.attrs.into();
LifetimeDef {
+ attrs: attrs.into_iter()
+ .flat_map(|x| fld.fold_attribute(x).into_iter())
+ .collect::<Vec<_>>()
+ .into(),
lifetime: fld.fold_lifetime(l.lifetime),
bounds: fld.fold_lifetimes(l.bounds),
}
PatKind::Range(e1, e2) => {
PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
},
- PatKind::Vec(before, slice, after) => {
- PatKind::Vec(before.move_map(|x| folder.fold_pat(x)),
+ PatKind::Slice(before, slice, after) => {
+ PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
slice.map(|x| folder.fold_pat(x)),
after.move_map(|x| folder.fold_pat(x)))
}
let lo = self.span.lo;
let (name, node) = if self.eat_keyword(keywords::Type) {
- let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
+ let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
self.expect(&token::Semi)?;
(ident, TraitItemKind::Type(bounds, default))
} else if self.is_const_item() {
// Parse the `; e` in `[ i32; e ]`
// where `e` is a const expression
let t = match self.maybe_parse_fixed_length_of_vec()? {
- None => TyKind::Vec(t),
- Some(suffix) => TyKind::FixedLengthVec(t, suffix)
+ None => TyKind::Slice(t),
+ Some(suffix) => TyKind::Array(t, suffix)
};
self.expect(&token::CloseDelim(token::Bracket))?;
t
/// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def =
/// lifetime [':' lifetimes]`
- pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
-
+ ///
+ /// If `followed_by_ty_params` is None, then we are in a context
+ /// where only lifetime parameters are allowed, and thus we should
+ /// error if we encounter attributes after the bound lifetimes.
+ ///
+ /// If `followed_by_ty_params` is Some(r), then there may be type
+ /// parameter bindings after the lifetimes, so we should pass
+ /// along the parsed attributes to be attached to the first such
+ /// type parmeter.
+ pub fn parse_lifetime_defs(&mut self,
+ followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
+ -> PResult<'a, Vec<ast::LifetimeDef>>
+ {
let mut res = Vec::new();
loop {
+ let attrs = self.parse_outer_attributes()?;
match self.token {
token::Lifetime(_) => {
let lifetime = self.parse_lifetime()?;
} else {
Vec::new()
};
- res.push(ast::LifetimeDef { lifetime: lifetime,
+ res.push(ast::LifetimeDef { attrs: attrs.into(),
+ lifetime: lifetime,
bounds: bounds });
}
_ => {
+ if let Some(recv) = followed_by_ty_params {
+ assert!(recv.is_empty());
+ *recv = attrs;
+ } else {
+ let msg = "trailing attribute after lifetime parameters";
+ return Err(self.fatal(msg));
+ }
+ debug!("parse_lifetime_defs ret {:?}", res);
return Ok(res);
}
}
self.bump();
let (before, slice, after) = self.parse_pat_vec_elements()?;
self.expect(&token::CloseDelim(token::Bracket))?;
- pat = PatKind::Vec(before, slice, after);
+ pat = PatKind::Slice(before, slice, after);
}
// At this point, token != _, &, &&, (, [
_ => if self.eat_keyword(keywords::Mut) {
}
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
- fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
+ fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
let span = self.span;
let ident = self.parse_ident()?;
};
Ok(TyParam {
+ attrs: preceding_attrs.into(),
ident: ident,
id: ast::DUMMY_NODE_ID,
bounds: bounds,
let span_lo = self.span.lo;
if self.eat(&token::Lt) {
- let lifetime_defs = self.parse_lifetime_defs()?;
+ // Upon encountering attribute in generics list, we do not
+ // know if it is attached to lifetime or to type param.
+ //
+ // Solution: 1. eagerly parse attributes in tandem with
+ // lifetime defs, 2. store last set of parsed (and unused)
+ // attributes in `attrs`, and 3. pass in those attributes
+ // when parsing formal type param after lifetime defs.
+ let mut attrs = vec![];
+ let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
let mut seen_default = false;
+ let mut post_lifetime_attrs = Some(attrs);
let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
p.forbid_lifetime()?;
- let ty_param = p.parse_ty_param()?;
+ // Move out of `post_lifetime_attrs` if present. O/w
+ // not first type param: parse attributes anew.
+ let attrs = match post_lifetime_attrs.as_mut() {
+ None => p.parse_outer_attributes()?,
+ Some(attrs) => mem::replace(attrs, vec![]),
+ };
+ post_lifetime_attrs = None;
+ let ty_param = p.parse_ty_param(attrs)?;
if ty_param.default.is_some() {
seen_default = true;
} else if seen_default {
}
Ok(ty_param)
})?;
+ if let Some(attrs) = post_lifetime_attrs {
+ if !attrs.is_empty() {
+ self.span_err(attrs[0].span,
+ "trailing attribute after lifetime parameters");
+ }
+ }
Ok(ast::Generics {
lifetimes: lifetime_defs,
ty_params: ty_params,
let bound_lifetimes = if self.eat_keyword(keywords::For) {
// Higher ranked constraint.
self.expect(&token::Lt)?;
- let lifetime_defs = self.parse_lifetime_defs()?;
+ let lifetime_defs = self.parse_lifetime_defs(None)?;
self.expect_gt()?;
lifetime_defs
} else {
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
if self.eat_keyword(keywords::For) {
self.expect(&token::Lt)?;
- let lifetime_defs = self.parse_lifetime_defs()?;
+ let lifetime_defs = self.parse_lifetime_defs(None)?;
self.expect_gt()?;
Ok(lifetime_defs)
} else {
try!(self.maybe_print_comment(ty.span.lo));
try!(self.ibox(0));
match ty.node {
- ast::TyKind::Vec(ref ty) => {
+ ast::TyKind::Slice(ref ty) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&ty));
try!(word(&mut self.s, "]"));
ast::TyKind::ImplTrait(ref bounds) => {
try!(self.print_bounds("impl ", &bounds[..]));
}
- ast::TyKind::FixedLengthVec(ref ty, ref v) => {
+ ast::TyKind::Array(ref ty, ref v) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&ty));
try!(word(&mut self.s, "; "));
try!(word(&mut self.s, "..."));
try!(self.print_expr(&end));
}
- PatKind::Vec(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref before, ref slice, ref after) => {
try!(word(&mut self.s, "["));
try!(self.commasep(Inconsistent,
&before[..],
let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.name());
// &'static [self::test::TestDescAndFn]
let static_type = ecx.ty_rptr(sp,
- ecx.ty(sp, ast::TyKind::Vec(struct_type)),
+ ecx.ty(sp, ast::TyKind::Slice(struct_type)),
Some(static_lt),
ast::Mutability::Immutable);
// static TESTS: $static_type = &[...];
pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
visitor.visit_lifetime(&lifetime_def.lifetime);
walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+ walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
}
pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
match typ.node {
- TyKind::Vec(ref ty) | TyKind::Paren(ref ty) => {
+ TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => {
visitor.visit_ty(ty)
}
TyKind::Ptr(ref mutable_type) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyKind::FixedLengthVec(ref ty, ref expression) => {
+ TyKind::Array(ref ty, ref expression) => {
visitor.visit_ty(ty);
visitor.visit_expr(expression)
}
visitor.visit_expr(upper_bound)
}
PatKind::Wild => (),
- PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+ PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
walk_list!(visitor, visit_pat, prepatterns);
walk_list!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
visitor.visit_ident(param.span, param.ident);
walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
walk_list!(visitor, visit_ty, ¶m.default);
+ walk_list!(visitor, visit_attribute, &*param.attrs);
}
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
for predicate in &generics.where_clause.predicates {
bounds.push((*declared_bound).clone());
}
- cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None)
+ cx.typaram(self.span, ty_param.ident, vec![], P::from_vec(bounds), None)
}));
// and similarly for where clauses
fn mk_ty_param(cx: &ExtCtxt,
span: Span,
name: &str,
+ attrs: &[ast::Attribute],
bounds: &[Path],
self_ident: Ident,
self_generics: &Generics)
cx.typarambound(path)
})
.collect();
- cx.typaram(span, cx.ident_of(name), bounds, None)
+ cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
}
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
let bounds = bounds.iter()
.map(|b| cx.lifetime(span, cx.ident_of(*b).name))
.collect();
- cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
+ cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds)
})
.collect();
let ty_params = self.bounds
.map(|t| {
match *t {
(ref name, ref bounds) => {
- mk_ty_param(cx, span, *name, bounds, self_ty, self_generics)
+ mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
}
}
})
-> P<ast::Expr> {
let sp = piece_ty.span;
let ty = ecx.ty_rptr(sp,
- ecx.ty(sp, ast::TyKind::Vec(piece_ty)),
+ ecx.ty(sp, ast::TyKind::Slice(piece_ty)),
Some(ecx.lifetime(sp, keywords::StaticLifetime.name())),
ast::Mutability::Immutable);
let slice = ecx.expr_vec_slice(sp, pieces);
}
}
- thread::spawn(move || {
- let data = Arc::new(Mutex::new(Vec::new()));
- let data2 = data.clone();
- let cfg = thread::Builder::new().name(match desc.name {
- DynTestName(ref name) => name.clone(),
- StaticTestName(name) => name.to_owned(),
+ // If the platform is single-threaded we're just going to run
+ // the test synchronously, regardless of the concurrency
+ // level.
+ let supports_threads = !cfg!(target_os = "emscripten");
+
+ // Buffer for capturing standard I/O
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let data2 = data.clone();
+
+ if supports_threads {
+ thread::spawn(move || {
+ let cfg = thread::Builder::new().name(match desc.name {
+ DynTestName(ref name) => name.clone(),
+ StaticTestName(name) => name.to_owned(),
+ });
+
+ let result_guard = cfg.spawn(move || {
+ if !nocapture {
+ io::set_print(Some(box Sink(data2.clone())));
+ io::set_panic(Some(box Sink(data2)));
+ }
+ testfn()
+ })
+ .unwrap();
+ let test_result = calc_result(&desc, result_guard.join());
+ let stdout = data.lock().unwrap().to_vec();
+ monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
});
+ } else {
+ let oldio = if !nocapture {
+ Some((
+ io::set_print(Some(box Sink(data2.clone()))),
+ io::set_panic(Some(box Sink(data2)))
+ ))
+ } else {
+ None
+ };
- let result_guard = cfg.spawn(move || {
- if !nocapture {
- io::set_print(box Sink(data2.clone()));
- io::set_panic(box Sink(data2));
- }
- testfn()
- })
- .unwrap();
- let test_result = calc_result(&desc, result_guard.join());
+ use std::panic::{catch_unwind, AssertUnwindSafe};
+
+ let result = catch_unwind(AssertUnwindSafe(|| {
+ testfn()
+ }));
+
+ if let Some((printio, panicio)) = oldio {
+ io::set_print(printio);
+ io::set_panic(panicio);
+ };
+
+ let test_result = calc_result(&desc, result);
let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
- });
+ }
}
match testfn {
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
- target_arch = "asmjs")))]
+ target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
// we need to "use" the argument in some way LLVM can't
// introspect.
dummy
}
#[cfg(any(all(target_os = "nacl", target_arch = "le32"),
- target_arch = "asmjs"))]
+ target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
dummy
#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;
-#[cfg(target_arch = "asmjs")]
+#[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20;
#[repr(C)]
-Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af
+Subproject commit 3e03f7374169cd41547d75e62ac2ab8a103a913c
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2016-09-17
+2016-09-25
fn main() {
let x = Test;
x.method::<i32>(); //~ ERROR E0035
+ //~| NOTE called with unneeded type parameters
}
let x = Test;
let v = &[0];
x.method::<i32, i32>(v); //~ ERROR E0036
+ //~| NOTE Passed 2 type arguments, expected 1
}
}
type Foo = Trait<F=i32>; //~ ERROR E0220
- //~^ ERROR E0191
-
+ //~| NOTE associated type `F` not found
+ //~| ERROR E0191
+ //~| NOTE missing associated type `Bar` value
fn main() {
}
// system allocator. Do this by linking in jemalloc and making sure that we get
// an error.
+// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
+
#![feature(alloc_jemalloc)]
extern crate allocator_dylib;
// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
// by linking in the system allocator here and ensuring that we get a complaint.
+// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
+
#![feature(alloc_system)]
extern crate allocator_dylib2;
--- /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.
+
+// This test ensures that attributes on formals in generic parameter
+// lists are included when we are checking for unstable attributes.
+//
+// Note that feature(generic_param_attrs) *is* enabled here. We are
+// checking feature-gating of the attributes themselves, not the
+// capability to parse such attributes in that context.
+
+#![feature(generic_param_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[lt_struct] 'a>(&'a u32);
+//~^ ERROR The attribute `lt_struct` is currently unknown to the compiler
+struct StTy<#[ty_struct] I>(I);
+//~^ ERROR The attribute `ty_struct` is currently unknown to the compiler
+
+enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
+//~^ ERROR The attribute `lt_enum` is currently unknown to the compiler
+enum EnTy<#[ty_enum] J> { A(J), B }
+//~^ ERROR The attribute `ty_enum` is currently unknown to the compiler
+
+trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+//~^ ERROR The attribute `lt_trait` is currently unknown to the compiler
+trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
+//~^ ERROR The attribute `ty_trait` is currently unknown to the compiler
+
+type TyLt<#[lt_type] 'd> = &'d u32;
+//~^ ERROR The attribute `lt_type` is currently unknown to the compiler
+type TyTy<#[ty_type] L> = (L, );
+//~^ ERROR The attribute `ty_type` is currently unknown to the compiler
+
+impl<#[lt_inherent] 'e> StLt<'e> { }
+//~^ ERROR The attribute `lt_inherent` is currently unknown to the compiler
+impl<#[ty_inherent] M> StTy<M> { }
+//~^ ERROR The attribute `ty_inherent` is currently unknown to the compiler
+
+impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+ //~^ ERROR The attribute `lt_impl_for` is currently unknown to the compiler
+ fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
+ //~^ ERROR The attribute `ty_impl_for` is currently unknown to the compiler
+ fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+//~^ ERROR The attribute `lt_fn` is currently unknown to the compiler
+fn f_ty<#[ty_fn] O>(_: O) { }
+//~^ ERROR The attribute `ty_fn` is currently unknown to the compiler
+
+impl<I> StTy<I> {
+ fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+ //~^ ERROR The attribute `lt_meth` is currently unknown to the compiler
+ fn m_ty<#[ty_meth] P>(_: P) { }
+ //~^ ERROR The attribute `ty_meth` is currently unknown to the compiler
+}
+
+fn hof_lt<Q>(_: Q)
+ where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+ //~^ ERROR The attribute `lt_hof` is currently unknown to the compiler
+{
+}
+
+fn main() {
+
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test ensures that attributes on formals in generic parameter
+// lists are rejected if feature(generic_param_attrs) is not enabled.
+//
+// (We are prefixing all tested features with `rustc_`, to ensure that
+// the attributes themselves won't be rejected by the compiler when
+// using `rustc_attrs` feature. There is a separate compile-fail/ test
+// ensuring that the attribute feature-gating works in this context.)
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+struct StTy<#[rustc_ty_struct] I>(I);
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+enum EnTy<#[rustc_ty_enum] J> { A(J), B }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+type TyLt<#[rustc_lt_type] 'd> = &'d u32;
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+type TyTy<#[rustc_ty_type] L> = (L, );
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+impl<#[rustc_ty_inherent] M> StTy<M> { }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+ //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+ fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
+ //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+ fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+fn f_ty<#[rustc_ty_fn] O>(_: O) { }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<I> StTy<I> {
+ fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+ //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+ fn m_ty<#[rustc_ty_meth] P>(_: P) { }
+ //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+}
+
+fn hof_lt<Q>(_: Q)
+ where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+ //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+{
+}
+
+fn main() {
+
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
+
+impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> {
+ //~^ ERROR trailing attribute after lifetime parameters
+}
+
+fn main() {
+
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct RefAny<'a, T>(&'a T);
+
+impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
+ //~^ ERROR expected identifier, found `>`
+}
+
+fn main() {
+
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
+
+fn hof_lt<Q>(_: Q)
+ where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
+ //~^ ERROR trailing attribute after lifetime parameters
+{
+
+}
+
+fn main() {
+
+}
enum A {
Ok = i8::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 127i8
+ //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome
}
}
enum A {
Ok = u8::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 255u8
+ //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome
}
}
enum A {
Ok = i16::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 32767i16
+ //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome
}
}
enum A {
Ok = u16::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 65535u16
+ //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome
}
}
enum A {
Ok = i32::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 2147483647i32
+ //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome
}
}
enum A {
Ok = u32::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 4294967295u32
+ //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome
}
}
enum A {
Ok = i64::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 9223372036854775807i64
+ //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
}
}
enum A {
Ok = u64::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 18446744073709551615u64
+ //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome
}
}
enum A {
Ok = i8::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 127i8
+ //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = u8::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 255u8
+ //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = i16::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| NOTE overflowed on value after 32767i16
+ //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = u16::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| overflowed on value after 65535u16
+ //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = i32::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| overflowed on value after 2147483647i32
+ //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = u32::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| overflowed on value after 4294967295u32
+ //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = i64::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| overflowed on value after 9223372036854775807i64
+ //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
}
let x = A::Ok;
enum A {
Ok = u64::MAX - 1,
Ok2,
- OhNo, //~ ERROR enum discriminant overflowed
+ OhNo, //~ ERROR enum discriminant overflowed [E0370]
+ //~| overflowed on value after 18446744073709551615u64
+ //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome
}
let x = A::Ok;
--- /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.
+
+fn main() {
+ extern crate rand;
+ use rand::Rng; //~ ERROR unresolved import
+}
fn f<F:Trait(isize) -> isize>(x: F) {}
//~^ ERROR E0244
//~| NOTE expected no type arguments, found 1
-//~| ERROR associated type `Output` not found
+//~| ERROR E0220
+//~| NOTE associated type `Output` not found
fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for enum definitions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// We also test the ICH for enum definitions exported in metadata. Same as
+// above, we want to make sure that the change between rev1 and rev2 also
+// results in a change of the ICH for the enum's metadata, and that it stays
+// the same between rev2 and rev3.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+
+// Change enum visibility -----------------------------------------------------
+#[cfg(cfail1)]
+enum EnumVisibility { A }
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub enum EnumVisibility { A }
+
+
+
+// Change name of a c-style variant -------------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameCStyleVariant {
+ Variant1,
+ Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameCStyleVariant {
+ Variant1,
+ Variant2Changed,
+}
+
+
+
+// Change name of a tuple-style variant ---------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameTupleStyleVariant {
+ Variant1,
+ Variant2(u32, f32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameTupleStyleVariant {
+ Variant1,
+ Variant2Changed(u32, f32),
+}
+
+
+
+// Change name of a struct-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameStructStyleVariant {
+ Variant1,
+ Variant2 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameStructStyleVariant {
+ Variant1,
+ Variant2Changed { a: u32, b: f32 },
+}
+
+
+
+// Change the value of a c-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeValueCStyleVariant0 {
+ Variant1,
+ Variant2 = 11,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeValueCStyleVariant0 {
+ Variant1,
+ Variant2 = 22,
+}
+
+#[cfg(cfail1)]
+enum EnumChangeValueCStyleVariant1 {
+ Variant1,
+ Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeValueCStyleVariant1 {
+ Variant1,
+ Variant2 = 11,
+}
+
+
+
+// Add a c-style variant ------------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddCStyleVariant {
+ Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddCStyleVariant {
+ Variant1,
+ Variant2,
+}
+
+
+
+// Remove a c-style variant ---------------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveCStyleVariant {
+ Variant1,
+ Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveCStyleVariant {
+ Variant1,
+}
+
+
+
+// Add a tuple-style variant --------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTupleStyleVariant {
+ Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddTupleStyleVariant {
+ Variant1,
+ Variant2(u32, f32),
+}
+
+
+
+// Remove a tuple-style variant -----------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveTupleStyleVariant {
+ Variant1,
+ Variant2(u32, f32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveTupleStyleVariant {
+ Variant1,
+}
+
+
+
+// Add a struct-style variant -------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddStructStyleVariant {
+ Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddStructStyleVariant {
+ Variant1,
+ Variant2 { a: u32, b: f32 },
+}
+
+
+
+// Remove a struct-style variant ----------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveStructStyleVariant {
+ Variant1,
+ Variant2 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveStructStyleVariant {
+ Variant1,
+}
+
+
+
+// Change the type of a field in a tuple-style variant ------------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldTypeTupleStyleVariant {
+ Variant1(u32, u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldTypeTupleStyleVariant {
+ Variant1(u32, u64),
+}
+
+
+
+// Change the type of a field in a struct-style variant -----------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldTypeStructStyleVariant {
+ Variant1,
+ Variant2 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldTypeStructStyleVariant {
+ Variant1,
+ Variant2 { a: u32, b: u64 },
+}
+
+
+
+// Change the name of a field in a struct-style variant -----------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldNameStructStyleVariant {
+ Variant1 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldNameStructStyleVariant {
+ Variant1 { a: u32, c: u32 },
+}
+
+
+
+// Change order of fields in a tuple-style variant ----------------------------
+#[cfg(cfail1)]
+enum EnumChangeOrderTupleStyleVariant {
+ Variant1(u32, u64),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeOrderTupleStyleVariant {
+ Variant1(u64, u32),
+}
+
+
+
+// Change order of fields in a struct-style variant ---------------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldOrderStructStyleVariant {
+ Variant1 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldOrderStructStyleVariant {
+ Variant1 { b: f32, a: u32 },
+}
+
+
+
+// Add a field to a tuple-style variant ---------------------------------------
+#[cfg(cfail1)]
+enum EnumAddFieldTupleStyleVariant {
+ Variant1(u32, u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddFieldTupleStyleVariant {
+ Variant1(u32, u32, u32),
+}
+
+
+
+// Add a field to a struct-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumAddFieldStructStyleVariant {
+ Variant1 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddFieldStructStyleVariant {
+ Variant1 { a: u32, b: u32, c: u32 },
+}
+
+
+
+// Add #[must_use] to the enum ------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddMustUse {
+ Variant1,
+ Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[must_use]
+enum EnumAddMustUse {
+ Variant1,
+ Variant2,
+}
+
+
+
+// Add #[repr(C)] to the enum -------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddReprC {
+ Variant1,
+ Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddReprC {
+ Variant1,
+ Variant2,
+}
+
+
+
+// Change the name of a type parameter ----------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameOfTypeParameter<S> {
+ Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumChangeNameOfTypeParameter<T> {
+ Variant1(T),
+}
+
+
+
+// Add a type parameter ------------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTypeParameter<S> {
+ Variant1(S),
+ Variant2(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTypeParameter<S, T> {
+ Variant1(S),
+ Variant2(T),
+}
+
+
+
+// Change the name of a lifetime parameter ------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameOfLifetimeParameter<'a> {
+ Variant1(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumChangeNameOfLifetimeParameter<'b> {
+ Variant1(&'b u32),
+}
+
+
+
+// Add a lifetime parameter ---------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameter<'a> {
+ Variant1(&'a u32),
+ Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameter<'a, 'b> {
+ Variant1(&'a u32),
+ Variant2(&'b u32),
+}
+
+
+
+// Add a lifetime bound to a lifetime parameter -------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameterBound<'a, 'b> {
+ Variant1(&'a u32),
+ Variant2(&'b u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
+ Variant1(&'a u32),
+ Variant2(&'b u32),
+}
+
+// Add a lifetime bound to a type parameter -----------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeBoundToParameter<'a, T> {
+ Variant1(T),
+ Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
+ Variant1(T),
+ Variant2(&'a u32),
+}
+
+
+
+// Add a trait bound to a type parameter --------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTraitBound<S> {
+ Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTraitBound<T: Sync> {
+ Variant1(T),
+}
+
+
+
+// Add a lifetime bound to a lifetime parameter in where clause ---------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
+ Variant1(&'a u32),
+ Variant2(&'b u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
+ Variant1(&'a u32),
+ Variant2(&'b u32),
+}
+
+
+
+// Add a lifetime bound to a type parameter in where clause -------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
+ Variant1(T),
+ Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
+ Variant1(T),
+ Variant2(&'a u32),
+}
+
+
+
+// Add a trait bound to a type parameter in where clause ----------------------
+#[cfg(cfail1)]
+enum EnumAddTraitBoundWhere<S> {
+ Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTraitBoundWhere<T> where T: Sync {
+ Variant1(T),
+}
+
+
+
+// In an enum with two variants, swap usage of type parameters ----------------
+#[cfg(cfail1)]
+enum EnumSwapUsageTypeParameters<A, B> {
+ Variant1 { a: A },
+ Variant2 { a: B },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumSwapUsageTypeParameters<A, B> {
+ Variant1 { a: B },
+ Variant2 { a: A },
+}
+
+
+
+// In an enum with two variants, swap usage of lifetime parameters ------------
+#[cfg(cfail1)]
+enum EnumSwapUsageLifetimeParameters<'a, 'b> {
+ Variant1 { a: &'a u32 },
+ Variant2 { b: &'b u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumSwapUsageLifetimeParameters<'a, 'b> {
+ Variant1 { a: &'b u32 },
+ Variant2 { b: &'a u32 },
+}
+
+
+
+struct ReferencedType1;
+struct ReferencedType2;
+
+
+
+// Change field type in tuple-style variant indirectly by modifying a use statement
+mod change_field_type_indirectly_tuple_style {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as FieldType;
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as FieldType;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ enum TupleStyle {
+ Variant1(FieldType)
+ }
+}
+
+
+
+// Change field type in record-style variant indirectly by modifying a use statement
+mod change_field_type_indirectly_struct_style {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as FieldType;
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as FieldType;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ enum StructStyle {
+ Variant1 { a: FieldType }
+ }
+}
+
+
+
+trait ReferencedTrait1 {}
+trait ReferencedTrait2 {}
+
+
+
+// Change trait bound of type parameter indirectly by modifying a use statement
+mod change_trait_bound_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedTrait1 as Trait;
+ #[cfg(not(cfail1))]
+ use super::ReferencedTrait2 as Trait;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ enum Enum<T: Trait> {
+ Variant1(T)
+ }
+}
+
+
+
+// Change trait bound of type parameter in where clause indirectly by modifying a use statement
+mod change_trait_bound_indirectly_where {
+ #[cfg(cfail1)]
+ use super::ReferencedTrait1 as Trait;
+ #[cfg(not(cfail1))]
+ use super::ReferencedTrait2 as Trait;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ enum Enum<T> where T: Trait {
+ Variant1(T)
+ }
+}
+
+
// except according to those terms.
// error-pattern:thread '<unnamed>' panicked at 'test'
+// ignore-emscripten Needs threads
use std::thread;
// except according to those terms.
// error-pattern:thread 'owned name' panicked at 'test'
+// ignore-emscripten Needs threads.
use std::thread::Builder;
// except according to those terms.
// error-pattern:Ensure that the child thread runs by panicking
+// ignore-emscripten Needs threads.
use std::thread;
// error-pattern:thread 'test_foo' panicked at
// compile-flags: --test
// ignore-pretty: does not work well with `--test`
+// ignore-emscripten
#[test]
fn test_foo() {
// error-pattern:thread 'test_foo' panicked at
// compile-flags: --test
// ignore-pretty: does not work well with `--test`
+// ignore-emscripten
#[test]
#[should_panic(expected = "foobar")]
// compile-flags: --test
// exec-env:RUST_TEST_THREADS=foo
// ignore-pretty: does not work well with `--test`
+// ignore-emscripten
#[test]
fn do_nothing() {}
// no-prefer-dynamic
// aux-build:allocator-dummy.rs
+// ignore-emscripten
#![feature(test)]
--- /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.
+
+// This test ensures we can attach attributes to the formals in all
+// places where generic parameter lists occur, assuming appropriate
+// feature gates are enabled.
+//
+// (We are prefixing all tested features with `rustc_`, to ensure that
+// the attributes themselves won't be rejected by the compiler when
+// using `rustc_attrs` feature. There is a separate compile-fail/ test
+// ensuring that the attribute feature-gating works in this context.)
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
+struct StTy<#[rustc_ty_struct] I>(I);
+
+enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
+enum EnTy<#[rustc_ty_enum] J> { A(J), B }
+
+trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
+
+type TyLt<#[rustc_lt_type] 'd> = &'d u32;
+type TyTy<#[rustc_ty_type] L> = (L, );
+
+impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
+impl<#[rustc_ty_inherent] M> StTy<M> { }
+
+impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+ fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
+ fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+fn f_ty<#[rustc_ty_fn] O>(_: O) { }
+
+impl<I> StTy<I> {
+ fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+ fn m_ty<#[rustc_ty_meth] P>(_: P) { }
+}
+
+fn hof_lt<Q>(_: Q)
+ where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+{
+}
+
+fn main() {
+
+}
StructVariant { x: isize, y : usize }
}
+#[derive(Debug)]
+struct Pointers(*const Send, *mut Sync);
+
macro_rules! t {
($x:expr, $expected:expr) => {
assert_eq!(format!("{:?}", $x), $expected.to_string())
--- /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.
+
+#![feature(discriminant_value)]
+
+use std::mem;
+
+enum ADT {
+ First(u32, u32),
+ Second(u64)
+}
+
+pub fn main() {
+ assert!(mem::discriminant(&ADT::First(0,0)) == mem::discriminant(&ADT::First(1,1)));
+ assert!(mem::discriminant(&ADT::Second(5)) == mem::discriminant(&ADT::Second(6)));
+ assert!(mem::discriminant(&ADT::First(2,2)) != mem::discriminant(&ADT::Second(2)));
+
+ let _ = mem::discriminant(&10);
+ let _ = mem::discriminant(&"test");
+}
+
// pretty-expanded FIXME #23616
// ignore-msvc
+// ignore-emscripten
struct TwoU8s {
one: u8,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten missing rust_begin_unwind
+
#![feature(lang_items, start, collections)]
#![no_std]
--- /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.
+
+// Ensure that types that rely on obligations are autoderefed
+// correctly
+
+fn main() {
+ let x : Vec<Box<Fn()>> = vec![Box::new(|| ())];
+ x[0]()
+}
--- /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.
+
+macro_rules! m { () => { 1 } }
+macro_rules! n { () => { 1 + m!() } }
+
+fn main() {
+ let _: [u32; n!()] = [0, 0];
+}
// <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.
+// ignore-emscripten Not sure what's happening here.
use std::mem;
// <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.
+// ignore-emscripten
use std::mem;
// compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind.rs
// no-prefer-dynamic
+// ignore-emscripten Function not implemented
extern crate exit_success_if_unwind;
// compile-flags:-C panic=abort
// no-prefer-dynamic
+// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
// compile-flags:-C lto -C panic=abort
// no-prefer-dynamic
+// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
// compile-flags:-C lto -C panic=unwind
// no-prefer-dynamic
+// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
// <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.
+// ignore-emscripten Function not implemented.
use std::env;
use std::io;
// <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.
+// ignore-emscripten linking with emcc failed
#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
#![allow(non_camel_case_types)]
let data = Arc::new(Mutex::new(Vec::new()));
let sink = Sink(data.clone());
let res = thread::Builder::new().spawn(move|| -> () {
- io::set_panic(Box::new(sink));
+ io::set_panic(Some(Box::new(sink)));
panic!("Hello, world!")
}).unwrap().join();
assert!(res.is_err());
--> $DIR/type-binding.rs:16:20
|
16 | fn homura<T: Deref<Trget = i32>>(_: T) {}
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ associated type `Trget` not found
error: aborting due to previous error
pub cflags: String,
pub llvm_components: String,
pub llvm_cxxflags: String,
+ pub nodejs: Option<String>,
}
reqopt("", "cflags", "flags for the C compiler", "FLAGS"),
reqopt("", "llvm-components", "list of LLVM components built in", "LIST"),
reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"),
+ optopt("", "nodejs", "the name of nodejs", "PATH"),
optflag("h", "help", "show this message"));
let (argv0, args_) = args.split_first().unwrap();
cflags: matches.opt_str("cflags").unwrap(),
llvm_components: matches.opt_str("llvm-components").unwrap(),
llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
+ nodejs: matches.opt_str("nodejs"),
}
}
}
};
+ // Debugging emscripten code doesn't make sense today
+ let mut ignore = early_props.ignore;
+ if (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) &&
+ config.target.contains("emscripten") {
+ ignore = true;
+ }
+
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testpaths),
- ignore: early_props.ignore,
+ ignore: ignore,
should_panic: should_panic,
},
testfn: make_test_closure(config, testpaths),
"arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
self._arm_exec_compiled_test(env)
}
-
_=> {
let aux_dir = self.aux_output_dir_name();
self.compose_and_run(self.make_run_args(),
fn make_exe_name(&self) -> PathBuf {
let mut f = self.output_base_name();
// FIXME: This is using the host architecture exe suffix, not target!
- if self.config.target == "asmjs-unknown-emscripten" {
+ if self.config.target.contains("emscripten") {
let mut fname = f.file_name().unwrap().to_os_string();
fname.push(".js");
f.set_file_name(&fname);
let mut args = self.split_maybe_args(&self.config.runtool);
// If this is emscripten, then run tests under nodejs
- if self.config.target == "asmjs-unknown-emscripten" {
- args.push("nodejs".to_owned());
+ if self.config.target.contains("emscripten") {
+ let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string());
+ args.push(nodejs);
}
let exe_file = self.make_exe_name();
("sparc", "sparc"),
("x86_64", "x86_64"),
("xcore", "xcore"),
- ("asmjs", "asmjs")];
+ ("asmjs", "asmjs"),
+ ("wasm32", "wasm32")];
pub fn get_os(triple: &str) -> &'static str {
for &(triple_os, os) in OS_TABLE {
mod features;
mod cargo;
mod cargo_lock;
+mod pal;
fn main() {
let path = env::args_os().skip(1).next().expect("need an argument");
cargo::check(&path, &mut bad);
features::check(&path, &mut bad);
cargo_lock::check(&path, &mut bad);
+ pal::check(&path, &mut bad);
if bad {
panic!("some tidy checks failed");
--- /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.
+
+//! Tidy check to enforce rules about platform-specific code in std
+//!
+//! This is intended to maintain existing standards of code
+//! organization in hopes that the standard library will continue to
+//! be refactored to isolate platform-specific bits, making porting
+//! easier; where "standard library" roughly means "all the
+//! dependencies of the std and test crates".
+//!
+//! This generally means placing restrictions on where `cfg(unix)`,
+//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear,
+//! the basic objective being to isolate platform-specific code to the
+//! platform-specific `std::sys` modules, and to the allocation,
+//! unwinding, and libc crates.
+//!
+//! Following are the basic rules, though there are currently
+//! exceptions:
+//!
+//! - core may not have platform-specific code
+//! - liballoc_system may have platform-specific code
+//! - liballoc_jemalloc may have platform-specific code
+//! - libpanic_abort may have platform-specific code
+//! - libpanic_unwind may have platform-specific code
+//! - libunwind may have platform-specific code
+//! - other crates in the std facade may not
+//! - std may have platform-specific code in the following places
+//! - sys/unix/
+//! - sys/windows/
+//! - os/
+//!
+//! `std/sys_common` should _not_ contain platform-specific code.
+//! Finally, because std contains tests with platform-specific
+//! `ignore` attributes, once the parser encounters `mod tests`,
+//! platform-specific cfgs are allowed. Not sure yet how to deal with
+//! this in the long term.
+
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+use std::iter::Iterator;
+
+// Paths that may contain platform-specific code
+const EXCEPTION_PATHS: &'static [&'static str] = &[
+ // std crates
+ "src/liballoc_jemalloc",
+ "src/liballoc_system",
+ "src/liblibc",
+ "src/libpanic_abort",
+ "src/libpanic_unwind",
+ "src/libunwind",
+ "src/libstd/sys/unix", // This is where platform-specific code for std should live
+ "src/libstd/sys/windows", // Ditto
+ "src/libstd/os", // Platform-specific public interfaces
+ "src/rtstartup", // Not sure what to do about this. magic stuff for mingw
+
+ // temporary exceptions
+ "src/libstd/lib.rs", // This could probably be done within the sys directory
+ "src/libstd/rtdeps.rs", // Until rustbuild replaces make
+ "src/libstd/path.rs",
+ "src/libstd/io/stdio.rs",
+ "src/libstd/num/f32.rs",
+ "src/libstd/num/f64.rs",
+ "src/libstd/thread/local.rs",
+ "src/libstd/sys/common/mod.rs",
+ "src/libstd/sys/common/net.rs",
+ "src/libstd/sys/common/util.rs",
+ "src/libterm", // Not sure how to make this crate portable, but test needs it
+ "src/libtest", // Probably should defer to unstable std::sys APIs
+
+ // std testing crates, ok for now at least
+ "src/libcoretest",
+
+ // non-std crates
+ "src/test",
+ "src/tools",
+ "src/librustc",
+ "src/librustdoc",
+ "src/libsyntax",
+ "src/bootstrap",
+];
+
+pub fn check(path: &Path, bad: &mut bool) {
+ let ref mut contents = String::new();
+ // Sanity check that the complex parsing here works
+ let ref mut saw_target_arch = false;
+ let ref mut saw_cfg_bang = false;
+ super::walk(path, &mut super::filter_dirs, &mut |file| {
+ let filestr = file.to_string_lossy().replace("\\", "/");
+ if !filestr.ends_with(".rs") { return }
+
+ let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
+ if is_exception_path { return }
+
+ check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang);
+ });
+
+ assert!(*saw_target_arch);
+ assert!(*saw_cfg_bang);
+}
+
+fn check_cfgs(contents: &mut String, file: &Path,
+ bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
+ contents.truncate(0);
+ t!(t!(File::open(file), file).read_to_string(contents));
+
+ // For now it's ok to have platform-specific code after 'mod tests'.
+ let mod_tests_idx = find_test_mod(contents);
+ let contents = &contents[..mod_tests_idx];
+ // Pull out all "cfg(...)" and "cfg!(...)" strings
+ let cfgs = parse_cfgs(contents);
+
+ let mut line_numbers: Option<Vec<usize>> = None;
+ let mut err = |idx: usize, cfg: &str| {
+ if line_numbers.is_none() {
+ line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect());
+ }
+ let line_numbers = line_numbers.as_ref().expect("");
+ let line = match line_numbers.binary_search(&idx) {
+ Ok(_) => unreachable!(),
+ Err(i) => i + 1
+ };
+ println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
+ *bad = true;
+ };
+
+ for (idx, cfg) in cfgs.into_iter() {
+ // Sanity check that the parsing here works
+ if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true }
+ if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true }
+
+ let contains_platform_specific_cfg =
+ cfg.contains("target_os")
+ || cfg.contains("target_env")
+ || cfg.contains("target_vendor")
+ || cfg.contains("unix")
+ || cfg.contains("windows");
+
+ if !contains_platform_specific_cfg { continue }
+
+ let preceeded_by_doc_comment = {
+ let pre_contents = &contents[..idx];
+ let pre_newline = pre_contents.rfind('\n');
+ let pre_doc_comment = pre_contents.rfind("///");
+ match (pre_newline, pre_doc_comment) {
+ (Some(n), Some(c)) => n < c,
+ (None, Some(_)) => true,
+ (_, None) => false,
+ }
+ };
+
+ if preceeded_by_doc_comment { continue }
+
+ err(idx, cfg);
+ }
+}
+
+fn find_test_mod(contents: &str) -> usize {
+ if let Some(mod_tests_idx) = contents.find("mod tests") {
+ // Also capture a previos line indicating "mod tests" in cfg-ed out
+ let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
+ let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
+ if let Some(nl) = prev_newline_idx {
+ let prev_line = &contents[nl + 1 .. mod_tests_idx];
+ let emcc_cfg = "cfg(all(test, not(target_os";
+ if prev_line.contains(emcc_cfg) {
+ nl
+ } else {
+ mod_tests_idx
+ }
+ } else {
+ mod_tests_idx
+ }
+ } else {
+ contents.len()
+ }
+}
+
+fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> {
+ let candidate_cfgs = contents.match_indices("cfg");
+ let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i);
+ // This is puling out the indexes of all "cfg" strings
+ // that appear to be tokens succeeded by a paren.
+ let cfgs = candidate_cfg_idxs.filter(|i| {
+ let pre_idx = i.saturating_sub(*i);
+ let succeeds_non_ident = !contents.as_bytes().get(pre_idx)
+ .cloned()
+ .map(char::from)
+ .map(char::is_alphanumeric)
+ .unwrap_or(false);
+ let contents_after = &contents[*i..];
+ let first_paren = contents_after.find('(');
+ let paren_idx = first_paren.map(|ip| i + ip);
+ let preceeds_whitespace_and_paren = paren_idx.map(|ip| {
+ let maybe_space = &contents[*i + "cfg".len() .. ip];
+ maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!')
+ }).unwrap_or(false);
+
+ succeeds_non_ident && preceeds_whitespace_and_paren
+ });
+
+ cfgs.map(|i| {
+ let mut depth = 0;
+ let contents_from = &contents[i..];
+ for (j, byte) in contents_from.bytes().enumerate() {
+ match byte {
+ b'(' => {
+ depth += 1;
+ }
+ b')' => {
+ depth -= 1;
+ if depth == 0 {
+ return (i, &contents_from[.. j + 1]);
+ }
+ }
+ _ => { }
+ }
+ }
+
+ unreachable!()
+ }).collect()
+}