-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) #46022
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
Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) #46022
Conversation
r? @pnkfelix |
I don't think loop {
let x = String::new();
drop(x);
} You probably want to create a separate dataflow for "propagating initializations" (basically the opposite of the |
838def0
to
8347043
Compare
Nice PR. However, I think we are getting quite a bit of separate move-in implementation sprawl - there are already 2, and now we're getting another one. I think we can merge them - that would imply changing the For that, you'll need to have some sort of flag on the |
@@ -337,6 +369,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { | |||
} | |||
if let Some((ref destination, _bb)) = *destination { | |||
self.create_move_path(destination); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only initializes the destination on the non-panic-path, so you'll probably want some label on the Init
you create to indicate that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
self.mir, | ||
move_data, | ||
move_data.rev_lookup.find(dest_lval), | ||
|mpi| for ii in &init_path_map[mpi] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong - you don't want to "christmas tree" every initialization for this lvalue, you want just the initialization for the call.
e.g. in a code like
let x;
if true {
x = 2;
} else {
x = get();
x = 3;
}
You want to highlight just the get
, not the other assignment to x
.
If you want to do this correctly, you could just do
let call_loc = Location { // why doesn't MIR have a terminator_loc method?
block: call_bb, // feel free to add one
statement_index: self.mir[call_bb].statements.len()
};
for init_index in &init_loc_map[call_loc] {
zero_to_one(sets.gen_set.words_mut(), *init_index);
}
r=me with the initialization sprawl bought under control. |
@matthewjasper the title of this PR still says "[WIP]", but it looks like your review is close to finished. Please make sure to remove that if you feel this PR should be merged. |
How are you doing with this PR? Could you address the nits so we can move forward? |
8347043
to
d895346
Compare
Comments addressed. |
src/librustc_mir/borrow_check.rs
Outdated
self.report_illegal_reassignment( | ||
context, (lvalue, span), assignment_stmt.source_info.span); | ||
for ii in &move_data.init_path_map[mpi] { | ||
if flow_state.ever_inits.curr_state.contains(ii) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: opening brace for if
s is in the same line as the if
:
if flow_state.ever_inits.curr_state.contains(ii) {
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: no newline at end of file
let bits_per_block = self.bits_per_block(); | ||
for init_index in &init_loc_map[location] { | ||
assert!(init_index.index() < bits_per_block); | ||
zero_to_one(sets.gen_set.words_mut(), *init_index); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use a in_out.add
rather than a zero_to_one
here - I'm not sure of a good reason for this to always be for an uninitialized variable (it could be that right now we only assign to temporaries, but that might not remain so in the future).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, even if it doesn't matter for borrow-check (because you can't have assignments in the panic path) you should not mark call destinations as uninitialized if the call unwinds (i.e. if the init loc map entry is a NonPanicPathOnly).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean as initialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea my bad
let path = self.data.rev_lookup.locals[arg]; | ||
let span = self.mir.local_decls[arg].source_info.span; | ||
|
||
let init = self.data.inits.push(Init { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want to have arguments assigned before the first statement, to avoid edge cases such as my wrong.
This is cool. r=me modulo nits |
356316b
to
88776fd
Compare
Nits addressed |
* Used for new dataflow to track if a variable has every been initialized * Used for other dataflows that need to be updated for initializations
Matches current ast-borrowck behavior.
88776fd
to
d64a318
Compare
@bors r+ |
📌 Commit d64a318 has been approved by |
…rror, r=arielb1 Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) - Closes rust-lang#45199 - Don't allow assigning to dropped immutable variables - Show the "first assignment" note on the first assignment that can actually come before the second assignment. - Make "first assignment" notes point to function parameters if needed. - Don't show a "first assignment" note if the first and second assignment have the same span (in a loop). This matches ast borrowck for now, but maybe this we should add "in previous loop iteration" as with some other borrowck errors. (Commit 2) - Use revisions to check mir borrowck for the existing tests for this error. (Commit 3) ~~Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments.~~ Now using a new dataflow pass.
…elb1 Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) - Closes #45199 - Don't allow assigning to dropped immutable variables - Show the "first assignment" note on the first assignment that can actually come before the second assignment. - Make "first assignment" notes point to function parameters if needed. - Don't show a "first assignment" note if the first and second assignment have the same span (in a loop). This matches ast borrowck for now, but maybe this we should add "in previous loop iteration" as with some other borrowck errors. (Commit 2) - Use revisions to check mir borrowck for the existing tests for this error. (Commit 3) ~~Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments.~~ Now using a new dataflow pass.
☀️ Test successful - status-appveyor, status-travis |
Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments.Now using a new dataflow pass.