I think this is really important. The current trend of "granular unsafe
" is a mitigation for not having it, but it's really not a great solution.
I keep imagining something where the requirements are spelled out separately, like
#[safety_requires(aligned(ptr), readable(ptr))]
unsafe fn read<T>(ptr: *const T);
Where the compiler doesn't actually know what aligned
and readable
mean, but when you use the function, you do something like
#[hold_my_beer(aligned(p), readable(p), aligned(q), readable(q))]
unsafe {
read(p) + read(q)
}
And some tool would check that you listed all the requirements for the variable, doing the name substitution as needed.
So you'd get
#[hold_my_beer(aligned(p), readable(p), aligned(q))]
unsafe {
read(p) + read(q) // ERROR: `readable(q)` is required
}
but you could also do
#[hold_my_beer(aligned(p), readable(p))]
unsafe {
read(p) + read(p)
}
because using the same fact twice is fine.
(This is all just a sketch; details and keywords and structure and everything are all placeholders.)