Stream: general

Topic: as cast on high-rank fn type


gnzlbg (Nov 02 2019 at 13:08, on Zulip):

Is there a way to cast a for<'a> fn(&'a i32) into a fn(*const i32) ?

Matthew Jasper (Nov 02 2019 at 13:11, on Zulip):

transmute

Matthew Jasper (Nov 02 2019 at 13:15, on Zulip):

It's definitely dubious whether the resulting function pointer can be called without UB.

gnzlbg (Nov 02 2019 at 13:49, on Zulip):

(deleted)

gnzlbg (Nov 02 2019 at 13:50, on Zulip):

@Matthew Jasper can you show an example? That cannot work if the for<'a> fn(&'a i32) is a zero-sized type and the fn(*const i32) is not

simulacrum (Nov 02 2019 at 13:55, on Zulip):

fn(&'a i32) is always a fn-ptr and not zero-sized, right?

simulacrum (Nov 02 2019 at 13:55, on Zulip):

it seems like that should always be a valid cast, so long as you call the latter with valid ptrs (i.e., essentially references)

gnzlbg (Nov 02 2019 at 13:55, on Zulip):

that type yes, but a function with that type not necessarily

simulacrum (Nov 02 2019 at 13:56, on Zulip):

I would expect that you can cast the function to that function ptr type

gnzlbg (Nov 02 2019 at 13:56, on Zulip):

I fixed this by doing:

fn foo<'a>(_: &'a i32) {}
let x: for<'a> fn(&'a i32) = foo;
let y: fn(*const i32) = transmute(x);
Matthew Jasper (Nov 02 2019 at 13:56, on Zulip):

If you have a function item then use a closure:

fn f<'a>(v: &'a i32) {}

fn g() -> fn(*const i32) {
    |x| unsafe { f(&*x) }
}
gnzlbg (Nov 02 2019 at 13:56, on Zulip):

I did not knew that one can already use for<'a> in patterns

gnzlbg (Nov 02 2019 at 13:57, on Zulip):

I did not have a function item, I had a F: Fn

gnzlbg (Nov 02 2019 at 13:57, on Zulip):

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=a8c261019d44a11af4969e46b390a10d
^^^ is what I ended up doing

gnzlbg (Nov 02 2019 at 13:58, on Zulip):

miri says that's fine

Matthew Jasper (Nov 02 2019 at 13:58, on Zulip):

That link's broken

gnzlbg (Nov 02 2019 at 14:00, on Zulip):

fixed

Matthew Jasper (Nov 02 2019 at 14:02, on Zulip):

You could also have done something like this:

pub fn foo<F: Fn()>(callback: F) {
    c_fn(
        |ptr, ()| unsafe { <F as Fn<()>>::call(&*(ptr as *const F), ()) },
        &callback as *const _ as *const c_void,
    )
}
simulacrum (Nov 02 2019 at 14:03, on Zulip):

you, you don't need anything like fn-traits for that

simulacrum (Nov 02 2019 at 14:03, on Zulip):

you can do this on stable, I think

simulacrum (Nov 02 2019 at 14:03, on Zulip):

what is the point of the unit tuple second argument?

simulacrum (Nov 02 2019 at 14:05, on Zulip):

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=dbc943c2702a8fc3c8765b15cf238851

simulacrum (Nov 02 2019 at 14:05, on Zulip):
pub fn foo<F: Fn()>(callback: F) {
    unsafe {
        c_fn(
            |data, ()| {
                (*(data as *const F))()
            },
            &callback as *const _ as *const c_void,
        )
    }
}
gnzlbg (Nov 02 2019 at 14:15, on Zulip):

what is the point of the unit tuple second argument?

I got a type error if I did not use it

gnzlbg (Nov 02 2019 at 14:24, on Zulip):

@simulacrum @Matthew Jasper so what's going on there ?

gnzlbg (Nov 02 2019 at 14:25, on Zulip):

The closure is being safely implicitly coerced

gnzlbg (Nov 02 2019 at 14:25, on Zulip):

but there is no way to spell out the coercions ?

simulacrum (Nov 02 2019 at 14:25, on Zulip):

Uh, you can just cast the closure to the fn ptr type

simulacrum (Nov 02 2019 at 14:26, on Zulip):

But there's really no point

gnzlbg (Nov 02 2019 at 14:27, on Zulip):

@simulacrum can I cast the callback to the fn ptr type ?

gnzlbg (Nov 02 2019 at 14:28, on Zulip):

I guess that's how I approached the problem

gnzlbg (Nov 02 2019 at 14:29, on Zulip):

(i.e. I wanted to pass callback to c_fn in foo, but instead of creating a closure, i tried to do that directly)

simulacrum (Nov 02 2019 at 19:01, on Zulip):

should be able to, yeah

RalfJ (Nov 03 2019 at 13:11, on Zulip):

Matthew Jasper can you show an example? That cannot work if the for<'a> fn(&'a i32) is a zero-sized type and the fn(*const i32) is not

that fn type is never a ZST, I think you are getting confused by the zero-sized anonymous singleton types we have for each function?

RalfJ (Nov 03 2019 at 13:12, on Zulip):

these are not fn types

RalfJ (Nov 03 2019 at 13:13, on Zulip):

https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/enum.TyKind.html#variant.FnDef is a ZST that doesnt have surface syntax, it is the type of foo when foo is the name of a fn item;
https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/enum.TyKind.html#variant.FnPtr is the thing that the fn type syntax compiles to

RalfJ (Nov 03 2019 at 13:14, on Zulip):

FnDef coerces to FnPtr, but that is an effectful coercion, not just a transmute (similar to e.g. coercing &[T; N] to &[T])

gnzlbg (Nov 04 2019 at 09:43, on Zulip):

should be able to, yeah

@simulacrum can you show how ?

gnzlbg (Nov 04 2019 at 09:44, on Zulip):

My original link was an attempt at that, and required two unstable features.

simulacrum (Nov 04 2019 at 12:56, on Zulip):

oh, I remembered wrong -- you can't cast closures to extern C, you need a shim. This, though, should work: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=902329e977c8e1467f7b15fd10549cec -- the insight is that you can have a extern "C" function that's generic; it's not something that's in your public interface (mangling is still a thing, since it's generic), but you can pass it's address just fine

simulacrum (Nov 04 2019 at 12:56, on Zulip):

@gnzlbg ^

simulacrum (Nov 04 2019 at 12:56, on Zulip):

See https://github.com/rust-lang/rust/issues/44291 for more

gnzlbg (Nov 04 2019 at 12:58, on Zulip):

Thanks, I guess what I was missing from my original approach is the *(data as *const F)() part

gnzlbg (Nov 04 2019 at 12:58, on Zulip):

I was trying to cast the F directly somehow

simulacrum (Nov 04 2019 at 13:08, on Zulip):

right, yeah, you can't do that

simulacrum (Nov 04 2019 at 13:08, on Zulip):

since it has "metadata"

simulacrum (Nov 04 2019 at 13:08, on Zulip):

well, associated data, not really meta

Last update: Nov 20 2019 at 12:00UTC