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 = ...;
or:
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.
Related: the raw reference RFC is also contending with similar issues.
Possible solutions:
Arrow operator:
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.
Postfix deref:
Make 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
Make 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 foo.read
when foo
has .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.