Skip to content

Commit ed72950

Browse files
committed
rework causal tracking to explore outlives relationships
Instead of tracking the "cause" of each bit that gets added, try to recover that by walking outlives relationships. This is currently imprecise, since it ignores the "point" where the outlives relationship is incurred -- but that's ok, since we're about to stop considering that overall in a later commit. This does seem to affect one error message negatively, I didn't dig *too* hard to find out why.
1 parent 1fb17ab commit ed72950

File tree

5 files changed

+42
-100
lines changed

5 files changed

+42
-100
lines changed

src/librustc_mir/borrow_check/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! This query borrow-checks the MIR to (further) ensure it is not broken.
1212
13-
use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext};
13+
use borrow_check::nll::region_infer::RegionInferenceContext;
1414
use rustc::hir;
1515
use rustc::hir::def_id::DefId;
1616
use rustc::hir::map::definitions::DefPathData;
@@ -248,7 +248,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
248248
nonlexical_regioncx: regioncx,
249249
used_mut: FxHashSet(),
250250
used_mut_upvars: SmallVec::new(),
251-
nonlexical_cause_info: None,
252251
borrow_set,
253252
dominators,
254253
};
@@ -367,7 +366,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
367366
/// contains the results from region inference and lets us e.g.
368367
/// find out which CFG points are contained in each borrow region.
369368
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
370-
nonlexical_cause_info: Option<RegionCausalInfo>,
371369

372370
/// The set of borrows extracted from the MIR
373371
borrow_set: Rc<BorrowSet<'tcx>>,

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3232
let regioncx = &&self.nonlexical_regioncx;
3333
let mir = self.mir;
3434

35-
if self.nonlexical_cause_info.is_none() {
36-
self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
37-
}
38-
39-
let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
40-
if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
41-
match *cause.root_cause() {
35+
let borrow_region_vid = regioncx.to_region_vid(borrow.region);
36+
if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) {
37+
match cause {
4238
Cause::LiveVar(local, location) => {
4339
match find_regular_use(mir, regioncx, borrow, location, local) {
4440
Some(p) => {

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 15 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ struct RegionDefinition<'tcx> {
101101
/// NB: The variants in `Cause` are intentionally ordered. Lower
102102
/// values are preferred when it comes to error messages. Do not
103103
/// reorder willy nilly.
104-
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
104+
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
105105
pub(crate) enum Cause {
106106
/// point inserted because Local was live at the given Location
107107
LiveVar(Local, Location),
@@ -115,23 +115,6 @@ pub(crate) enum Cause {
115115

116116
/// part of the initial set of values for a universally quantified region
117117
UniversalRegion(RegionVid),
118-
119-
/// Element E was added to R because there was some
120-
/// outlives obligation `R: R1 @ P` and `R1` contained `E`.
121-
Outlives {
122-
/// the reason that R1 had E
123-
original_cause: Rc<Cause>,
124-
125-
/// the point P from the relation
126-
constraint_location: Location,
127-
128-
/// The span indicating why we added the outlives constraint.
129-
constraint_span: Span,
130-
},
131-
}
132-
133-
pub(crate) struct RegionCausalInfo {
134-
inferred_values: RegionValues,
135118
}
136119

137120
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -477,21 +460,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
477460
}
478461
}
479462

480-
/// Re-execute the region inference, this time tracking causal information.
481-
/// This is significantly slower, so it is done only when an error is being reported.
482-
pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
483-
let dfs_storage = &mut self.new_dfs_storage();
484-
let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(true));
485-
RegionCausalInfo { inferred_values }
486-
}
487-
488463
/// Propagate the region constraints: this will grow the values
489464
/// for each region variable until all the constraints are
490465
/// satisfied. Note that some values may grow **too** large to be
491466
/// feasible, but we check this later.
492467
fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) {
493468
self.dependency_map = Some(self.build_dependency_map());
494-
let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(false));
469+
let inferred_values = self.compute_region_values(mir, dfs_storage);
495470
self.inferred_values = Some(inferred_values);
496471
}
497472

@@ -500,7 +475,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
500475
&self,
501476
mir: &Mir<'tcx>,
502477
dfs_storage: &mut dfs::DfsStorage,
503-
track_causes: TrackCauses,
504478
) -> RegionValues {
505479
debug!("compute_region_values()");
506480
debug!("compute_region_values: constraints={:#?}", {
@@ -511,7 +485,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
511485

512486
// The initial values for each region are derived from the liveness
513487
// constraints we have accumulated.
514-
let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
488+
let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false));
515489

516490
let dependency_map = self.dependency_map.as_ref().unwrap();
517491

@@ -1095,6 +1069,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10951069
diag.emit();
10961070
}
10971071

