A C++ function passing a class Foo instance by value may pass Foo equivalently to the C ABI if Foo was a C struct, or it might pass it by pointer. This is also dependent on the platform:
namespace lib {
class Foo {
public:
Foo();
private:
int data{0};
};
Foo createFoo();
}
This class gets passed through registers on SysV but is passed by-reference on MSVC. A function that returns Foo like createFoo needs to be called through a C++ shim to choose the ABI manually, or needs to have conditional compilation on the Rust side:
unsafe extern "C" {
#[cfg_attr(windows, link_name = "?createFoo@lib@@")]
#[cfg_attr(not(windows), link_name = "\u{1}_ZN3lib8createFooE")]
#[cfg(windows)]
fn createFoo(out: *mut Foo) -> *mut Foo;
#[cfg(not(windows))]
fn createFoo() -> Foo;
}
Tools can perform the shimming, or the conditional compilation. But fundamentally the ABI is a trait of the type, not of the function call. It might also be interesting for there to be a way to mark a Rust struct as non-POD - at least in the C ABI. The MSVC / SysV conditionality would then be fairly easy to implement with conditional marker fields.
A C++ function passing a
class Fooinstance by value may passFooequivalently to the C ABI ifFoowas a C struct, or it might pass it by pointer. This is also dependent on the platform:This class gets passed through registers on SysV but is passed by-reference on MSVC. A function that returns
FoolikecreateFooneeds to be called through a C++ shim to choose the ABI manually, or needs to have conditional compilation on the Rust side:Tools can perform the shimming, or the conditional compilation. But fundamentally the ABI is a trait of the type, not of the function call. It might also be interesting for there to be a way to mark a Rust struct as non-POD - at least in the C ABI. The MSVC / SysV conditionality would then be fairly easy to implement with conditional marker fields.