Hi, I was sure that
transmute<&Wrapper, &Inner>(...) or
*const Wrapper as *Const Inner.
But going over
UnsafeCell impl I've found this: https://doc.rust-lang.org/src/core/cell.rs.html#1543
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of // #[repr(transparent)]. This exploits libstd's special status, there is // no guarantee for user code that this will work in future versions of the compiler!
Does this mean that repr(transparent) doesn't work that way for everyone?
I think that might be because repr(transparent) on UnsafeCell isn't stabilized for end-users, or at least I see no mention in the docs
This part of the comment was added in https://github.com/rust-lang/rust/pull/66248 for reasons discussed there, seems more related to what we document about
get as being special) than repr(transparent) in particular.
However, there are significant caveats to "repr(transparent) allows type punning via pointer casts" -- e.g. transparent wrappers do not necessarily have the same safety and validity invariants as the type they wrap. Such issues can be ruled out if you control both types or the types provide sufficient documented guarantees, but libstd types don't usually give that many guarantees.
Indeed the main reason for that comment is the special status of
UnsafeCell::get. That is the only way to get an interior mutable pointer. This trumps
ah, so transmuting
&mut UnsafeCell<T> to
*mut T wouldn't also do it? Interesting. If so, is that written down somewhere?
(i mean somewhere outside of that one code comment on the unsafecell impl)
ah, so transmuting
*mut Twouldn't also do it? Interesting. If so, is that written down somewhere?
wait no that is no problem
the issue is about interior mutability
so, you cannot transmute
*mut T and write to it
oh, right right,
Okay but is that noted anywhere outside of the docs of libcore? Perhaps we should write it down somewhere.
well it's noted in
not sure which other place would fit?
FWIW I'd rather just get rid of this rule altogether. I'm pretty sure there's no good reason for it nowadays.
well, Stacked Borrows doesn't need it
but I am not sure if we are willing to commit to "whatever Stacked Borrows does" for interior mutability
get() isn't special to the compiler either, and I can't see why we'd ever want to change that. The special casing for
UnsafeCell that we have (e.g., whether statics are read-only memory, or whether aliasing attributes are added to LLVM IR) is all just based on "does this type contain an
earlier versions of stacked borrows relied on some really weird sequence of casts in
get to make things work
so just a normal transmute from
*mut T would not have worked
current Stacked Borrows handles this better and the transmute would be fine, but who knows what final model we end up with
(the transmute is still somewhat odd as the pointer remains "tagged", so if you ever lose provenance -- such as through an integer roundtrip -- you get UB.)
&UnsafeCell<T> as *const _ as *mut T is the better "non-
get" alternative. and that is entirely equivalent to
get as far as latest Stacked Borrows is concerned.
Hm, I see. Then I won't push further for this change right now. But still,
get should definitely not be magic :
transmute may be weird around pointer provenance in general, but the obvious
as cast really ought to work and IMO a formal model that can't make them work probably won't be satisfactory.