Fat raw pointers into fat rust pointers


#1
fn bar<T: ?Sized>(x: &mut T) {
    let x: *mut T = x;
    let _: &mut T = unsafe {x.as_mut().unwrap()};
}
error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied
   --> src/lib.rs:100:31
    |
100 |     let _: &mut T = unsafe {x.as_mut().unwrap()};
    |                               ^^^^^^ `T` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = help: consider adding a `where T: std::marker::Sized` bound

From the documentation, it looks like <*mut T>::as_mut supports T: ?Sized (scroll up to the inherent impl’s bounds)… However, if you look at the source, you’ll see the that there is an explicit T: Sized hiding in as_mut's definition!

What’s up with that?


#2

Looks like all of the methods in that inherent impl have a Sized restriction, not just as_mut. It does seem strange.


#3

They use is_null(), which compares self == null() or self == null_mut(), but there’s no generic way to create such null pointers.

It seems feasible to just compare is_null() as thin pointers, self as *const u8 as usize == 0. That’s what Zeroable::is_zero() does for pointers, anyway. I’m going to try this and send a PR if it works out, then is_null(), as_ref(), and as_mut() can be T: ?Sized.


#4

https://github.com/rust-lang/rust/pull/44932


#5

is_null is a tricky one isn’t it? If you just compare one field (the pointer) to null, then for a fat pointer there are many null values. Might surprise someone down the line, don’t know if there is any worse impact than that.


#6

That’s true! We could apply the broadened test only for as_ref and as_mut, if that’s deemed too surprising, but I think it’s still reasonable for is_null. Maybe I’ll add a note to the docs that two pointers being null doesn’t necessarily imply their equality.