You would not need an UnsafeCell around the raw pointer itself, but depending on where you got the raw pointer from, you might need an UnsafeCell around what it points to.
Yes, it is fine. How you read or write to the pointer is irrelevant. The important part is that if you got the pointer by converting a Rust reference into a pointer, special rules apply to that pointer.
UnsafeCell purpose is to interact exclusively with shared references (&T type vs.&UnsafeCell<T>). So all is fine, unless you create or "imply" the existence of such a shared reference:
&'_ (*mut T) does not "imply" &'_ T,
but any dereferenceable pointer such as &'_ mut T or Box<T> do:
So you're saying that casting a &T to a *mut T will still cause UB if I violate the many immutable or 1 mutable ref contract (by e.g. calling ptr::write on the *mut T?
No, if you have a &T, that pointer can never be used to modify the T it points to. An &UnsafeCell<T> allows you to get an &mut T, sure, but if you are accessing the value through a &T instead of through the UnsafeCell, the usual rules apply
Sorry I meant what you are saying, that you have a &UnsafeCell<T>, then you can get mutable access to the T and the compiler can't assume that you won't.
Thanks for all the answers - it seems like the key takeaway is "it's not what the thing literally is that matters, it's what it semantically is" so if you have a &T then even though you can convert it to a *mut T you must not violate the contract to not mutate T, because it's still a &T to the compiler and so the compiler will assume T is immutable.
Yeah. The *mut T and *const T pointers are just lints that help make sure that you're doing the right thing. Besides sometimes requiring a cast due to these lints, the only difference is their variance.