Description
rust-lang/rfcs#2582 suggested the addition of a lint that warns against unnecessary intermediate references: expressions like &x as *const _
, that could be written as &raw const x
and thus avoid creating a reference. The rest of this RFC has been implemented (Cc #64490), but the lint has not -- that's what this issue tracks.
The essence of the problem is that direct_raw
and via_ref
below are not equivalent:
// This dos the equivalent of `ptr::offset` to the field, so as long as that is inbounds,
// all is good. No alignment is required.
fn direct_raw(x: *const (i32, i32)) -> *const i32 {
unsafe { &raw const (*x).0 }
}
// This creates a full reference to the first field, so that must be aligned and
// the entire field must be inbounds.
fn via_ref(x: *const (i32, i32)) -> *const i32 {
unsafe { &(*x).0 as *const i32 }
}
When people write the latter, we should nudge them towards the former, as that avoids UB. That said, the cases where that really makes a difference are probably rather rare: they occur when x
is unaligned for some reason, or when the beginning of the projected field is still in-bounds but the end of the field is not.
This is related to #99437 in that both are about "lint against cases where references are created but a raw pointer would have sufficed".
Unresolved questions:
- Maybe the lint should also cover cases that look like
&[mut] <place> as *[mut|const] ?T
in the surface syntax but had a method call inserted, thus manifesting a reference (with the associated guarantees). The lint as described would not fire because the reference actually gets used as such (being passed toderef
). However, what would the lint suggest to do instead? There just is no way to write this code without creating a reference.