Haven’t tested it, but I think the distinction here is that a zero value of anyopaque would imply a null pointer, and null pointers are explicitly prohibited by the spec. If you want null values, you need an optional. A zero size would mean a zero value, hence it’s not allowed.
(This is the output in both -ODebug and -OReleaseFast.)
So maybe not necessarily invalid, but probably not something you want to do in practice, unless you are properly handling the type and never reference the pointer; with that said though, this did not produce a panic in -ODebug, so it may be safe (I give no guarantees on that statement though).
Note that this is technically not a zero value - you’re taking the address of the location of the value at this LOC (here, the void{}, or the T{} in your example). This might be where the confusion lies.
So *void has a non-zero size, which makes sense since it’s a pointer. anyopaque is a type-erased pointer and must be of non-zero size, which is correct. Again, maybe not recommended to use with void, but correct.
If anything, the language that distinguishes anyopaque from void could probably be omitted, or changed to explain that it is more akin to void * in C terms. It’s a type-erased pointer, not a type-erased value.
This reads to me that to fully understand the purpose of anyopaque, you need to take into account both parts here; that anyopaque is analogous to void, yes, but then add the additional qualifier that it’s only supposed to be used in the context of pointers. Hence, it’s more equivalent to void * (*anyopaque <=> void *).
This is conjecture based on a few minutes of searching through old issues and commits, but I suspect that
anyopaque has an unknown, but non-zero, size
is a leftover from an older version of the language that had different semantics, and that it should more correctly be
anyopaque has an unknown size
(indirectly implying that the size can be 0).
In 0.8.x, pointers to zero-bit types were themselves also zero-bit types, i.e. @sizeOf(*void) == 0 and @sizeOf(*void) == @sizeOf(void). *c_void (the old name for *anyopaque) on the other hand was not a zero-bit type, i.e. @sizeOf(*c_void) != 0, and therefore it was important to clarify that a *c_void/*anyopaque payload is at least one byte in size.
*void and pointers to OPV types (“One Possible Value”, a different name for zero-bit types) have addresses just like pointers to non-OPV types. The main distinction is that dereferencing a pointer to an OPV type is a no-op that always succeeds and never results in a memory access violation, and that you can’t use pointer arithmetic with pointers to OPV types like [*]u0.