diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 4c36deae1011..c61a57cdda0e 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -292,32 +292,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { location: Location, is_activations: bool) { if let Some(ref regioncx) = self.nonlexical_regioncx { + // NOTE: The state associated with a given `location` + // reflects the dataflow on entry to the statement. If it + // does not contain `borrow_region`, then then that means + // that the statement at `location` kills the borrow. + // + // We are careful always to call this function *before* we + // set up the gen-bits for the statement or + // termanator. That way, if the effect of the statement or + // terminator *does* introduce a new loan of the same + // region, then setting that gen-bit will override any + // potential kill introduced here. for (borrow_index, borrow_data) in self.borrows.iter_enumerated() { let borrow_region = borrow_data.region.to_region_vid(); if !regioncx.region_contains_point(borrow_region, location) { - // The region checker really considers the borrow - // to start at the point **after** the location of - // the borrow, but the borrow checker puts the gen - // directly **on** the location of the - // borrow. This results in a gen/kill both being - // generated for same point if we are not - // careful. Probably we should change the point of - // the gen, but for now we hackily account for the - // mismatch here by not generating a kill for the - // location on the borrow itself. - if location != borrow_data.location { - sets.kill(&ReserveOrActivateIndex::reserved(borrow_index)); - } - - // FIXME: the logic used to justify the above - // "accounting for mismatch" does not generalize - // to activations, so we set the kill-bits without - // that same location check here. - // - // But... can we get into a situation where the - // gen/kill bits are both sets in this case, in - // which case we *do* need an analogous guard of - // some kind? + sets.kill(&ReserveOrActivateIndex::reserved(borrow_index)); if is_activations { sets.kill(&ReserveOrActivateIndex::active(borrow_index)); } @@ -340,14 +329,18 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { panic!("could not find statement at location {:?}"); }); + // Do kills introduced by NLL before setting up any potential + // gens. (See NOTE in kill_loans_out_of_scope_at_location.) + self.kill_loans_out_of_scope_at_location(sets, location, is_activations); + if is_activations { - // INVARIANT: At this point, `sets.on_entry` should - // correctly reflect the reservations as we enter the - // statement (because accumulates_intrablock_state is - // overridden) + // INVARIANT: `sets.on_entry` accurately captures + // reservations on entry to statement (b/c + // accumulates_intrablock_state is overridden for + // ActiveBorrows). // - // Now compute effect of the statement on the activations - // themselves in the ActiveBorrows state. + // Now compute the activations generated by uses within + // the statement based on that reservation state. let mut find = FindPlaceUses { sets, assigned_map: &self.assigned_map }; find.visit_statement(location.block, stmt, location); } @@ -414,8 +407,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::Nop => {} } - - self.kill_loans_out_of_scope_at_location(sets, location, is_activations); } /// Models terminator effect in Reservations and ActiveBorrows @@ -429,9 +420,19 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { panic!("could not find block at location {:?}", location); }); + // Do kills introduced by NLL before setting up any potential + // gens. (See NOTE in kill_loans_out_of_scope_at_location.) + self.kill_loans_out_of_scope_at_location(sets, location, is_activations); + let term = block.terminator(); if is_activations { - // Any uses of reserved Places in the statement are now activated. + // INVARIANT: `sets.on_entry` accurately captures + // reservations on entry to terminator (b/c + // accumulates_intrablock_state is overridden for + // ActiveBorrows). + // + // Now compute effect of the terminator on the activations + // themselves in the ActiveBorrows state. let mut find = FindPlaceUses { sets, assigned_map: &self.assigned_map }; find.visit_terminator(location.block, term, location); } @@ -474,7 +475,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { mir::TerminatorKind::FalseEdges {..} | mir::TerminatorKind::Unreachable => {} } - self.kill_loans_out_of_scope_at_location(sets, location, is_activations); } }