-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DROP
to DROP_IF
#558
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed. cc @rust-lang/compiler @rust-lang/compiler-contributors |
@rustbot second |
@rustbot label -final-comment-period +major-change-accepted |
Treat Drop as a rmw operation Previously, a Drop terminator was considered a move in MIR. This commit changes the behavior to only treat Drop as a mutable access to the dropped place. In order for this change to be correct, we need to guarantee that 1. A dropped value won't be used again 2. Places that appear in a drop won't be used again before a subsequent initialization. We can ensure this to be correct at MIR construction because Drop will only be emitted when a variable goes out of scope, thus having: * (1) as there is no way of reaching the old value. drop-elaboration will also remove any uninitialized drop. * (2) as the place can't be named following the end of the scope. However, the initialization status, previously tracked by moves, should also be tied to the execution of a Drop, hence the additional logic in the dataflow analyses. From discussion in [this thread](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/.60DROP.60.20to.20.60DROP_IF.60.20compiler-team.23558), originating from rust-lang/compiler-team#558. See also rust-lang#104488 (comment)
Treat Drop as a rmw operation Previously, a Drop terminator was considered a move in MIR. This commit changes the behavior to only treat Drop as a mutable access to the dropped place. In order for this change to be correct, we need to guarantee that 1. A dropped value won't be used again 2. Places that appear in a drop won't be used again before a subsequent initialization. We can ensure this to be correct at MIR construction because Drop will only be emitted when a variable goes out of scope, thus having: * (1) as there is no way of reaching the old value. drop-elaboration will also remove any uninitialized drop. * (2) as the place can't be named following the end of the scope. However, the initialization status, previously tracked by moves, should also be tied to the execution of a Drop, hence the additional logic in the dataflow analyses. From discussion in [this thread](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/.60DROP.60.20to.20.60DROP_IF.60.20compiler-team.23558), originating from rust-lang/compiler-team#558. See also rust-lang#104488 (comment)
Treat Drop as a rmw operation Previously, a Drop terminator was considered a move in MIR. This commit changes the behavior to only treat Drop as a mutable access to the dropped place. In order for this change to be correct, we need to guarantee that 1. A dropped value won't be used again 2. Places that appear in a drop won't be used again before a subsequent initialization. We can ensure this to be correct at MIR construction because Drop will only be emitted when a variable goes out of scope, thus having: * (1) as there is no way of reaching the old value. drop-elaboration will also remove any uninitialized drop. * (2) as the place can't be named following the end of the scope. However, the initialization status, previously tracked by moves, should also be tied to the execution of a Drop, hence the additional logic in the dataflow analyses. From discussion in [this thread](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/.60DROP.60.20to.20.60DROP_IF.60.20compiler-team.23558), originating from rust-lang/compiler-team#558. See also rust-lang#104488 (comment)
Proposal
This is a proposal to modify the MIR such that we can run "drop elaboration" before borrow check. This eliminates duplicate logic and simplifies borrow check, moving us closer to our goal of having borrow check run against MIR that is as close as possible to the MIR that we will use for codegen. It also establishes a single "analysis MIR" that is used for both borrow check and const-promotion/const-safety, and potentially other future analyses (e.g., user-provided analyses based on the stable MIR effort).
Background: How MIR and drop-evaluation works today
In MIR today, the semantics of
DROP
in MIR change over time:DROP(x)
means "dropx
if it is initialized at runtime".DROP(x)
for every variable that is going out of scope, without doing any sort of flow-sensitive analysis.DROP(x)
has this semantics.DROP(x)
wherex
is not initialized are removed.DROP(x)
may be expanded to statements likeDROP(x.y)
if only some fields are initialized.DROP(x)
is converted toif tmp { DROP(x) }
. This requires modifying the control-flow graph in non-trivial ways.The MIR itself has the following drop-related terminators:
Drop(Place)
-- drop the value at place, if it is initialized; after drop-elaboration, the place will always be initializedDropAndReplace(Place, Value)
-- drop the value at place, if it is initialized, and stuff inValue
if there is a panic (I think?)Proposal
Alter the MIR to have the following terminators:
DropIfInit(Place)
-- emitted only by MIR build, indicates we should dropPlace
if it is (dynamically) initializedDropIf(Operand, Place)
-- if operand is true, drop place (which must be initialized)DropAndReplaceIf(Operand, Place, Value)
-- if operand is true, drop place (which must be initialized)During MIR build, we create
DropIfInit
.Drop elaboration will convert to the other two, and hence most code can expect
DropIfInit
to never occur:DropIf(True, Place.F1)
etcF
can be introduced and we can then change toDropIf(F, Place)
DropIf(F, Place.F1)
.DropIf(True, X)
toDropIf(True, X.F)
andDropIf(True, X.G)
).Borrow check will run on this "fixed" IR. It can treat the operands to
DropIf
as trusted, meaning that it does not verify that the flagF
is true iff the value is initialized, but rather assumes that is true. Borrow check should, I believe, no longer need the "maybe initialized" analysis, however, because drop elaboration will already have removed or refined the drops using those results.Other analyses and codegen become very mildly more complicated, in that they have to take into account that
DropIf
now introduces a small bit of control-flow. But this control-flow is very simple, and amounts toif !Flag { goto next_block }; else Drop()
. In other words, the basic block is now an "extended basic block". I've not looked at codegen recently, so I don't know how much complexity is introduced here. If this is a problem, it could be reduced by a MIR->MIR transformation that ensures that convertsDropIf(F, P)
toif F { DropIf(True, P) }
.Update to the above: DropAndReplace
As discussed on Zulip, we need to investigate the best way to manage
DropAndReplace
. However, it is likely that we can remove it altogether in drop elaboration, just as we do today, and replace it withDropIf
and an assignment. This will require borrow check to treat drop as an&mut
access and not a move, but this is believed to be ok. The idea is that the borrow checker trusts that...DropIf
statements only apply to "maybe initialized" content -- there should be noDrop
orDropAndReplace
statements by the time the borrow check runs.DROP_IF
will evaluate to true when the place is initialized or false if it is not.Mentors or Reviewers
nikomatsakis to mentor. Giacomo Pasini is interested in implementing.
cc @oli-obk @RalfJung @ecstatic-morse and I guess @rust-lang/wg-mir-opt
This was previously discussed on Zulip around here.
Process
The main points of the Major Change Process are as follows:
@rustbot second
.-C flag
, then full team check-off is required.@rfcbot fcp merge
on either the MCP or the PR.You can read more about Major Change Proposals on forge.
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.
History
DropIf(true)
during MIR build. This was changed to a distinctDropIfInit
terminator at the suggestion of @bjorn3 so as to make the constructor more robust.DropAndReplaceIf
.The text was updated successfully, but these errors were encountered: