Closed 0xAdk closed 3 months ago
while reading the help doc to verify (T, ())
is a transparent wrapper (I'm pretty sure it is) I noticed it mentions PhantomData as a common ZST, so I added it as well.
Other than [T;1]
I don't believe any of them are guaranteed to even be layout compatible. [T;1]
is layout compatible by definition with T
but not ABI Compatible at all.
IIRC tuples do not have a defined layout (they are implicitly repr(Rust)
and specifically not repr(transparent)
), even single-element tuples, so it would not be correct to implement TransparentWrapper<T>
for (T,)
or (T, Zst)
.
impl TransparentWrapper<T> for [T; 1]
would be fine (since they layout is the same), except that TransparentWrapper
's docs explicitly call out that repr(transparent)
must be used, which means that [T; 1]
does not qualify (repr(transparent)
has implications for passing by value to a function, e.g.).
Even if the repr(transparent)
restriction is lifted (which would be a breaking change IMO) and instead it is just required that the types have the same size and alignment, then [T; 1]
is okay, but for the tuples, at the very least there would need to be some kind of generic const assertion that their layouts are the same before any actual use of the trait for a particular instatiation.
I think I'm having a hard time wrapping my head around what what repr(rust) actually guaranteed. Re-reading it again I think I get it now that it only talks about alignment not size, so (T, ())
could be any size and offset_of!((T, ()), 0)
could be any offset?
except that TransparentWrapper's docs explicitly call out that repr(transparent) must be used
I think I misread that part as requiring they have the same alignment and size.
So, when I reviewed the exact unsafe contract for TransparentWrapper
(https://github.com/Lokathor/bytemuck/blob/main/src/transparent.rs#L15-L35), it's definitely a little confusingly worded. Point (1) contains the word "either", but then only gives one way to satisfy that point (the type must be repr(transparent)
).
Since all previous usage of TransparentWrapper
seems to have been built around this repr(transparent)
assumption, and since that's a higher bar than the basic "data layout compatible" criteria, then I think that we have to continue to require the high bar for the trait, and so I don't think we can accept any new impls that aren't repr(transparent)
.
repr(Rust)
doesn't guarantee much about alignment either (or call ABI).
The requirements are that which is required for soundness:
repr(packed)
),and so I don't think we can accept any new impls that aren't repr(transparent)
ok I'll just close this then, looks like what I was trying to remove unsafe from might not be safe then? Is this something miri don't catch?
I changed the commit if you do want the [T; 1]
impl
In your specific context it might be safe, depending on how much that situation was assuming.
If you've got a link to some code you can post about it in the #dark-arts
channel of the rust community discord (if you use discord that is), or you could open a new issue in this repo and approximately the same people would take a look there too.
Point (1) contains the word "either", but then only gives one way to satisfy that point (the type must be repr(transparent)).
I think this is why I got confused about what it exactly wanted. I thought #1 was just saying "Wrapper
must be a wrapper around Inner
with an identical data representations", I think the either is just confusing since the other option is wrapped in parentheses
When attempting to remove some unsafe code I came across the limitation that
TransparentWrapper<T>
isn't implemented for(T, ())
. I added the other two since they also make sense and I don't see a downside.