Support coercing non-capturing closures to extern function pointers
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.)
(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 _, ) }jethrogb at 2017-09-03 16:27:35
(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
est31 at 2017-09-03 17:40:59
What happens if the same closure is coerced to both
fnandextern 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; } }David Tolnay at 2017-09-03 18:11:26
@dtolnay I'd expect a thin shim, and you'd get a duplicated closure body only if LLVM inlines it.
Eduard-Mihai Burtescu at 2017-09-03 18:33:55
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]`Steve Klabnik at 2019-03-10 23:03:10
The PR has been closed due to inactivity so it is free if anyone wants to pick it up
Dylan DPC at 2019-07-22 12:32:59