Repository navigation
Document universal &mut reborrows - #2373
Jules-Bertholet wants to merge 5 commits into
Conversation
| If the type of that value implements [`Copy`], then the value will be copied. | ||
|
|
||
| r[expr.move.mut-ref] | ||
| If the type of that value is `&mut T`, and the place expression is mutable, then the value will be reborrowed. This is equivalent to applying `&mut *` (a [dereference][deref] and then a [mutable borrow][borrow]) to the place. |
There was a problem hiding this comment.
What do you make of this example (the first example in the stabilization report) under the rule? How would we justify the reborrow here?
fn generic(_: impl Sized) {}
let x = &mut ();
generic(x);
generic(x);There was a problem hiding this comment.
The x in generic(x) is a "place expression in value expression context" with type &mut.
There was a problem hiding this comment.
The rule as written requires that the place expression be mutable, and x is not a mutable place expression.
(Perhaps it means to say, e.g., that a dereference of the place expression be mutable?)
There was a problem hiding this comment.
It should be "mutable or movable". Fixed
There was a problem hiding this comment.
What do you make of this, which is accepted by your PR but rejected by the rule?
struct S<'a>(&'a mut u8);
impl Drop for S<'_> { fn drop(&mut self) {} }
fn f(x: S<'_>) {
let y = x.0; // ERROR or OK?
*y = 1;
}There was a problem hiding this comment.
Good point. The current wording of the Reference concerning Drop isn't even grammatically correct lol (matches a singular with a plural). I've changed this again to just re-use the wording from expr.deref.mut
There was a problem hiding this comment.
Thanks. What do you make of this, which is accepted by your PR but (I believe) rejected by the rule?
struct S<'a>(&'a mut u8);
impl Drop for S<'_> { fn drop(&mut self) {} }
fn f(x: S<'_>) {
let b = Box::new(x);
let y = b.0; // ERROR or OK?
*y = 1;
}More broadly, it feels as though we're risking some duplication and doing a lot of case analysis. Looking at your PR and what it does, I wonder if we couldn't express this rule somewhat more simply, leaning on other Reference rules (and also capture the fact that let x = v[0];, for mut v: Vec<&mut T> doesn't work). Could we say, e.g.?
r[expr.move.mut-ref]
If the type of the value is&mut T(as determined without substituting generic parameters or revealing opaque types outside of their defining scopes), rather than moving it, a mutable borrow is taken of the dereferenced place, with the place itself evaluated in an immutable place expression context (see [expr.deref.traits] and [expr.array.index.trait]), subject to the rules for mutable borrows.
Note
Consequently, the borrow is an error when the place expression contains 1) a dereference (including automatic dereference) whose operand has a type other than a raw pointer type, a reference type, or Box<U> or 2) an index whose indexed expression (possibly after automatic dereferencing) has a type other than an array or slice type or whose index has a type other than usize, since a shared reference will be inserted. This is different from applying &mut * to the place, as that evaluates the place in a mutable place expression context.
Then, in expr.mut.valid-places, replace the &mut T entry to say:
- Dereference of a place expression with type
&mut Twhere that place expression is a mutable place expression, is a variable, or is obtained from one of those by any sequence of parenthesization, dereferencing of an expression of type&mut UorBox<U>, or field access or indexing of an array or slice by a value of typeusize(in either case, possibly after automatic dereferencing where that dereferencing is of an expression of type&mut UorBox<U>). Note: This is an exception to the requirement of the next rule.
Would that make sense? If so, perhaps let me push up some commits to that effect for your review, as I'm seeing a number of other related tightenings and cleanups that we should make (including revising expr.field.autoref-deref to refer to mutable place expression contexts).
There was a problem hiding this comment.
Yes, you are right that expr.deref.mut is wrong, it doesn't really handle your Box example either. Ideally we would fix in one place and reference that everywhere else. Feel free to commit whatever you like
Re-use phrasing from expr.deref.mut
Documents rust-lang/rust#163494.