Open joshtriplett opened 7 years ago
(I'm also curious what it would take to make a capturing closure work as an extern function pointer, but that's a separate issue.)
You don't. It basically only works for callback functions that take a data pointer (which many do). Then you can do something like this (highly unsafe):
#![feature(fn_traits, unboxed_closures)]
fn closure_to_fn_and_data<A, F: Fn<A> + 'static>(
f: F,
) -> (
unsafe extern "C" fn(*const Box<Fn<A, Output = F::Output>>, A) -> F::Output,
*const Box<Fn<A, Output = F::Output>>,
) {
unsafe extern "C" fn callback<A, F: Fn<A> + 'static>(
closure: *const Box<Fn<A, Output = F::Output>>,
args: A,
) -> F::Output {
std::ops::Fn::call(&**closure, args)
}
(
callback::<A, F>,
Box::into_raw(Box::new(Box::new(f) as Box<Fn<A, Output = F::Output>>)) as _,
)
}
(I'm also curious what it would take to make a capturing closure work as an extern function pointer, but that's a separate issue.)
@joshtriplett could you factor out this question from this issue? I'd like to comment on that as well but I dont want to pollute this discussion
What happens if the same closure is coerced to both fn
and extern fn
? Do I end up with two monomorphizations of the closure, one for each calling convention?
fn joshtriplett(hi: bool) {
let closure = || ();
if hi {
let _rust_fn: fn() = closure;
} else {
let _c_fn: extern fn() = closure;
}
}
@dtolnay I'd expect a thin shim, and you'd get a duplicated closure body only if LLVM inlines it.
Triage: I don't believe there's been any change here. I'd expect this to work:
const foo: [extern fn(&mut u32); 1] = [
|var: &mut u32| {},
];
But it does not:
error[E0308]: mismatched types
--> src/lib.rs:2:3
|
2 | |var: &mut u32| {},
| ^^^^^^^^^^^^^^^^^^ expected "C" fn, found "Rust" fn
|
= note: expected type `for<'r> extern "C" fn(&'r mut u32)`
found type `[closure@src/lib.rs:2:3: 2:21]`
The PR has been closed due to inactivity so it is free if anyone wants to pick it up
This is a followup to https://github.com/rust-lang/rust/issues/39817 . Non-capturing closures now coerce to function pointers, but not to
extern fn
pointers, as provided to C functions expecting a callback. Adding support for this would make it much simpler to call a C function and provide an appropriate callback inline.(I'm also curious what it would take to make a capturing closure work as an extern function pointer, but that's a separate issue.)