Skip to content

Commit 76a9936

Browse files
committed
move and maintain live loans to LivenessValues
Liveness data is pushed from multiple parts of NLL. Instead of changing the call sites to maintain live loans, move the latter to `LivenessValues` where this liveness data is pushed to, and maintain live loans there. This fixes the differences in polonius scopes on some CFGs where a variable was dead in tracing but as a MIR terminator its regions were marked live from "constraint generation"
1 parent 16af7f5 commit 76a9936

File tree

5 files changed

+99
-95
lines changed

5 files changed

+99
-95
lines changed

compiler/rustc_borrowck/src/nll.rs

+16-21
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,22 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
182182
let elements = &Rc::new(RegionValueElements::new(&body));
183183

184184
// Run the MIR type-checker.
185-
let MirTypeckResults {
186-
constraints,
187-
universal_region_relations,
188-
opaque_type_values,
189-
live_loans,
190-
} = type_check::type_check(
191-
infcx,
192-
param_env,
193-
body,
194-
promoted,
195-
&universal_regions,
196-
location_table,
197-
borrow_set,
198-
&mut all_facts,
199-
flow_inits,
200-
move_data,
201-
elements,
202-
upvars,
203-
polonius_input,
204-
);
185+
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
186+
type_check::type_check(
187+
infcx,
188+
param_env,
189+
body,
190+
promoted,
191+
&universal_regions,
192+
location_table,
193+
borrow_set,
194+
&mut all_facts,
195+
flow_inits,
196+
move_data,
197+
elements,
198+
upvars,
199+
polonius_input,
200+
);
205201

206202
if let Some(all_facts) = &mut all_facts {
207203
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
@@ -279,7 +275,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
279275
type_tests,
280276
liveness_constraints,
281277
elements,
282-
live_loans,
283278
);
284279

285280
// Generate various additional constraints.

compiler/rustc_borrowck/src/region_infer/mod.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
77
use rustc_data_structures::graph::scc::Sccs;
88
use rustc_errors::Diagnostic;
99
use rustc_hir::def_id::CRATE_DEF_ID;
10-
use rustc_index::bit_set::SparseBitMatrix;
1110
use rustc_index::{IndexSlice, IndexVec};
1211
use rustc_infer::infer::outlives::test_type_match;
1312
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
@@ -31,8 +30,8 @@ use crate::{
3130
nll::PoloniusOutput,
3231
region_infer::reverse_sccs::ReverseSccGraph,
3332
region_infer::values::{
34-
LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements,
35-
RegionValues, ToElementIndex,
33+
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
34+
ToElementIndex,
3635
},
3736
type_check::{free_region_relations::UniversalRegionRelations, Locations},
3837
universal_regions::UniversalRegions,
@@ -120,9 +119,6 @@ pub struct RegionInferenceContext<'tcx> {
120119
/// Information about how the universally quantified regions in
121120
/// scope on this function relate to one another.
122121
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
123-
124-
/// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
125-
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
126122
}
127123

128124
/// Each time that `apply_member_constraint` is successful, it appends
@@ -334,7 +330,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
334330
type_tests: Vec<TypeTest<'tcx>>,
335331
liveness_constraints: LivenessValues<RegionVid>,
336332
elements: &Rc<RegionValueElements>,
337-
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
338333
) -> Self {
339334
debug!("universal_regions: {:#?}", universal_regions);
340335
debug!("outlives constraints: {:#?}", outlives_constraints);
@@ -388,7 +383,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
388383
type_tests,
389384
universal_regions,
390385
universal_region_relations,
391-
live_loans,
392386
};
393387

394388
result.init_free_and_bound_regions();
@@ -2316,7 +2310,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23162310
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
23172311
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
23182312
let point = self.liveness_constraints.point_from_location(location);
2319-
self.live_loans.contains(point, loan_idx)
2313+
self.liveness_constraints.is_loan_live_at(loan_idx, point)
23202314
}
23212315
}
23222316

compiler/rustc_borrowck/src/region_infer/values.rs

+63-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use rustc_middle::ty::{self, RegionVid};
1111
use std::fmt::Debug;
1212
use std::rc::Rc;
1313

