diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 3e3f510e308c..265cadb49516 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -10,7 +10,7 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. -use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext}; +use borrow_check::nll::region_infer::RegionInferenceContext; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; @@ -248,7 +248,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( nonlexical_regioncx: regioncx, used_mut: FxHashSet(), used_mut_upvars: SmallVec::new(), - nonlexical_cause_info: None, borrow_set, dominators, }; @@ -367,7 +366,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// contains the results from region inference and lets us e.g. /// find out which CFG points are contained in each borrow region. nonlexical_regioncx: Rc>, - nonlexical_cause_info: Option, /// The set of borrows extracted from the MIR borrow_set: Rc>, diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 56e388a5b609..2807a4e8857e 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -32,13 +32,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let regioncx = &&self.nonlexical_regioncx; let mir = self.mir; - if self.nonlexical_cause_info.is_none() { - self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir)); - } - - let cause_info = self.nonlexical_cause_info.as_ref().unwrap(); - if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) { - match *cause.root_cause() { + let borrow_region_vid = regioncx.to_region_vid(borrow.region); + if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) { + match cause { Cause::LiveVar(local, location) => { match find_regular_use(mir, regioncx, borrow, location, local) { Some(p) => { 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 39f31531a9c3..d3d3750a98ad 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -101,7 +101,7 @@ struct RegionDefinition<'tcx> { /// NB: The variants in `Cause` are intentionally ordered. Lower /// values are preferred when it comes to error messages. Do not /// reorder willy nilly. -#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub(crate) enum Cause { /// point inserted because Local was live at the given Location LiveVar(Local, Location), @@ -115,23 +115,6 @@ pub(crate) enum Cause { /// part of the initial set of values for a universally quantified region UniversalRegion(RegionVid), - - /// Element E was added to R because there was some - /// outlives obligation `R: R1 @ P` and `R1` contained `E`. - Outlives { - /// the reason that R1 had E - original_cause: Rc, - - /// the point P from the relation - constraint_location: Location, - - /// The span indicating why we added the outlives constraint. - constraint_span: Span, - }, -} - -pub(crate) struct RegionCausalInfo { - inferred_values: RegionValues, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -477,21 +460,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// Re-execute the region inference, this time tracking causal information. - /// This is significantly slower, so it is done only when an error is being reported. - pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo { - let dfs_storage = &mut self.new_dfs_storage(); - let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(true)); - RegionCausalInfo { inferred_values } - } - /// Propagate the region constraints: this will grow the values /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) { self.dependency_map = Some(self.build_dependency_map()); - let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(false)); + let inferred_values = self.compute_region_values(mir, dfs_storage); self.inferred_values = Some(inferred_values); } @@ -500,7 +475,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage, - track_causes: TrackCauses, ) -> RegionValues { debug!("compute_region_values()"); debug!("compute_region_values: constraints={:#?}", { @@ -511,7 +485,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // The initial values for each region are derived from the liveness // constraints we have accumulated. - let mut inferred_values = self.liveness_constraints.duplicate(track_causes); + let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false)); let dependency_map = self.dependency_map.as_ref().unwrap(); @@ -1095,6 +1069,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag.emit(); } + crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option { + // Find some constraint `X: Y` where: + // - `fr1: X` transitively + // - and `Y` is live at `elem` + let index = self.blame_constraint(fr1, elem); + let region_sub = self.constraints[index].sub; + + // then return why `Y` was live at `elem` + self.liveness_constraints.cause(region_sub, elem) + } + /// Tries to finds a good span to blame for the fact that `fr1` /// contains `fr2`. fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex { @@ -1112,7 +1097,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let relevant_constraint = self.constraints .iter_enumerated() .filter_map(|(i, constraint)| { - if self.liveness_constraints.contains(constraint.sub, elem) { + if !self.liveness_constraints.contains(constraint.sub, elem) { None } else { influenced_fr1[constraint.sup] @@ -1163,16 +1148,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -impl RegionCausalInfo { - /// Returns the *reason* that the region `r` contains the given point. - pub(super) fn why_region_contains_point(&self, r: R, p: Location) -> Option> - where - R: ToRegionVid, - { - self.inferred_values.cause(r.to_region_vid(), p) - } -} - impl<'tcx> RegionDefinition<'tcx> { fn new(origin: RegionVariableOrigin) -> Self { // Create a new region definition. Note that, for free @@ -1316,31 +1291,3 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi }) } } - -trait CauseExt { - fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause; -} - -impl CauseExt for Rc { - /// Creates a derived cause due to an outlives constraint. - fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause { - Cause::Outlives { - original_cause: self.clone(), - constraint_location, - constraint_span, - } - } -} - -impl Cause { - pub(crate) fn root_cause(&self) -> &Cause { - match self { - Cause::LiveVar(..) - | Cause::DropVar(..) - | Cause::LiveOther(..) - | Cause::UniversalRegion(..) => self, - - Cause::Outlives { original_cause, .. } => original_cause.root_cause(), - } - } -} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index ce9397a25aa4..a25b6ef90188 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -8,17 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use borrow_check::nll::region_infer::TrackCauses; use rustc_data_structures::bitvec::SparseBitMatrix; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use rustc::mir::{BasicBlock, Location, Mir}; -use rustc::ty::{self, RegionVid}; +use rustc::ty::RegionVid; use std::fmt::Debug; use std::rc::Rc; use syntax::codemap::Span; -use super::{Cause, CauseExt, TrackCauses}; +use super::Cause; /// Maps between the various kinds of elements of a region value to /// the internal indices that w use. @@ -196,7 +197,7 @@ pub(super) struct RegionValues { causes: Option, } -type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc>; +type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Cause>; impl RegionValues { /// Creates a new set of "region values" that tracks causal information. @@ -255,7 +256,7 @@ impl RegionValues { debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i)); if let Some(causes) = &mut self.causes { - let cause = Rc::new(make_cause(causes)); + let cause = make_cause(causes); causes.insert((r, i), cause); } @@ -267,15 +268,8 @@ impl RegionValues { // #49998: compare using root cause alone to avoid // useless traffic from similar outlives chains. - let overwrite = if ty::tls::with(|tcx| { - tcx.sess.opts.debugging_opts.nll_subminimal_causes - }) { - cause.root_cause() < old_cause.root_cause() - } else { - cause < **old_cause - }; - if overwrite { - *old_cause = Rc::new(cause); + if cause < *old_cause { + *old_cause = cause; return true; } } @@ -294,13 +288,11 @@ impl RegionValues { from_region: RegionVid, to_region: RegionVid, elem: T, - constraint_location: Location, - constraint_span: Span, + _constraint_location: Location, + _constraint_span: Span, ) -> bool { let elem = self.elements.index(elem); - self.add_internal(to_region, elem, |causes| { - causes[&(from_region, elem)].outlives(constraint_location, constraint_span) - }) + self.add_internal(to_region, elem, |causes| causes[&(from_region, elem)]) } /// Adds all the universal regions outlived by `from_region` to @@ -445,7 +437,7 @@ impl RegionValues { /// /// Returns None if cause tracking is disabled or `elem` is not /// actually found in `r`. - pub(super) fn cause(&self, r: RegionVid, elem: T) -> Option> { + pub(super) fn cause(&self, r: RegionVid, elem: T) -> Option { let index = self.elements.index(elem); if let Some(causes) = &self.causes { causes.get(&(r, index)).cloned() diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr index fc288e6b1d61..2284f0784c54 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr @@ -2,19 +2,28 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:20:25 | LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | borrow later used here error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:26:25 | LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | borrow later used here error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:33:25 | LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | borrow later used here error: aborting due to 3 previous errors