Skip to content

Commit 560a5da

Browse files
committed
Auto merge of #46022 - matthewjasper:cannot-assign-twice-error, r=arielb1
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.
2 parents 58e1234 + d64a318 commit 560a5da

15 files changed

+575
-140
lines changed

src/librustc_mir/borrow_check.rs

+50-32
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use dataflow::{do_dataflow};
3131
use dataflow::{MoveDataParamEnv};
3232
use dataflow::{BitDenotation, BlockSets, DataflowResults, DataflowResultsConsumer};
3333
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
34-
use dataflow::{MovingOutStatements};
34+
use dataflow::{MovingOutStatements, EverInitializedLvals};
3535
use dataflow::{Borrows, BorrowData, BorrowIndex};
3636
use dataflow::move_paths::{MoveError, IllegalMoveOriginKind};
3737
use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult, MoveOutIndex};
@@ -130,6 +130,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
130130
let flow_move_outs = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
131131
MovingOutStatements::new(tcx, mir, &mdpe),
132132
|bd, i| &bd.move_data().moves[i]);
133+
let flow_ever_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
134+
EverInitializedLvals::new(tcx, mir, &mdpe),
135+
|bd, i| &bd.move_data().inits[i]);
133136

134137
let mut mbcx = MirBorrowckCtxt {
135138
tcx: tcx,
@@ -143,7 +146,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
143146
let mut state = InProgress::new(flow_borrows,
144147
flow_inits,
145148
flow_uninits,
146-
flow_move_outs);
149+
flow_move_outs,
150+
flow_ever_inits);
147151

148152
mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
149153
}
@@ -167,6 +171,7 @@ pub struct InProgress<'b, 'gcx: 'tcx, 'tcx: 'b> {
167171
inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
168172
uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
169173
move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
174+
ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
170175
}
171176

172177
struct FlowInProgress<BD> where BD: BitDenotation {
@@ -190,7 +195,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
190195
flow_state.each_flow(|b| b.reset_to_entry_of(bb),
191196
|i| i.reset_to_entry_of(bb),
192197
|u| u.reset_to_entry_of(bb),
193-
|m| m.reset_to_entry_of(bb));
198+
|m| m.reset_to_entry_of(bb),
199+
|e| e.reset_to_entry_of(bb));
194200
}
195201

196202
fn reconstruct_statement_effect(&mut self,
@@ -199,7 +205,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
199205
flow_state.each_flow(|b| b.reconstruct_statement_effect(location),
200206
|i| i.reconstruct_statement_effect(location),
201207
|u| u.reconstruct_statement_effect(location),
202-
|m| m.reconstruct_statement_effect(location));
208+
|m| m.reconstruct_statement_effect(location),
209+
|e| e.reconstruct_statement_effect(location));
203210
}
204211

205212
fn apply_local_effect(&mut self,
@@ -208,7 +215,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
208215
flow_state.each_flow(|b| b.apply_local_effect(),
209216
|i| i.apply_local_effect(),
210217
|u| u.apply_local_effect(),
211-
|m| m.apply_local_effect());
218+
|m| m.apply_local_effect(),
219+
|e| e.apply_local_effect());
212220
}
213221

214222
fn reconstruct_terminator_effect(&mut self,
@@ -217,7 +225,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
217225
flow_state.each_flow(|b| b.reconstruct_terminator_effect(location),
218226
|i| i.reconstruct_terminator_effect(location),
219227
|u| u.reconstruct_terminator_effect(location),
220-
|m| m.reconstruct_terminator_effect(location));
228+
|m| m.reconstruct_terminator_effect(location),
229+
|e| e.reconstruct_terminator_effect(location));
221230
}
222231

223232
fn visit_block_entry(&mut self,
@@ -750,22 +759,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
750759
}
751760

