Description
Currently, the types for fn-items are always zero-sized. As described in #19925, this was defined in RFC 401, but the implementation lagged quite a bit from 1.0, and as a result a number of crates had to be converted because they were relying on transmutes from fn-item types into fn pointers -- generally speaking, these pointers were used in FFI situations. We only recently ended the "future incompatibility" warning period and made this into a hard error.
Towards the end of that FCP, @wycats floated the interesting idea that we could make the representation of an fn item dependent on its declared ABI. In particular, while the type of a standard Rust fn foo()
would still be a zero-sized type, the type of a extern "C" fn foo()
(or, presumably, any ABI intended for FFI, which basically means everything but Rust
) would change from being zero-sized to being a function pointer:
fn foo() { } // sizeof::<typeof(foo)>() == 0
extern "C" fn bar() { } // sizeof::<typeof(bar)>() == sizeof::<usize>()
Note that the fn item would still have a unique type, it would just not be zero-sized. Its value would be the same as an equivalent function pointer (in this case, extern "C" fn()
). Because each fn item still has a unique type, it means that if you have a higher-order fn like fn map<T: Fn()>()
and you invoke it with map(bar)
, we will still monomorphize a version of map
that statically dispatches to bar
. This was the primary motivation for RFC 401.
We could indeed go further, and just say that the size of any the type for any fn-item has the same representation as a fn-pointer, even if it is not precisely the same type. (This was the case before we made the changes that led to #19925, in fact.) This would mean that it is always safe to transmute a fn item to its corresponding fn()
type.
Strictly speaking, changing anything here would be a breaking change from the current behavior, and we would want to test its impact. My hypothesis thought is that it would only make some crates work that are currently broken. It seems unlikely -- but not impossible -- that people are relying on the fact that fn types are currently zero-sized.
Nominating for @rust-lang/lang discussion. I'm not sure the best way to proceed with this idea and want to talk it over. My motivation here is both to "unbreak" a certain amount of crates and to potentially ease an ergonomic sore spot with FFI. I know that there is vociferous opposition from others, however, and @eddyb in particular doesn't want to encourage the use of transmute
. This comment from @wycats is also worth reading.