I lost a long detailed draft of this, so I’ll keep it short this time. In my experience, the two most common miri-caught violations of the Unsafe Code Guidelines we have are:
- We materialize or hold onto a too-large reference when working with raw pointers
- We mess up pointer alignment in low-level code, often in niche cases like with ZSTs
This post is about the former. I am bothered by the former because it tends to be the consequence of a common problem: it’s a pain in the neck to offset a raw pointer to fields. As such, we often see code like:
// OOPS, we had a mutable ref to node.elem, and this aliases it! let node = &mut *node_ptr; // Code which doesn't actually access node.elem, but it doesn't matter node.next = ...; node.prev = ...;
let node = &mut *node_ptr; ptr::drop_in_place(&mut node.elem);
I contend that this would be less likely if we had the arrow operator, or some other way to ergonomically offset to fields without instantiating a reference.
ptr->field is an ergonomic alternative to
(*ptr).field, especially relevant when
ptr is a complex expression.
May alternatively be
.* if you object to arrow syntax.
ptr* work, from-which
ptr*.field naturally falls out.
NOTE: this proposal is ambiguous with
x*.0, as this may be “multiply x by floating point literal 0.0”
Field Access on Raw Pointers as Sugar for Offset
ptr.field equivalent to
((&?mut (*ptr).field) as *?mut FieldTy) (or more accurately
&raw (*ptr).field as defined by the raw reference RFC). This would allow things like
ptr.field.drop_in_place(), which is very nice. Although
*ptr.field = val is a bit surprising?
I believe there is no language-level ambiguity here though, as raw pointers have no fields, only methods. And
.read() method seems to be unambiguous since we don’t support getting a function pointer in this way. Adding such a function pointer sugar would likely be a footgun, and would cause trouble for the common idiom of
foo.field() being the common getter idiom.