1072+
crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
1073+
// Find some constraint `X: Y` where:
1074+
// - `fr1: X` transitively
1075+
// - and `Y` is live at `elem`
1076+
let index = self.blame_constraint(fr1, elem);
1077+
let region_sub = self.constraints[index].sub;
1078+
1079+
// then return why `Y` was live at `elem`
1080+
self.liveness_constraints.cause(region_sub, elem)
1081+
}
1082+
10981083
/// Tries to finds a good span to blame for the fact that `fr1`
10991084
/// contains `fr2`.
11001085
fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
@@ -1112,7 +1097,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11121097
let relevant_constraint = self.constraints
11131098
.iter_enumerated()
11141099
.filter_map(|(i, constraint)| {
1115-
if self.liveness_constraints.contains(constraint.sub, elem) {
1100+
if !self.liveness_constraints.contains(constraint.sub, elem) {
11161101
None
11171102
} else {
11181103
influenced_fr1[constraint.sup]
@@ -1163,16 +1148,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11631148
}
11641149
}
11651150

1166-
impl RegionCausalInfo {
1167-
/// Returns the *reason* that the region `r` contains the given point.
1168-
pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
1169-
where
1170-
R: ToRegionVid,
1171-
{
1172-
self.inferred_values.cause(r.to_region_vid(), p)
1173-
}
1174-
}
1175-
11761151
impl<'tcx> RegionDefinition<'tcx> {
11771152
fn new(origin: RegionVariableOrigin) -> Self {
11781153
// Create a new region definition. Note that, for free
@@ -1316,31 +1291,3 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
13161291
})
13171292
}
13181293
}
1319-
1320-
trait CauseExt {
1321-
fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause;
1322-
}
1323-
1324-
impl CauseExt for Rc<Cause> {
1325-
/// Creates a derived cause due to an outlives constraint.
1326-
fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause {
1327-
Cause::Outlives {
1328-
original_cause: self.clone(),
1329-
constraint_location,
1330-
constraint_span,
1331-
}
1332-
}
1333-
}
1334-
1335-
impl Cause {
1336-
pub(crate) fn root_cause(&self) -> &Cause {
1337-
match self {
1338-
Cause::LiveVar(..)
1339-
| Cause::DropVar(..)
1340-
| Cause::LiveOther(..)
1341-
| Cause::UniversalRegion(..) => self,
1342-
1343-
Cause::Outlives { original_cause, .. } => original_cause.root_cause(),
1344-
}
1345-
}
1346-
}

src/librustc_mir/borrow_check/nll/region_infer/values.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use borrow_check::nll::region_infer::TrackCauses;
1112
use rustc_data_structures::bitvec::SparseBitMatrix;
1213
use rustc_data_structures::fx::FxHashMap;
1314
use rustc_data_structures::indexed_vec::Idx;
1415
use rustc_data_structures::indexed_vec::IndexVec;
1516
use rustc::mir::{BasicBlock, Location, Mir};
16-
use rustc::ty::{self, RegionVid};
17+
use rustc::ty::RegionVid;
1718
use std::fmt::Debug;
1819
use std::rc::Rc;
1920
use syntax::codemap::Span;
2021

21-
use super::{Cause, CauseExt, TrackCauses};
22+
use super::Cause;
2223

2324
/// Maps between the various kinds of elements of a region value to
2425
/// the internal indices that w use.
@@ -196,7 +197,7 @@ pub(super) struct RegionValues {
196197
causes: Option<CauseMap>,
197198
}
198199

199-
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
200+
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Cause>;
200201

201202
impl RegionValues {
202203
/// Creates a new set of "region values" that tracks causal information.
@@ -255,7 +256,7 @@ impl RegionValues {
255256
debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
256257

257258
if let Some(causes) = &mut self.causes {
258-
let cause = Rc::new(make_cause(causes));
259+
let cause = make_cause(causes);
259260
causes.insert((r, i), cause);
260261
}
261262

@@ -267,15 +268,8 @@ impl RegionValues {
267268
// #49998: compare using root cause alone to avoid
268269
// useless traffic from similar outlives chains.
269270

270-
let overwrite = if ty::tls::with(|tcx| {
271-
tcx.sess.opts.debugging_opts.nll_subminimal_causes
272-
}) {
273-
cause.root_cause() < old_cause.root_cause()
274-
} else {
275-
cause < **old_cause
276-
};
277-
if overwrite {
278-
*old_cause = Rc::new(cause);
271+
if cause < *old_cause {
272+
*old_cause = cause;
279273
return true;
280274
}
281275
}
@@ -294,13 +288,11 @@ impl RegionValues {
294288
from_region: RegionVid,
295289
to_region: RegionVid,
296290
elem: T,
297-
constraint_location: Location,
298-
constraint_span: Span,
291+
_constraint_location: Location,
292+
_constraint_span: Span,
299293
) -> bool {
300294
let elem = self.elements.index(elem);
301-
self.add_internal(to_region, elem, |causes| {
302-
causes[&(from_region, elem)].outlives(constraint_location, constraint_span)
303-
})
295+
self.add_internal(to_region, elem, |causes| causes[&(from_region, elem)])
304296
}
305297

306298
/// Adds all the universal regions outlived by `from_region` to
@@ -445,7 +437,7 @@ impl RegionValues {
445437
///
446438
/// Returns None if cause tracking is disabled or `elem` is not
447439
/// actually found in `r`.
448-
pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Rc<Cause>> {
440+
pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Cause> {
449441
let index = self.elements.index(elem);
450442
if let Some(causes) = &self.causes {
451443
causes.get(&(r, index)).cloned()

src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,28 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time
22
--> $DIR/mut-borrow-in-loop.rs:20:25
33
|
44
LL | (self.func)(arg) //~ ERROR cannot borrow
5-
| ^^^ mutable borrow starts here in previous iteration of loop
5+
| ------------^^^-
6+
| | |
7+
| | mutable borrow starts here in previous iteration of loop
8+
| borrow later used here
69

710
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
811
--> $DIR/mut-borrow-in-loop.rs:26:25
912
|
1013
LL | (self.func)(arg) //~ ERROR cannot borrow
11-
| ^^^ mutable borrow starts here in previous iteration of loop
14+
| ------------^^^-
15+
| | |
16+
| | mutable borrow starts here in previous iteration of loop
17+
| borrow later used here
1218

1319
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
1420
--> $DIR/mut-borrow-in-loop.rs:33:25
1521
|
1622
LL | (self.func)(arg) //~ ERROR cannot borrow
17-
| ^^^ mutable borrow starts here in previous iteration of loop
23+
| ------------^^^-
24+
| | |
25+
| | mutable borrow starts here in previous iteration of loop
26+
| borrow later used here
1827

1928
error: aborting due to 3 previous errors
2029

0 commit comments

Comments
 (0)