I originally posted this question on Stack Overflow. Someone elected to open an Github issue for rust-lang on the topic, and a commenter suggested that posing the question here would could get more traction.
Context
I'm looking at rewriting part of a Rust library which wraps a C library because the current wrapper is unsafe. The C library expects a function pointer of the form void(*)(...)
, so the obvious choice on the Rust side would be a function pointer of type extern "C" fn(...) -> ()
. For safety reasons, I would like to create a type family Invariant<'a>
, which is invariant with respect to 'a
, such that we can safely transmute a function pointer of type extern "C" fn(...) -> Invariant<'a>
to a function pointer of type extern "C" fn(...) -> ()
. Users of my wrapped library would then pass a function pointer that returns an Invariant
.
In order to make such a transmutation safe, we need Invariant<'a>
to have the same size, alignment, and ABI as ()
. Surprisingly, there seems to be no way to do this that's guaranteed to work. I've tried quite a few tricks with #[repr(transparent)]
, but nothing seems to work (at least according to Miri) (see the Stack Overflow question for some of my attempts, one of which passes #[deny(improper_ctypes_definitions)]
, but all of which fail Miri). The issue is that #[repr(transparent)]
is only guaranteed to work for structs which have a single non-zero-sized field (and for equivalent enums). In fact, according to the Rust Reference and the Rustonomicon, you're not actually allowed to use #[repr(transparent)]
on a struct where all fields are zero-sized (although the compiler will usually allow this anyway). There was a
pull request to try to address this, but this pull request seems to be in limbo.
Question
Is there some technique I haven't thought of for creating a newtype wrapper around ()
that lets us do what I want? In general, is there a way to create a newtype
wrapper around a ZST?
If not, how can we modify #[repr(transparent)]
to allow this? My proposal would be that if you have a #[repr(transparent)]
struct where all fields are ZSTs, you should be able to designate a single field which will be the newtype
-wrapped field. However, I'm not exactly sure how this will work with generics - there may be some technical issues I haven't thought of.