14+
use crate::dataflow::BorrowIndex;
15+
1416
/// Maps between a `Location` and a `PointIndex` (and vice versa).
1517
pub(crate) struct RegionValueElements {
1618
/// For each basic block, how many points are contained within?
@@ -119,16 +121,47 @@ pub(crate) enum RegionElement {
119121
/// When we initially compute liveness, we use an interval matrix storing
120122
/// liveness ranges for each region-vid.
121123
pub(crate) struct LivenessValues<N: Idx> {
124+
/// The map from locations to points.
122125
elements: Rc<RegionValueElements>,
126+
127+
/// For each region: the points where it is live.
123128
points: SparseIntervalMatrix<N, PointIndex>,
129+
130+
/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
131+
/// that point.
132+
pub(crate) loans: Option<LiveLoans<N>>,
133+
}
134+
135+
/// Data used to compute the loans that are live at a given point in the CFG, when using
136+
/// `-Zpolonius=next`.
137+
pub(crate) struct LiveLoans<N: Idx> {
138+
/// The set of loans that flow into a given region. When individual regions are marked as live
139+
/// in the CFG, these inflowing loans are recorded as live.
140+
pub(crate) inflowing_loans: SparseBitMatrix<N, BorrowIndex>,
141+
142+
/// The set of loans that are live at a given point in the CFG.
143+
pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
144+
}
145+
146+
impl<N: Idx> LiveLoans<N> {
147+
pub(crate) fn new(num_loans: usize) -> Self {
148+
LiveLoans {
149+
live_loans: SparseBitMatrix::new(num_loans),
150+
inflowing_loans: SparseBitMatrix::new(num_loans),
151+
}
152+
}
124153
}
125154

126155
impl<N: Idx> LivenessValues<N> {
127156
/// Creates a new set of "region values" that tracks causal information.
128157
/// Each of the regions in num_region_variables will be initialized with an
129158
/// empty set of points and no causal information.
130159
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
131-
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
160+
LivenessValues {
161+
points: SparseIntervalMatrix::new(elements.num_points),
162+
elements,
163+
loans: None,
164+
}
132165
}
133166

134167
/// Iterate through each region that has a value in this set.
@@ -141,13 +174,33 @@ impl<N: Idx> LivenessValues<N> {
141174
pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool {
142175
debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
143176
let index = self.elements.point_from_location(location);
177+
178+
// When available, record the loans flowing into this region as live at the given point.
179+
if let Some(loans) = self.loans.as_mut() {
180+
if let Some(inflowing) = loans.inflowing_loans.row(row) {
181+
loans.live_loans.union_row(index, inflowing);
182+
}
183+
}
184+
144185
self.points.insert(row, index)
145186
}
146187

147188
/// Adds all the elements in the given bit array into the given
148189
/// region. Returns whether any of them are newly added.
149190
pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
150191
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
192+
193+
// When available, record the loans flowing into this region as live at the given points.
194+
if let Some(loans) = self.loans.as_mut() {
195+
if let Some(inflowing) = loans.inflowing_loans.row(row) {
196+
if !inflowing.is_empty() {
197+
for point in locations.iter() {
198+
loans.live_loans.union_row(point, inflowing);
199+
}
200+
}
201+
}
202+
}
203+
151204
self.points.union_row(row, locations)
152205
}
153206

@@ -181,6 +234,15 @@ impl<N: Idx> LivenessValues<N> {
181234
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
182235
self.elements.point_from_location(location)
183236
}
237+
238+
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
239+
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
240+
self.loans
241+
.as_ref()
242+
.expect("Accessing live loans requires `-Zpolonius=next`")
243+
.live_loans
244+
.contains(point, loan_idx)
245+
}
184246
}
185247

186248
/// Maps from `ty::PlaceholderRegion` values that are used in the rest of

compiler/rustc_borrowck/src/type_check/liveness/trace.rs

+16-49
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
22
use rustc_data_structures::graph::WithSuccessors;
3-
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
3+
use rustc_index::bit_set::HybridBitSet;
44
use rustc_index::interval::IntervalSet;
55
use rustc_infer::infer::canonical::QueryRegionConstraints;
66
use rustc_infer::infer::outlives::for_liveness;
77
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
88
use rustc_middle::traits::query::DropckOutlivesResult;
9-
use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
9+
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
1010
use rustc_span::DUMMY_SP;
1111
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
1212
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -16,9 +16,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
1616
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
1717
use rustc_mir_dataflow::ResultsCursor;
1818

