Skip to content

Document universal &mut reborrows - #2373

Draft
Jules-Bertholet wants to merge 5 commits into
rust-lang:masterfrom
Jules-Bertholet:reborrow-everywhere
Draft

Jules-Bertholet wants to merge 5 commits into
rust-lang:masterfrom
Jules-Bertholet:reborrow-everywhere

Conversation

@Jules-Bertholet

Copy link
Copy Markdown
Contributor

Comment thread src/expressions.md Outdated
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.

@traviscross traviscross Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The x in generic(x) is a "place expression in value expression context" with type &mut.

@traviscross traviscross Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be "mutable or movable". Fixed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 T where 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 U or Box<U>, or field access or indexing of an array or slice by a value of type usize (in either case, possibly after automatic dereferencing where that dereferencing is of an expression of type &mut U or Box<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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants