rustc disagrees with emcc about WASM struct ABI in parameters #88152
Description
I have the following Rust code, being compiled with cargo +nightly build --target wasm32-unknown-unknown
// in crate "em"
#[repr(C)]
pub struct Options {
a: u8,
b: u8
}
#[no_mangle]
pub extern "C" fn take_struct(o: Options) {}
And the following C++ code, compiled with emcc -std=c++17 test.cpp target/wasm32-unknown-unknown/debug/libem.a -ldl -lpthread -lm -g -o main.html --emrun -sWASM=1
(using the emscripten sdk)
# test.cpp
extern "C" {
typedef struct Options {
uint8_t a;
uint8_t b;
} Options;
void take_struct(Options o);
}
int main() {
Options o;
take_struct(o);
return 0;
}
I expected to see this happen: The code would compile without warnings and run fine.
Instead, this happened:
emcc shows up the following warning:
wasm-ld: warning: function signature mismatch: take_struct
>>> defined as (i32) -> void in /tmp/emscripten_temp_qz2pbc3_/test_0.o
>>> defined as (i32, i32) -> void in target/wasm32-unknown-unknown/debug/libem.a(em.zb05z167nruq6bs.rcgu.o)
and running main.html
in the browser throws the following error (to be expected based on the warning)
exception thrown: RuntimeError: unreachable,RuntimeError: unreachable
at signature_mismatch:take_struct (http://localhost:8000/main.wasm:wasm-function[1]:0x165)
at __original_main (http://localhost:8000/main.wasm:wasm-function[2]:0x1f1)
at main (http://localhost:8000/main.wasm:wasm-function[3]:0x20e)
at http://localhost:8000/main.js:1560:22
at callMain (http://localhost:8000/main.js:2142:15)
at doRun (http://localhost:8000/main.js:2212:23)
at http://localhost:8000/main.js:2223:7
Seems like rustc believes that the signature for fn({u8, u8})
should be (i32, i32) -> void
, whereas emcc believes it should be (i32) -> void
.
A lot of other function signatures work (including returning Option
), it's specifically when such a struct is a parameter that this happens.
I'm not sure which side is at fault here, but an incompatibility between Rust and emcc means that it won't be possible to use WASM with C++ programs that embed a little Rust (or vice versa), which seems like a problem worth highlighting. I think there are other ways to compile C++ to WASM via clang that I need to check out next.
Meta
Version info
$ rustc --version --verbose
rustc 1.56.0-nightly (2d2bc94c8 2021-08-15)
binary: rustc
commit-hash: 2d2bc94c8c3aa778e191f80261c726e4777439f1
commit-date: 2021-08-15
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
$ emcc --version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.27 (7e538a419c3649f3a540a57beab347aa8f6c6271)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
cc @fitzgen