keep fake borrows alive until exiting their scopes - #162242
Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
keep fake borrows alive until exiting their scopes
There was a problem hiding this comment.
maybe this should have a test involving coroutine drops just to make sure nothing breaks horribly?
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (4162643): comparison URL. Overall result: ❌ regressions - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary 4.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 1.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.0%, secondary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 477.112s -> 479.569s (0.51%) |
|
@craterbot check |
|
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
r? @matthewjasper since I gave you those other PRs, but feel free to reassign. To address the pings regarding changing MIR syntax: I had to add derives for |
|
Some changes occurred in coverage tests. cc @Zalathar Some changes occurred in match lowering cc @Nadrieril This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @vakaras |
|
Another note for language team consideration: this only affects fake borrows. Separate from that, we also prevent mutation within guards of places we move/copy from to produce that arm's by-value bindings. That behavior is unaffected by this PR: fn fails() {
let mut x = 0;
match x {
// These are forbidden: there's a fake read for `y`'s ref-within-guard
// binding after the guard succeeds.
y if { x = 1; true } => {}
//~^ error[E0506]: cannot assign to `x` because it is borrowed
y if { x = 1; true } || return => {}
//~^ error[E0506]: cannot assign to `x` because it is borrowed
_ => {}
}
}
fn works() {
let mut x = 0;
match x {
// The fake read isn't present on failure, so this is fine:
y if { x = 1; true } && return => {}
// The fake read isn't present for by-ref bindings, so this is fine as
// long as we never use `y`.
ref y if { x = 1; true } => {}
_ => {}
}
}If changing this would be desirable, I'd prefer to save doing so for a follow-up. |
This is an alternative to #161581 and #161857 that implements a more restrictive semantics: fake borrowed places may not be mutated until execution leaves the fake borrow's scope (i.e. a match guard or the outermost indexing expression in a place expression).
Fixes #161578
Fixes #161852
In contrast to the above PRs, the following are also no longer allowed:
Not being sensitive to CFG shape should make this easier to describe at a high-level than #161581 and #161857 would be. The tradeoff here is implementation complexity: since borrow-checking is sensitive to CFG shape, this puts fake reads at every point where execution leaves fake borrows' scopes, as though the fake reads are drops. The resultant MIR might not be quite as nice in some cases as something purpose-built, but I think it's worth being able to reuse the machinery we have for drops.