752761
if let Some(mpi) = self.move_path_for_lvalue(lvalue) {
753-
if flow_state.inits.curr_state.contains(&mpi) {
754-
// may already be assigned before reaching this statement;
755-
// report error.
756-
// FIXME: Not ideal, it only finds the assignment that lexically comes first
757-
let assigned_lvalue = &move_data.move_paths[mpi].lvalue;
758-
let assignment_stmt = self.mir.basic_blocks().iter().filter_map(|bb| {
759-
bb.statements.iter().find(|stmt| {
760-
if let StatementKind::Assign(ref lv, _) = stmt.kind {
761-
*lv == *assigned_lvalue
762-
} else {
763-
false
764-
}
765-
})
766-
}).next().unwrap();
767-
self.report_illegal_reassignment(
768-
context, (lvalue, span), assignment_stmt.source_info.span);
762+
for ii in &move_data.init_path_map[mpi] {
763+
if flow_state.ever_inits.curr_state.contains(ii) {
764+
let first_assign_span = self.move_data.inits[*ii].span;
765+
self.report_illegal_reassignment(
766+
context, (lvalue, span), first_assign_span);
767+
break;
768+
}
769769
}
770770
}
771771
}
@@ -1586,13 +1586,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15861586
_context: Context,
15871587
(lvalue, span): (&Lvalue<'tcx>, Span),
15881588
assigned_span: Span) {
1589-
self.tcx.cannot_reassign_immutable(span,
1589+
let mut err = self.tcx.cannot_reassign_immutable(span,
15901590
&self.describe_lvalue(lvalue),
1591-
Origin::Mir)
1592-
.span_label(span, "cannot assign twice to immutable variable")
1593-
.span_label(assigned_span, format!("first assignment to `{}`",
1594-
self.describe_lvalue(lvalue)))
1595-
.emit();
1591+
Origin::Mir);
1592+
err.span_label(span, "cannot assign twice to immutable variable");
1593+
if span != assigned_span {
1594+
err.span_label(assigned_span, format!("first assignment to `{}`",
1595+
self.describe_lvalue(lvalue)));
1596+
}
1597+
err.emit();
15961598
}
15971599