19-
use crate::dataflow::BorrowIndex;
2019
use crate::{
21-
region_infer::values::{self, PointIndex, RegionValueElements},
20+
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
2221
type_check::liveness::local_use_map::LocalUseMap,
2322
type_check::liveness::polonius,
2423
type_check::NormalizeLocation,
@@ -54,17 +53,17 @@ pub(super) fn trace<'mir, 'tcx>(
5453
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
5554

5655
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
57-
let num_loans = typeck.borrowck_context.borrow_set.len();
58-
let mut inflowing_loans = SparseBitMatrix::new(num_loans);
5956
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
60-
let borrowck_context = &typeck.borrowck_context;
57+
let borrowck_context = &mut typeck.borrowck_context;
58+
6159
let borrow_set = &borrowck_context.borrow_set;
62-
let constraint_set = &borrowck_context.constraints.outlives_constraints;
60+
let mut live_loans = LiveLoans::new(borrow_set.len());
6361

6462
let num_region_vars = typeck.infcx.num_region_vars();
65-
let graph = constraint_set.graph(num_region_vars);
63+
let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
64+
let graph = outlives_constraints.graph(num_region_vars);
6665
let region_graph =
67-
graph.region_graph(&constraint_set, borrowck_context.universal_regions.fr_static);
66+
graph.region_graph(&outlives_constraints, borrowck_context.universal_regions.fr_static);
6867

6968
// Traverse each issuing region's constraints, and record the loan as flowing into the
7069
// outlived region.
@@ -75,9 +74,13 @@ pub(super) fn trace<'mir, 'tcx>(
7574
continue;
7675
}
7776

78-
inflowing_loans.insert(succ, loan);
77+
live_loans.inflowing_loans.insert(succ, loan);
7978
}
8079
}
80+
81+
// Store the inflowing loans in the liveness constraints: they will be used to compute live
82+
// loans when liveness data is recorded there.
83+
borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
8184
};
8285

8386
let cx = LivenessContext {
@@ -88,7 +91,6 @@ pub(super) fn trace<'mir, 'tcx>(
8891
local_use_map,
8992
move_data,
9093
drop_data: FxIndexMap::default(),
91-
inflowing_loans,
9294
};
9395

9496
let mut results = LivenessResults::new(cx);
@@ -126,9 +128,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
126128
/// Index indicating where each variable is assigned, used, or
127129
/// dropped.
128130
local_use_map: &'me LocalUseMap,
129-
130-
/// Set of loans that flow into a given region, when using `-Zpolonius=next`.
131-
inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
132131
}
133132

134133
struct DropData<'tcx> {
@@ -520,13 +519,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
520519
) {
521520
debug!("add_use_live_facts_for(value={:?})", value);
522521

523-
Self::make_all_regions_live(
524-
self.elements,
525-
&mut self.typeck,
526-
value,
527-
live_at,
528-
&self.inflowing_loans,
529-
);
522+
Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at);
530523
}
531524

532525
/// Some variable with type `live_ty` is "drop live" at `location`
@@ -577,13 +570,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
577570
// All things in the `outlives` array may be touched by
578571
// the destructor and must be live at this point.
579572
for &kind in &drop_data.dropck_result.kinds {
580-
Self::make_all_regions_live(
581-
self.elements,
582-
&mut self.typeck,
583-
kind,
584-
live_at,
585-
&self.inflowing_loans,
586-
);
573+
Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at);
587574

588575
polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind);
589576
}
@@ -594,20 +581,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
594581
typeck: &mut TypeChecker<'_, 'tcx>,
595582
value: impl TypeVisitable<TyCtxt<'tcx>>,
596583
live_at: &IntervalSet<PointIndex>,
597-
inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
598584
) {
599585
debug!("make_all_regions_live(value={:?})", value);
600586
debug!(
601587
"make_all_regions_live: live_at={}",
602588
values::location_set_str(elements, live_at.iter()),
603589
);
604590

605-
// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
606-
// regions as being live at the given `live_at` points: this will be used to compute the
607-
// location where a loan goes out of scope.
608-
let num_loans = typeck.borrowck_context.borrow_set.len();
609-
let value_loans = &mut HybridBitSet::new_empty(num_loans);
610-
611591
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
612592
tcx: typeck.tcx(),
613593
param_env: typeck.param_env,
@@ -619,21 +599,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
619599
.constraints
620600
.liveness_constraints
621601
.add_elements(live_region_vid, live_at);
622-
623-
// There can only be inflowing loans for this region when we are using
624-
// `-Zpolonius=next`.
625-
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
626-
value_loans.union(inflowing);
627-
}
628602
},
629603
});
630-
631-
// Record the loans reaching the value.
632-
if !value_loans.is_empty() {
633-
for point in live_at.iter() {
634-
typeck.borrowck_context.live_loans.union_row(point, value_loans);
635-
}
636-
}
637604
}
638605

639606
fn compute_drop_data(

0 commit comments

Comments
 (0)