Description
The following code is not even unsafe, so it certainly cannot be UB:
fn foo(ptr: *const bool) {
let _ = *ptr;
}
foo(&3u8 as *const u8 as *const bool);
This indicates that the pointer does not really get dereferenced, so the pointed-to data is never interpreted at type bool
and thus must not be valid. I am not sure I like this; *ptr
(as a value expression!) to me seems like it should conceptually perform the load even if the result is later discarded.
Something similar happens here:
fn bar(ptr: *const (i8, bool)) { unsafe {
let (x, _) = *ptr;
} }
This compiles effectively to let x = (*ptr).0
, so again whatever data is in the second field does not matter. (Note that *ptr
here occurs only as a place expression, not as a value expression, so it makes sense that in (*ptr).0
we do not require the second field to be valid.)
I think this behavior of "_" can be explained by saying that it suppresses the place-to-value coercion, and it is smart enough to even do this in cases like (x, _)
where the coercion is partially suppressed. But I am not sure I like this semantics, it seems rather counter-intuitive to me. It also makes patterns much harder to explain. And it leads to strange special cases such as rust-lang/rust#79735 (I cannot tell if this is some compiler author also being confused by "_", or if the intention is that !
is special in that even creating the place is already UB, or something else).