diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index c8b7616e64509..3d9aa7b523119 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; @@ -2342,12 +2342,6 @@ impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> { } } -impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.cx.wasm_c_abi_opt() - } -} - impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> { fn x86_abi_opt(&self) -> X86Abi { self.cx.x86_abi_opt() diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 1e1f577bb3a15..0323d59c5fe9e 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -19,9 +19,7 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::{ - HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi, -}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi}; use crate::callee::get_fn; use crate::common::SignType; @@ -536,12 +534,6 @@ impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.tcx.sess.opts.unstable_opts.wasm_c_abi - } -} - impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { fn x86_abi_opt(&self) -> X86Abi { X86Abi { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 96d1ab018f60d..94dcfd1f170a9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,14 +1,13 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_parsing::InstructionSetAttr; -use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; use rustc_middle::mir::{Body, InlineAsmOperand}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{Instance, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug, ty}; +use rustc_middle::{bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::{BinaryFormat, WasmCAbi}; +use rustc_target::spec::BinaryFormat; use crate::common; use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; @@ -268,12 +267,7 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, "{}", arch_prefix).unwrap(); } writeln!(begin, "{asm_name}:").unwrap(); - writeln!( - begin, - ".functype {asm_name} {}", - wasm_functype(tcx, fn_abi, instance.def_id()) - ) - .unwrap(); + writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap(); writeln!(end).unwrap(); // .size is ignored for function symbols, so we can skip it @@ -287,7 +281,7 @@ fn prefix_and_suffix<'tcx>( /// The webassembly type signature for the given function. /// /// Used by the `.functype` directive on wasm targets. -fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String { +fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { let mut signature = String::with_capacity(64); let ptr_type = match tcx.data_layout.pointer_size.bits() { @@ -296,17 +290,6 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id other => bug!("wasm pointer size cannot be {other} bits"), }; - // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed - // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs` - // basically the commit introducing this comment should be reverted - if let PassMode::Pair { .. } = fn_abi.ret.mode { - let _ = WasmCAbi::Legacy; - span_bug!( - tcx.def_span(def_id), - "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" - ); - } - let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); signature.push('('); @@ -320,7 +303,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id let mut it = fn_abi.args.iter().peekable(); while let Some(arg_abi) = it.next() { - wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id); + wasm_type(&mut signature, arg_abi, ptr_type); if it.peek().is_some() { signature.push_str(", "); } @@ -329,7 +312,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id signature.push_str(") -> ("); if !hidden_return { - wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id); + wasm_type(&mut signature, &fn_abi.ret, ptr_type); } signature.push(')'); @@ -337,27 +320,13 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id signature } -fn wasm_type<'tcx>( - tcx: TyCtxt<'tcx>, - signature: &mut String, - arg_abi: &ArgAbi<'_, Ty<'tcx>>, - ptr_type: &'static str, - def_id: DefId, -) { +fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) { match arg_abi.mode { PassMode::Ignore => { /* do nothing */ } PassMode::Direct(_) => { let direct_type = match arg_abi.layout.backend_repr { BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type), BackendRepr::SimdVector { .. } => "v128", - BackendRepr::Memory { .. } => { - // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed - let _ = WasmCAbi::Legacy; - span_bug!( - tcx.def_span(def_id), - "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" - ); - } other => unreachable!("unexpected BackendRepr: {:?}", other), }; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index aabd235bcabed..205fbf36ae0ea 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -27,7 +27,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, SourceFileHashAlgorithm, sym}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, }; use crate::interface::{initialize_checked_jobserver, parse_cfg}; @@ -877,7 +877,6 @@ fn test_unstable_options_tracking_hash() { tracked!(verify_llvm_ir, true); tracked!(virtual_function_elimination, true); tracked!(wasi_exec_model, Some(WasiExecModel::Reactor)); - tracked!(wasm_c_abi, WasmCAbi::Spec); // tidy-alphabetical-end macro_rules! tracked_no_crate_hash { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 272bb0cc915f9..832a338439c72 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -19,9 +19,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{ - HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi, -}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -573,12 +571,6 @@ impl<'tcx> HasTargetSpec for TyCtxt<'tcx> { } } -impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.sess.opts.unstable_opts.wasm_c_abi - } -} - impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> { fn x86_abi_opt(&self) -> X86Abi { X86Abi { @@ -633,12 +625,6 @@ impl<'tcx> HasTargetSpec for LayoutCx<'tcx> { } } -impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.calc.cx.wasm_c_abi_opt() - } -} - impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> { fn x86_abi_opt(&self) -> X86Abi { self.calc.cx.x86_abi_opt() diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7586c5766b585..fa55ecf80540f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2939,7 +2939,7 @@ pub(crate) mod dep_tracking { use rustc_target::spec::{ CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple, - TlsModel, WasmCAbi, + TlsModel, }; use super::{ @@ -3050,7 +3050,6 @@ pub(crate) mod dep_tracking { Polonius, InliningThreshold, FunctionReturn, - WasmCAbi, Align, ); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8977365ee73d9..66c10960ca147 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -16,7 +16,7 @@ use rustc_span::{RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, - TargetTuple, TlsModel, WasmCAbi, + TargetTuple, TlsModel, }; use crate::config::*; @@ -790,7 +790,6 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub(crate) const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`"; - pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`"; pub(crate) const parse_mir_include_spans: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)"; pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29"; @@ -1883,15 +1882,6 @@ pub mod parse { true } - pub(crate) fn parse_wasm_c_abi(slot: &mut WasmCAbi, v: Option<&str>) -> bool { - match v { - Some("spec") => *slot = WasmCAbi::Spec, - Some("legacy") => *slot = WasmCAbi::Legacy, - _ => return false, - } - true - } - pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool { *slot = match v { Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On, @@ -2599,8 +2589,6 @@ written to standard error output)"), Requires `-Clto[=[fat,yes]]`"), wasi_exec_model: Option = (None, parse_wasi_exec_model, [TRACKED], "whether to build a wasi command or reactor"), - wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy, parse_wasm_c_abi, [TRACKED], - "use spec-compliant C ABI for `wasm32-unknown-unknown` (default: legacy)"), write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED], "whether long type names should be written to files instead of being printed in errors"), // tidy-alphabetical-end diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 198d08864bec3..e62dffffc23c8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -7,7 +7,7 @@ use rustc_abi::{ }; use rustc_macros::HashStable_Generic; -use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; +use crate::spec::{HasTargetSpec, HasX86AbiOpt, RustcAbi}; mod aarch64; mod amdgpu; @@ -626,7 +626,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { pub fn adjust_for_foreign_abi(&mut self, cx: &C, abi: ExternAbi) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt, + C: HasDataLayout + HasTargetSpec + HasX86AbiOpt, { if abi == ExternAbi::X86Interrupt { if let Some(arg) = self.args.first_mut() { @@ -699,14 +699,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "hexagon" => hexagon::compute_abi_info(self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), - "wasm32" => { - if spec.os == "unknown" && cx.wasm_c_abi_opt() == WasmCAbi::Legacy { - wasm::compute_wasm_abi_info(self) - } else { - wasm::compute_c_abi_info(cx, self) - } - } - "wasm64" => wasm::compute_c_abi_info(cx, self), + "wasm32" | "wasm64" => wasm::compute_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), arch => panic!("no lowering implemented for {arch}"), } diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index 364a655113114..527c314780f83 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs @@ -56,7 +56,7 @@ where } /// The purpose of this ABI is to match the C ABI (aka clang) exactly. -pub(crate) fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, @@ -72,43 +72,3 @@ where classify_arg(cx, arg); } } - -/// The purpose of this ABI is for matching the WebAssembly standard. This -/// intentionally diverges from the C ABI and is specifically crafted to take -/// advantage of LLVM's support of multiple returns in WebAssembly. -/// -/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM -/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change. -/// Also see . -pub(crate) fn compute_wasm_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { - if !fn_abi.ret.is_ignore() { - classify_ret_wasm_abi(&mut fn_abi.ret); - } - - for arg in fn_abi.args.iter_mut() { - if arg.is_ignore() { - continue; - } - classify_arg_wasm_abi(arg); - } - - fn classify_ret_wasm_abi(ret: &mut ArgAbi<'_, Ty>) { - if !ret.layout.is_sized() { - // Not touching this... - return; - } - // FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666 - ret.make_direct_deprecated(); - ret.extend_integer_width_to(32); - } - - fn classify_arg_wasm_abi(arg: &mut ArgAbi<'_, Ty>) { - if !arg.layout.is_sized() { - // Not touching this... - return; - } - // FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666 - arg.make_direct_deprecated(); - arg.extend_integer_width_to(32); - } -} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index cc8162a2f27ea..8246bf581dbdf 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2228,19 +2228,6 @@ impl HasTargetSpec for Target { } } -/// Which C ABI to use for `wasm32-unknown-unknown`. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum WasmCAbi { - /// Spec-compliant C ABI. - Spec, - /// Legacy ABI. Which is non-spec-compliant. - Legacy, -} - -pub trait HasWasmCAbiOpt { - fn wasm_c_abi_opt(&self) -> WasmCAbi; -} - /// x86 (32-bit) abi options. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct X86Abi { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e317768ff602c..6df786ec66755 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -468,28 +468,18 @@ fn fn_abi_sanity_check<'tcx>( // For an unsized type we'd only pass the sized prefix, so there is no universe // in which we ever want to allow this. assert!(sized, "`PassMode::Direct` for unsized type in ABI: {:#?}", fn_abi); + // This really shouldn't happen even for sized aggregates, since // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an // LLVM type. This means all sorts of Rust type details leak into the ABI. - // However wasm sadly *does* currently use this mode for it's "C" ABI so we - // have to allow it -- but we absolutely shouldn't let any more targets do - // that. (Also see .) - // - // The unadjusted ABI also uses Direct for all args and is ill-specified, + // The unadjusted ABI however uses Direct for all args. It is ill-specified, // but unfortunately we need it for calling certain LLVM intrinsics. - - match spec_abi { - ExternAbi::Unadjusted => {} - ExternAbi::C { unwind: _ } - if matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") => {} - _ => { - panic!( - "`PassMode::Direct` for aggregates only allowed for \"unadjusted\" functions and on wasm\n\ - Problematic type: {:#?}", - arg.layout, - ); - } - } + assert!( + matches!(spec_abi, ExternAbi::Unadjusted), + "`PassMode::Direct` for aggregates only allowed for \"unadjusted\"\n\ + Problematic type: {:#?}", + arg.layout, + ); } } } diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index ba95ab7af6d1a..ffd752ee6dee2 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -207,120 +207,3 @@ conditionally compile code instead. This is notably different to the way native platforms such as x86\_64 work, and this is due to the fact that WebAssembly binaries must only contain code the engine understands. Native binaries work so long as the CPU doesn't execute unknown code dynamically at runtime. - -## Broken `extern "C"` ABI - -This target has what is considered a broken `extern "C"` ABI implementation at -this time. Notably the same signature in Rust and C will compile to different -WebAssembly functions and be incompatible. This is considered a bug and it will -be fixed in a future version of Rust. - -For example this Rust code: - -```rust,ignore (does-not-link) -#[repr(C)] -struct MyPair { - a: u32, - b: u32, -} - -extern "C" { - fn take_my_pair(pair: MyPair) -> u32; -} - -#[no_mangle] -pub unsafe extern "C" fn call_c() -> u32 { - take_my_pair(MyPair { a: 1, b: 2 }) -} -``` - -compiles to a WebAssembly module that looks like: - -```wasm -(module - (import "env" "take_my_pair" (func $take_my_pair (param i32 i32) (result i32))) - (func $call_c - i32.const 1 - i32.const 2 - call $take_my_pair - ) -) -``` - -The function when defined in C, however, looks like - -```c -struct my_pair { - unsigned a; - unsigned b; -}; - -unsigned take_my_pair(struct my_pair pair) { - return pair.a + pair.b; -} -``` - -```wasm -(module - (import "env" "__linear_memory" (memory 0)) - (func $take_my_pair (param i32) (result i32) - local.get 0 - i32.load offset=4 - local.get 0 - i32.load - i32.add - ) -) -``` - -Notice how Rust thinks `take_my_pair` takes two `i32` parameters but C thinks it -only takes one. - -The correct definition of the `extern "C"` ABI for WebAssembly is located in the -[WebAssembly/tool-conventions](https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md) -repository. The `wasm32-unknown-unknown` target (and only this target, not other -WebAssembly targets Rust support) does not correctly follow this document. - -Example issues in the Rust repository about this bug are: - -* [#115666](https://github.com/rust-lang/rust/issues/115666) -* [#129486](https://github.com/rust-lang/rust/issues/129486) - -This current state of the `wasm32-unknown-unknown` backend is due to an -unfortunate accident which got relied on. The `wasm-bindgen` project prior to -0.2.89 was incompatible with the "correct" definition of `extern "C"` and it was -seen as not worth the tradeoff of breaking `wasm-bindgen` historically to fix -this issue in the compiler. - -Thanks to the heroic efforts of many involved in this, however, `wasm-bindgen` -0.2.89 and later are compatible with the correct definition of `extern "C"` and -the nightly compiler currently supports a `-Zwasm-c-abi` implemented in -[#117919](https://github.com/rust-lang/rust/pull/117919). This nightly-only flag -can be used to indicate whether the spec-defined version of `extern "C"` should -be used instead of the "legacy" version of -whatever-the-Rust-target-originally-implemented. For example using the above -code you can see (lightly edited for clarity): - -```shell -$ rustc +nightly -Zwasm-c-abi=spec foo.rs --target wasm32-unknown-unknown --crate-type lib --emit obj -O -$ wasm-tools print foo.o -(module - (import "env" "take_my_pair" (func $take_my_pair (param i32) (result i32))) - (func $call_c (result i32) - ;; ... - ) - ;; ... -) -``` - -which shows that the C and Rust definitions of the same function now agree like -they should. - -The `-Zwasm-c-abi` compiler flag is tracked in -[#122532](https://github.com/rust-lang/rust/issues/122532) and a lint was -implemented in [#117918](https://github.com/rust-lang/rust/issues/117918) to -help warn users about the transition if they're using `wasm-bindgen` 0.2.88 or -prior. The current plan is to, in the future, switch `-Zwasm-c-api=spec` to -being the default. Some time after that the `-Zwasm-c-abi` flag and the -"legacy" implementation will all be removed. During this process users on a -sufficiently updated version of `wasm-bindgen` should not experience breakage.