diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index ac9f863264e..7b2f4ea43db 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -155,6 +155,7 @@ impl ToTokens for ast::Struct { impl ::wasm_bindgen::__rt::core::convert::From<#name> for ::wasm_bindgen::JsValue { + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] fn from(value: #name) -> Self { let ptr = ::wasm_bindgen::convert::IntoWasmAbi::into_abi( value, @@ -174,8 +175,14 @@ impl ToTokens for ast::Struct { ) } } + + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + fn from(_value: #name) -> Self { + panic!("cannot convert to JsValue outside of the wasm target") + } } + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] #[no_mangle] pub unsafe extern fn #free_fn(ptr: u32) { <#name as ::wasm_bindgen::convert::FromWasmAbi>::from_abi( @@ -229,6 +236,7 @@ impl ToTokens for ast::StructField { let desc = syn::Ident::from(format!("__wbindgen_describe_{}", getter)); (quote! { #[no_mangle] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] pub unsafe extern fn #getter(js: u32) -> <#ty as ::wasm_bindgen::convert::IntoWasmAbi>::Abi { @@ -260,6 +268,7 @@ impl ToTokens for ast::StructField { (quote! { #[no_mangle] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] pub unsafe extern fn #setter( js: u32, val: <#ty as ::wasm_bindgen::convert::FromWasmAbi>::Abi, @@ -395,6 +404,7 @@ impl ToTokens for ast::Export { let tokens = quote! { #[export_name = #export_name] #[allow(non_snake_case)] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] pub extern fn #generated_name(#(#args),*) #ret_ty { ::wasm_bindgen::__rt::link_this_library(); let #ret = { @@ -424,6 +434,7 @@ impl ToTokens for ast::Export { // this, but the tl;dr; is that this is stripped from the final wasm // binary along with anything it references. #[no_mangle] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] pub extern fn #descriptor_name() { use wasm_bindgen::describe::*; inform(FUNCTION); @@ -640,6 +651,7 @@ impl ToTokens for ast::ImportFunction { .iter() .skip(if is_method { 1 } else { 0 }) .collect::>(); + let arguments = &arguments[..]; let me = if is_method { quote! { &self, } @@ -650,6 +662,7 @@ impl ToTokens for ast::ImportFunction { let invocation = quote! { #(#attrs)* #[allow(bad_style)] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] #vis extern #fn_token #rust_name(#me #(#arguments),*) #ret { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] @@ -668,6 +681,14 @@ impl ToTokens for ast::ImportFunction { } } + #(#attrs)* + #[allow(bad_style, unused_variables)] + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + #vis extern #fn_token #rust_name(#me #(#arguments),*) #ret { + panic!("cannot call wasm-bindgen imported functions on \ + non-wasm targets"); + } + }; if let Some(class) = class_ty { @@ -766,6 +787,7 @@ impl ToTokens for ast::ImportStatic { (quote! { #[allow(bad_style)] #vis static #name: ::wasm_bindgen::JsStatic<#ty> = { + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] fn init() -> #ty { #[wasm_import_module = "__wbindgen_placeholder__"] extern { @@ -779,6 +801,10 @@ impl ToTokens for ast::ImportStatic { } } + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + fn init() -> #ty { + panic!("cannot access imported statics on non-wasm targets") + } static mut _VAL: ::wasm_bindgen::__rt::core::cell::UnsafeCell> = ::wasm_bindgen::__rt::core::cell::UnsafeCell::new(None); ::wasm_bindgen::JsStatic { diff --git a/src/lib.rs b/src/lib.rs index d19187e4e42..f189d6f3688 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -275,10 +275,27 @@ macro_rules! numbers { numbers! { i8 u8 i16 u16 i32 u32 f32 f64 } -#[wasm_import_module = "__wbindgen_placeholder__"] -extern { +macro_rules! externs { + ($(fn $name:ident($($args:tt)*) -> $ret:ty;)*) => ( + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + #[wasm_import_module = "__wbindgen_placeholder__"] + extern { + $(fn $name($($args)*) -> $ret;)* + } + + $( + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + #[allow(unused_variables)] + unsafe extern fn $name($($args)*) -> $ret { + panic!("function not implemented on non-wasm32 targets") + } + )* + ) +} + +externs! { fn __wbindgen_object_clone_ref(idx: u32) -> u32; - fn __wbindgen_object_drop_ref(idx: u32); + fn __wbindgen_object_drop_ref(idx: u32) -> (); fn __wbindgen_string_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_number_new(f: f64) -> u32; fn __wbindgen_number_get(idx: u32, invalid: *mut u8) -> f64; @@ -293,10 +310,10 @@ extern { fn __wbindgen_string_get(idx: u32, len: *mut usize) -> *mut u8; fn __wbindgen_throw(a: *const u8, b: usize) -> !; - fn __wbindgen_cb_drop(idx: u32); - fn __wbindgen_cb_forget(idx: u32); + fn __wbindgen_cb_drop(idx: u32) -> (); + fn __wbindgen_cb_forget(idx: u32) -> (); - fn __wbindgen_describe(v: u32); + fn __wbindgen_describe(v: u32) -> (); fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32; fn __wbindgen_json_serialize(idx: u32, ptr: *mut *mut u8) -> usize; diff --git a/tests/all/main.rs b/tests/all/main.rs index 07ae9535c78..c149ed51e5e 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -17,6 +17,8 @@ struct Project { node: bool, no_std: bool, serde: bool, + rlib: bool, + deps: Vec, } fn project() -> Project { @@ -29,23 +31,9 @@ fn project() -> Project { node: false, no_std: false, serde: false, + rlib: false, + deps: Vec::new(), files: vec![ - ("Cargo.toml".to_string(), format!(r#" - [package] - name = "test{}" - version = "0.0.1" - authors = [] - - [workspace] - - [lib] - crate-type = ["cdylib"] - - # XXX: It is important that `[dependencies]` is the last section - # here, so that `add_local_dependency` functions correctly! - [dependencies] - "#, IDX.with(|x| *x))), - ("Cargo.lock".to_string(), lockfile), ("run.js".to_string(), r#" @@ -158,49 +146,58 @@ impl Project { self } + fn rlib(&mut self, rlib: bool) -> &mut Project { + self.rlib = rlib; + self + } + fn depend(&mut self, dep: &str) -> &mut Project { - { - let cargo_toml = self.files - .iter_mut() - .find(|f| f.0 == "Cargo.toml") - .expect("should have Cargo.toml file!"); - cargo_toml.1.push_str(dep); - cargo_toml.1.push_str("\n"); - } + self.deps.push(dep.to_string()); self } fn add_local_dependency(&mut self, name: &str, path: &str) -> &mut Project { - { - let cargo_toml = self.files - .iter_mut() - .find(|f| f.0 == "Cargo.toml") - .expect("should have Cargo.toml file!"); - cargo_toml.1.push_str(name); - cargo_toml.1.push_str(" = { path = '"); - cargo_toml.1.push_str(path); - cargo_toml.1.push_str("' }\n"); - } + self.deps.push(format!("{} = {{ path = '{}' }}", name, path)); self } - fn test(&mut self) { - { - let cargo_toml = self.files - .iter_mut() - .find(|f| f.0 == "Cargo.toml") - .expect("should have Cargo.toml file!"); - cargo_toml.1.push_str("wasm-bindgen = { path = '"); - cargo_toml.1.push_str(env!("CARGO_MANIFEST_DIR")); - cargo_toml.1.push_str("'"); - if self.no_std { - cargo_toml.1.push_str(", default-features = false"); - } - if self.serde { - cargo_toml.1.push_str(", features = ['serde-serialize']"); - } - cargo_toml.1.push_str(" }\n"); + fn crate_name(&self) -> String { + format!("test{}", IDX.with(|x| *x)) + } + + fn build(&mut self) -> (PathBuf, PathBuf) { + let mut manifest = format!(r#" + [package] + name = "test{}" + version = "0.0.1" + authors = [] + + [workspace] + + [lib] + "#, IDX.with(|x| *x)); + + if !self.rlib { + manifest.push_str("crate-type = [\"cdylib\"]\n"); + } + + manifest.push_str("[dependencies]\n"); + for dep in self.deps.iter() { + manifest.push_str(dep); + manifest.push_str("\n"); + } + manifest.push_str("wasm-bindgen = { path = '"); + manifest.push_str(env!("CARGO_MANIFEST_DIR")); + manifest.push_str("'"); + if self.no_std { + manifest.push_str(", default-features = false"); } + if self.serde { + manifest.push_str(", features = ['serde-serialize']"); + } + manifest.push_str(" }\n"); + self.files.push(("Cargo.toml".to_string(), manifest)); + let root = root(); drop(fs::remove_dir_all(&root)); for &(ref file, ref contents) in self.files.iter() { @@ -208,9 +205,13 @@ impl Project { fs::create_dir_all(dst.parent().unwrap()).unwrap(); fs::File::create(&dst).unwrap().write_all(contents.as_ref()).unwrap(); } - let target_dir = root.parent().unwrap() // chop off test name .parent().unwrap(); // chop off `generated-tests` + (root.clone(), target_dir.to_path_buf()) + } + + fn test(&mut self) { + let (root, target_dir) = self.build(); let mut cmd = Command::new("cargo"); cmd.arg("build") @@ -333,3 +334,4 @@ mod non_debug; mod simple; mod slice; mod structural; +mod non_wasm; diff --git a/tests/all/non_wasm.rs b/tests/all/non_wasm.rs new file mode 100644 index 00000000000..dcb23b67ac6 --- /dev/null +++ b/tests/all/non_wasm.rs @@ -0,0 +1,86 @@ +use std::process::Command; +use super::{run, project}; + +#[test] +fn works() { + let mut p = project(); + let name = p.crate_name(); + p + .rlib(true) + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + pub struct A { + x: u32, + } + + #[wasm_bindgen] + impl A { + pub fn new() -> A { + A { x: 3 } + } + + pub fn foo(&self) { + } + } + + #[wasm_bindgen] + pub fn foo(x: bool) { + A::new().foo(); + + if x { + bar("test"); + baz(JsValue::from(3)); + } + } + + #[wasm_bindgen] + extern { + fn some_import(); + static A: JsValue; + } + + #[wasm_bindgen] + pub fn bar(_: &str) -> JsValue { + some_import(); + A.clone() + } + + #[wasm_bindgen] + pub fn baz(_: JsValue) { + } + "#) + .file("tests/foo.rs", &format!(" + extern crate {} as mytest; + + #[test] + fn foo() {{ + mytest::foo(false); + mytest::A::new().foo(); + }} + ", name)) + .file("benches/foo.rs", &format!(" + #![feature(test)] + extern crate test; + extern crate {} as mytest; + + #[bench] + fn foo(b: &mut test::Bencher) {{ + b.iter(|| mytest::foo(false)); + }} + ", name)); + let (root, target_dir) = p.build(); + let mut cmd = Command::new("cargo"); + cmd.arg("test") + .arg("--test").arg("foo") + .arg("--bench").arg("foo") + .current_dir(&root) + .env("CARGO_TARGET_DIR", &target_dir); + run(&mut cmd, "cargo"); +} +