For sizeof(T)>0, I understand the rules: no two &muts can reference overlapping memory.
What exactly are the rules for ZSTs, though?
For x: ((),()) to be a ZST (which we want), &mut x.0 and &mut x.1 are allowed, but are NOP transformations of &mut x, with the same value. But with unsafe code, I can take &mut x as *mut _, perform two NOP transformations to it, cast it as *mut (), and dereference it, and I don't know how to determine whether I'm reading the "first" or "second" fields, and thus whether I'm violating aliasing. Similar arguments apply to things like split_at_mut on a &mut [()], which is also creating multiple pointers of the same value.
But if all ZST reads are legal, that means all ZSTs are effectively Copy, which means a private-constructor ZST cannot safely be used as an access token, as it can be copied by ptr::read'ing it twice (legal because all ZST reads are legal, by premise).
For
sizeof(T)>0, I understand the rules: no two&muts can reference overlapping memory.What exactly are the rules for ZSTs, though?
For
x: ((),())to be a ZST (which we want),&mut x.0and&mut x.1are allowed, but are NOP transformations of&mut x, with the same value. But with unsafe code, I can take&mut x as *mut _, perform two NOP transformations to it, cast itas *mut (), and dereference it, and I don't know how to determine whether I'm reading the "first" or "second" fields, and thus whether I'm violating aliasing. Similar arguments apply to things likesplit_at_muton a&mut [()], which is also creating multiple pointers of the same value.But if all ZST reads are legal, that means all ZSTs are effectivelyCopy, which means a private-constructor ZST cannot safely be used as an access token, as it can be copied by ptr::read'ing it twice (legal because all ZST reads are legal, by premise).