diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 85f05a10cd9d..e8bf543b70b6 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -139,11 +139,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { location: Location) { if let Some(regioncx) = self.nonlexical_regioncx { for (borrow_index, borrow_data) in self.borrows.iter_enumerated() { - let borrow_region = regioncx.region_value(borrow_data.region.to_region_index()); - if !borrow_region.may_contain_point(location) && location != borrow_data.location { - debug!("kill_loans_out_of_scope_at_location: kill{:?} \ - location={:?} borrow_data={:?}", borrow_index, location, borrow_data); - sets.kill(&borrow_index); + let borrow_region = borrow_data.region.to_region_index(); + 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(&borrow_index); + } } } } diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index 2dd9b85c2946..e24def2292ec 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -9,13 +9,12 @@ // except according to those terms. use rustc::ty::{self, RegionKind}; -use rustc::mir::{Location, Mir}; +use rustc::mir::Mir; use rustc::mir::transform::MirSource; use rustc::infer::InferCtxt; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use std::collections::BTreeSet; -use std::fmt; use util::liveness::{self, LivenessMode, LivenessResult, LocalSet}; use util as mir_util; @@ -151,39 +150,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }); } -#[derive(Clone, Default, PartialEq, Eq)] -pub struct Region { - points: BTreeSet, - free_regions: BTreeSet, -} - -impl fmt::Debug for Region { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.debug_set() - .entries(&self.points) - .entries(&self.free_regions) - .finish() - } -} - -impl Region { - pub fn add_point(&mut self, point: Location) -> bool { - self.points.insert(point) - } - - pub fn add_free_region(&mut self, region: RegionIndex) -> bool { - self.free_regions.insert(region) - } - - pub fn may_contain_point(&self, point: Location) -> bool { - self.points.contains(&point) - } - - pub fn may_contain_free_region(&self, region: RegionIndex) -> bool { - self.free_regions.contains(®ion) - } -} - newtype_index!(RegionIndex { DEBUG_FORMAT = "'_#{}r", }); diff --git a/src/librustc_mir/transform/nll/region_infer.rs b/src/librustc_mir/transform/nll/region_infer.rs index 195448226ec1..f4a7682e9d62 100644 --- a/src/librustc_mir/transform/nll/region_infer.rs +++ b/src/librustc_mir/transform/nll/region_infer.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Region, RegionIndex}; +use super::RegionIndex; use super::free_regions::FreeRegions; use rustc::infer::InferCtxt; use rustc::mir::{Location, Mir}; use rustc::ty; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; +use std::collections::BTreeSet; +use std::fmt; pub struct RegionInferenceContext<'tcx> { /// Contains the definition for every region variable. Region @@ -54,6 +56,41 @@ struct RegionDefinition<'tcx> { value: Region, } +/// The value of an individual region variable. Region variables +/// consist of a set of points in the CFG as well as a set of "free +/// regions", which are sometimes written as `end(R)`. These +/// correspond to the named lifetimes and refer to portions of the +/// caller's control-flow graph -- specifically some portion that can +/// be reached after we return. +#[derive(Clone, Default, PartialEq, Eq)] +struct Region { + points: BTreeSet, + free_regions: BTreeSet, +} + +impl fmt::Debug for Region { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.debug_set() + .entries(&self.points) + .entries(&self.free_regions) + .finish() + } +} + +impl Region { + fn add_point(&mut self, point: Location) -> bool { + self.points.insert(point) + } + + fn add_free_region(&mut self, region: RegionIndex) -> bool { + self.free_regions.insert(region) + } + + fn contains_point(&self, point: Location) -> bool { + self.points.contains(&point) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Constraint { sub: RegionIndex, @@ -157,10 +194,15 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> { self.definitions.indices() } - /// Returns the inferred value for the region `r`. + /// Returns true if the region `r` contains the point `p`. /// /// Until `solve()` executes, this value is not particularly meaningful. - pub fn region_value(&self, r: RegionIndex) -> &Region { + pub fn region_contains_point(&self, r: RegionIndex, p: Location) -> bool { + self.definitions[r].value.contains_point(p) + } + + /// Returns access to the value of `r` for debugging purposes. + pub(super) fn region_value(&self, r: RegionIndex) -> &fmt::Debug { &self.definitions[r].value } @@ -235,7 +277,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> { while let Some(p) = stack.pop() { debug!(" dfs: p={:?}", p); - if !from_region.may_contain_point(p) { + if !from_region.contains_point(p) { debug!(" not in from-region"); continue; }