Closed
Description
check.rs
extern crate libc;
use std::mem;
type VPtr = *mut ::libc::c_void;
type CbClosure<'s> = Fn<(&'s i32,), i32> + 's;
extern "C" fn callback(data: VPtr) {
unsafe {
let func: &CbClosure = mem::transmute::<VPtr, &CbClosure>(data);
let x = 5;
(*func)(&x);
}
}
#[link(name = "extlib")]
extern {
fn register_callback(cb: extern fn(VPtr)) -> i32;
fn trigger_callback(val: VPtr);
}
fn main() {
let func = |&mut: x: &i32| *x*2;
go(func);
}
fn go<CbClosure>(func: CbClosure) {
unsafe {
register_callback(callback);
let data: VPtr = mem::transmute::<&CbClosure, VPtr>(&func);
trigger_callback(data);
}
}
extlib.c
#include <stdint.h>
typedef void (*rust_callback)(void*);
rust_callback cb;
int32_t register_callback(rust_callback callback) {
cb = callback;
return 1;
}
void trigger_callback(void *val) {
cb(val);
}
$ gcc extlib.c -fPIC -shared -o libextlib.so
$ rustc -L . check.rs
check.rs:10:32: 10:66 error: transmute called on types with different sizes: *mut libc::types::common::c95::c_void (64 bits) to &core::ops::Fn(&i32) -> i32 (128 bits)
check.rs:10 let func: &CbClosure = mem::transmute::<VPtr, &CbClosure>(data);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
But if you comment out the whole unsafe block in callback
...
$ rustc -L . check.rs
check.rs:8:24: 8:28 warning: unused variable: `data`, #[warn(unused_variables)] on by default
check.rs:8 extern "C" fn callback(data: VPtr) {
despite there being a conversion the other way in go
. Surely these type cannot vary in size?
To compound my confusion, you can add the line below to after let data: [...]
in go
and it will compile - this is exactly the same line as in callback
, with a different variable name.
let func2: &CbClosure = mem::transmute::<VPtr, &CbClosure>(data);