Skip to content

Commit 838bcef

Browse files
authored
Merge pull request #1620 from dtolnay/receiver
Pass Rust method receiver to C function as pointer not reference
2 parents 53219c3 + edb48ad commit 838bcef

File tree

4 files changed

+35
-6
lines changed

4 files changed

+35
-6
lines changed

macro/src/expand.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,16 @@ fn expand_extern_shared_struct(ety: &ExternType, ffi: &Module) -> TokenStream {
583583
fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
584584
let generics = &efn.generics;
585585
let receiver = efn.receiver().into_iter().map(|receiver| {
586-
let receiver_type = receiver.ty();
587-
quote!(_: #receiver_type)
586+
if types.is_considered_improper_ctype(&receiver.ty) {
587+
if receiver.mutable {
588+
quote!(_: *mut ::cxx::core::ffi::c_void)
589+
} else {
590+
quote!(_: *const ::cxx::core::ffi::c_void)
591+
}
592+
} else {
593+
let receiver_type = receiver.ty();
594+
quote!(_: #receiver_type)
595+
}
588596
});
589597
let args = efn.args.iter().map(|arg| {
590598
let var = &arg.name.rust;
@@ -650,10 +658,23 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
650658
expand_return_type(&efn.ret)
651659
};
652660
let indirect_return = indirect_return(efn, types);
653-
let receiver_var = efn
654-
.receiver()
655-
.into_iter()
656-
.map(|receiver| receiver.var.to_token_stream());
661+
let receiver_var = efn.receiver().into_iter().map(|receiver| {
662+
if types.is_considered_improper_ctype(&receiver.ty) {
663+
let var = receiver.var;
664+
let ty = &receiver.ty.rust;
665+
let resolve = types.resolve(ty);
666+
let lifetimes = resolve.generics.to_underscore_lifetimes();
667+
if receiver.pinned {
668+
quote!(::cxx::core::pin::Pin::into_inner_unchecked(#var) as *mut #ty #lifetimes as *mut ::cxx::core::ffi::c_void)
669+
} else if receiver.mutable {
670+
quote!(#var as *mut #ty #lifetimes as *mut ::cxx::core::ffi::c_void)
671+
} else {
672+
quote!(#var as *const #ty #lifetimes as *const ::cxx::core::ffi::c_void)
673+
}
674+
} else {
675+
receiver.var.to_token_stream()
676+
}
677+
});
657678
let arg_vars = efn.args.iter().map(|arg| {
658679
let var = &arg.name.rust;
659680
let span = var.span();

tests/ffi/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ pub mod ffi {
352352
fn r_static_method() -> usize;
353353
}
354354

355+
unsafe extern "C++" {
356+
fn c_member_function_on_rust_type(self: &R);
357+
}
358+
355359
struct Dag0 {
356360
i: i32,
357361
}

tests/ffi/tests.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ std::unique_ptr<::F::F> c_return_ns_opaque_ptr() {
771771
return f;
772772
}
773773

774+
void R::c_member_function_on_rust_type() const noexcept {}
775+
774776
extern "C" const char *cxx_run_test() noexcept {
775777
#define STRINGIFY(x) #x
776778
#define TOSTRING(x) STRINGIFY(x)

tests/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ fn test_c_method_calls() {
281281
};
282282
array.c_set_array(val);
283283
assert_eq!(array.a.len() as i32 * val, array.r_get_array_sum());
284+
285+
R(2020).c_member_function_on_rust_type();
284286
}
285287

286288
#[test]

0 commit comments

Comments
 (0)