-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
This can be sort-of considered a tracking issue for the implementation of rust-lang/rfcs#2025
Right now, two phase borrow support can only handle the very simple case where there is exactly one activation point. In particular, this means we can't expose two-phase borrows to user code since the following wouldn't work:
let x = &mut some_val;
if some_cond {
*x = 1;
} else {
*x = 2;
}
We also intentionally limit two-phase borrows to a very narrow subset of its possible applications; specifically cases where the compiler is injecting mutable auto borrows which are used as method/function parameters. In practice, this covers the following cases:
- using
x.some_method()
syntax, where some_method takes &mut self - using
Foo::some_method(&mut x, ...)
syntax - binary assignment operators (+=, -=, *=, etc.) Note this does /not/ include
IndexMut
operations at this time
Basically, things that desugar to method calls with a mutable self parameter with the exception of IndexMut
. The intention with these restrictions is leverage two-phase borrows to make MIR borrowck accept AST borrowck can, without introducing too much new flexibility (ref #48431 for a more detailed discussion of how and why this came to be). The eventual intention (per rust-lang/rfcs#2025) is to extend this to the general case outlined above, which is what this issue tracks.
Activity
pnkfelix commentedon Mar 28, 2018
I've become less convinced that we will actually want generalized two-phase borrows, as I commented earlier, (quoted here for convenient reference:
KiChjang commentedon Oct 11, 2018
Here is a sample code that highlights the deficiency of the current formulation:
(playground)
which results in
This is baffling because the
x.push(x.len());
statement did not throw an error, but somehow dereffing and callingSlice::get_mut
causes the mutable borrow to be activated prematurely.pnkfelix commentedon Dec 19, 2018
Hmm. I think this ties into broader questions of the semantics of two-phase borrows (see #56254) and how we document it (#46901).
pnkfelix commentedon Dec 19, 2018
In terms of re-triaging for #56754, I think this is NLL-complete, P-medium.
bluescreen303 commentedon Mar 12, 2019
I ran into a very similar issue, borrow-after-move, where a generalized two-phase solution would help and would make behaviours more as expected.
Please see https://stackoverflow.com/questions/55117392/am-i-misunderstanding-evaluation-order-borrow-of-moved-value
Tom-Phinney commentedon Mar 13, 2020
See also Avoiding "mutably borrowed" with std::mem::replace()
let
should preserve borrowing soundness on "pure" left arguments #77104jeapostrophe commentedon Sep 23, 2020
vec.swap(0, vec.len() - 1)
, whilevec.push(vec.len())
works. #74319pnkfelix commentedon May 27, 2022
Visting for T-compiler backlog bonanza.
I'm still of the opinion that I don't want us to invest too much effort in generalizing two-phase borrows without more formal proof of its soundness.
The new T-types team is in the best spot to produce that.
So, moving this to T-types and adding S-tracking-design-concerns:
@rustbot label: -T-compiler +T-types +S-tracking-design-concerns