Repository: rust
Issue: rustc disagrees with emcc about WASM struct ABI in parameters
Labels: O-wasm,C-bug,A-ABI,O-emscripten

I have the following Rust code, being compiled with `cargo +nightly build --target wasm32-unknown-unknown`


```rust
// 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](https://emscripten.org/docs/getting_started/downloads.html))

```cpp
# 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

<details>
<summary> Version info </summary>

```
$ 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.
```

</details>

cc @fitzgen