From 80ff0f74b0c4a8d384160af81a1b21f53622d8af Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 22 Oct 2017 20:01:00 -0700 Subject: [PATCH] std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them! --- .gitmodules | 6 + src/Cargo.lock | 22 +- src/binaryen | 1 + src/bootstrap/check.rs | 3 +- src/bootstrap/dist.rs | 5 + src/dlmalloc | 1 + src/etc/wasm32-shim.js | 119 +++++++ src/liballoc_jemalloc/build.rs | 2 +- src/liballoc_system/Cargo.toml | 4 + src/liballoc_system/lib.rs | 90 +++++ src/libcore/Cargo.toml | 3 - src/libcore/tests/lib.rs | 2 - src/libcore/tests/num/flt2dec/mod.rs | 85 +---- .../tests/num/flt2dec/strategy/grisu.rs | 48 --- src/libcore/tests/slice.rs | 68 ---- src/libpanic_abort/lib.rs | 15 +- src/libpanic_unwind/lib.rs | 8 +- src/libpanic_unwind/wasm32.rs | 29 ++ src/librustc/session/mod.rs | 2 +- src/librustc_back/lib.rs | 1 + src/librustc_back/target/mod.rs | 26 ++ .../target/wasm32_unknown_unknown.rs | 104 ++++++ src/librustc_binaryen/BinaryenWrapper.cpp | 132 +++++++ src/librustc_binaryen/Cargo.toml | 16 + src/librustc_binaryen/build.rs | 60 ++++ src/librustc_binaryen/lib.rs | 150 ++++++++ src/librustc_llvm/ffi.rs | 3 +- src/librustc_trans/Cargo.toml | 5 +- src/librustc_trans/back/link.rs | 56 ++- src/librustc_trans/back/linker.rs | 3 + src/librustc_trans/back/symbol_export.rs | 17 +- src/librustc_trans/back/write.rs | 101 +++++- src/librustc_trans/lib.rs | 9 +- src/librustc_trans_utils/link.rs | 35 +- src/libstd/build.rs | 8 +- src/libstd/f32.rs | 1 - src/libstd/macros.rs | 36 ++ src/libstd/sys/mod.rs | 3 + src/libstd/sys/wasm/args.rs | 90 +++++ src/libstd/sys/wasm/backtrace.rs | 37 ++ src/libstd/sys/wasm/cmath.rs | 119 +++++++ src/libstd/sys/wasm/condvar.rs | 43 +++ src/libstd/sys/wasm/env.rs | 19 + src/libstd/sys/wasm/fs.rs | 304 ++++++++++++++++ src/libstd/sys/wasm/memchr.rs | 11 + src/libstd/sys/wasm/mod.rs | 104 ++++++ src/libstd/sys/wasm/mutex.rs | 79 ++++ src/libstd/sys/wasm/net.rs | 337 ++++++++++++++++++ src/libstd/sys/wasm/os.rs | 136 +++++++ src/libstd/sys/wasm/os_str.rs | 159 +++++++++ src/libstd/sys/wasm/path.rs | 29 ++ src/libstd/sys/wasm/pipe.rs | 35 ++ src/libstd/sys/wasm/process.rs | 151 ++++++++ src/libstd/sys/wasm/rwlock.rs | 82 +++++ src/libstd/sys/wasm/stack_overflow.rs | 23 ++ src/libstd/sys/wasm/stdio.rs | 92 +++++ src/libstd/sys/wasm/thread.rs | 48 +++ src/libstd/sys/wasm/thread_local.rs | 50 +++ src/libstd/sys/wasm/time.rs | 63 ++++ src/libstd/sys_common/mod.rs | 14 +- src/libstd/sys_common/thread.rs | 3 +- src/libsyntax/feature_gate.rs | 8 + src/libtest/lib.rs | 81 +++-- src/libunwind/lib.rs | 19 +- src/libunwind/macros.rs | 45 +++ src/rustc/dlmalloc_shim/Cargo.toml | 14 + src/rustllvm/PassWrapper.cpp | 8 +- .../feature-gate-wasm_import_memory.rs | 14 + src/test/run-pass-fulldeps/flt2dec.rs | 163 +++++++++ src/test/run-pass-fulldeps/sort-unstable.rs | 83 +++++ src/test/run-pass/allocator/custom.rs | 4 +- src/test/run-pass/allocator/xcrate-use.rs | 1 - src/test/run-pass/allocator/xcrate-use2.rs | 1 - .../run-pass/anon-extern-mod-cross-crate-2.rs | 1 + src/test/run-pass/anon-extern-mod.rs | 1 + src/test/run-pass/auxiliary/issue-3012-1.rs | 7 +- src/test/run-pass/builtin-clone-unwind.rs | 2 + src/test/run-pass/c-stack-as-value.rs | 1 + src/test/run-pass/c-stack-returning-int64.rs | 2 +- src/test/run-pass/cabi-int-widening.rs | 2 + src/test/run-pass/catch-unwind-bang.rs | 2 + src/test/run-pass/cfg-family.rs | 1 + src/test/run-pass/cfg-target-family.rs | 2 + .../check-static-recursion-foreign.rs | 1 + src/test/run-pass/const-cast.rs | 11 +- src/test/run-pass/duplicated-external-mods.rs | 1 + src/test/run-pass/dynamic-drop.rs | 2 + src/test/run-pass/env-vars.rs | 1 + src/test/run-pass/extern-call-deep.rs | 2 + src/test/run-pass/extern-call-indirect.rs | 2 + src/test/run-pass/extern-crosscrate.rs | 3 +- src/test/run-pass/extern-pass-TwoU16s.rs | 2 + src/test/run-pass/extern-pass-TwoU32s.rs | 2 + src/test/run-pass/extern-pass-TwoU64s.rs | 2 + src/test/run-pass/extern-pass-TwoU8s.rs | 2 + src/test/run-pass/extern-pass-char.rs | 2 + src/test/run-pass/extern-pass-double.rs | 1 + src/test/run-pass/extern-pass-u32.rs | 2 + src/test/run-pass/extern-pass-u64.rs | 2 + src/test/run-pass/extern-return-TwoU16s.rs | 1 + src/test/run-pass/extern-return-TwoU32s.rs | 1 + src/test/run-pass/extern-return-TwoU64s.rs | 1 + src/test/run-pass/extern-return-TwoU8s.rs | 1 + src/test/run-pass/extern_fat_drop.rs | 3 +- src/test/run-pass/fmt-pointer-trait.rs | 4 +- src/test/run-pass/foreign-dupe.rs | 1 + src/test/run-pass/foreign-fn-linkname.rs | 2 +- src/test/run-pass/foreign-fn-with-byval.rs | 1 + src/test/run-pass/foreign-mod-unused-const.rs | 9 +- src/test/run-pass/foreign-no-abi.rs | 1 + src/test/run-pass/foreign2.rs | 2 +- src/test/run-pass/generator/panic-drops.rs | 2 + src/test/run-pass/generator/panic-safe.rs | 2 + .../run-pass/generator/resume-after-return.rs | 2 + src/test/run-pass/intrinsic-alignment.rs | 1 + src/test/run-pass/invoke-external-foreign.rs | 1 + src/test/run-pass/issue-1251.rs | 1 + src/test/run-pass/issue-12699.rs | 2 + src/test/run-pass/issue-13507-2.rs | 3 - src/test/run-pass/issue-14875.rs | 3 +- src/test/run-pass/issue-2214.rs | 1 + src/test/run-pass/issue-25185.rs | 1 + src/test/run-pass/issue-28676.rs | 3 +- src/test/run-pass/issue-29948.rs | 2 + src/test/run-pass/issue-3012-2.rs | 8 +- src/test/run-pass/issue-3656.rs | 1 + src/test/run-pass/issue-43853.rs | 2 + src/test/run-pass/issue-4735.rs | 15 +- src/test/run-pass/issue-5791.rs | 8 +- src/test/run-pass/item-attributes.rs | 7 +- src/test/run-pass/iter-step-overflow-debug.rs | 1 + src/test/run-pass/iter-sum-overflow-debug.rs | 1 + .../iter-sum-overflow-overflow-checks.rs | 1 + src/test/run-pass/lib-defaults.rs | 2 + src/test/run-pass/mir_calls_to_shims.rs | 2 + src/test/run-pass/mir_drop_order.rs | 2 + src/test/run-pass/mir_misc_casts.rs | 56 ++- src/test/run-pass/mir_trans_calls_variadic.rs | 2 + src/test/run-pass/newtype-struct-with-dtor.rs | 10 +- src/test/run-pass/paths-containing-nul.rs | 2 + src/test/run-pass/pub-extern-privacy.rs | 2 + .../run-pass/reachable-unnameable-items.rs | 1 + src/test/run-pass/rec-align-u64.rs | 2 + src/test/run-pass/regions-mock-trans.rs | 12 +- src/test/run-pass/rfc-1014.rs | 3 + src/test/run-pass/rfc1717/library-override.rs | 1 + src/test/run-pass/rfc1857-drop-order.rs | 2 + .../signal-alternate-stack-cleanup.rs | 1 + src/test/run-pass/static-method-xcrate.rs | 1 - src/test/run-pass/static-mut-foreign.rs | 1 + src/test/run-pass/struct-return.rs | 3 +- src/test/run-pass/supported-cast.rs | 28 +- src/test/run-pass/sync-send-in-std.rs | 2 + src/test/run-pass/test-allow-fail-attr.rs | 1 + .../run-pass/test-should-fail-good-message.rs | 1 + src/test/run-pass/union/union-c-interop.rs | 2 + src/test/run-pass/variadic-ffi.rs | 2 + src/test/run-pass/x86stdcall.rs | 2 + src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/runtest.rs | 26 +- src/tools/compiletest/src/util.rs | 9 +- src/tools/tidy/src/lib.rs | 2 + 162 files changed, 3644 insertions(+), 440 deletions(-) create mode 160000 src/binaryen create mode 160000 src/dlmalloc create mode 100644 src/etc/wasm32-shim.js create mode 100644 src/libpanic_unwind/wasm32.rs create mode 100644 src/librustc_back/target/wasm32_unknown_unknown.rs create mode 100644 src/librustc_binaryen/BinaryenWrapper.cpp create mode 100644 src/librustc_binaryen/Cargo.toml create mode 100644 src/librustc_binaryen/build.rs create mode 100644 src/librustc_binaryen/lib.rs create mode 100644 src/libstd/sys/wasm/args.rs create mode 100644 src/libstd/sys/wasm/backtrace.rs create mode 100644 src/libstd/sys/wasm/cmath.rs create mode 100644 src/libstd/sys/wasm/condvar.rs create mode 100644 src/libstd/sys/wasm/env.rs create mode 100644 src/libstd/sys/wasm/fs.rs create mode 100644 src/libstd/sys/wasm/memchr.rs create mode 100644 src/libstd/sys/wasm/mod.rs create mode 100644 src/libstd/sys/wasm/mutex.rs create mode 100644 src/libstd/sys/wasm/net.rs create mode 100644 src/libstd/sys/wasm/os.rs create mode 100644 src/libstd/sys/wasm/os_str.rs create mode 100644 src/libstd/sys/wasm/path.rs create mode 100644 src/libstd/sys/wasm/pipe.rs create mode 100644 src/libstd/sys/wasm/process.rs create mode 100644 src/libstd/sys/wasm/rwlock.rs create mode 100644 src/libstd/sys/wasm/stack_overflow.rs create mode 100644 src/libstd/sys/wasm/stdio.rs create mode 100644 src/libstd/sys/wasm/thread.rs create mode 100644 src/libstd/sys/wasm/thread_local.rs create mode 100644 src/libstd/sys/wasm/time.rs create mode 100644 src/libunwind/macros.rs create mode 100644 src/rustc/dlmalloc_shim/Cargo.toml create mode 100644 src/test/compile-fail/feature-gate-wasm_import_memory.rs create mode 100644 src/test/run-pass-fulldeps/flt2dec.rs create mode 100644 src/test/run-pass-fulldeps/sort-unstable.rs diff --git a/.gitmodules b/.gitmodules index 2802c8d63913f..0a1188e83eae6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -42,3 +42,9 @@ [submodule "src/tools/miri"] path = src/tools/miri url = https://github.com/solson/miri.git +[submodule "src/dlmalloc"] + path = src/dlmalloc + url = https://github.com/alexcrichton/dlmalloc-rs.git +[submodule "src/binaryen"] + path = src/binaryen + url = https://github.com/alexcrichton/binaryen.git diff --git a/src/Cargo.lock b/src/Cargo.lock index bc20304945357..276980699a2f4 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -50,6 +50,7 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "core 0.0.0", + "dlmalloc 0.0.0", "libc 0.0.0", ] @@ -372,9 +373,6 @@ version = "0.1.0" [[package]] name = "core" version = "0.0.0" -dependencies = [ - "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "core-foundation" @@ -509,6 +507,14 @@ name = "diff" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "dlmalloc" +version = "0.0.0" +dependencies = [ + "alloc 0.0.0", + "core 0.0.0", +] + [[package]] name = "docopt" version = "0.8.1" @@ -1608,6 +1614,15 @@ dependencies = [ "syntax 0.0.0", ] +[[package]] +name = "rustc_binaryen" +version = "0.0.0" +dependencies = [ + "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_borrowck" version = "0.0.0" @@ -1880,6 +1895,7 @@ dependencies = [ "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", + "rustc_binaryen 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", diff --git a/src/binaryen b/src/binaryen new file mode 160000 index 0000000000000..1c9bf65aa0e37 --- /dev/null +++ b/src/binaryen @@ -0,0 +1 @@ +Subproject commit 1c9bf65aa0e371b84755a8ddd6e79497fac57171 diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 1401bc80a1ac2..4d69b19c7310f 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1211,7 +1211,8 @@ impl Step for Crate { // ends up messing with various mtime calculations and such. if !name.contains("jemalloc") && *name != *"build_helper" && - !(name.starts_with("rustc_") && name.ends_with("san")) { + !(name.starts_with("rustc_") && name.ends_with("san")) && + name != "dlmalloc" { cargo.arg("-p").arg(&format!("{}:0.0.0", name)); } for dep in build.crates[&name].deps.iter() { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 7bf385301fab5..9f7e3de9dc051 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -672,6 +672,9 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di spath.ends_with(".s")) { return false } + if spath.contains("test/emscripten") || spath.contains("test\\emscripten") { + return false + } let full_path = Path::new(dir).join(path); if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) { @@ -736,6 +739,7 @@ impl Step for Src { // (essentially libstd and all of its path dependencies) let std_src_dirs = [ "src/build_helper", + "src/dlmalloc", "src/liballoc", "src/liballoc_jemalloc", "src/liballoc_system", @@ -754,6 +758,7 @@ impl Step for Src { "src/libunwind", "src/rustc/compiler_builtins_shim", "src/rustc/libc_shim", + "src/rustc/dlmalloc_shim", "src/libtest", "src/libterm", "src/jemalloc", diff --git a/src/dlmalloc b/src/dlmalloc new file mode 160000 index 0000000000000..d3812c3accaee --- /dev/null +++ b/src/dlmalloc @@ -0,0 +1 @@ +Subproject commit d3812c3accaee7ad23068ed4fc089cc05c7a538f diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js new file mode 100644 index 0000000000000..b595cc1205336 --- /dev/null +++ b/src/etc/wasm32-shim.js @@ -0,0 +1,119 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a small "shim" program which is used when wasm32 unit tests are run +// in this repository. This program is intended to be run in node.js and will +// load a wasm module into memory, instantiate it with a set of imports, and +// then run it. +// +// There's a bunch of helper functions defined here in `imports.env`, but note +// that most of them aren't actually needed to execute most programs. Many of +// these are just intended for completeness or debugging. Hopefully over time +// nothing here is needed for completeness. + +const fs = require('fs'); +const process = require('process'); +const buffer = fs.readFileSync(process.argv[2]); + +Error.stackTraceLimit = 20; + +let m = new WebAssembly.Module(buffer); + +let memory = null; + +function copystr(a, b) { + if (memory === null) { + return null + } + let view = new Uint8Array(memory.buffer).slice(a, a + b); + return String.fromCharCode.apply(null, view); +} + +let imports = {}; +imports.env = { + // These are generated by LLVM itself for various intrinsic calls. Hopefully + // one day this is not necessary and something will automatically do this. + fmod: function(x, y) { return x % y; }, + exp2: function(x) { return Math.pow(2, x); }, + exp2f: function(x) { return Math.pow(2, x); }, + ldexp: function(x, y) { return x * Math.pow(2, y); }, + ldexpf: function(x, y) { return x * Math.pow(2, y); }, + log10: function(x) { return Math.log10(x); }, + log10f: function(x) { return Math.log10(x); }, + + // These are called in src/libstd/sys/wasm/stdio.rs and are used when + // debugging is enabled. + rust_wasm_write_stdout: function(a, b) { + let s = copystr(a, b); + if (s !== null) { + process.stdout.write(s); + } + }, + rust_wasm_write_stderr: function(a, b) { + let s = copystr(a, b); + if (s !== null) { + process.stderr.write(s); + } + }, + + // These are called in src/libstd/sys/wasm/args.rs and are used when + // debugging is enabled. + rust_wasm_args_count: function() { + if (memory === null) + return 0; + return process.argv.length - 2; + }, + rust_wasm_args_arg_size: function(i) { + return process.argv[i + 2].length; + }, + rust_wasm_args_arg_fill: function(idx, ptr) { + let arg = process.argv[idx + 2]; + let view = new Uint8Array(memory.buffer); + for (var i = 0; i < arg.length; i++) { + view[ptr + i] = arg.charCodeAt(i); + } + }, + + // These are called in src/libstd/sys/wasm/os.rs and are used when + // debugging is enabled. + rust_wasm_getenv_len: function(a, b) { + let key = copystr(a, b); + if (key === null) { + return -1; + } + if (!(key in process.env)) { + return -1; + } + return process.env[key].length; + }, + rust_wasm_getenv_data: function(a, b, ptr) { + let key = copystr(a, b); + let value = process.env[key]; + let view = new Uint8Array(memory.buffer); + for (var i = 0; i < value.length; i++) { + view[ptr + i] = value.charCodeAt(i); + } + }, +}; + +let module_imports = WebAssembly.Module.imports(m); + +for (var i = 0; i < module_imports.length; i++) { + let imp = module_imports[i]; + if (imp.module != 'env') { + continue + } + if (imp.name == 'memory' && imp.kind == 'memory') { + memory = new WebAssembly.Memory({initial: 20}); + imports.env.memory = memory; + } +} + +let instance = new WebAssembly.Instance(m, imports); diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 65e035d4ffdef..a41a04d7cd4f6 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -31,7 +31,7 @@ fn main() { let host = env::var("HOST").expect("HOST was not set"); if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") || target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") || - target.contains("redox") { + target.contains("redox") || target.contains("wasm32") { println!("cargo:rustc-cfg=dummy_jemalloc"); return; } diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml index a725a8608be29..f9a57f7d97a74 100644 --- a/src/liballoc_system/Cargo.toml +++ b/src/liballoc_system/Cargo.toml @@ -13,3 +13,7 @@ doc = false alloc = { path = "../liballoc" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } + +# See comments in the source for what this dependency is +[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] +dlmalloc = { path = "../rustc/dlmalloc_shim" } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7aa5f8a9186b0..05cacf6e88195 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -34,12 +34,14 @@ target_arch = "powerpc64", target_arch = "asmjs", target_arch = "wasm32")))] +#[allow(dead_code)] const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64")))] +#[allow(dead_code)] const MIN_ALIGN: usize = 16; extern crate alloc; @@ -458,3 +460,91 @@ mod platform { } } } + +// This is an implementation of a global allocator on the wasm32 platform when +// emscripten is not in use. In that situation there's no actual runtime for us +// to lean on for allocation, so instead we provide our own! +// +// The wasm32 instruction set has two instructions for getting the current +// amount of memory and growing the amount of memory. These instructions are the +// foundation on which we're able to build an allocator, so we do so! Note that +// the instructions are also pretty "global" and this is the "global" allocator +// after all! +// +// The current allocator here is the `dlmalloc` crate which we've got included +// in the rust-lang/rust repository as a submodule. The crate is a port of +// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust" +// for now which is currently technically required (can't link with C yet). +// +// The crate itself provides a global allocator which on wasm has no +// synchronization as there are no threads! +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +mod platform { + extern crate dlmalloc; + + use alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; + use System; + use self::dlmalloc::GlobalDlmalloc; + + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + GlobalDlmalloc.alloc(layout) + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) + -> Result<*mut u8, AllocErr> + { + GlobalDlmalloc.alloc_zeroed(layout) + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + GlobalDlmalloc.dealloc(ptr, layout) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + GlobalDlmalloc.realloc(ptr, old_layout, new_layout) + } + + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + GlobalDlmalloc.usable_size(layout) + } + + #[inline] + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + GlobalDlmalloc.alloc_excess(layout) + } + + #[inline] + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + GlobalDlmalloc.realloc_excess(ptr, layout, new_layout) + } + + #[inline] + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + GlobalDlmalloc.grow_in_place(ptr, layout, new_layout) + } + + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + GlobalDlmalloc.shrink_in_place(ptr, layout, new_layout) + } + } +} diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index d1a0a5f09e0d5..5af63aa970f2c 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -9,9 +9,6 @@ path = "lib.rs" test = false bench = false -[dev-dependencies] -rand = "0.3" - [[test]] name = "coretests" path = "../libcore/tests/lib.rs" diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index afc5de7b0ee35..edf7f44e5925c 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,6 @@ #![feature(iter_rfind)] #![feature(iter_rfold)] #![feature(nonzero)] -#![feature(rand)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] @@ -48,7 +47,6 @@ extern crate core; extern crate test; -extern crate rand; mod any; mod array; diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index 2720c5c8677af..ef0178815f98b 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -9,9 +9,7 @@ // except according to those terms. use std::prelude::v1::*; -use std::{str, mem, i16, f32, f64, fmt}; -use rand::{self, Rand, XorShiftRng}; -use rand::distributions::{IndependentSample, Range}; +use std::{str, i16, f32, f64, fmt}; use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; use core::num::flt2dec::{MAX_SIG_DIGITS, round_up, Part, Formatted, Sign}; @@ -463,87 +461,6 @@ pub fn more_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8] exp: 0, inclusive: false} => b"99999999999999999", 17); } -fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), - V: FnMut(usize) -> Decoded { - assert!(k <= 1024); - - let mut npassed = 0; // f(x) = Some(g(x)) - let mut nignored = 0; // f(x) = None - - for i in 0..n { - if (i & 0xfffff) == 0 { - println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", - i, n, nignored, npassed, i - nignored - npassed); - } - - let decoded = v(i); - let mut buf1 = [0; 1024]; - if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [0; 1024]; - let (len2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && &buf1[..len1] == &buf2[..len2] { - npassed += 1; - } else { - println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", - i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), e2); - } - } else { - nignored += 1; - } - } - println!("{}({}): done, ignored={} passed={} failed={}", - func, k, nignored, npassed, n - nignored - npassed); - assert!(nignored + npassed == n, - "{}({}): {} out of {} values returns an incorrect value!", - func, k, n - nignored - npassed, n); - (npassed, nignored) -} - -pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); - iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); - iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, - // so why not simply testing all of them? - // - // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), - // but with `-C opt-level=3 -C lto` this only takes about an hour or so. - - // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges - let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", - k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; - decode_finite(x) - }); - assert_eq!((npassed, nignored), (2121451881, 17643158)); -} - fn to_string_with_parts(mut f: F) -> String where F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a> { let mut buf = [0; 1024]; diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index 17fb99bcc9224..286b39d8cf3b3 100644 --- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::i16; use super::super::*; use core::num::flt2dec::strategy::grisu::*; @@ -46,35 +45,6 @@ fn shortest_sanity_test() { more_shortest_sanity_test(format_shortest); } -#[test] -fn shortest_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f32_exhaustive_equivalence_test() { - // it is hard to directly test the optimality of the output, but we can at least test if - // two different algorithms agree to each other. - // - // this reports the progress and the number of f32 values returned `None`. - // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: - // `done, ignored=17643158 passed=2121451881 failed=0`. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f64_hard_random_equivalence_test() { - // this again probably has to use appropriate rustc flags. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, - MAX_SIG_DIGITS, 100_000_000); -} - #[test] fn exact_sanity_test() { // See comments in dragon.rs's exact_sanity_test for why this test is @@ -85,24 +55,6 @@ fn exact_sanity_test() { f32_exact_sanity_test(format_exact); } -#[test] -fn exact_f32_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} - -#[test] -fn exact_f64_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} - #[test] fn test_to_shortest_str() { to_shortest_str_test(format_shortest); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 7835080db1d45..60e4e6d2ff328 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::cmp::Ordering::{Equal, Greater, Less}; -use core::slice::heapsort; use core::result::Result::{Ok, Err}; -use rand::{Rng, XorShiftRng}; #[test] fn test_binary_search() { @@ -290,68 +287,3 @@ fn test_rotate() { assert_eq!(a[(i+k)%N], i); } } - -#[test] -fn sort_unstable() { - let mut v = [0; 600]; - let mut tmp = [0; 600]; - let mut rng = XorShiftRng::new_unseeded(); - - for len in (2..25).chain(500..510) { - let v = &mut v[0..len]; - let tmp = &mut tmp[0..len]; - - for &modulus in &[5, 10, 100, 1000] { - for _ in 0..100 { - for i in 0..len { - v[i] = rng.gen::() % modulus; - } - - // Sort in default order. - tmp.copy_from_slice(v); - tmp.sort_unstable(); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in ascending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| a.cmp(b)); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in descending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| b.cmp(a)); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - - // Test heapsort using `<` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a < b); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Test heapsort using `>` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a > b); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - } - } - } - - // Sort using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - for i in 0..v.len() { - v[i] = i as i32; - } - v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); - v.sort_unstable(); - for i in 0..v.len() { - assert_eq!(v[i], i as i32); - } - - // Should not panic. - [0i32; 0].sort_unstable(); - [(); 10].sort_unstable(); - [(); 100].sort_unstable(); - - let mut v = [0xDEADBEEFu64]; - v.sort_unstable(); - assert!(v == [0xDEADBEEF]); -} diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 8be6f6470231d..29a9e1aadaf3c 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -20,13 +20,13 @@ html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![deny(warnings)] - -#![feature(staged_api)] - #![panic_runtime] +#![allow(unused_features)] + +#![feature(core_intrinsics)] +#![feature(libc)] #![feature(panic_runtime)] -#![cfg_attr(unix, feature(libc))] -#![cfg_attr(any(target_os = "redox", windows), feature(core_intrinsics))] +#![feature(staged_api)] // Rust's "try" function, but if we're aborting on panics we just call the // function as there's nothing else we need to do here. @@ -59,7 +59,9 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { libc::abort(); } - #[cfg(any(target_os = "redox", windows))] + #[cfg(any(target_os = "redox", + windows, + all(target_arch = "wasm32", not(target_os = "emscripten"))))] unsafe fn abort() -> ! { core::intrinsics::abort(); } @@ -92,7 +94,6 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { // binaries, but it should never be called as we don't link in an unwinding // runtime at all. pub mod personalities { - #[no_mangle] #[cfg(not(all(target_os = "windows", target_env = "gnu", diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 558286f4ec070..6b8da7a51ceb8 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -34,9 +34,7 @@ #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(libc)] -#![cfg_attr(not(any(target_env = "msvc", - all(windows, target_arch = "x86_64", target_env = "gnu"))), - feature(panic_unwind))] +#![feature(panic_unwind)] #![feature(raw)] #![feature(staged_api)] #![feature(unwind_attributes)] @@ -80,6 +78,10 @@ mod imp; #[path = "emcc.rs"] mod imp; +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +#[path = "wasm32.rs"] +mod imp; + mod dwarf; mod windows; diff --git a/src/libpanic_unwind/wasm32.rs b/src/libpanic_unwind/wasm32.rs new file mode 100644 index 0000000000000..8aed61b3c385a --- /dev/null +++ b/src/libpanic_unwind/wasm32.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unwinding for wasm32 +//! +//! Right now we don't support this, so this is just stubs + +use alloc::boxed::Box; +use core::any::Any; +use core::intrinsics; + +pub fn payload() -> *mut u8 { + 0 as *mut u8 +} + +pub unsafe fn cleanup(_ptr: *mut u8) -> Box { + intrinsics::abort() +} + +pub unsafe fn panic(_data: Box) -> u32 { + intrinsics::abort() +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 00a91eeb9c18e..9f957cd780829 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -432,7 +432,7 @@ impl Session { self.opts.debugging_opts.borrowck_mir } pub fn lto(&self) -> bool { - self.opts.cg.lto + self.opts.cg.lto || self.target.target.options.requires_lto } /// Returns the panic strategy for this compile session. If the user explicitly selected one /// using '-C panic', use that, otherwise use the panic strategy defined by the target. diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index d67de123415f2..824b553104760 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -84,6 +84,7 @@ macro_rules! linker_flavor { linker_flavor! { (Em, "em"), + (Binaryen, "binaryen"), (Gcc, "gcc"), (Ld, "ld"), (Msvc, "msvc"), diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d60d6438b4d61..7599a60ba5ada 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -218,6 +218,7 @@ supported_targets! { ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), + ("wasm32-unknown-unknown", wasm32_unknown_unknown), ("wasm32-experimental-emscripten", wasm32_experimental_emscripten), ("thumbv6m-none-eabi", thumbv6m_none_eabi), @@ -303,6 +304,8 @@ pub struct TargetOptions { pub features: String, /// Whether dynamic linking is available on this target. Defaults to false. pub dynamic_linking: bool, + /// If dynamic linking is available, whether only cdylibs are supported. + pub only_cdylib: bool, /// Whether executables are available on this target. iOS, for example, only allows static /// libraries. Defaults to false. pub executables: bool, @@ -439,6 +442,17 @@ pub struct TargetOptions { /// Whether to generate trap instructions in places where optimization would /// otherwise produce control flow that falls through into unrelated memory. pub trap_unreachable: bool, + + /// This target requires everything to be compiled with LTO to emit a final + /// executable, aka there is no native linker for this target. + pub requires_lto: bool, + + /// This target has no support for threads. + pub singlethread: bool, + + /// Whether library functions call lowering/optimization is disabled in LLVM + /// for this target unconditionally. + pub no_builtins: bool, } impl Default for TargetOptions { @@ -454,6 +468,7 @@ impl Default for TargetOptions { cpu: "generic".to_string(), features: "".to_string(), dynamic_linking: false, + only_cdylib: false, executables: false, relocation_model: "pic".to_string(), code_model: "default".to_string(), @@ -503,6 +518,9 @@ impl Default for TargetOptions { min_global_align: None, default_codegen_units: None, trap_unreachable: true, + requires_lto: false, + singlethread: false, + no_builtins: false, } } } @@ -702,6 +720,7 @@ impl Target { key!(cpu); key!(features); key!(dynamic_linking, bool); + key!(only_cdylib, bool); key!(executables, bool); key!(relocation_model); key!(code_model); @@ -745,6 +764,9 @@ impl Target { key!(min_global_align, Option); key!(default_codegen_units, Option); key!(trap_unreachable, bool); + key!(requires_lto, bool); + key!(singlethread, bool); + key!(no_builtins, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -896,6 +918,7 @@ impl ToJson for Target { target_option_val!(cpu); target_option_val!(features); target_option_val!(dynamic_linking); + target_option_val!(only_cdylib); target_option_val!(executables); target_option_val!(relocation_model); target_option_val!(code_model); @@ -939,6 +962,9 @@ impl ToJson for Target { target_option_val!(min_global_align); target_option_val!(default_codegen_units); target_option_val!(trap_unreachable); + target_option_val!(requires_lto); + target_option_val!(singlethread); + target_option_val!(no_builtins); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs new file mode 100644 index 0000000000000..7e1011ab8af96 --- /dev/null +++ b/src/librustc_back/target/wasm32_unknown_unknown.rs @@ -0,0 +1,104 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The wasm32-unknown-unknown target is currently a highly experimental version +// of a wasm-based target which does *not* use the Emscripten toolchain. Instead +// this is a pretty flavorful (aka hacked up) target right now. The definition +// and semantics of this target are likely to change and so this shouldn't be +// relied on just yet. +// +// In general everyone is currently waiting on a linker for wasm code. In the +// meantime we have no means of actually making use of the traditional separate +// compilation model. At a high level this means that assembling Rust programs +// into a WebAssembly program looks like: +// +// 1. All intermediate artifacts are LLVM bytecode. We'll be using LLVM as +// a linker later on. +// 2. For the final artifact we emit one giant assembly file (WebAssembly +// doesn't have an object file format). To do this we force LTO to be turned +// on (`requires_lto` below) to ensure all Rust code is in one module. Any +// "linked" C library is basically just ignored. +// 3. Using LLVM we emit a `foo.s` file (assembly) with some... what I can only +// describe as arcane syntax. From there we need to actually change this +// into a wasm module. For this step we use the `binaryen` project. This +// project is mostly intended as a WebAssembly code generator, but for now +// we're just using its LLVM-assembly-to-wasm-module conversion utilities. +// +// And voila, out comes a web assembly module! There's some various tweaks here +// and there, but that's the high level at least. Note that this will be +// rethought from the ground up once a linker (lld) is available, so this is all +// temporary and should improve in the future. + +use LinkerFlavor; +use super::{Target, TargetOptions, PanicStrategy}; + +pub fn target() -> Result { + let opts = TargetOptions { + linker: "not-used".to_string(), + + // we allow dynamic linking, but only cdylibs. Basically we allow a + // final library artifact that exports some symbols (a wasm module) but + // we don't allow intermediate `dylib` crate types + dynamic_linking: true, + only_cdylib: true, + + // This means we'll just embed a `start` function in the wasm module + executables: true, + + // relatively self-explanatory! + exe_suffix: ".wasm".to_string(), + dll_prefix: "".to_string(), + dll_suffix: ".wasm".to_string(), + linker_is_gnu: false, + + // We're storing bitcode for now in all the rlibs + obj_is_bitcode: true, + + // A bit of a lie, but "eh" + max_atomic_width: Some(32), + + // Unwinding doesn't work right now, so the whole target unconditionally + // defaults to panic=abort. Note that this is guaranteed to change in + // the future once unwinding is implemented. Don't rely on this. + panic_strategy: PanicStrategy::Abort, + + // There's no linker yet so we're forced to use LLVM as a linker. This + // means that we must always enable LTO for final artifacts. + requires_lto: true, + + // Wasm doesn't have atomics yet, so tell LLVM that we're in a single + // threaded model which will legalize atomics to normal operations. + singlethread: true, + + // Because we're always enabling LTO we can't enable builtin lowering as + // otherwise we'll lower the definition of the `memcpy` function to + // memcpy itself. Note that this is specifically because we're + // performing LTO with compiler-builtins. + no_builtins: true, + + .. Default::default() + }; + Ok(Target { + llvm_target: "wasm32-unknown-unknown".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + // This is basically guaranteed to change in the future, don't rely on + // this. Use `not(target_os = "emscripten")` for now. + target_os: "unknown".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(), + arch: "wasm32".to_string(), + // A bit of a lie, but it gets the job done + linker_flavor: LinkerFlavor::Binaryen, + options: opts, + }) +} diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp new file mode 100644 index 0000000000000..d1095a7819d4a --- /dev/null +++ b/src/librustc_binaryen/BinaryenWrapper.cpp @@ -0,0 +1,132 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a small C API inserted on top of the Binaryen C++ API which we use +// from Rust. Once we have a real linker for we'll be able to remove all this, +// and otherwise this is just all on a "as we need it" basis for now. + +#include +#include +#include + +#include "s2wasm.h" +#include "wasm-binary.h" +#include "wasm-linker.h" + +using namespace wasm; + +struct BinaryenRustModule { + BufferWithRandomAccess buffer; +}; + +struct BinaryenRustModuleOptions { + uint64_t globalBase; + bool debug; + uint64_t stackAllocation; + uint64_t initialMem; + uint64_t maxMem; + bool importMemory; + bool ignoreUnknownSymbols; + bool debugInfo; + std::string startFunction; + + BinaryenRustModuleOptions() : + globalBase(0), + debug(false), + stackAllocation(0), + initialMem(0), + maxMem(0), + importMemory(false), + ignoreUnknownSymbols(false), + debugInfo(false), + startFunction("") + {} + +}; + +extern "C" BinaryenRustModuleOptions* +BinaryenRustModuleOptionsCreate() { + return new BinaryenRustModuleOptions; +} + +extern "C" void +BinaryenRustModuleOptionsFree(BinaryenRustModuleOptions *options) { + delete options; +} + +extern "C" void +BinaryenRustModuleOptionsSetDebugInfo(BinaryenRustModuleOptions *options, + bool debugInfo) { + options->debugInfo = debugInfo; +} + +extern "C" void +BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options, + char *start) { + options->startFunction = start; +} + +extern "C" void +BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options, + uint64_t stack) { + options->stackAllocation = stack; +} + +extern "C" void +BinaryenRustModuleOptionsSetImportMemory(BinaryenRustModuleOptions *options, + bool import) { + options->importMemory = import; +} + +extern "C" BinaryenRustModule* +BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options, + const char *assembly) { + Linker linker( + options->globalBase, + options->stackAllocation, + options->initialMem, + options->maxMem, + options->importMemory, + options->ignoreUnknownSymbols, + options->startFunction, + options->debug); + + S2WasmBuilder mainbuilder(assembly, options->debug); + linker.linkObject(mainbuilder); + linker.layout(); + + auto ret = make_unique(); + { + WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug); + writer.setNamesSection(options->debugInfo); + // FIXME: support source maps? + // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl); + + // FIXME: support symbol maps? + // writer.setSymbolMap(symbolMap); + writer.write(); + } + return ret.release(); +} + +extern "C" const uint8_t* +BinaryenRustModulePtr(const BinaryenRustModule *M) { + return M->buffer.data(); +} + +extern "C" size_t +BinaryenRustModuleLen(const BinaryenRustModule *M) { + return M->buffer.size(); +} + +extern "C" void +BinaryenRustModuleFree(BinaryenRustModule *M) { + delete M; +} diff --git a/src/librustc_binaryen/Cargo.toml b/src/librustc_binaryen/Cargo.toml new file mode 100644 index 0000000000000..9573c89471404 --- /dev/null +++ b/src/librustc_binaryen/Cargo.toml @@ -0,0 +1,16 @@ +# Wondering what this crate is? Take a look at the `lib.rs`! + +[package] +name = "rustc_binaryen" +version = "0.0.0" +authors = ["The Rust Project Developers"] + +[lib] +path = "lib.rs" + +[dependencies] +libc = "0.2" + +[build-dependencies] +cmake = "0.1" +cc = "1.0" diff --git a/src/librustc_binaryen/build.rs b/src/librustc_binaryen/build.rs new file mode 100644 index 0000000000000..f23ff3cee555b --- /dev/null +++ b/src/librustc_binaryen/build.rs @@ -0,0 +1,60 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate cc; +extern crate cmake; + +use std::env; + +use cmake::Config; + +fn main() { + let target = env::var("TARGET").unwrap(); + + // Bring in `__emutls_get_address` which is apparently needed for now + if target.contains("pc-windows-gnu") { + println!("cargo:rustc-link-lib=gcc_eh"); + println!("cargo:rustc-link-lib=pthread"); + } + + Config::new("../binaryen") + .define("BUILD_STATIC_LIB", "ON") + .build_target("binaryen") + .build(); + + // I couldn't figure out how to link just one of these, so link everything. + println!("cargo:rustc-link-lib=static=asmjs"); + println!("cargo:rustc-link-lib=static=binaryen"); + println!("cargo:rustc-link-lib=static=cfg"); + println!("cargo:rustc-link-lib=static=emscripten-optimizer"); + println!("cargo:rustc-link-lib=static=ir"); + println!("cargo:rustc-link-lib=static=passes"); + println!("cargo:rustc-link-lib=static=support"); + println!("cargo:rustc-link-lib=static=wasm"); + + let out_dir = env::var("OUT_DIR").unwrap(); + println!("cargo:rustc-link-search=native={}/build/lib", out_dir); + + // Add in our own little shim along with some extra files that weren't + // included in the main build. + let mut cfg = cc::Build::new(); + cfg.file("BinaryenWrapper.cpp") + .file("../binaryen/src/wasm-linker.cpp") + .file("../binaryen/src/wasm-emscripten.cpp") + .include("../binaryen/src") + .cpp_link_stdlib(None) + .warnings(false) + .cpp(true); + + if !target.contains("msvc") { + cfg.flag("-std=c++11"); + } + cfg.compile("binaryen_wrapper"); +} diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs new file mode 100644 index 0000000000000..6c7feb6a7a9d3 --- /dev/null +++ b/src/librustc_binaryen/lib.rs @@ -0,0 +1,150 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Rustc bindings to the binaryen project. +//! +//! This crate is a small shim around the binaryen project which provides us the +//! ability to take LLVM's output and generate a wasm module. Specifically this +//! only supports one operation, creating a module from LLVM's assembly format +//! and then serializing that module to a wasm module. + +extern crate libc; + +use std::slice; +use std::ffi::{CString, CStr}; + +/// In-memory representation of a serialized wasm module. +pub struct Module { + ptr: *mut BinaryenRustModule, +} + +impl Module { + /// Creates a new wasm module from the LLVM-assembly provided (in a C string + /// format). + /// + /// The actual module creation can be tweaked through the various options in + /// `ModuleOptions` as well. Any errors are just returned as a bland string. + pub fn new(assembly: &CStr, opts: &ModuleOptions) -> Result { + unsafe { + let ptr = BinaryenRustModuleCreate(opts.ptr, assembly.as_ptr()); + if ptr.is_null() { + Err(format!("failed to create binaryen module")) + } else { + Ok(Module { ptr }) + } + } + } + + /// Returns the data of the serialized wasm module. This is a `foo.wasm` + /// file contents. + pub fn data(&self) -> &[u8] { + unsafe { + let ptr = BinaryenRustModulePtr(self.ptr); + let len = BinaryenRustModuleLen(self.ptr); + slice::from_raw_parts(ptr, len) + } + } +} + +impl Drop for Module { + fn drop(&mut self) { + unsafe { + BinaryenRustModuleFree(self.ptr); + } + } +} + +pub struct ModuleOptions { + ptr: *mut BinaryenRustModuleOptions, +} + +impl ModuleOptions { + pub fn new() -> ModuleOptions { + unsafe { + let ptr = BinaryenRustModuleOptionsCreate(); + ModuleOptions { ptr } + } + } + + /// Turns on or off debug info. + /// + /// From what I can tell this just creates a "names" section of the wasm + /// module which contains a table of the original function names. + pub fn debuginfo(&mut self, debug: bool) -> &mut Self { + unsafe { + BinaryenRustModuleOptionsSetDebugInfo(self.ptr, debug); + } + self + } + + /// Configures a `start` function for the module, to be executed when it's + /// loaded. + pub fn start(&mut self, func: &str) -> &mut Self { + let func = CString::new(func).unwrap(); + unsafe { + BinaryenRustModuleOptionsSetStart(self.ptr, func.as_ptr()); + } + self + } + + /// Configures how much stack is initially allocated for the module. 1MB is + /// probably good enough for now. + pub fn stack(&mut self, amt: u64) -> &mut Self { + unsafe { + BinaryenRustModuleOptionsSetStackAllocation(self.ptr, amt); + } + self + } + + /// Flags whether the initial memory should be imported or exported. So far + /// we export it by default. + pub fn import_memory(&mut self, import: bool) -> &mut Self { + unsafe { + BinaryenRustModuleOptionsSetImportMemory(self.ptr, import); + } + self + } +} + +impl Drop for ModuleOptions { + fn drop(&mut self) { + unsafe { + BinaryenRustModuleOptionsFree(self.ptr); + } + } +} + +enum BinaryenRustModule {} +enum BinaryenRustModuleOptions {} + +extern { + fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions, + assembly: *const libc::c_char) + -> *mut BinaryenRustModule; + fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8; + fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize; + fn BinaryenRustModuleFree(module: *mut BinaryenRustModule); + + fn BinaryenRustModuleOptionsCreate() + -> *mut BinaryenRustModuleOptions; + fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions, + debuginfo: bool); + fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions, + start: *const libc::c_char); + fn BinaryenRustModuleOptionsSetStackAllocation( + module: *mut BinaryenRustModuleOptions, + stack: u64, + ); + fn BinaryenRustModuleOptionsSetImportMemory( + module: *mut BinaryenRustModuleOptions, + import: bool, + ); + fn BinaryenRustModuleOptionsFree(module: *mut BinaryenRustModuleOptions); +} diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 24c3963fbc4b3..cff584c16802e 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1606,7 +1606,8 @@ extern "C" { PositionIndependentExecutable: bool, FunctionSections: bool, DataSections: bool, - TrapUnreachable: bool) + TrapUnreachable: bool, + Singlethread: bool) -> TargetMachineRef; pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef); diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index f797464c1f8f1..96102cad3ef5e 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,16 +11,17 @@ test = false [dependencies] bitflags = "1.0" -num_cpus = "1.0" flate2 = "0.2" jobserver = "0.1.5" log = "0.3" +num_cpus = "1.0" owning_ref = "0.3.3" -rustc-demangle = "0.1.4" rustc = { path = "../librustc" } +rustc-demangle = "0.1.4" rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_back = { path = "../librustc_back" } +rustc_binaryen = { path = "../librustc_binaryen" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 1d2bfd001f1fe..89f182d178b94 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -27,7 +27,7 @@ use rustc::util::common::time; use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; use rustc_back::tempdir::TempDir; -use rustc_back::{PanicStrategy, RelroLevel}; +use rustc_back::{PanicStrategy, RelroLevel, LinkerFlavor}; use context::get_reloc_model; use llvm; @@ -245,12 +245,12 @@ pub fn each_linked_rlib(sess: &Session, /// It's unusual for a crate to not participate in LTO. Typically only /// compiler-specific and unstable crates have a reason to not participate in /// LTO. -pub fn ignored_for_lto(info: &CrateInfo, cnum: CrateNum) -> bool { - // `#![no_builtins]` crates don't participate in LTO because the state - // of builtins gets messed up (our crate isn't tagged with no builtins). - // Similarly `#![compiler_builtins]` doesn't participate because we want - // those builtins! - info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum) +pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { + // If our target enables builtin function lowering in LLVM then the + // crates providing these functions don't participate in LTO (e.g. + // no_builtins or compiler builtins crates). + !sess.target.target.options.no_builtins && + (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum)) } fn link_binary_output(sess: &Session, @@ -488,7 +488,7 @@ fn link_staticlib(sess: &Session, }); ab.add_rlib(path, &name.as_str(), - sess.lto() && !ignored_for_lto(&trans.crate_info, cnum), + sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum), skip_object_files).unwrap(); all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned()); @@ -548,6 +548,11 @@ fn link_natively(sess: &Session, info!("preparing {:?} to {:?}", crate_type, out_filename); let flavor = sess.linker_flavor(); + // The "binaryen linker" is massively special, so skip everything below. + if flavor == LinkerFlavor::Binaryen { + return link_binaryen(sess, crate_type, out_filename, trans, tmpdir); + } + // The invocations of cc share some flags across platforms let (pname, mut cmd, envs) = get_linker(sess); // This will set PATH on windows @@ -1176,7 +1181,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - if (!sess.lto() || ignored_for_lto(&trans.crate_info, cnum)) && + if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) && crate_type != config::CrateTypeDylib && !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); @@ -1229,8 +1234,10 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - let skip_because_lto = sess.lto() && is_rust_object && - !trans.crate_info.is_no_builtins.contains(&cnum); + let skip_because_lto = sess.lto() && + is_rust_object && + (sess.target.target.options.no_builtins || + !trans.crate_info.is_no_builtins.contains(&cnum)); if skip_because_cfg_say_so || skip_because_lto { archive.remove_file(&f); @@ -1345,3 +1352,30 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { None => true, } } + +/// For now "linking with binaryen" is just "move the one module we generated in +/// the backend to the final output" +/// +/// That is, all the heavy lifting happens during the `back::write` phase. Here +/// we just clean up after that. +/// +/// Note that this is super temporary and "will not survive the night", this is +/// guaranteed to get removed as soon as a linker for wasm exists. This should +/// not be used for anything other than wasm. +fn link_binaryen(sess: &Session, + _crate_type: config::CrateType, + out_filename: &Path, + trans: &CrateTranslation, + _tmpdir: &Path) { + assert!(trans.allocator_module.is_none()); + assert_eq!(trans.modules.len(), 1); + + let object = trans.modules[0].object.as_ref().expect("object must exist"); + let res = fs::hard_link(object, out_filename) + .or_else(|_| fs::copy(object, out_filename).map(|_| ())); + if let Err(e) = res { + sess.fatal(&format!("failed to create `{}`: {}", + out_filename.display(), + e)); + } +} diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 51f89110eb4ae..aa29c3cc12058 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -77,6 +77,9 @@ impl LinkerInfo { is_ld: true, }) as Box } + LinkerFlavor::Binaryen => { + panic!("can't instantiate binaryen linker") + } } } } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 132b8fa7acfb0..fa6fe2e9e93ef 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -21,6 +21,7 @@ use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use rustc::util::nodemap::FxHashMap; use rustc_allocator::ALLOCATOR_METHODS; +use rustc_back::LinkerFlavor; use syntax::attr; pub type ExportedSymbols = FxHashMap< @@ -154,12 +155,26 @@ pub fn provide_extern(providers: &mut Providers) { let special_runtime_crate = tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); + // Dealing with compiler-builtins and wasm right now is super janky. + // There's no linker! As a result we need all of the compiler-builtins + // exported symbols to make their way through all the way to the end of + // compilation. We want to make sure that LLVM doesn't remove them as + // well because we may or may not need them in the final output + // artifact. For now just force them to always get exported at the C + // layer, and we'll worry about gc'ing them later. + let compiler_builtins_and_binaryen = + tcx.is_compiler_builtins(cnum) && + tcx.sess.linker_flavor() == LinkerFlavor::Binaryen; + let mut crate_exports: Vec<_> = tcx .exported_symbol_ids(cnum) .iter() .map(|&def_id| { let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = if special_runtime_crate { + let export_level = if compiler_builtins_and_binaryen && + tcx.contains_extern_indicator(def_id) { + SymbolExportLevel::C + } else if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index e443f13a7a1ca..da67940abcb77 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,6 +22,7 @@ use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Pas AllPasses, Sanitizer}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; +use rustc_back::LinkerFlavor; use time_graph::{self, TimeGraph, Timeline}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; @@ -47,7 +48,7 @@ use std::any::Any; use std::ffi::{CString, CStr}; use std::fs::{self, File}; use std::io; -use std::io::Write; +use std::io::{Read, Write}; use std::mem; use std::path::{Path, PathBuf}; use std::str; @@ -186,6 +187,8 @@ pub fn target_machine_factory(sess: &Session) } }; + let singlethread = sess.target.target.options.singlethread; + let triple = &sess.target.target.llvm_target; let triple = CString::new(triple.as_bytes()).unwrap(); @@ -210,6 +213,7 @@ pub fn target_machine_factory(sess: &Session) ffunction_sections, fdata_sections, trap_unreachable, + singlethread, ) }; @@ -287,7 +291,7 @@ impl ModuleConfig { fn set_flags(&mut self, sess: &Session, no_builtins: bool) { self.no_verify = sess.no_verify(); self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; - self.no_builtins = no_builtins; + self.no_builtins = no_builtins || sess.target.target.options.no_builtins; self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; @@ -330,6 +334,9 @@ pub struct CodegenContext { pub tm_factory: Arc Result + Send + Sync>, pub msvc_imps_needed: bool, pub target_pointer_width: String, + binaryen_linker: bool, + debuginfo: config::DebugInfoLevel, + wasm_import_memory: bool, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -625,14 +632,21 @@ unsafe fn codegen(cgcx: &CodegenContext, f(cpm) } + // If we're going to generate wasm code from the assembly that llvm + // generates then we'll be transitively affecting a ton of options below. + // This only happens on the wasm target now. + let asm2wasm = cgcx.binaryen_linker && + !cgcx.crate_types.contains(&config::CrateTypeRlib) && + mtrans.kind == ModuleKind::Regular; + // Change what we write and cleanup based on whether obj files are // just llvm bitcode. In that case write bitcode, and possibly // delete the bitcode if it wasn't requested. Don't generate the // machine code, instead copy the .o file from the .bc - let write_bc = config.emit_bc || config.obj_is_bitcode; - let rm_bc = !config.emit_bc && config.obj_is_bitcode; - let write_obj = config.emit_obj && !config.obj_is_bitcode; - let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; + let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm); + let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm; + let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm; + let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm; let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); @@ -711,7 +725,7 @@ unsafe fn codegen(cgcx: &CodegenContext, timeline.record("ir"); } - if config.emit_asm { + if config.emit_asm || (asm2wasm && config.emit_obj) { let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers @@ -732,7 +746,15 @@ unsafe fn codegen(cgcx: &CodegenContext, timeline.record("asm"); } - if write_obj { + if asm2wasm && config.emit_obj { + let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out); + timeline.record("binaryen"); + + if !config.emit_asm { + drop(fs::remove_file(&assembly)); + } + } else if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) @@ -764,6 +786,44 @@ unsafe fn codegen(cgcx: &CodegenContext, &cgcx.output_filenames)) } +/// Translates the LLVM-generated `assembly` on the filesystem into a wasm +/// module using binaryen, placing the output at `object`. +/// +/// In this case the "object" is actually a full and complete wasm module. We +/// won't actually be doing anything else to the output for now. This is all +/// pretty janky and will get removed as soon as a linker for wasm exists. +fn binaryen_assemble(cgcx: &CodegenContext, + handler: &Handler, + assembly: &Path, + object: &Path) { + use rustc_binaryen::{Module, ModuleOptions}; + + let input = File::open(&assembly).and_then(|mut f| { + let mut contents = Vec::new(); + f.read_to_end(&mut contents)?; + Ok(CString::new(contents)?) + }); + let mut options = ModuleOptions::new(); + if cgcx.debuginfo != config::NoDebugInfo { + options.debuginfo(true); + } + if cgcx.crate_types.contains(&config::CrateTypeExecutable) { + options.start("main"); + } + options.stack(1024 * 1024); + options.import_memory(cgcx.wasm_import_memory); + let assembled = input.and_then(|input| { + Module::new(&input, &options) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + }); + let err = assembled.and_then(|binary| { + File::create(&object).and_then(|mut f| f.write_all(binary.data())) + }); + if let Err(e) = err { + handler.err(&format!("failed to run binaryen assembler: {}", e)); + } +} + pub struct CompiledModules { pub modules: Vec, pub metadata_module: CompiledModule, @@ -1318,17 +1378,33 @@ fn start_executing_work(tcx: TyCtxt, let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { - if link::ignored_for_lto(crate_info, cnum) { + if link::ignored_for_lto(sess, crate_info, cnum) { return } each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); + let crate_types = sess.crate_types.borrow(); + let only_rlib = crate_types.len() == 1 && + crate_types[0] == config::CrateTypeRlib; + + let wasm_import_memory = + attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory"); + let cgcx = CodegenContext { crate_types: sess.crate_types.borrow().clone(), each_linked_rlib_for_lto, - lto: sess.lto(), - thinlto: sess.opts.debugging_opts.thinlto, + // If we're only building an rlibc then allow the LTO flag to be passed + // but don't actually do anything, the full LTO will happen later + lto: sess.lto() && !only_rlib, + + // Enable ThinLTO if requested, but only if the target we're compiling + // for doesn't require full LTO. Some targets require one LLVM module + // (they effectively don't have a linker) so it's up to us to use LTO to + // link everything together. + thinlto: sess.opts.debugging_opts.thinlto && + !sess.target.target.options.requires_lto, + no_landing_pads: sess.no_landing_pads(), save_temps: sess.opts.cg.save_temps, opts: Arc::new(sess.opts.clone()), @@ -1349,6 +1425,9 @@ fn start_executing_work(tcx: TyCtxt, total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), + binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen, + debuginfo: tcx.sess.opts.debuginfo, + wasm_import_memory: wasm_import_memory, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 96e11d366423a..ae25e7d94bffa 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -43,18 +43,19 @@ extern crate flate2; extern crate libc; extern crate owning_ref; #[macro_use] extern crate rustc; +extern crate jobserver; +extern crate num_cpus; extern crate rustc_allocator; extern crate rustc_apfloat; extern crate rustc_back; +extern crate rustc_binaryen; +extern crate rustc_const_math; extern crate rustc_data_structures; +extern crate rustc_demangle; extern crate rustc_incremental; extern crate rustc_llvm as llvm; extern crate rustc_platform_intrinsics as intrinsics; -extern crate rustc_const_math; extern crate rustc_trans_utils; -extern crate rustc_demangle; -extern crate jobserver; -extern crate num_cpus; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs index 47484488fb8e8..c1e670cc7caf5 100644 --- a/src/librustc_trans_utils/link.rs +++ b/src/librustc_trans_utils/link.rs @@ -163,15 +163,30 @@ pub fn default_output_for_target(sess: &Session) -> config::CrateType { /// Checks if target supports crate_type as output pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) -> bool { - match (sess.target.target.options.dynamic_linking, - sess.target.target.options.executables, crate_type) { - (false, _, config::CrateTypeCdylib) | - (false, _, config::CrateTypeDylib) | - (false, _, config::CrateTypeProcMacro) => true, - (true, _, config::CrateTypeCdylib) | - (true, _, config::CrateTypeDylib) => sess.crt_static() && - !sess.target.target.options.crt_static_allows_dylibs, - (_, false, config::CrateTypeExecutable) => true, - _ => false + match crate_type { + config::CrateTypeCdylib | + config::CrateTypeDylib | + config::CrateTypeProcMacro => { + if !sess.target.target.options.dynamic_linking { + return true + } + if sess.crt_static() && !sess.target.target.options.crt_static_allows_dylibs { + return true + } + } + _ => {} } + if sess.target.target.options.only_cdylib { + match crate_type { + config::CrateTypeProcMacro | config::CrateTypeDylib => return true, + _ => {} + } + } + if !sess.target.target.options.executables { + if crate_type == config::CrateTypeExecutable { + return true + } + } + + false } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 0e6214ea04fc0..06f11c8deb458 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -19,8 +19,12 @@ use build_helper::{run, native_lib_boilerplate, BuildExpectation}; fn main() { let target = env::var("TARGET").expect("TARGET was not set"); let host = env::var("HOST").expect("HOST was not set"); - if cfg!(feature = "backtrace") && !target.contains("msvc") && - !target.contains("emscripten") && !target.contains("fuchsia") { + if cfg!(feature = "backtrace") && + !target.contains("msvc") && + !target.contains("emscripten") && + !target.contains("fuchsia") && + !target.contains("wasm32") + { let _ = build_libbacktrace(&host, &target); } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7ec6124dfa462..14f0edc369058 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -26,7 +26,6 @@ use num::FpCategory; #[cfg(not(test))] use sys::cmath; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6318e2e40875f..9d0373404aaa7 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -663,3 +663,39 @@ pub mod builtin { #[macro_export] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } } + +/// A macro for defining #[cfg] if-else statements. +/// +/// This is similar to the `if/elif` C preprocessor macro by allowing definition +/// of a cascade of `#[cfg]` cases, emitting the implementation which matches +/// first. +/// +/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// without having to rewrite each clause multiple times. +macro_rules! cfg_if { + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + __cfg_if_items! { + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + } +} + +macro_rules! __cfg_if_items { + (($($not:meta,)*) ; ) => {}; + (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } + __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } + } +} + +macro_rules! __cfg_if_apply { + ($m:meta, $($it:item)*) => { + $(#[$m] $it)* + } +} diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index d91c2073a23a8..27d6433b329bb 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -46,6 +46,9 @@ mod imp; #[path = "redox/mod.rs"] mod imp; +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +#[path = "wasm/mod.rs"] +mod imp; // Import essential modules from both platforms when documenting. diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs new file mode 100644 index 0000000000000..d2a4a7b19d548 --- /dev/null +++ b/src/libstd/sys/wasm/args.rs @@ -0,0 +1,90 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi::OsString; +use marker::PhantomData; +use mem; +use vec; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + // On wasm these should always be null, so there's nothing for us to do here +} + +pub unsafe fn cleanup() { +} + +pub fn args() -> Args { + // When the runtime debugging is enabled we'll link to some extra runtime + // functions to actually implement this. These are for now just implemented + // in a node.js script but they're off by default as they're sort of weird + // in a web-wasm world. + if !super::DEBUG { + return Args { + iter: Vec::new().into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These + // are just meant for debugging and should not be relied on. + extern { + fn rust_wasm_args_count() -> usize; + fn rust_wasm_args_arg_size(a: usize) -> usize; + fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8); + } + + unsafe { + let cnt = rust_wasm_args_count(); + let mut v = Vec::with_capacity(cnt); + for i in 0..cnt { + let n = rust_wasm_args_arg_size(i); + let mut data = vec![0; n]; + rust_wasm_args_arg_fill(i, data.as_mut_ptr()); + v.push(mem::transmute::, OsString>(data)); + } + Args { + iter: v.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } +} + +pub struct Args { + iter: vec::IntoIter, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + self.iter.as_slice() + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + 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 { + self.iter.next_back() + } +} diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs new file mode 100644 index 0000000000000..9a8c48ff29fc7 --- /dev/null +++ b/src/libstd/sys/wasm/backtrace.rs @@ -0,0 +1,37 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::unsupported; +use sys_common::backtrace::Frame; + +pub struct BacktraceContext; + +pub fn unwind_backtrace(_frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + unsupported() +} + +pub fn resolve_symname(_frame: Frame, + _callback: F, + _: &BacktraceContext) -> io::Result<()> + where F: FnOnce(Option<&str>) -> io::Result<()> +{ + unsupported() +} + +pub fn foreach_symbol_fileline(_: Frame, + _: F, + _: &BacktraceContext) -> io::Result + where F: FnMut(&[u8], u32) -> io::Result<()> +{ + unsupported() +} diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs new file mode 100644 index 0000000000000..87ac2091cad41 --- /dev/null +++ b/src/libstd/sys/wasm/cmath.rs @@ -0,0 +1,119 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[inline] +pub unsafe fn cbrtf(n: f32) -> f32 { + f64::cbrt(n as f64) as f32 +} + +#[inline] +pub unsafe fn expm1f(n: f32) -> f32 { + f64::exp_m1(n as f64) as f32 +} + +#[inline] +#[allow(deprecated)] +pub unsafe fn fdimf(a: f32, b: f32) -> f32 { + f64::abs_sub(a as f64, b as f64) as f32 +} + +#[inline] +pub unsafe fn log1pf(n: f32) -> f32 { + f64::ln_1p(n as f64) as f32 +} + +#[inline] +pub unsafe fn hypotf(x: f32, y: f32) -> f32 { + f64::hypot(x as f64, y as f64) as f32 +} + +#[inline] +pub unsafe fn acosf(n: f32) -> f32 { + f64::acos(n as f64) as f32 +} + +#[inline] +pub unsafe fn asinf(n: f32) -> f32 { + f64::asin(n as f64) as f32 +} + +#[inline] +pub unsafe fn atan2f(n: f32, b: f32) -> f32 { + f64::atan2(n as f64, b as f64) as f32 +} + +#[inline] +pub unsafe fn atanf(n: f32) -> f32 { + f64::atan(n as f64) as f32 +} + +#[inline] +pub unsafe fn coshf(n: f32) -> f32 { + f64::cosh(n as f64) as f32 +} + +#[inline] +pub unsafe fn sinhf(n: f32) -> f32 { + f64::sinh(n as f64) as f32 +} + +#[inline] +pub unsafe fn tanf(n: f32) -> f32 { + f64::tan(n as f64) as f32 +} + +#[inline] +pub unsafe fn tanhf(n: f32) -> f32 { + f64::tanh(n as f64) as f32 +} + +// Right now all these functions, the f64 version of the functions above, all +// shell out to random names. These names aren't actually defined anywhere, per +// se, but we need this to compile somehow. +// +// The idea with this is that when you're using wasm then, for now, we have no +// way of providing an implementation of these which delegates to a "correct" +// implementation. For example most wasm applications probably just want to +// delegate to the javascript `Math` object and its related functions, but wasm +// doesn't currently have the ability to seamlessly do that (when you +// instantiate a module you have to set that up). +// +// As a result these are just defined here with "hopefully helpful" names. The +// symbols won't ever be needed or show up unless these functions are called, +// and hopefully when they're called the errors are self-explanatory enough to +// figure out what's going on. + +extern { + #[link_name = "Math_acos"] + pub fn acos(n: f64) -> f64; + #[link_name = "Math_asin"] + pub fn asin(n: f64) -> f64; + #[link_name = "Math_atan"] + pub fn atan(n: f64) -> f64; + #[link_name = "Math_atan2"] + pub fn atan2(a: f64, b: f64) -> f64; + #[link_name = "Math_cbrt"] + pub fn cbrt(n: f64) -> f64; + #[link_name = "Math_cosh"] + pub fn cosh(n: f64) -> f64; + #[link_name = "Math_expm1"] + pub fn expm1(n: f64) -> f64; + pub fn fdim(a: f64, b: f64) -> f64; + #[link_name = "Math_log1p"] + pub fn log1p(n: f64) -> f64; + #[link_name = "Math_sinh"] + pub fn sinh(n: f64) -> f64; + #[link_name = "Math_tan"] + pub fn tan(n: f64) -> f64; + #[link_name = "Math_tanh"] + pub fn tanh(n: f64) -> f64; + #[link_name = "Math_hypot"] + pub fn hypot(x: f64, y: f64) -> f64; +} diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs new file mode 100644 index 0000000000000..afa7afeef5988 --- /dev/null +++ b/src/libstd/sys/wasm/condvar.rs @@ -0,0 +1,43 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::mutex::Mutex; +use time::Duration; + +pub struct Condvar { } + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn notify_one(&self) { + } + + #[inline] + pub unsafe fn notify_all(&self) { + } + + pub unsafe fn wait(&self, _mutex: &Mutex) { + panic!("can't block with web assembly") + } + + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + panic!("can't block with web assembly"); + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/wasm/env.rs b/src/libstd/sys/wasm/env.rs new file mode 100644 index 0000000000000..1422042bd0228 --- /dev/null +++ b/src/libstd/sys/wasm/env.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 = ""; + pub const OS: &'static str = ""; + pub const DLL_PREFIX: &'static str = ""; + pub const DLL_SUFFIX: &'static str = ".wasm"; + pub const DLL_EXTENSION: &'static str = "wasm"; + pub const EXE_SUFFIX: &'static str = ".wasm"; + pub const EXE_EXTENSION: &'static str = "wasm"; +} diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs new file mode 100644 index 0000000000000..b3c70a6685a6c --- /dev/null +++ b/src/libstd/sys/wasm/fs.rs @@ -0,0 +1,304 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi::OsString; +use fmt; +use hash::{Hash, Hasher}; +use io::{self, SeekFrom}; +use path::{Path, PathBuf}; +use sys::time::SystemTime; +use sys::{unsupported, Void}; + +pub struct File(Void); + +pub struct FileAttr(Void); + +pub struct ReadDir(Void); + +pub struct DirEntry(Void); + +#[derive(Clone, Debug)] +pub struct OpenOptions { } + +pub struct FilePermissions(Void); + +pub struct FileType(Void); + +#[derive(Debug)] +pub struct DirBuilder { } + +impl FileAttr { + pub fn size(&self) -> u64 { + match self.0 {} + } + + pub fn perm(&self) -> FilePermissions { + match self.0 {} + } + + pub fn file_type(&self) -> FileType { + match self.0 {} + } + + pub fn modified(&self) -> io::Result { + match self.0 {} + } + + pub fn accessed(&self) -> io::Result { + match self.0 {} + } + + pub fn created(&self) -> io::Result { + match self.0 {} + } +} + +impl Clone for FileAttr { + fn clone(&self) -> FileAttr { + match self.0 {} + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + match self.0 {} + } + + pub fn set_readonly(&mut self, _readonly: bool) { + match self.0 {} + } +} + +impl Clone for FilePermissions { + fn clone(&self) -> FilePermissions { + match self.0 {} + } +} + +impl PartialEq for FilePermissions { + fn eq(&self, _other: &FilePermissions) -> bool { + match self.0 {} + } +} + +impl Eq for FilePermissions { +} + +impl fmt::Debug for FilePermissions { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + match self.0 {} + } + + pub fn is_file(&self) -> bool { + match self.0 {} + } + + pub fn is_symlink(&self) -> bool { + match self.0 {} + } +} + +impl Clone for FileType { + fn clone(&self) -> FileType { + match self.0 {} + } +} + +impl Copy for FileType {} + +impl PartialEq for FileType { + fn eq(&self, _other: &FileType) -> bool { + match self.0 {} + } +} + +impl Eq for FileType { +} + +impl Hash for FileType { + fn hash(&self, _h: &mut H) { + match self.0 {} + } +} + +impl fmt::Debug for FileType { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + match self.0 {} + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + match self.0 {} + } + + pub fn file_name(&self) -> OsString { + match self.0 {} + } + + pub fn metadata(&self) -> io::Result { + match self.0 {} + } + + pub fn file_type(&self) -> io::Result { + match self.0 {} + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { } + } + + pub fn read(&mut self, _read: bool) { } + pub fn write(&mut self, _write: bool) { } + pub fn append(&mut self, _append: bool) { } + pub fn truncate(&mut self, _truncate: bool) { } + pub fn create(&mut self, _create: bool) { } + pub fn create_new(&mut self, _create_new: bool) { } +} + +impl File { + pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { + unsupported() + } + + pub fn file_attr(&self) -> io::Result { + match self.0 {} + } + + pub fn fsync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn datasync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + match self.0 {} + } + + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn flush(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { } + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub fn readdir(_p: &Path) -> io::Result { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + unsupported() +} + +pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { + match perm.0 {} +} + +pub fn rmdir(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn readlink(_p: &Path) -> io::Result { + unsupported() +} + +pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result { + unsupported() +} diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs new file mode 100644 index 0000000000000..e611d94af30b1 --- /dev/null +++ b/src/libstd/sys/wasm/memchr.rs @@ -0,0 +1,11 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use sys_common::memchr::fallback::{memchr, memrchr}; diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs new file mode 100644 index 0000000000000..b838dbafd6f0c --- /dev/null +++ b/src/libstd/sys/wasm/mod.rs @@ -0,0 +1,104 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! System bindings for the wasm/web platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for wasm. Note that this wasm is *not* the emscripten +//! wasm, so we have no runtime here. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. +//! +//! Currently all functions here are basically stubs that immediately return +//! errors. The hope is that with a portability lint we can turn actually just +//! remove all this and just omit parts of the standard library if we're +//! compiling for wasm. That way it's a compile time error for something that's +//! guaranteed to be a runtime error! + +use io; +use os::raw::c_char; + +// Right now the wasm backend doesn't even have the ability to print to the +// console by default. Wasm can't import anything from JS! (you have to +// explicitly provide it). +// +// Sometimes that's a real bummer, though, so this flag can be set to `true` to +// enable calling various shims defined in `src/etc/wasm32-shim.js` which should +// help receive debug output and see what's going on. In general this flag +// currently controls "will we call out to our own defined shims in node.js", +// and this flag should always be `false` for release builds. +const DEBUG: bool = false; + +pub mod args; +pub mod backtrace; +pub mod cmath; +pub mod condvar; +pub mod env; +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 rwlock; +pub mod stack_overflow; +pub mod thread; +pub mod thread_local; +pub mod time; +pub mod stdio; + +#[cfg(not(test))] +pub fn init() { +} + +pub fn unsupported() -> io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> io::Error { + io::Error::new(io::ErrorKind::Other, + "operation not supported on wasm yet") +} + +pub fn decode_error_kind(_code: i32) -> io::ErrorKind { + io::ErrorKind::Other +} + +// This enum is used as the storage for a bunch of types which can't actually +// exist. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Void {} + +pub unsafe fn strlen(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n +} + +pub unsafe fn abort_internal() -> ! { + ::intrinsics::abort(); +} + +// We don't have randomness yet, but I totally used a random number generator to +// generate these numbers. +// +// More seriously though this is just for DOS protection in hash maps. It's ok +// if we don't do that on wasm just yet. +pub fn hashmap_random_keys() -> (u64, u64) { + (1, 2) +} diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs new file mode 100644 index 0000000000000..4197bdcc80839 --- /dev/null +++ b/src/libstd/sys/wasm/mutex.rs @@ -0,0 +1,79 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; + +pub struct Mutex { + locked: UnsafeCell, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} // no threads on wasm + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { locked: UnsafeCell::new(false) } + } + + #[inline] + pub unsafe fn init(&mut self) { + } + + #[inline] + pub unsafe fn lock(&self) { + let locked = self.locked.get(); + assert!(!*locked, "cannot recursively acquire mutex"); + *locked = true; + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.locked.get() = false; + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let locked = self.locked.get(); + if *locked { + false + } else { + *locked = true; + true + } + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} + +// All empty stubs because wasm has no threads yet, so lock acquisition always +// succeeds. +pub struct ReentrantMutex { +} + +impl ReentrantMutex { + pub unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn lock(&self) {} + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + true + } + + pub unsafe fn unlock(&self) {} + + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs new file mode 100644 index 0000000000000..e7476ab37f7c8 --- /dev/null +++ b/src/libstd/sys/wasm/net.rs @@ -0,0 +1,337 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use io; +use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; +use time::Duration; +use sys::{unsupported, Void}; + +pub struct TcpStream(Void); + +impl TcpStream { + pub fn connect(_: &SocketAddr) -> io::Result { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn nodelay(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct TcpListener(Void); + +impl TcpListener { + pub fn bind(_: &SocketAddr) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn only_v6(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct UdpSocket(Void); + +impl UdpSocket { + pub fn bind(_: &SocketAddr) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn broadcast(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v6(&self) -> io::Result { + match self.0 {} + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn send(&self, _: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct LookupHost(Void); + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + match self.0 {} + } +} + +pub fn lookup_host(_: &str) -> io::Result { + unsupported() +} + +#[allow(bad_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr { + } + + pub type socklen_t = usize; +} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs new file mode 100644 index 0000000000000..c98030f7ebf53 --- /dev/null +++ b/src/libstd/sys/wasm/os.rs @@ -0,0 +1,136 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::intrinsics; + +use error::Error as StdError; +use ffi::{OsString, OsStr}; +use fmt; +use io; +use mem; +use path::{self, PathBuf}; +use str; +use sys::{unsupported, Void}; + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(_errno: i32) -> String { + format!("operation successful") +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a Void); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + match *self.0 {} + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result + where I: Iterator, T: AsRef +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "not supported on wasm yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + fn description(&self) -> &str { + "not supported on wasm yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +pub struct Env(Void); + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + match self.0 {} + } +} + +pub fn env() -> Env { + panic!("not supported on web assembly") +} + +pub fn getenv(k: &OsStr) -> io::Result> { + // If we're debugging the runtime then we actually probe node.js to ask for + // the value of environment variables to help provide inputs to programs. + // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are + // intended for debugging only, you should not rely on them. + if !super::DEBUG { + return Ok(None) + } + + extern { + fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize; + fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8); + } + unsafe { + let k: &[u8] = mem::transmute(k); + let n = rust_wasm_getenv_len(k.as_ptr(), k.len()); + if n == -1 { + return Ok(None) + } + let mut data = vec![0; n as usize]; + rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr()); + Ok(Some(mem::transmute(data))) + } +} + +pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { + unsupported() +} + +pub fn unsetenv(_n: &OsStr) -> io::Result<()> { + unsupported() +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on wasm") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + unsafe { intrinsics::abort() } +} + +pub fn getpid() -> u32 { + panic!("no pids on wasm") +} diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs new file mode 100644 index 0000000000000..c5908a7a8dc22 --- /dev/null +++ b/src/libstd/sys/wasm/os_str.rs @@ -0,0 +1,159 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The underlying OsString/OsStr implementation on Unix systems: just +/// a `Vec`/`[u8]`. + +use borrow::Cow; +use fmt; +use str; +use mem; +use sys_common::{AsInner, IntoInner}; +use std_unicode::lossy::Utf8Lossy; + +#[derive(Clone, Hash)] +pub struct Buf { + pub inner: Vec +} + +pub struct Slice { + pub inner: [u8] +} + +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) + } +} + +impl IntoInner> for Buf { + fn into_inner(self) -> Vec { + self.inner + } +} + +impl AsInner<[u8]> for Buf { + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + + +impl Buf { + pub fn from_string(s: String) -> Buf { + Buf { inner: s.into_bytes() } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { + inner: Vec::with_capacity(capacity) + } + } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + + pub fn as_slice(&self) -> &Slice { + unsafe { mem::transmute(&*self.inner) } + } + + pub fn into_string(self) -> Result { + String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) + } + + pub fn push_slice(&mut self, s: &Slice) { + self.inner.extend_from_slice(&s.inner) + } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } +} + +impl Slice { + fn from_u8_slice(s: &[u8]) -> &Slice { + unsafe { mem::transmute(s) } + } + + pub fn from_str(s: &str) -> &Slice { + Slice::from_u8_slice(s.as_bytes()) + } + + pub fn to_str(&self) -> Option<&str> { + str::from_utf8(&self.inner).ok() + } + + pub fn to_string_lossy(&self) -> Cow { + String::from_utf8_lossy(&self.inner) + } + + pub fn to_owned(&self) -> Buf { + Buf { inner: self.inner.to_vec() } + } + + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.inner.into(); + unsafe { mem::transmute(boxed) } + } + + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } +} diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs new file mode 100644 index 0000000000000..395b8c1e40e98 --- /dev/null +++ b/src/libstd/sys/wasm/path.rs @@ -0,0 +1,29 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 { + None +} + +pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs new file mode 100644 index 0000000000000..992e1ac409cfb --- /dev/null +++ b/src/libstd/sys/wasm/pipe.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::Void; + +pub struct AnonPipe(Void); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec, + _p2: AnonPipe, + _v2: &mut Vec) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs new file mode 100644 index 0000000000000..4febe8a146382 --- /dev/null +++ b/src/libstd/sys/wasm/process.rs @@ -0,0 +1,151 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi::OsStr; +use fmt; +use io; +use sys::fs::File; +use sys::pipe::AnonPipe; +use sys::{unsupported, Void}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +impl Command { + pub fn new(_program: &OsStr) -> Command { + Command {} + } + + pub fn arg(&mut self, _arg: &OsStr) { + } + + pub fn env(&mut self, _key: &OsStr, _val: &OsStr) { + } + + pub fn env_remove(&mut self, _key: &OsStr) { + } + + pub fn env_clear(&mut self) { + } + + pub fn cwd(&mut self, _dir: &OsStr) { + } + + pub fn stdin(&mut self, _stdin: Stdio) { + } + + pub fn stdout(&mut self, _stdout: Stdio) { + } + + pub fn stderr(&mut self, _stderr: Stdio) { + } + + pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + unsupported() + } +} + +impl From for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From for Stdio { + fn from(file: File) -> Stdio { + file.diverge() + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +pub struct ExitStatus(Void); + +impl ExitStatus { + pub fn success(&self) -> bool { + match self.0 {} + } + + pub fn code(&self) -> Option { + match self.0 {} + } +} + +impl Clone for ExitStatus { + fn clone(&self) -> ExitStatus { + match self.0 {} + } +} + +impl Copy for ExitStatus {} + +impl PartialEq for ExitStatus { + fn eq(&self, _other: &ExitStatus) -> bool { + match self.0 {} + } +} + +impl Eq for ExitStatus { +} + +impl fmt::Debug for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result> { + match self.0 {} + } +} diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs new file mode 100644 index 0000000000000..8b06f54167487 --- /dev/null +++ b/src/libstd/sys/wasm/rwlock.rs @@ -0,0 +1,82 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; + +pub struct RWLock { + mode: UnsafeCell, +} + +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} // no threads on wasm + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { + mode: UnsafeCell::new(0), + } + } + + #[inline] + pub unsafe fn read(&self) { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + } else { + panic!("rwlock locked for writing"); + } + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn write(&self) { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + } else { + panic!("rwlock locked for reading") + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + *self.mode.get() -= 1; + } + + #[inline] + pub unsafe fn write_unlock(&self) { + *self.mode.get() += 1; + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs new file mode 100644 index 0000000000000..bed274142f1ce --- /dev/null +++ b/src/libstd/sys/wasm/stack_overflow.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Handler; + +impl Handler { + pub unsafe fn new() -> Handler { + Handler + } +} + +pub unsafe fn init() { +} + +pub unsafe fn cleanup() { +} diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs new file mode 100644 index 0000000000000..0f75f24025183 --- /dev/null +++ b/src/libstd/sys/wasm/stdio.rs @@ -0,0 +1,92 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::{Void, unsupported}; + +pub struct Stdin(Void); +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result { + unsupported() + } + + pub fn read(&self, _data: &mut [u8]) -> io::Result { + match self.0 {} + } +} + +impl Stdout { + pub fn new() -> io::Result { + Ok(Stdout) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + // If runtime debugging is enabled at compile time we'll invoke some + // runtime functions that are defined in our src/etc/wasm32-shim.js + // debugging script. Note that this ffi function call is intended + // *purely* for debugging only and should not be relied upon. + if !super::DEBUG { + return unsupported() + } + extern { + fn rust_wasm_write_stdout(data: *const u8, len: usize); + } + unsafe { + rust_wasm_write_stdout(data.as_ptr(), data.len()) + } + Ok(data.len()) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result { + Ok(Stderr) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + // See comments in stdout for what's going on here. + if !super::DEBUG { + return unsupported() + } + extern { + fn rust_wasm_write_stderr(data: *const u8, len: usize); + } + unsafe { + rust_wasm_write_stderr(data.as_ptr(), data.len()) + } + Ok(data.len()) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result { + (&*self).write(data) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs new file mode 100644 index 0000000000000..13980e0cc19d1 --- /dev/null +++ b/src/libstd/sys/wasm/thread.rs @@ -0,0 +1,48 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use alloc::boxed::FnBox; +use ffi::CStr; +use io; +use sys::{unsupported, Void}; +use time::Duration; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + pub unsafe fn new<'a>(_stack: usize, _p: Box) + -> io::Result + { + unsupported() + } + + pub fn yield_now() { + // do nothing + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(_dur: Duration) { + panic!("can't sleep"); + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } +} diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs new file mode 100644 index 0000000000000..442dd3302a058 --- /dev/null +++ b/src/libstd/sys/wasm/thread_local.rs @@ -0,0 +1,50 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use boxed::Box; +use ptr; + +pub type Key = usize; + +struct Allocated { + value: *mut u8, + dtor: Option, +} + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { + Box::into_raw(Box::new(Allocated { + value: ptr::null_mut(), + dtor, + })) as usize +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + (*(key as *mut Allocated)).value = value; +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + (*(key as *mut Allocated)).value +} + +#[inline] +pub unsafe fn destroy(key: Key) { + let key = Box::from_raw(key as *mut Allocated); + if let Some(f) = key.dtor { + f(key.value); + } +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs new file mode 100644 index 0000000000000..7907720e4dac6 --- /dev/null +++ b/src/libstd/sys/wasm/time.rs @@ -0,0 +1,63 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Instant; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct SystemTime; + +pub const UNIX_EPOCH: SystemTime = SystemTime; + +impl Instant { + pub fn now() -> Instant { + panic!("not supported on web assembly"); + } + + pub fn sub_instant(&self, _other: &Instant) -> Duration { + panic!("can't sub yet"); + } + + pub fn add_duration(&self, _other: &Duration) -> Instant { + panic!("can't add yet"); + } + + pub fn sub_duration(&self, _other: &Duration) -> Instant { + panic!("can't sub yet"); + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + panic!("not supported on web assembly"); + } + + pub fn sub_time(&self, _other: &SystemTime) + -> Result { + panic!() + } + + pub fn add_duration(&self, _other: &Duration) -> SystemTime { + panic!() + } + + pub fn sub_duration(&self, _other: &Duration) -> SystemTime { + panic!() + } +} + +impl fmt::Debug for SystemTime { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + panic!() + } +} diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index d7654ce9300b3..14e5697b94e57 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -44,11 +44,15 @@ pub mod thread_local; pub mod util; pub mod wtf8; -#[cfg(any(target_os = "redox", target_os = "l4re"))] -pub use sys::net; - -#[cfg(not(any(target_os = "redox", target_os = "l4re")))] -pub mod net; +cfg_if! { + if #[cfg(any(target_os = "redox", target_os = "l4re"))] { + pub use sys::net; + } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + pub use sys::net; + } else { + pub mod net; + } +} #[cfg(feature = "backtrace")] #[cfg(any(all(unix, not(target_os = "emscripten")), diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index c19424f295226..f1379b6ec6375 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use env; use alloc::boxed::FnBox; +use env; use sync::atomic::{self, Ordering}; use sys::stack_overflow; use sys::thread as imp; +#[allow(dead_code)] pub unsafe fn start_thread(main: *mut u8) { // Next, set up our stack overflow handler which may get triggered if we run // out of stack. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 97eec3a21e9d1..ebe7853b8abdb 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -415,6 +415,9 @@ declare_features! ( // Allow trait methods with arbitrary self types (active, arbitrary_self_types, "1.23.0", Some(44874)), + + // #![wasm_import_memory] attribute + (active, wasm_import_memory, "1.22.0", None), ); declare_features! ( @@ -928,6 +931,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG never be stable", cfg_fn!(rustc_attrs))), + ("wasm_import_memory", Whitelisted, Gated(Stability::Unstable, + "wasm_import_memory", + "wasm_import_memory attribute is currently unstable", + cfg_fn!(wasm_import_memory))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 76abcb83edc53..ef08b877262fc 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -434,7 +434,8 @@ Test Attributes: // Parses command line arguments into test options pub fn parse_opts(args: &[String]) -> Option { let opts = optgroups(); - let matches = match opts.parse(&args[1..]) { + let args = args.get(1..).unwrap_or(args); + let matches = match opts.parse(args) { Ok(m) => m, Err(f) => return Some(Err(f.to_string())), }; @@ -1034,6 +1035,10 @@ fn stdout_isatty() -> bool { // FIXME: Implement isatty on Redox false } +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +fn stdout_isatty() -> bool { + false +} #[cfg(unix)] fn stdout_isatty() -> bool { unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } @@ -1132,45 +1137,47 @@ pub fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) }}) }; - while pending > 0 || !remaining.is_empty() { - while pending < concurrency && !remaining.is_empty() { + if concurrency == 1 { + while !remaining.is_empty() { let test = remaining.pop().unwrap(); - if concurrency == 1 { - // We are doing one test at a time so we can print the name - // of the test before we run it. Useful for debugging tests - // that hang forever. - callback(TeWait(test.desc.clone(), test.testfn.padding()))?; - } - let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); - running_tests.insert(test.desc.clone(), timeout); + callback(TeWait(test.desc.clone(), test.testfn.padding()))?; run_test(opts, !opts.run_tests, test, tx.clone()); - pending += 1; + let (test, result, stdout) = rx.recv().unwrap(); + callback(TeResult(test, result, stdout))?; } + } else { + while pending > 0 || !remaining.is_empty() { + while pending < concurrency && !remaining.is_empty() { + let test = remaining.pop().unwrap(); + let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + running_tests.insert(test.desc.clone(), timeout); + run_test(opts, !opts.run_tests, test, tx.clone()); + pending += 1; + } - let mut res; - loop { - if let Some(timeout) = calc_timeout(&running_tests) { - res = rx.recv_timeout(timeout); - for test in get_timed_out_tests(&mut running_tests) { - callback(TeTimeout(test))?; - } - if res != Err(RecvTimeoutError::Timeout) { + let mut res; + loop { + if let Some(timeout) = calc_timeout(&running_tests) { + res = rx.recv_timeout(timeout); + for test in get_timed_out_tests(&mut running_tests) { + callback(TeTimeout(test))?; + } + if res != Err(RecvTimeoutError::Timeout) { + break; + } + } else { + res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); break; } - } else { - res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); - break; } - } - let (desc, result, stdout) = res.unwrap(); - running_tests.remove(&desc); + let (desc, result, stdout) = res.unwrap(); + running_tests.remove(&desc); - if concurrency != 1 { callback(TeWait(desc.clone(), PadNone))?; + callback(TeResult(desc, result, stdout))?; + pending -= 1; } - callback(TeResult(desc, result, stdout))?; - pending -= 1; } if opts.bench_benchmarks { @@ -1235,6 +1242,11 @@ fn get_concurrency() -> usize { 1 } + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + fn num_cpus() -> usize { + 1 + } + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", @@ -1393,7 +1405,12 @@ pub fn run_test(opts: &TestOpts, let TestDescAndFn {desc, testfn} = test; - if force_ignore || desc.ignore { + let ignore_because_panic_abort = + cfg!(target_arch = "wasm32") && + !cfg!(target_os = "emscripten") && + desc.should_panic != ShouldPanic::No; + + if force_ignore || desc.ignore || ignore_because_panic_abort { monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap(); return; } @@ -1445,7 +1462,9 @@ pub fn run_test(opts: &TestOpts, // 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"); + let supports_threads = + !cfg!(target_os = "emscripten") && + !cfg!(target_arch = "wasm32"); if supports_threads { let cfg = thread::Builder::new().name(match name { DynTestName(ref name) => name.clone(), diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 461b49aa363b4..5bb1eb96dcfad 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -20,13 +20,20 @@ #![cfg_attr(not(target_env = "msvc"), feature(libc))] -#[cfg(not(target_env = "msvc"))] -extern crate libc; +#[macro_use] +mod macros; -#[cfg(not(target_env = "msvc"))] -mod libunwind; -#[cfg(not(target_env = "msvc"))] -pub use libunwind::*; +cfg_if! { + if #[cfg(target_env = "msvc")] { + // no extra unwinder support needed + } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + // no unwinder on the system! + } else { + extern crate libc; + mod libunwind; + pub use libunwind::*; + } +} #[cfg(all(target_env = "musl", not(target_arch = "mips")))] #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] diff --git a/src/libunwind/macros.rs b/src/libunwind/macros.rs new file mode 100644 index 0000000000000..26376a3733f4f --- /dev/null +++ b/src/libunwind/macros.rs @@ -0,0 +1,45 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A macro for defining #[cfg] if-else statements. +/// +/// This is similar to the `if/elif` C preprocessor macro by allowing definition +/// of a cascade of `#[cfg]` cases, emitting the implementation which matches +/// first. +/// +/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// without having to rewrite each clause multiple times. +macro_rules! cfg_if { + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + __cfg_if_items! { + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + } +} + +macro_rules! __cfg_if_items { + (($($not:meta,)*) ; ) => {}; + (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } + __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } + } +} + +macro_rules! __cfg_if_apply { + ($m:meta, $($it:item)*) => { + $(#[$m] $it)* + } +} diff --git a/src/rustc/dlmalloc_shim/Cargo.toml b/src/rustc/dlmalloc_shim/Cargo.toml new file mode 100644 index 0000000000000..cf8440c40da1a --- /dev/null +++ b/src/rustc/dlmalloc_shim/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "dlmalloc" +version = "0.0.0" +authors = ["The Rust Project Developers"] + +[lib] +path = "../../dlmalloc/src/lib.rs" +test = false +bench = false +doc = false + +[dependencies] +core = { path = "../../libcore" } +alloc = { path = "../../liballoc" } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index b4116c96ba130..d0c042e6451c7 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -366,7 +366,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, - bool DataSections, bool TrapUnreachable) { + bool DataSections, + bool TrapUnreachable, + bool Singlethread) { auto CM = fromRust(RustCM); auto OptLevel = fromRust(RustOptLevel); @@ -406,6 +408,10 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.TrapUnreachable = true; } + if (Singlethread) { + Options.ThreadModel = ThreadModel::Single; + } + TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), RealCPU, Feature, Options, RM, CM, OptLevel); return wrap(TM); diff --git a/src/test/compile-fail/feature-gate-wasm_import_memory.rs b/src/test/compile-fail/feature-gate-wasm_import_memory.rs new file mode 100644 index 0000000000000..a010ebb3551d0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-wasm_import_memory.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![wasm_import_memory] //~ ERROR: currently unstable + +fn main() {} + diff --git a/src/test/run-pass-fulldeps/flt2dec.rs b/src/test/run-pass-fulldeps/flt2dec.rs new file mode 100644 index 0000000000000..3db0644d1ef3c --- /dev/null +++ b/src/test/run-pass-fulldeps/flt2dec.rs @@ -0,0 +1,163 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test + +#![feature(rustc_private, flt2dec)] + +extern crate core; +extern crate rand; + +use std::i16; +use std::mem; +use std::str; + +use core::num::flt2dec::MAX_SIG_DIGITS; +use core::num::flt2dec::strategy::grisu::format_exact_opt; +use core::num::flt2dec::strategy::grisu::format_shortest_opt; +use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; + +use rand::{Rand, XorShiftRng}; +use rand::distributions::{IndependentSample, Range}; +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {:?} instead", full_decoded) + } +} + + +fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + V: FnMut(usize) -> Decoded { + assert!(k <= 1024); + + let mut npassed = 0; // f(x) = Some(g(x)) + let mut nignored = 0; // f(x) = None + + for i in 0..n { + if (i & 0xfffff) == 0 { + println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", + i, n, nignored, npassed, i - nignored - npassed); + } + + let decoded = v(i); + let mut buf1 = [0; 1024]; + if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [0; 1024]; + let (len2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + npassed += 1; + } else { + println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", + i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, + str::from_utf8(&buf2[..len2]).unwrap(), e2); + } + } else { + nignored += 1; + } + } + println!("{}({}): done, ignored={} passed={} failed={}", + func, k, nignored, npassed, n - nignored - npassed); + assert!(nignored + npassed == n, + "{}({}): {} out of {} values returns an incorrect value!", + func, k, n - nignored - npassed, n); + (npassed, nignored) +} + +pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); + iterate("f32_random_equivalence_test", k, n, f, g, |_| { + let i: u32 = f32_range.ind_sample(&mut rng); + let x: f32 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); + iterate("f64_random_equivalence_test", k, n, f, g, |_| { + let i: u64 = f64_range.ind_sample(&mut rng); + let x: f64 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, + // so why not simply testing all of them? + // + // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. + + // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges + let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", + k, 0x7f7f_ffff, f, g, |i: usize| { + let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + decode_finite(x) + }); + assert_eq!((npassed, nignored), (2121451881, 17643158)); +} + +#[test] +fn shortest_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f32_exhaustive_equivalence_test() { + // it is hard to directly test the optimality of the output, but we can at least test if + // two different algorithms agree to each other. + // + // this reports the progress and the number of f32 values returned `None`. + // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: + // `done, ignored=17643158 passed=2121451881 failed=0`. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f64_hard_random_equivalence_test() { + // this again probably has to use appropriate rustc flags. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, + MAX_SIG_DIGITS, 100_000_000); +} + +#[test] +fn exact_f32_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + +#[test] +fn exact_f64_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} diff --git a/src/test/run-pass-fulldeps/sort-unstable.rs b/src/test/run-pass-fulldeps/sort-unstable.rs new file mode 100644 index 0000000000000..af8a691aa3ec6 --- /dev/null +++ b/src/test/run-pass-fulldeps/sort-unstable.rs @@ -0,0 +1,83 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_private, sort_internals)] + +extern crate core; +extern crate rand; + +use std::cmp::Ordering::{Equal, Greater, Less}; +use core::slice::heapsort; + +use rand::{Rng, XorShiftRng}; + +fn main() { + let mut v = [0; 600]; + let mut tmp = [0; 600]; + let mut rng = XorShiftRng::new_unseeded(); + + for len in (2..25).chain(500..510) { + let v = &mut v[0..len]; + let tmp = &mut tmp[0..len]; + + for &modulus in &[5, 10, 100, 1000] { + for _ in 0..100 { + for i in 0..len { + v[i] = rng.gen::() % modulus; + } + + // Sort in default order. + tmp.copy_from_slice(v); + tmp.sort_unstable(); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in ascending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| a.cmp(b)); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in descending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| b.cmp(a)); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + + // Test heapsort using `<` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a < b); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Test heapsort using `>` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a > b); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + } + } + } + + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort_unstable(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + + // Should not panic. + [0i32; 0].sort_unstable(); + [(); 10].sort_unstable(); + [(); 100].sort_unstable(); + + let mut v = [0xDEADBEEFu64]; + v.sort_unstable(); + assert!(v == [0xDEADBEEF]); +} diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index b46f024b5bff3..22081678fb999 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,7 +15,6 @@ extern crate helper; -use std::env; use std::heap::{Heap, Alloc, System, Layout, AllocErr}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; @@ -39,8 +38,7 @@ unsafe impl<'a> Alloc for &'a A { static GLOBAL: A = A; fn main() { - env::set_var("FOO", "bar"); - drop(env::var("FOO")); + println!("hello!"); let n = HITS.load(Ordering::SeqCst); assert!(n > 0); diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs index 4b987b9223d6d..04d2ef466e73d 100644 --- a/src/test/run-pass/allocator/xcrate-use.rs +++ b/src/test/run-pass/allocator/xcrate-use.rs @@ -17,7 +17,6 @@ extern crate custom; extern crate helper; -use std::env; use std::heap::{Heap, Alloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index 7e6cd9fdf4950..155fb5d6c5de9 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -19,7 +19,6 @@ extern crate custom; extern crate custom_as_global; extern crate helper; -use std::env; use std::heap::{Heap, Alloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs index b40774e2be82f..8c480d7deebd9 100644 --- a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs +++ b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs @@ -10,6 +10,7 @@ // aux-build:anon-extern-mod-cross-crate-1.rs // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test ffi with extern crate anonexternmod; diff --git a/src/test/run-pass/anon-extern-mod.rs b/src/test/run-pass/anon-extern-mod.rs index 208b4df3c3e7e..16ca7bce95b59 100644 --- a/src/test/run-pass/anon-extern-mod.rs +++ b/src/test/run-pass/anon-extern-mod.rs @@ -9,6 +9,7 @@ // except according to those terms. // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/auxiliary/issue-3012-1.rs b/src/test/run-pass/auxiliary/issue-3012-1.rs index b6199f59ebe06..f34a97519e77d 100644 --- a/src/test/run-pass/auxiliary/issue-3012-1.rs +++ b/src/test/run-pass/auxiliary/issue-3012-1.rs @@ -10,13 +10,10 @@ #![crate_name="socketlib"] #![crate_type = "lib"] -#![feature(libc)] pub mod socket { - extern crate libc; - pub struct socket_handle { - sockfd: libc::c_int, + sockfd: u32, } impl Drop for socket_handle { @@ -25,7 +22,7 @@ pub mod socket { } } - pub fn socket_handle(x: libc::c_int) -> socket_handle { + pub fn socket_handle(x: u32) -> socket_handle { socket_handle { sockfd: x } diff --git a/src/test/run-pass/builtin-clone-unwind.rs b/src/test/run-pass/builtin-clone-unwind.rs index 90a411352869c..7e7c5ee412556 100644 --- a/src/test/run-pass/builtin-clone-unwind.rs +++ b/src/test/run-pass/builtin-clone-unwind.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + // Test that builtin implementations of `Clone` cleanup everything // in case of unwinding. diff --git a/src/test/run-pass/c-stack-as-value.rs b/src/test/run-pass/c-stack-as-value.rs index 5319693405b5d..df4989d89ab5e 100644 --- a/src/test/run-pass/c-stack-as-value.rs +++ b/src/test/run-pass/c-stack-as-value.rs @@ -9,6 +9,7 @@ // except according to those terms. // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index 84f22025a1d7a..46b3fd1f1e746 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +// ignore-wasm32-bare no libc to test with #![feature(libc, std_misc)] diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs index bf94dd178821a..5b1677c184c74 100644 --- a/src/test/run-pass/cabi-int-widening.rs +++ b/src/test/run-pass/cabi-int-widening.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_int8_to_int32(_: i8) -> i32; diff --git a/src/test/run-pass/catch-unwind-bang.rs b/src/test/run-pass/catch-unwind-bang.rs index df54ec90022ee..849132b8ebfab 100644 --- a/src/test/run-pass/catch-unwind-bang.rs +++ b/src/test/run-pass/catch-unwind-bang.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + fn worker() -> ! { panic!() } diff --git a/src/test/run-pass/cfg-family.rs b/src/test/run-pass/cfg-family.rs index 415607aa72bfc..1797ad1019c3d 100644 --- a/src/test/run-pass/cfg-family.rs +++ b/src/test/run-pass/cfg-family.rs @@ -9,6 +9,7 @@ // except according to those terms. // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no target_family #[cfg(windows)] pub fn main() { diff --git a/src/test/run-pass/cfg-target-family.rs b/src/test/run-pass/cfg-target-family.rs index b6954f7c2eeaf..0b8574e117478 100644 --- a/src/test/run-pass/cfg-target-family.rs +++ b/src/test/run-pass/cfg-target-family.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no target_family + // pretty-expanded FIXME #23616 #[cfg(target_family = "windows")] diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index 8e718f328ff91..9c87f2ca68203 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -11,6 +11,7 @@ // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs +// ignore-wasm32-bare no libc to test ffi with // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs index 411df2b3e0759..e77fd5f71394e 100644 --- a/src/test/run-pass/const-cast.rs +++ b/src/test/run-pass/const-cast.rs @@ -8,21 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(libc)] - -extern crate libc; - struct TestStruct { - x: *const libc::c_void + x: *const u8, } unsafe impl Sync for TestStruct {} extern fn foo() {} const x: extern "C" fn() = foo; -static y: TestStruct = TestStruct { x: x as *const libc::c_void }; +static y: TestStruct = TestStruct { x: x as *const u8 }; pub fn main() { - assert_eq!(x as *const libc::c_void, y.x); + assert_eq!(x as *const u8, y.x); } diff --git a/src/test/run-pass/duplicated-external-mods.rs b/src/test/run-pass/duplicated-external-mods.rs index 91c9887300935..4cb3dbe027a16 100644 --- a/src/test/run-pass/duplicated-external-mods.rs +++ b/src/test/run-pass/duplicated-external-mods.rs @@ -11,6 +11,7 @@ // aux-build:anon-extern-mod-cross-crate-1.rs // aux-build:anon-extern-mod-cross-crate-1.rs // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test ffi with extern crate anonexternmod; diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 483dbb356ce6a..3310d3a89b92b 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + #![feature(generators, generator_trait, untagged_unions)] use std::cell::{Cell, RefCell}; diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs index 933d9a728dbe7..af44a6567e405 100644 --- a/src/test/run-pass/env-vars.rs +++ b/src/test/run-pass/env-vars.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no env vars use std::env::*; diff --git a/src/test/run-pass/extern-call-deep.rs b/src/test/run-pass/extern-call-deep.rs index 6a9da767ad6eb..a41ab8da9de11 100644 --- a/src/test/run-pass/extern-call-deep.rs +++ b/src/test/run-pass/extern-call-deep.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #![feature(libc)] extern crate libc; diff --git a/src/test/run-pass/extern-call-indirect.rs b/src/test/run-pass/extern-call-indirect.rs index 256eedccb8bfa..ba108955c28d6 100644 --- a/src/test/run-pass/extern-call-indirect.rs +++ b/src/test/run-pass/extern-call-indirect.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #![feature(libc)] extern crate libc; diff --git a/src/test/run-pass/extern-crosscrate.rs b/src/test/run-pass/extern-crosscrate.rs index 7157d0658be34..825b502d95485 100644 --- a/src/test/run-pass/extern-crosscrate.rs +++ b/src/test/run-pass/extern-crosscrate.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//aux-build:extern-crosscrate-source.rs +// aux-build:extern-crosscrate-source.rs +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index afdd53db775a8..a1aa9b69fadaa 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a foreign function that accepts and returns a struct // by value. diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 035084ae9bd3a..6442f230d3024 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a foreign function that accepts and returns a struct // by value. diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index cb1a4d278256a..bfb649c3f74ea 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a foreign function that accepts and returns a struct // by value. diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index 657348c99aad8..1f90d9c436677 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a foreign function that accepts and returns a struct // by value. diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index 9042aed6639b8..920e15bf2c119 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a function that takes/returns a u8. diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index 38d29180fbc8f..9c184477ad340 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing #[link(name = "rust_test_helpers", kind = "static")] extern { diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index ed254ac46f20b..691bd6295b143 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a function that takes/returns a u32. diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 6fc630e6d7e1a..4b351ed2836cc 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc for ffi testing + // Test a call to a function that takes/returns a u64. diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs index ec1c6130e7adc..b9ce3f4588688 100644 --- a/src/test/run-pass/extern-return-TwoU16s.rs +++ b/src/test/run-pass/extern-return-TwoU16s.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with pub struct TwoU16s { one: u16, two: u16 diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs index e829e993052a5..686ff16fe4d6b 100644 --- a/src/test/run-pass/extern-return-TwoU32s.rs +++ b/src/test/run-pass/extern-return-TwoU32s.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with pub struct TwoU32s { one: u32, two: u32 diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs index ef7325b33fe3d..e754674fd1ebd 100644 --- a/src/test/run-pass/extern-return-TwoU64s.rs +++ b/src/test/run-pass/extern-return-TwoU64s.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with pub struct TwoU64s { one: u64, two: u64 diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs index 46f2e81a5564a..68fe3832e90ab 100644 --- a/src/test/run-pass/extern-return-TwoU8s.rs +++ b/src/test/run-pass/extern-return-TwoU8s.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with pub struct TwoU8s { one: u8, two: u8 diff --git a/src/test/run-pass/extern_fat_drop.rs b/src/test/run-pass/extern_fat_drop.rs index 8ce1f744dee17..123458ff97e13 100644 --- a/src/test/run-pass/extern_fat_drop.rs +++ b/src/test/run-pass/extern_fat_drop.rs @@ -14,7 +14,8 @@ extern crate fat_drop; fn main() { unsafe { - let s: &mut fat_drop::S = std::mem::uninitialized(); + let data: &mut [u8] = &mut [0]; + let s: &mut fat_drop::S = std::mem::transmute::<&mut [u8], _>(data); std::ptr::drop_in_place(s); assert!(fat_drop::DROPPED); } diff --git a/src/test/run-pass/fmt-pointer-trait.rs b/src/test/run-pass/fmt-pointer-trait.rs index 96f31891f2f34..4ecb9da4eb9c6 100644 --- a/src/test/run-pass/fmt-pointer-trait.rs +++ b/src/test/run-pass/fmt-pointer-trait.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(libc)] -extern crate libc; use std::ptr; use std::rc::Rc; use std::sync::Arc; fn main() { - let p: *const libc::c_void = ptr::null(); + let p: *const u8 = ptr::null(); let rc = Rc::new(1usize); let arc = Arc::new(1usize); let b = Box::new("hi"); diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs index fb162d8793356..b79e6e98fc056 100644 --- a/src/test/run-pass/foreign-dupe.rs +++ b/src/test/run-pass/foreign-dupe.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:foreign_lib.rs +// ignore-wasm32-bare no libc to test ffi with // Check that we can still call duplicated extern (imported) functions // which were declared in another crate. See issues #32740 and #32783. diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index a9001a3cdcf6e..ab8e4fbedcff7 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +// ignore-wasm32-bare no libc to test ffi with #![feature(std_misc, libc)] diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs index 2d4542540e7a3..65efa571a9b4b 100644 --- a/src/test/run-pass/foreign-fn-with-byval.rs +++ b/src/test/run-pass/foreign-fn-with-byval.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with #[derive(Copy, Clone)] pub struct S { diff --git a/src/test/run-pass/foreign-mod-unused-const.rs b/src/test/run-pass/foreign-mod-unused-const.rs index 70d4801ae3b3c..5e9e529669a01 100644 --- a/src/test/run-pass/foreign-mod-unused-const.rs +++ b/src/test/run-pass/foreign-mod-unused-const.rs @@ -8,18 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // pretty-expanded FIXME #23616 -#![feature(libc)] - -extern crate libc; - mod foo { - use libc::c_int; - extern { - pub static errno: c_int; + pub static errno: u32; } } diff --git a/src/test/run-pass/foreign-no-abi.rs b/src/test/run-pass/foreign-no-abi.rs index 979e57eba9d1a..b516cdf4416b8 100644 --- a/src/test/run-pass/foreign-no-abi.rs +++ b/src/test/run-pass/foreign-no-abi.rs @@ -10,6 +10,7 @@ // ABI is cdecl by default +// ignore-wasm32-bare no libc to test ffi with // pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/foreign2.rs b/src/test/run-pass/foreign2.rs index d83bd940d1978..d69d6976e4a90 100644 --- a/src/test/run-pass/foreign2.rs +++ b/src/test/run-pass/foreign2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +// ignore-wasm32-bare no libc to test ffi with // pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 53cd3235d9d0c..36e401a54bcdd 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled as panic=abort by default + #![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs index a583f42b93d8c..0d5bae7876bd3 100644 --- a/src/test/run-pass/generator/panic-safe.rs +++ b/src/test/run-pass/generator/panic-safe.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + #![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index b2e2a3e7e9d5b..56511dcd53a6a 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index cfae9903a95e5..99edd2550c01b 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare seems not important to test here #![feature(intrinsics, main)] diff --git a/src/test/run-pass/invoke-external-foreign.rs b/src/test/run-pass/invoke-external-foreign.rs index 1aae8131d8008..d01c3b67895e6 100644 --- a/src/test/run-pass/invoke-external-foreign.rs +++ b/src/test/run-pass/invoke-external-foreign.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:foreign_lib.rs +// ignore-wasm32-bare no libc to test ffi with // The purpose of this test is to check that we can // successfully (and safely) invoke external, cdecl diff --git a/src/test/run-pass/issue-1251.rs b/src/test/run-pass/issue-1251.rs index ddd30ed3bb0c0..00e8aa69a8942 100644 --- a/src/test/run-pass/issue-1251.rs +++ b/src/test/run-pass/issue-1251.rs @@ -9,6 +9,7 @@ // except according to those terms. // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs index 1e9f30bb766b2..4620d982c1ea5 100644 --- a/src/test/run-pass/issue-12699.rs +++ b/src/test/run-pass/issue-12699.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare can't block the thread + use std::thread; fn main() { diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 084b7a166cdd3..75a724e55fb11 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -10,9 +10,6 @@ // aux-build:issue13507.rs - -#![feature(core)] - extern crate issue13507; use issue13507::testtypes; diff --git a/src/test/run-pass/issue-14875.rs b/src/test/run-pass/issue-14875.rs index ad19a9be76f88..e705539bb4772 100644 --- a/src/test/run-pass/issue-14875.rs +++ b/src/test/run-pass/issue-14875.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare always compiled as panic=abort right now + // Check that values are not leaked when a dtor panics (#14875) use std::panic::{self, UnwindSafe}; @@ -29,7 +31,6 @@ impl Drop for PanicOnDrop { } } - fn main() { let mut set_on_drop = false; { diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs index 316e379e664ae..7b7ecc91484ba 100644 --- a/src/test/run-pass/issue-2214.rs +++ b/src/test/run-pass/issue-2214.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/issue-25185.rs b/src/test/run-pass/issue-25185.rs index d8d2d5078c5e7..9a2dbd1c96e31 100644 --- a/src/test/run-pass/issue-25185.rs +++ b/src/test/run-pass/issue-25185.rs @@ -10,6 +10,7 @@ // aux-build:issue-25185-1.rs // aux-build:issue-25185-2.rs +// ignore-wasm32-bare no libc for ffi testing extern crate issue_25185_2; diff --git a/src/test/run-pass/issue-28676.rs b/src/test/run-pass/issue-28676.rs index 8f83e51f0a02d..a7bee427a813c 100644 --- a/src/test/run-pass/issue-28676.rs +++ b/src/test/run-pass/issue-28676.rs @@ -7,7 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// + +// ignore-wasm32-bare no libc to test ffi with #[derive(Copy, Clone)] pub struct Quad { a: u64, b: u64, c: u64, d: u64 } diff --git a/src/test/run-pass/issue-29948.rs b/src/test/run-pass/issue-29948.rs index 281dde15bd336..3a7e9ba93e190 100644 --- a/src/test/run-pass/issue-29948.rs +++ b/src/test/run-pass/issue-29948.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + use std::panic; impl<'a> panic::UnwindSafe for Foo<'a> {} diff --git a/src/test/run-pass/issue-3012-2.rs b/src/test/run-pass/issue-3012-2.rs index ecce5df0fc200..bcf8a9180918c 100644 --- a/src/test/run-pass/issue-3012-2.rs +++ b/src/test/run-pass/issue-3012-2.rs @@ -12,15 +12,11 @@ // pretty-expanded FIXME #23616 -#![allow(unknown_features)] -#![feature(box_syntax, libc)] - extern crate socketlib; -extern crate libc; use socketlib::socket; pub fn main() { - let fd: libc::c_int = 1 as libc::c_int; - let _sock: Box<_> = box socket::socket_handle(fd); + let fd: u32 = 1 as u32; + let _sock: Box<_> = Box::new(socket::socket_handle(fd)); } diff --git a/src/test/run-pass/issue-3656.rs b/src/test/run-pass/issue-3656.rs index 10930474799c5..c278dcef9dde7 100644 --- a/src/test/run-pass/issue-3656.rs +++ b/src/test/run-pass/issue-3656.rs @@ -13,6 +13,7 @@ // the alignment of elements into account. // pretty-expanded FIXME #23616 +// ignore-wasm32-bare no libc to test with #![feature(libc)] diff --git a/src/test/run-pass/issue-43853.rs b/src/test/run-pass/issue-43853.rs index f55d584ea24fb..e9f8d2744a16a 100644 --- a/src/test/run-pass/issue-43853.rs +++ b/src/test/run-pass/issue-43853.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + use std::panic; fn test() { diff --git a/src/test/run-pass/issue-4735.rs b/src/test/run-pass/issue-4735.rs index 56e69a9f36e78..7eb09e055a292 100644 --- a/src/test/run-pass/issue-4735.rs +++ b/src/test/run-pass/issue-4735.rs @@ -8,28 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // pretty-expanded FIXME #23616 -#![allow(unknown_features)] -#![feature(box_syntax, libc)] - -extern crate libc; - use std::mem::transmute; -use libc::c_void; -struct NonCopyable(*const c_void); +struct NonCopyable(*const u8); impl Drop for NonCopyable { fn drop(&mut self) { let NonCopyable(p) = *self; - let _v = unsafe { transmute::<*const c_void, Box>(p) }; + let _v = unsafe { transmute::<*const u8, Box>(p) }; } } pub fn main() { - let t = box 0; - let p = unsafe { transmute::, *const c_void>(t) }; + let t = Box::new(0); + let p = unsafe { transmute::, *const u8>(t) }; let _z = NonCopyable(p); } diff --git a/src/test/run-pass/issue-5791.rs b/src/test/run-pass/issue-5791.rs index aad90bd4181d9..2e93279f756f0 100644 --- a/src/test/run-pass/issue-5791.rs +++ b/src/test/run-pass/issue-5791.rs @@ -10,15 +10,11 @@ // pretty-expanded FIXME #23616 -#![feature(libc)] - -extern crate libc; - extern { #[link_name = "malloc"] - fn malloc1(len: libc::c_int) -> *const libc::c_void; + fn malloc1(len: i32) -> *const u8; #[link_name = "malloc"] - fn malloc2(len: libc::c_int, foo: libc::c_int) -> *const libc::c_void; + fn malloc2(len: i32, foo: i32) -> *const u8; } pub fn main () {} diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index f1ac96ab63e5c..0fc13319b8734 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -12,8 +12,7 @@ // for completeness since .rs files linked from .rc files support this // notation to specify their module's attributes - -#![feature(custom_attribute, libc)] +#![feature(custom_attribute)] #![allow(unused_attribute)] #![attr1 = "val"] #![attr2 = "val"] @@ -159,13 +158,11 @@ mod test_other_forms { mod test_foreign_items { pub mod rustrt { - extern crate libc; - extern { #![attr] #[attr] - fn rust_get_test_int() -> libc::intptr_t; + fn rust_get_test_int() -> u32; } } } diff --git a/src/test/run-pass/iter-step-overflow-debug.rs b/src/test/run-pass/iter-step-overflow-debug.rs index 5b9b58f028894..c45a10eac52b1 100644 --- a/src/test/run-pass/iter-step-overflow-debug.rs +++ b/src/test/run-pass/iter-step-overflow-debug.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: -C debug_assertions=yes use std::panic; diff --git a/src/test/run-pass/iter-sum-overflow-debug.rs b/src/test/run-pass/iter-sum-overflow-debug.rs index 6c07afb37b8a0..c640f7cd28045 100644 --- a/src/test/run-pass/iter-sum-overflow-debug.rs +++ b/src/test/run-pass/iter-sum-overflow-debug.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: -C debug_assertions=yes use std::panic; diff --git a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs index a3a7179fb7112..517cd139cf354 100644 --- a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs +++ b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: -C overflow-checks use std::panic; diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs index 6e5dccae0a07d..fcaeda9a5495b 100644 --- a/src/test/run-pass/lib-defaults.rs +++ b/src/test/run-pass/lib-defaults.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + // compile-flags: -lrust_test_helpers #[link(name = "rust_test_helpers", kind = "static")] diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index 7300a322ec4b7..9641ed282936f 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + #![feature(fn_traits)] #![feature(never_type)] diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs index e7da43597f169..41cb458c0b8b4 100644 --- a/src/test/run-pass/mir_drop_order.rs +++ b/src/test/run-pass/mir_drop_order.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + use std::cell::RefCell; use std::panic; diff --git a/src/test/run-pass/mir_misc_casts.rs b/src/test/run-pass/mir_misc_casts.rs index ae719ac2800ee..81c8b75fb9b6a 100644 --- a/src/test/run-pass/mir_misc_casts.rs +++ b/src/test/run-pass/mir_misc_casts.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(libc)] - -extern crate libc; - fn func(){} const STR: &'static str = "hello"; @@ -19,7 +15,7 @@ const BSTR: &'static [u8; 5] = b"hello"; fn from_ptr() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, *const ()) { - let f = 1_usize as *const libc::FILE; + let f = 1_usize as *const String; let c1 = f as isize; let c2 = f as usize; let c3 = f as i8; @@ -35,7 +31,7 @@ fn from_ptr() } fn from_1() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1 as isize; let c2 = 1 as usize; let c3 = 1 as i8; @@ -48,12 +44,12 @@ fn from_1() let c10 = 1 as u64; let c11 = 1 as f32; let c12 = 1 as f64; - let c13 = 1 as *const libc::FILE; + let c13 = 1 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1usize() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_usize as isize; let c2 = 1_usize as usize; let c3 = 1_usize as i8; @@ -66,12 +62,12 @@ fn from_1usize() let c10 = 1_usize as u64; let c11 = 1_usize as f32; let c12 = 1_usize as f64; - let c13 = 1_usize as *const libc::FILE; + let c13 = 1_usize as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1isize() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_isize as isize; let c2 = 1_isize as usize; let c3 = 1_isize as i8; @@ -84,12 +80,12 @@ fn from_1isize() let c10 = 1_isize as u64; let c11 = 1_isize as f32; let c12 = 1_isize as f64; - let c13 = 1_isize as *const libc::FILE; + let c13 = 1_isize as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1u8() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_u8 as isize; let c2 = 1_u8 as usize; let c3 = 1_u8 as i8; @@ -102,12 +98,12 @@ fn from_1u8() let c10 = 1_u8 as u64; let c11 = 1_u8 as f32; let c12 = 1_u8 as f64; - let c13 = 1_u8 as *const libc::FILE; + let c13 = 1_u8 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1i8() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_i8 as isize; let c2 = 1_i8 as usize; let c3 = 1_i8 as i8; @@ -120,12 +116,12 @@ fn from_1i8() let c10 = 1_i8 as u64; let c11 = 1_i8 as f32; let c12 = 1_i8 as f64; - let c13 = 1_i8 as *const libc::FILE; + let c13 = 1_i8 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1u16() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_u16 as isize; let c2 = 1_u16 as usize; let c3 = 1_u16 as i8; @@ -138,12 +134,12 @@ fn from_1u16() let c10 = 1_u16 as u64; let c11 = 1_u16 as f32; let c12 = 1_u16 as f64; - let c13 = 1_u16 as *const libc::FILE; + let c13 = 1_u16 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1i16() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_i16 as isize; let c2 = 1_i16 as usize; let c3 = 1_i16 as i8; @@ -156,12 +152,12 @@ fn from_1i16() let c10 = 1_i16 as u64; let c11 = 1_i16 as f32; let c12 = 1_i16 as f64; - let c13 = 1_i16 as *const libc::FILE; + let c13 = 1_i16 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1u32() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_u32 as isize; let c2 = 1_u32 as usize; let c3 = 1_u32 as i8; @@ -174,12 +170,12 @@ fn from_1u32() let c10 = 1_u32 as u64; let c11 = 1_u32 as f32; let c12 = 1_u32 as f64; - let c13 = 1_u32 as *const libc::FILE; + let c13 = 1_u32 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1i32() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_i32 as isize; let c2 = 1_i32 as usize; let c3 = 1_i32 as i8; @@ -192,12 +188,12 @@ fn from_1i32() let c10 = 1_i32 as u64; let c11 = 1_i32 as f32; let c12 = 1_i32 as f64; - let c13 = 1_i32 as *const libc::FILE; + let c13 = 1_i32 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1u64() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_u64 as isize; let c2 = 1_u64 as usize; let c3 = 1_u64 as i8; @@ -210,12 +206,12 @@ fn from_1u64() let c10 = 1_u64 as u64; let c11 = 1_u64 as f32; let c12 = 1_u64 as f64; - let c13 = 1_u64 as *const libc::FILE; + let c13 = 1_u64 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } fn from_1i64() --> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { +-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) { let c1 = 1_i64 as isize; let c2 = 1_i64 as usize; let c3 = 1_i64 as i8; @@ -228,7 +224,7 @@ fn from_1i64() let c10 = 1_i64 as u64; let c11 = 1_i64 as f32; let c12 = 1_i64 as f64; - let c13 = 1_i64 as *const libc::FILE; + let c13 = 1_i64 as *const String; (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } @@ -297,9 +293,9 @@ fn other_casts() } pub fn assert_eq_13(l: (isize, usize, i8, i16, i32, i64, u8, - u16, u32, u64, f32, f64, *const libc::FILE), + u16, u32, u64, f32, f64, *const String), r: (isize, usize, i8, i16, i32, i64, u8, - u16, u32, u64, f32, f64, *const libc::FILE)) -> bool { + u16, u32, u64, f32, f64, *const String)) -> bool { let (l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13) = l; let (r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13) = r; l1 == r1 && l2 == r2 && l3 == r3 && l4 == r4 && l5 == r5 && l6 == r6 && l7 == r7 && @@ -308,7 +304,7 @@ pub fn assert_eq_13(l: (isize, usize, i8, i16, i32, i64, u8, pub fn main() { - let f = 1_usize as *const libc::FILE; + let f = 1_usize as *const String; let t13 = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.0, 1.0, f); let t12 = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.0, 1.0); assert_eq_13(from_1(), t13); diff --git a/src/test/run-pass/mir_trans_calls_variadic.rs b/src/test/run-pass/mir_trans_calls_variadic.rs index e4d528e80e104..7845c9426e23b 100644 --- a/src/test/run-pass/mir_trans_calls_variadic.rs +++ b/src/test/run-pass/mir_trans_calls_variadic.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: i64, ...) -> f64; diff --git a/src/test/run-pass/newtype-struct-with-dtor.rs b/src/test/run-pass/newtype-struct-with-dtor.rs index d1ad5614e3f35..07c76e27284f5 100644 --- a/src/test/run-pass/newtype-struct-with-dtor.rs +++ b/src/test/run-pass/newtype-struct-with-dtor.rs @@ -8,21 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // pretty-expanded FIXME #23616 -#![feature(libc)] - -extern crate libc; -use libc::c_int; +pub struct Fd(u32); -pub struct Fd(c_int); +fn foo(a: u32) {} impl Drop for Fd { fn drop(&mut self) { unsafe { let Fd(s) = *self; - libc::close(s); + foo(s); } } } diff --git a/src/test/run-pass/paths-containing-nul.rs b/src/test/run-pass/paths-containing-nul.rs index 2da3e59e54c58..9f39146e238d6 100644 --- a/src/test/run-pass/paths-containing-nul.rs +++ b/src/test/run-pass/paths-containing-nul.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no files or I/O + use std::fs; use std::io; diff --git a/src/test/run-pass/pub-extern-privacy.rs b/src/test/run-pass/pub-extern-privacy.rs index b9a3f788f9794..1ef804fe8feea 100644 --- a/src/test/run-pass/pub-extern-privacy.rs +++ b/src/test/run-pass/pub-extern-privacy.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + // pretty-expanded FIXME #23616 use std::mem::transmute; diff --git a/src/test/run-pass/reachable-unnameable-items.rs b/src/test/run-pass/reachable-unnameable-items.rs index 75a2e36ffb7a4..d087be6d10cfc 100644 --- a/src/test/run-pass/reachable-unnameable-items.rs +++ b/src/test/run-pass/reachable-unnameable-items.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // aux-build:reachable-unnameable-items.rs extern crate reachable_unnameable_items; diff --git a/src/test/run-pass/rec-align-u64.rs b/src/test/run-pass/rec-align-u64.rs index 4863979b3f6c2..d051e05b5f9e7 100644 --- a/src/test/run-pass/rec-align-u64.rs +++ b/src/test/run-pass/rec-align-u64.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare seems unimportant to test + // Issue #2303 #![feature(intrinsics)] diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index b67612c94b009..8f278a315d1af 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -10,10 +10,9 @@ // pretty-expanded FIXME #23616 -#![feature(libc)] +#![feature(allocator_api)] -extern crate libc; -use std::mem; +use std::heap::{Alloc, Heap, Layout}; struct arena(()); @@ -32,8 +31,9 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { - mem::transmute(libc::malloc(mem::size_of::>() - as libc::size_t)) + let ptr = Heap.alloc(Layout::new::()) + .unwrap_or_else(|e| Heap.oom(e)); + &*(ptr as *const _) } } @@ -45,7 +45,7 @@ fn g(fcx : &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { - libc::free(mem::transmute(bcx2)); + Heap.dealloc(bcx2 as *const _ as *mut _, Layout::new::()); } } diff --git a/src/test/run-pass/rfc-1014.rs b/src/test/run-pass/rfc-1014.rs index df969070a2ad4..950c2e0c4dfab 100644 --- a/src/test/run-pass/rfc-1014.rs +++ b/src/test/run-pass/rfc-1014.rs @@ -7,6 +7,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// ignore-wasm32-bare no libc + #![feature(libc)] extern crate libc; diff --git a/src/test/run-pass/rfc1717/library-override.rs b/src/test/run-pass/rfc1717/library-override.rs index 26713a2554377..c51b33f9c4af6 100644 --- a/src/test/run-pass/rfc1717/library-override.rs +++ b/src/test/run-pass/rfc1717/library-override.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with // compile-flags: -lstatic=wronglibrary:rust_test_helpers #[link(name = "wronglibrary", kind = "dylib")] diff --git a/src/test/run-pass/rfc1857-drop-order.rs b/src/test/run-pass/rfc1857-drop-order.rs index 42f989538c890..b2e5ff62eb86e 100644 --- a/src/test/run-pass/rfc1857-drop-order.rs +++ b/src/test/run-pass/rfc1857-drop-order.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default + #![allow(dead_code, unreachable_code)] use std::cell::RefCell; diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs index 26fa36f0c13d4..73ccd28a3e963 100644 --- a/src/test/run-pass/signal-alternate-stack-cleanup.rs +++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs @@ -13,6 +13,7 @@ // triggers this situation by sending signal from atexit handler. // // ignore-windows +// ignore-wasm32-bare no libc #![feature(libc)] extern crate libc; diff --git a/src/test/run-pass/static-method-xcrate.rs b/src/test/run-pass/static-method-xcrate.rs index 57609cec9f2b0..ab6adcbbffe7a 100644 --- a/src/test/run-pass/static-method-xcrate.rs +++ b/src/test/run-pass/static-method-xcrate.rs @@ -10,7 +10,6 @@ // aux-build:static-methods-crate.rs - extern crate static_methods_crate; use static_methods_crate::read; diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs index 24d58487f061e..2b7fa0166a8ed 100644 --- a/src/test/run-pass/static-mut-foreign.rs +++ b/src/test/run-pass/static-mut-foreign.rs @@ -12,6 +12,7 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. +// ignore-wasm32-bare no libc to test ffi with #![feature(libc)] diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs index ed618cea98ac0..61a2bcb3a9b75 100644 --- a/src/test/run-pass/struct-return.rs +++ b/src/test/run-pass/struct-return.rs @@ -7,7 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// + +// ignore-wasm32-bare no libc to test ffi with #[repr(C)] #[derive(Copy, Clone)] diff --git a/src/test/run-pass/supported-cast.rs b/src/test/run-pass/supported-cast.rs index a47ae52f5902c..7f92707586b28 100644 --- a/src/test/run-pass/supported-cast.rs +++ b/src/test/run-pass/supported-cast.rs @@ -8,12 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(libc)] - -extern crate libc; - pub fn main() { - let f = 1_usize as *const libc::FILE; + let f = 1_usize as *const String; println!("{:?}", f as isize); println!("{:?}", f as usize); println!("{:?}", f as i8); @@ -27,7 +23,7 @@ pub fn main() { println!("{:?}", 1 as isize); println!("{:?}", 1 as usize); - println!("{:?}", 1 as *const libc::FILE); + println!("{:?}", 1 as *const String); println!("{:?}", 1 as i8); println!("{:?}", 1 as i16); println!("{:?}", 1 as i32); @@ -41,7 +37,7 @@ pub fn main() { println!("{:?}", 1_usize as isize); println!("{:?}", 1_usize as usize); - println!("{:?}", 1_usize as *const libc::FILE); + println!("{:?}", 1_usize as *const String); println!("{:?}", 1_usize as i8); println!("{:?}", 1_usize as i16); println!("{:?}", 1_usize as i32); @@ -55,7 +51,7 @@ pub fn main() { println!("{:?}", 1i8 as isize); println!("{:?}", 1i8 as usize); - println!("{:?}", 1i8 as *const libc::FILE); + println!("{:?}", 1i8 as *const String); println!("{:?}", 1i8 as i8); println!("{:?}", 1i8 as i16); println!("{:?}", 1i8 as i32); @@ -69,7 +65,7 @@ pub fn main() { println!("{:?}", 1u8 as isize); println!("{:?}", 1u8 as usize); - println!("{:?}", 1u8 as *const libc::FILE); + println!("{:?}", 1u8 as *const String); println!("{:?}", 1u8 as i8); println!("{:?}", 1u8 as i16); println!("{:?}", 1u8 as i32); @@ -83,7 +79,7 @@ pub fn main() { println!("{:?}", 1i16 as isize); println!("{:?}", 1i16 as usize); - println!("{:?}", 1i16 as *const libc::FILE); + println!("{:?}", 1i16 as *const String); println!("{:?}", 1i16 as i8); println!("{:?}", 1i16 as i16); println!("{:?}", 1i16 as i32); @@ -97,7 +93,7 @@ pub fn main() { println!("{:?}", 1u16 as isize); println!("{:?}", 1u16 as usize); - println!("{:?}", 1u16 as *const libc::FILE); + println!("{:?}", 1u16 as *const String); println!("{:?}", 1u16 as i8); println!("{:?}", 1u16 as i16); println!("{:?}", 1u16 as i32); @@ -111,7 +107,7 @@ pub fn main() { println!("{:?}", 1i32 as isize); println!("{:?}", 1i32 as usize); - println!("{:?}", 1i32 as *const libc::FILE); + println!("{:?}", 1i32 as *const String); println!("{:?}", 1i32 as i8); println!("{:?}", 1i32 as i16); println!("{:?}", 1i32 as i32); @@ -125,7 +121,7 @@ pub fn main() { println!("{:?}", 1u32 as isize); println!("{:?}", 1u32 as usize); - println!("{:?}", 1u32 as *const libc::FILE); + println!("{:?}", 1u32 as *const String); println!("{:?}", 1u32 as i8); println!("{:?}", 1u32 as i16); println!("{:?}", 1u32 as i32); @@ -139,7 +135,7 @@ pub fn main() { println!("{:?}", 1i64 as isize); println!("{:?}", 1i64 as usize); - println!("{:?}", 1i64 as *const libc::FILE); + println!("{:?}", 1i64 as *const String); println!("{:?}", 1i64 as i8); println!("{:?}", 1i64 as i16); println!("{:?}", 1i64 as i32); @@ -153,7 +149,7 @@ pub fn main() { println!("{:?}", 1u64 as isize); println!("{:?}", 1u64 as usize); - println!("{:?}", 1u64 as *const libc::FILE); + println!("{:?}", 1u64 as *const String); println!("{:?}", 1u64 as i8); println!("{:?}", 1u64 as i16); println!("{:?}", 1u64 as i32); @@ -167,7 +163,7 @@ pub fn main() { println!("{:?}", 1u64 as isize); println!("{:?}", 1u64 as usize); - println!("{:?}", 1u64 as *const libc::FILE); + println!("{:?}", 1u64 as *const String); println!("{:?}", 1u64 as i8); println!("{:?}", 1u64 as i16); println!("{:?}", 1u64 as i32); diff --git a/src/test/run-pass/sync-send-in-std.rs b/src/test/run-pass/sync-send-in-std.rs index 85ab59a298323..4dadfdf9c756e 100644 --- a/src/test/run-pass/sync-send-in-std.rs +++ b/src/test/run-pass/sync-send-in-std.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare networking not available + #![feature(lookup_host)] use std::net::lookup_host; diff --git a/src/test/run-pass/test-allow-fail-attr.rs b/src/test/run-pass/test-allow-fail-attr.rs index aa9cf76617f69..884633df66b1b 100644 --- a/src/test/run-pass/test-allow-fail-attr.rs +++ b/src/test/run-pass/test-allow-fail-attr.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: --test #![feature(allow_fail)] diff --git a/src/test/run-pass/test-should-fail-good-message.rs b/src/test/run-pass/test-should-fail-good-message.rs index e665fa4fc7b58..360d4952d16aa 100644 --- a/src/test/run-pass/test-should-fail-good-message.rs +++ b/src/test/run-pass/test-should-fail-good-message.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: --test #[test] #[should_panic(expected = "foo")] diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs index b3df7d658b15f..dd16bf2e4a38e 100644 --- a/src/test/run-pass/union/union-c-interop.rs +++ b/src/test/run-pass/union/union-c-interop.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #[derive(Clone, Copy)] #[repr(C)] struct LARGE_INTEGER_U { diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index ec6261febc54d..2198ead106bb7 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + #[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: u64, ...) -> f64; diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs index 106bf8ce7dfa4..e2e64ddfa3158 100644 --- a/src/test/run-pass/x86stdcall.rs +++ b/src/test/run-pass/x86stdcall.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32-bare no libc to test ffi with + // GetLastError doesn't seem to work with stack switching #[cfg(windows)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e03d9f89e5d8c..39f41f57d11df 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -531,7 +531,7 @@ impl Config { let name = line[prefix.len()+1 ..].split(&[':', ' '][..]).next().unwrap(); name == "test" || - name == util::get_os(&self.target) || // target + util::matches_os(&self.target, name) || // target name == util::get_arch(&self.target) || // architecture name == util::get_pointer_width(&self.target) || // pointer width name == self.stage_id.split('-').next().unwrap() || // stage diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 2ff3eb7678f1a..3e3c56a07962a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1271,6 +1271,7 @@ actual:\n\ let crate_type = if aux_props.no_prefer_dynamic { None } else if (self.config.target.contains("musl") && !aux_props.force_host) || + self.config.target.contains("wasm32") || self.config.target.contains("emscripten") { // We primarily compile all auxiliary libraries as dynamic libraries // to avoid code size bloat and large binaries as much as possible @@ -1431,7 +1432,10 @@ actual:\n\ } } - if !self.props.no_prefer_dynamic { + + if self.config.target == "wasm32-unknown-unknown" { + // rustc.arg("-g"); // get any backtrace at all on errors + } else if !self.props.no_prefer_dynamic { rustc.args(&["-C", "prefer-dynamic"]); } @@ -1472,6 +1476,10 @@ actual:\n\ let mut fname = f.file_name().unwrap().to_os_string(); fname.push(".js"); f.set_file_name(&fname); + } else if self.config.target.contains("wasm32") { + let mut fname = f.file_name().unwrap().to_os_string(); + fname.push(".wasm"); + f.set_file_name(&fname); } else if !env::consts::EXE_SUFFIX.is_empty() { let mut fname = f.file_name().unwrap().to_os_string(); fname.push(env::consts::EXE_SUFFIX); @@ -1494,6 +1502,22 @@ actual:\n\ } } + // If this is otherwise wasm , then run tests under nodejs with our + // shim + if self.config.target.contains("wasm32") { + if let Some(ref p) = self.config.nodejs { + args.push(p.clone()); + } else { + self.fatal("no NodeJS binary found (--nodejs)"); + } + + let src = self.config.src_base + .parent().unwrap() // chop off `run-pass` + .parent().unwrap() // chop off `test` + .parent().unwrap(); // chop off `src` + args.push(src.join("src/etc/wasm32-shim.js").display().to_string()); + } + let exe_file = self.make_exe_name(); // FIXME (#9639): This needs to handle non-utf8 paths diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index bd4044b4df3b4..c00f28eae67af 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -51,10 +51,15 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("wasm32", "wasm32"), ]; -pub fn get_os(triple: &str) -> &'static str { +pub fn matches_os(triple: &str, name: &str) -> bool { + // For the wasm32 bare target we ignore anything also ignored on emscripten + // and then we also recognize `wasm32-bare` as the os for the target + if triple == "wasm32-unknown-unknown" { + return name == "emscripten" || name == "wasm32-bare" + } for &(triple_os, os) in OS_TABLE { if triple.contains(triple_os) { - return os; + return os == name; } } panic!("Cannot determine OS from triple"); diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c316ec467620a..598620fa29392 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -50,6 +50,8 @@ pub mod unstable_book; fn filter_dirs(path: &Path) -> bool { let skip = [ + "src/binaryen", + "src/dlmalloc", "src/jemalloc", "src/llvm", "src/libbacktrace",