I still think that focusing too much on which functions are safe or unsafe is the wrong direction for making this better. It's whether the preconditions are met that's really important, and turning Foo::new_unchecked(x)
into unsafe.Foo::new_unchecked(x)
or whatever isn't really helping to focus the effort on the important part.
The particularly-bad problems I see in unsafe code are not that people don't know which things are unsafe, but they end up focusing on proving one of the preconditions, but forget the other one.
Code like this is really common, for example:
let next_four: &[u8] = &slice[..4];
// SAFETY: The slicing on the previous line ensures that we have
// sizeof(u32) == 4 bytes to read, and `u8` can't have padding or
// be uninitialized, so the `u32` will always be valid.
unsafe {
ptr::read(next_four.as_ptr() as *const u32)
}
That's clearly someone really trying to do it right, and knowing which methods are unsafe and being good about writing down their reasoning. But it's still unsound, because they remembered two of the things but forgot about the alignment requirement.
So if we have something (sketch) that instead helps get the preconditions right, then we can have larger unsafe
blocks again without issue.