From bbcace5080a73ea36417b1d4f6b846a2a01f9202 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 27 May 2018 11:15:52 +0100 Subject: [PATCH 1/8] Use precomputed DFS of borrows that out of scope at a location. --- src/librustc_mir/dataflow/impls/borrows.rs | 130 ++++++++++++++++++--- 1 file changed, 116 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 04c62854c5cbd..7018ab345db43 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -15,12 +15,13 @@ use rustc; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::region; -use rustc::mir::{self, Location, Place, Mir}; +use rustc::mir::{self, Location, Place, Mir, TerminatorKind}; use rustc::ty::TyCtxt; -use rustc::ty::RegionKind; +use rustc::ty::{RegionKind, RegionVid}; use rustc::ty::RegionKind::ReScope; use rustc_data_structures::bitslice::BitwiseOperator; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_set::IdxSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::Lrc; @@ -46,9 +47,103 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { root_scope: Option, borrow_set: Rc>, + borrows_out_of_scope_at_location: FxHashMap>, /// NLL region inference context with which NLL queries should be resolved - nonlexical_regioncx: Rc>, + _nonlexical_regioncx: Rc>, +} + +fn precompute_borrows_out_of_scope<'a, 'tcx>( + mir: &'a Mir<'tcx>, + regioncx: &Rc>, + borrows_out_of_scope_at_location: &mut FxHashMap>, + borrow_index: BorrowIndex, + borrow_region: RegionVid, + location: Location +) { + // Start by dealing with the current location. + if !regioncx.region_contains_point(borrow_region, location) { + borrows_out_of_scope_at_location + .entry(location.clone()) + .and_modify(|m| m.push(borrow_index)) + .or_insert(vec![ borrow_index ]); + } + + let bb_data = &mir[location.block]; + // If we are on the last statement, then check the terminator + // to determine which location to proceed to. + if location.statement_index == bb_data.statements.len() - 1 { + if let Some(ref terminator) = bb_data.terminator { + match terminator.kind { + TerminatorKind::Goto { target } | + TerminatorKind::FalseEdges { real_target: target, .. } | + TerminatorKind::FalseUnwind { real_target: target, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + }, + TerminatorKind::SwitchInt { ref targets, .. } => { + for block in targets { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + TerminatorKind::Drop { target, unwind, .. } | + TerminatorKind::DropAndReplace { target, unwind, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + + if let Some(unwind_block) = unwind { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, unwind_block.start_location() + ); + } + }, + TerminatorKind::Call { ref destination, cleanup, .. } => { + if let Some((_, block)) = destination { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + + if let Some(block) = cleanup { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + TerminatorKind::Assert { target, cleanup, .. } | + TerminatorKind::Yield { resume: target, drop: cleanup, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + + if let Some(block) = cleanup { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + _ => {}, + }; + }; + // If we're not on the last statement, then go to the next + // statement in this block. + } else { + precompute_borrows_out_of_scope(mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, + location.successor_within_block()); + } } impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { @@ -65,18 +160,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id) }); + let mut borrows_out_of_scope_at_location = FxHashMap(); + for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() { + let borrow_region = borrow_data.region.to_region_vid(); + let location = borrow_set.borrows[borrow_index].reserve_location; + + precompute_borrows_out_of_scope(mir, &nonlexical_regioncx, + &mut borrows_out_of_scope_at_location, + borrow_index, borrow_region, location); + } + Borrows { tcx: tcx, mir: mir, borrow_set: borrow_set.clone(), + borrows_out_of_scope_at_location, scope_tree, root_scope, - nonlexical_regioncx, + _nonlexical_regioncx: nonlexical_regioncx, } } crate fn borrows(&self) -> &IndexVec> { &self.borrow_set.borrows } - pub fn scope_tree(&self) -> &Lrc { &self.scope_tree } pub fn location(&self, idx: BorrowIndex) -> &Location { @@ -89,12 +194,10 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { fn kill_loans_out_of_scope_at_location(&self, sets: &mut BlockSets, location: Location) { - let 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. + // reflects the dataflow on entry to the statement. + // Iterate over each of the borrows that we've precomputed + // to have went out of scope at this location and kill them. // // We are careful always to call this function *before* we // set up the gen-bits for the statement or @@ -102,10 +205,9 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { // 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.borrow_set.borrows.iter_enumerated() { - let borrow_region = borrow_data.region.to_region_vid(); - if !regioncx.region_contains_point(borrow_region, location) { - sets.kill(&borrow_index); + if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { + for index in indices { + sets.kill(&index); } } } From 0eeebe179590836cb4d9307bbc13f31e7f2f80e5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 27 May 2018 11:31:05 +0100 Subject: [PATCH 2/8] Ensure that we don't skip the last statement. --- src/librustc_mir/dataflow/impls/borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 7018ab345db43..ed111c994f41a 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -70,9 +70,9 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( } let bb_data = &mir[location.block]; - // If we are on the last statement, then check the terminator + // If we are past the last statement, then check the terminator // to determine which location to proceed to. - if location.statement_index == bb_data.statements.len() - 1 { + if location.statement_index == bb_data.statements.len() { if let Some(ref terminator) = bb_data.terminator { match terminator.kind { TerminatorKind::Goto { target } | From 24ee5069134e6ee6b88487f229cd05e383e1a314 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 27 May 2018 22:26:10 +0100 Subject: [PATCH 3/8] Ensure that depth first search does not get stuck in cycles. --- src/librustc_mir/dataflow/impls/borrows.rs | 40 +++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index ed111c994f41a..317b62b22dc3a 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -59,9 +59,16 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( borrows_out_of_scope_at_location: &mut FxHashMap>, borrow_index: BorrowIndex, borrow_region: RegionVid, - location: Location + location: Location, + visited_locations: &mut Vec ) { - // Start by dealing with the current location. + // Check if we have already visited this location and skip + // it if we have - avoids infinite loops. + if visited_locations.contains(&location) { return; } + visited_locations.push(location.clone()); + + // Next, add the borrow index to the current location's vector if the region does + // not contain the point at that location (or create a new vector if required). if !regioncx.region_contains_point(borrow_region, location) { borrows_out_of_scope_at_location .entry(location.clone()) @@ -80,14 +87,16 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( TerminatorKind::FalseUnwind { real_target: target, .. } => { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location() + borrow_index, borrow_region, target.start_location(), + visited_locations ); }, TerminatorKind::SwitchInt { ref targets, .. } => { for block in targets { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location() + borrow_index, borrow_region, block.start_location(), + visited_locations ); } }, @@ -95,13 +104,15 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( TerminatorKind::DropAndReplace { target, unwind, .. } => { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location() + borrow_index, borrow_region, target.start_location(), + visited_locations ); if let Some(unwind_block) = unwind { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, unwind_block.start_location() + borrow_index, borrow_region, unwind_block.start_location(), + visited_locations ); } }, @@ -109,14 +120,16 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( if let Some((_, block)) = destination { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location() + borrow_index, borrow_region, block.start_location(), + visited_locations ); } if let Some(block) = cleanup { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location() + borrow_index, borrow_region, block.start_location(), + visited_locations ); } }, @@ -124,13 +137,15 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( TerminatorKind::Yield { resume: target, drop: cleanup, .. } => { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location() + borrow_index, borrow_region, target.start_location(), + visited_locations ); if let Some(block) = cleanup { precompute_borrows_out_of_scope( mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location() + borrow_index, borrow_region, block.start_location(), + visited_locations ); } }, @@ -142,7 +157,7 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( } else { precompute_borrows_out_of_scope(mir, regioncx, borrows_out_of_scope_at_location, borrow_index, borrow_region, - location.successor_within_block()); + location.successor_within_block(), visited_locations); } } @@ -167,7 +182,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { precompute_borrows_out_of_scope(mir, &nonlexical_regioncx, &mut borrows_out_of_scope_at_location, - borrow_index, borrow_region, location); + borrow_index, borrow_region, location, + &mut Vec::new()); } Borrows { From 4500fe004be6690971f2cab95f823d447d479699 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 29 May 2018 18:22:01 +0100 Subject: [PATCH 4/8] Refactored DFS to be much cleaner. Added continue after noting that borrow is out of scope at location. --- src/librustc_mir/dataflow/impls/borrows.rs | 126 +++++---------------- 1 file changed, 27 insertions(+), 99 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 317b62b22dc3a..af6eb517b1e58 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -15,13 +15,13 @@ use rustc; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::region; -use rustc::mir::{self, Location, Place, Mir, TerminatorKind}; +use rustc::mir::{self, Location, Place, Mir}; use rustc::ty::TyCtxt; use rustc::ty::{RegionKind, RegionVid}; use rustc::ty::RegionKind::ReScope; use rustc_data_structures::bitslice::BitwiseOperator; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_set::IdxSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::Lrc; @@ -60,104 +60,33 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( borrow_index: BorrowIndex, borrow_region: RegionVid, location: Location, - visited_locations: &mut Vec ) { - // Check if we have already visited this location and skip - // it if we have - avoids infinite loops. - if visited_locations.contains(&location) { return; } - visited_locations.push(location.clone()); - - // Next, add the borrow index to the current location's vector if the region does - // not contain the point at that location (or create a new vector if required). - if !regioncx.region_contains_point(borrow_region, location) { - borrows_out_of_scope_at_location - .entry(location.clone()) - .and_modify(|m| m.push(borrow_index)) - .or_insert(vec![ borrow_index ]); - } + // Keep track of places we've locations to check and locations that we have checked. + let mut stack = vec![ location ]; + let mut visited = FxHashSet(); + visited.insert(location); + + while let Some(location) = stack.pop() { + // If region does not contain a point at the location, then add to list and skip + // successor locations. + if !regioncx.region_contains_point(borrow_region, location) { + borrows_out_of_scope_at_location + .entry(location) + .or_insert(vec![]) + .push(borrow_index); + continue; + } - let bb_data = &mir[location.block]; - // If we are past the last statement, then check the terminator - // to determine which location to proceed to. - if location.statement_index == bb_data.statements.len() { + // Add successors to locations to visit, if not visited before. + let bb_data = &mir[location.block]; if let Some(ref terminator) = bb_data.terminator { - match terminator.kind { - TerminatorKind::Goto { target } | - TerminatorKind::FalseEdges { real_target: target, .. } | - TerminatorKind::FalseUnwind { real_target: target, .. } => { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location(), - visited_locations - ); - }, - TerminatorKind::SwitchInt { ref targets, .. } => { - for block in targets { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location(), - visited_locations - ); - } - }, - TerminatorKind::Drop { target, unwind, .. } | - TerminatorKind::DropAndReplace { target, unwind, .. } => { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location(), - visited_locations - ); - - if let Some(unwind_block) = unwind { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, unwind_block.start_location(), - visited_locations - ); - } - }, - TerminatorKind::Call { ref destination, cleanup, .. } => { - if let Some((_, block)) = destination { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location(), - visited_locations - ); - } - - if let Some(block) = cleanup { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location(), - visited_locations - ); - } - }, - TerminatorKind::Assert { target, cleanup, .. } | - TerminatorKind::Yield { resume: target, drop: cleanup, .. } => { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, target.start_location(), - visited_locations - ); - - if let Some(block) = cleanup { - precompute_borrows_out_of_scope( - mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, block.start_location(), - visited_locations - ); - } - }, - _ => {}, - }; - }; - // If we're not on the last statement, then go to the next - // statement in this block. - } else { - precompute_borrows_out_of_scope(mir, regioncx, borrows_out_of_scope_at_location, - borrow_index, borrow_region, - location.successor_within_block(), visited_locations); + for block in terminator.successors() { + let loc = block.start_location(); + if visited.insert(loc) { + stack.push(loc); + } + } + } } } @@ -182,8 +111,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { precompute_borrows_out_of_scope(mir, &nonlexical_regioncx, &mut borrows_out_of_scope_at_location, - borrow_index, borrow_region, location, - &mut Vec::new()); + borrow_index, borrow_region, location); } Borrows { From 9c637144f5e7761e04c62232a69993c30b5b797f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 May 2018 14:03:26 -0400 Subject: [PATCH 5/8] add some debugging statements --- src/librustc_mir/dataflow/impls/borrows.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index af6eb517b1e58..bd16e3ac5ff53 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -66,10 +66,13 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( let mut visited = FxHashSet(); visited.insert(location); + debug!("borrow {:?} starts at {:?}", borrow_index, location); + while let Some(location) = stack.pop() { // If region does not contain a point at the location, then add to list and skip // successor locations. if !regioncx.region_contains_point(borrow_region, location) { + debug!("borrow {:?} gets killed at {:?}", borrow_index, location); borrows_out_of_scope_at_location .entry(location) .or_insert(vec![]) From 62b1e6532adce4847153f6b6ac197d5906d389d0 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 29 May 2018 19:38:04 +0100 Subject: [PATCH 6/8] Ensure that all statements in block are visited not just successors of a block. --- src/librustc_mir/dataflow/impls/borrows.rs | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index bd16e3ac5ff53..b8949e0ad063b 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -66,8 +66,8 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( let mut visited = FxHashSet(); visited.insert(location); - debug!("borrow {:?} starts at {:?}", borrow_index, location); - + debug!("borrow {:?} (region: {:?}) starts at {:?}", + borrow_index, borrow_region, location); while let Some(location) = stack.pop() { // If region does not contain a point at the location, then add to list and skip // successor locations. @@ -80,15 +80,25 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( continue; } - // Add successors to locations to visit, if not visited before. let bb_data = &mir[location.block]; - if let Some(ref terminator) = bb_data.terminator { - for block in terminator.successors() { - let loc = block.start_location(); - if visited.insert(loc) { - stack.push(loc); + // If this is the last statement in the block, then add the + // terminator successors next. + if location.statement_index == bb_data.statements.len() - 1 { + // Add successors to locations to visit, if not visited before. + if let Some(ref terminator) = bb_data.terminator { + for block in terminator.successors() { + let loc = block.start_location(); + if visited.insert(loc) { + stack.push(loc); + } } } + } else { + // Visit next statement in block. + let loc = location.successor_within_block(); + if visited.insert(loc) { + stack.push(loc); + } } } } From 948f77c71ff8fdfda0bec2f335498e8de075799a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 May 2018 15:09:37 -0400 Subject: [PATCH 7/8] tweak debug output some more --- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 5a1ab73b2b814..dea2683789bdf 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -352,7 +352,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Returns access to the value of `r` for debugging purposes. - pub(super) fn region_value_str(&self, r: RegionVid) -> String { + crate fn region_value_str(&self, r: RegionVid) -> String { let inferred_values = self.inferred_values .as_ref() .expect("region values not yet inferred"); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index b8949e0ad063b..59ff12eface05 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -66,8 +66,13 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( let mut visited = FxHashSet(); visited.insert(location); - debug!("borrow {:?} (region: {:?}) starts at {:?}", - borrow_index, borrow_region, location); + debug!( + "borrow {:?} has region {:?} with value {:?}", + borrow_index, + borrow_region, + regioncx.region_value_str(borrow_region), + ); + debug!("borrow {:?} starts at {:?}", borrow_index, location); while let Some(location) = stack.pop() { // If region does not contain a point at the location, then add to list and skip // successor locations. From 3a9134dec568d39e3d9b064b532483eb9daa0a2c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 May 2018 15:09:48 -0400 Subject: [PATCH 8/8] fix off by one error --- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 59ff12eface05..cb3a14c411523 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -88,7 +88,7 @@ fn precompute_borrows_out_of_scope<'a, 'tcx>( let bb_data = &mir[location.block]; // If this is the last statement in the block, then add the // terminator successors next. - if location.statement_index == bb_data.statements.len() - 1 { + if location.statement_index == bb_data.statements.len() { // Add successors to locations to visit, if not visited before. if let Some(ref terminator) = bb_data.terminator { for block in terminator.successors() {