Skip to content

async functions do not compile correctly for WASM #139829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
naskya opened this issue Apr 14, 2025 · 2 comments
Closed

async functions do not compile correctly for WASM #139829

naskya opened this issue Apr 14, 2025 · 2 comments
Labels
A-async-await Area: Async & Await C-discussion Category: Discussion or questions that doesn't represent real issues.

Comments

@naskya
Copy link
Contributor

naskya commented Apr 14, 2025

I tried this code:

// src/lib.rs
#[unsafe(no_mangle)]
pub async fn foo() {}

#[unsafe(no_mangle)]
pub async fn bar(_: i32) {}
# Cargo.toml
[package]
name = "test"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

I expected to see this happen: foo returns no results and bar takes only one argument (or it fails to compile if async functions are not supported)

Instead, this happened: When compiled for wasm32-unknown-unknown, wasm32-wasip1 and wasm32-wasip2, it doesn’t hold

$ cargo +nightly build --release --target wasm32-unknown-unknown
$ wasm-tools print target/wasm32-unknown-unknown/release/test.wasm
(module $test.wasm
  (type (;0;) (func (result i32)))
  (type (;1;) (func (param i32 i32)))
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global $__stack_pointer (;0;) (mut i32) i32.const 1048576)
  (global (;1;) i32 i32.const 1048576)
  (global (;2;) i32 i32.const 1048576)
  (export "memory" (memory 0))
  (export "foo" (func $foo))
  (export "bar" (func $bar))
  (export "__data_end" (global 1))
  (export "__heap_base" (global 2))
  (func $foo (;0;) (type 0) (result i32)
    i32.const 0
  )
  (func $bar (;1;) (type 1) (param i32 i32)
    local.get 0
    i32.const 0
    i32.store8 offset=4
    local.get 0
    local.get 1
    i32.store
  )
  (@producers
    (language "Rust" "")
    (processed-by "rustc" "1.88.0-nightly (092a284ba 2025-04-13)")
  )
  (@custom "target_features" (after code) "\08+\0bbulk-memory+\0fbulk-memory-opt+\16call-indirect-overlong+\0amultivalue+\0fmutable-globals+\13nontrapping-fptoint+\0freference-types+\08sign-ext")
)

Notice the func $foo (;0;) (type 0) (result i32) and func $bar (;1;) (type 1) (param i32 i32).

Meta

rustc --version --verbose:

rustc 1.88.0-nightly (092a284ba 2025-04-13)
binary: rustc
commit-hash: 092a284ba0421695f2032c947765429fd7095796
commit-date: 2025-04-13
host: x86_64-unknown-linux-gnu
release: 1.88.0-nightly
LLVM version: 20.1.2

@rustbot label +O-wasm +O-wasi

@naskya naskya added the C-bug Category: This is a bug. label Apr 14, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. O-wasi Operating system: Wasi, Webassembly System Interface O-wasm Target: WASM (WebAssembly), http://webassembly.org/ labels Apr 14, 2025
@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-async-await Area: Async & Await I-miscompile Issue: Correct Rust code lowers to incorrect machine code and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 15, 2025
@saethlin
Copy link
Member

async fn is a function that returns a generator. They are fundamentally different from normal fn.

So the codegen here looks fine to me.

@saethlin saethlin added C-discussion Category: Discussion or questions that doesn't represent real issues. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. O-wasm Target: WASM (WebAssembly), http://webassembly.org/ C-bug Category: This is a bug. O-wasi Operating system: Wasi, Webassembly System Interface I-miscompile Issue: Correct Rust code lowers to incorrect machine code labels Apr 15, 2025
@bjorn3
Copy link
Member

bjorn3 commented Apr 15, 2025

If you want to export a function to non-Rust code, you have to use extern "C". And if you do, rustc will give you the following warning for async functions:

warning: `extern` fn uses type `impl Future<Output = ()>`, which is not FFI-safe
 --> src/lib.rs:2:1
  |
2 | pub async extern "C" fn foo() {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
  |
  = note: opaque types have no C equivalent
  = note: `#[warn(improper_ctypes_definitions)]` on by default

@saethlin saethlin closed this as not planned Won't fix, can't repro, duplicate, stale Apr 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await C-discussion Category: Discussion or questions that doesn't represent real issues.
Projects
None yet
Development

No branches or pull requests

5 participants