15981600
fn report_assignment_to_static(&mut self,
@@ -1852,30 +1854,35 @@ impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
18521854
pub(super) fn new(borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>,
18531855
inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
18541856
uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
1855-
move_out: DataflowResults<MovingOutStatements<'b, 'gcx, 'tcx>>)
1857+
move_out: DataflowResults<MovingOutStatements<'b, 'gcx, 'tcx>>,
1858+
ever_inits: DataflowResults<EverInitializedLvals<'b, 'gcx, 'tcx>>)
18561859
-> Self {
18571860
InProgress {
18581861
borrows: FlowInProgress::new(borrows),
18591862
inits: FlowInProgress::new(inits),
18601863
uninits: FlowInProgress::new(uninits),
1861-
move_outs: FlowInProgress::new(move_out)
1864+
move_outs: FlowInProgress::new(move_out),
1865+
ever_inits: FlowInProgress::new(ever_inits)
18621866
}
18631867
}
18641868

1865-
fn each_flow<XB, XI, XU, XM>(&mut self,
1869+
fn each_flow<XB, XI, XU, XM, XE>(&mut self,
18661870
mut xform_borrows: XB,
18671871
mut xform_inits: XI,
18681872
mut xform_uninits: XU,
1869-
mut xform_move_outs: XM) where
1873+
mut xform_move_outs: XM,
1874+
mut xform_ever_inits: XE) where
18701875
XB: FnMut(&mut FlowInProgress<Borrows<'b, 'gcx, 'tcx>>),
18711876
XI: FnMut(&mut FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>),
18721877
XU: FnMut(&mut FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>),
18731878
XM: FnMut(&mut FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>),
1879+
XE: FnMut(&mut FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>),
18741880
{
18751881
xform_borrows(&mut self.borrows);
18761882
xform_inits(&mut self.inits);
18771883
xform_uninits(&mut self.uninits);
18781884
xform_move_outs(&mut self.move_outs);
1885+
xform_ever_inits(&mut self.ever_inits);
18791886
}
18801887

18811888
fn summary(&self) -> String {
@@ -1932,6 +1939,17 @@ impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
19321939
&self.move_outs.base_results.operator().move_data().moves[mpi_move_out];
19331940
s.push_str(&format!("{:?}", move_out));
19341941
});
1942+
s.push_str("] ");
1943+
1944+
s.push_str("ever_init: [");
1945+
let mut saw_one = false;
1946+
self.ever_inits.each_state_bit(|mpi_ever_init| {
1947+
if saw_one { s.push_str(", "); };
1948+
saw_one = true;
1949+
let ever_init =
1950+
&self.ever_inits.base_results.operator().move_data().inits[mpi_ever_init];
1951+
s.push_str(&format!("{:?}", ever_init));
1952+
});
19351953
s.push_str("]");
19361954

19371955
return s;

src/librustc_mir/dataflow/drop_flag_effects.rs

+34-41
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use util::elaborate_drops::DropFlagState;
1414

1515
use super::{MoveDataParamEnv};
1616
use super::indexes::MovePathIndex;
17-
use super::move_paths::{MoveData, LookupResult};
17+
use super::move_paths::{MoveData, LookupResult, InitKind};
1818

1919
pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
2020
path: MovePathIndex,
@@ -197,47 +197,40 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>(
197197
|mpi| callback(mpi, DropFlagState::Absent))
198198
}
199199

200-
let block = &mir[loc.block];
201-
match block.statements.get(loc.statement_index) {
202-
Some(stmt) => match stmt.kind {
203-
mir::StatementKind::SetDiscriminant{ .. } => {
204-
span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck");
205-
}
206-
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
207-
match rvalue.initialization_state() {
208-
mir::tcx::RvalueInitializationState::Shallow => {
209-
debug!("drop_flag_effects: box assignment {:?}", stmt);
210-
if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(lvalue) {
211-
callback(mpi, DropFlagState::Present);
212-
}
213-
}
214-
mir::tcx::RvalueInitializationState::Deep => {
215-
debug!("drop_flag_effects: assignment {:?}", stmt);
216-
on_lookup_result_bits(tcx, mir, move_data,
217-
move_data.rev_lookup.find(lvalue),
218-
|mpi| callback(mpi, DropFlagState::Present))
219-
}
220-
}
221-
}
222-
mir::StatementKind::StorageLive(_) |
223-
mir::StatementKind::StorageDead(_) |
224-
mir::StatementKind::InlineAsm { .. } |
225-
mir::StatementKind::EndRegion(_) |
226-
mir::StatementKind::Validate(..) |
227-
mir::StatementKind::Nop => {}
228-
},
229-
None => {
230-
debug!("drop_flag_effects: replace {:?}", block.terminator());
231-
match block.terminator().kind {
232-
mir::TerminatorKind::DropAndReplace { ref location, .. } => {
233-
on_lookup_result_bits(tcx, mir, move_data,
234-
move_data.rev_lookup.find(location),
235-
|mpi| callback(mpi, DropFlagState::Present))
236-
}
237-
_ => {
238-
// other terminators do not contain move-ins
239-
}
200+
debug!("drop_flag_effects: assignment for location({:?})", loc);
201+
202+
for_location_inits(
203+
tcx,
204+
mir,
205+
move_data,
206+
loc,
207+
|mpi| callback(mpi, DropFlagState::Present)
208+
);
209+
}
210+
211+
pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>(
212+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
213+
mir: &Mir<'tcx>,
214+
move_data: &MoveData<'tcx>,
215+
loc: Location,
216+
mut callback: F)
217+
where F: FnMut(MovePathIndex)
218+
{
219+
for ii in &move_data.init_loc_map[loc] {
220+
let init = move_data.inits[*ii];
221+
match init.kind {
222+
InitKind::Deep => {
223+
let path = init.path;
224+
225+
on_all_children_bits(tcx, mir, move_data,
226+
path,
227+
&mut callback)
228+
},
229+
InitKind::Shallow => {
230+
let mpi = init.path;
231+
callback(mpi);
240232
}
233+
InitKind::NonPanicPathOnly => (),
241234
}
242235
}
243236
}

0 commit comments

Comments
 (0)