Unless the target/OS defines what it means to pass a zero-sized function argument — and not doing so would not be a surprising oversight due to not existing in C/C++ and functionally useless at a machine level — Rust also defines what the behavior of ZST arguments in extern "C"
is. Almost all (but not quite all) ways of defining a ZST result in the compiler warning about the use of improper C types and them having a nonguaranteed ABI.
Obviously the failure of repr(transparent)
to be fully transparent in that case on that target is a bug. A bad one, certainly, since it impacts a nominally stable ABI, but a bug. We'll need to decide if we prioritize bug-for-bug compatibility with (our extensions to) the ABI or being spec correct in this case.
extern "C"
is essentially a newtype alias around the platform specific ABI, e.g. extern "sysv64"
on non-Windows x86_64 and extern "win64"
on x86_64 Windows.
The SysV ABI doc does not define how zero byte objects (with trivial copy and drop) should be passed. ≥32 byte objects are passed as MEMORY, "C++ objects with non-trivial copy constructor or non-trivial destructor" are passed by reference, and then each eightbyte of small aggregates are classified separately. A zero-byte object (with trivial copy and drop) contains zero eightbytes and thus cannot be classified by this process. (Classifying an empty aggregate as MEMORY would have the desired no-op effect, pushing zero eightbytes to the stack.)
The Win64 ABI documentation says that any argument that isn't 1, 2, 4, or 8 bytes must be passed by reference. This results in it being fairly clear that zero-sized objects do always take up a parameter slot, but the docs are less formal than the SysV doc and as far as I'm aware it's not possible to have a zero-sized object with the official MSVC compiler.
When also considering return types, both ABIs make a distinction between POD and data with a non-trivial destructor. So that's probably the axis to look at for seeing if/when ZST (return) ABI differs in practice. (The Win64 one would be simple to adjust to make returning ZST the same as returning void — just add 0 bit length to the list of bit lengths returned in a register. Didn't particularly look at SysV.)