Skip to content

Commit 60d4eb2

Browse files
committed
move and maintain live loans in 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 231acdd commit 60d4eb2

File tree

5 files changed

+94
-97
lines changed

5 files changed

+94
-97
lines changed

compiler/rustc_borrowck/src/nll.rs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -101,26 +101,22 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
101101
let elements = &Rc::new(RegionValueElements::new(body));
102102

103103
// Run the MIR type-checker.
104-
let MirTypeckResults {
105-
constraints,
106-
universal_region_relations,
107-
opaque_type_values,
108-
live_loans,
109-
} = type_check::type_check(
110-
infcx,
111-
param_env,
112-
body,
113-
promoted,
114-
&universal_regions,
115-
location_table,
116-
borrow_set,
117-
&mut all_facts,
118-
flow_inits,
119-
move_data,
120-
elements,
121-
upvars,
122-
polonius_input,
123-
);
104+
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
105+
type_check::type_check(
106+
infcx,
107+
param_env,
108+
body,
109+
promoted,
110+
&universal_regions,
111+
location_table,
112+
borrow_set,
113+
&mut all_facts,
114+
flow_inits,
115+
move_data,
116+
elements,
117+
upvars,
118+
polonius_input,
119+
);
124120

125121
// Create the region inference context, taking ownership of the
126122
// region inference data that was contained in `infcx`, and the
@@ -161,7 +157,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
161157
type_tests,
162158
liveness_constraints,
163159
elements,
164-
live_loans,
165160
);
166161

167162
// If requested: dump NLL facts, and run legacy polonius analysis.

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 3 additions & 9 deletions
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
@@ -335,7 +331,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
335331
type_tests: Vec<TypeTest<'tcx>>,
336332
liveness_constraints: LivenessValues,
337333
elements: &Rc<RegionValueElements>,
338-
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
339334
) -> Self {
340335
debug!("universal_regions: {:#?}", universal_regions);
341336
debug!("outlives constraints: {:#?}", outlives_constraints);
@@ -389,7 +384,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
389384
type_tests,
390385
universal_regions,
391386
universal_region_relations,
392-
live_loans,
393387
};
394388

395389
result.init_free_and_bound_regions();
@@ -2325,7 +2319,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23252319
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
23262320
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
23272321
let point = self.liveness_constraints.point_from_location(location);
2328-
self.live_loans.contains(point, loan_idx)
2322+
self.liveness_constraints.is_loan_live_at(loan_idx, point)
23292323
}
23302324
}
23312325

compiler/rustc_borrowck/src/region_infer/values.rs

Lines changed: 61 additions & 1 deletion
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?
@@ -120,14 +122,45 @@ pub(crate) enum RegionElement {
120122
/// Records the CFG locations where each region is live. When we initially compute liveness, we use
121123
/// an interval matrix storing liveness ranges for each region-vid.
122124
pub(crate) struct LivenessValues {
125+
/// The map from locations to points.
123126
elements: Rc<RegionValueElements>,
127+
128+
/// For each region: the points where it is live.
124129
points: SparseIntervalMatrix<RegionVid, PointIndex>,
130+
131+
/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
132+
/// that point.
133+
pub(crate) loans: Option<LiveLoans>,
134+
}
135+
136+
/// Data used to compute the loans that are live at a given point in the CFG, when using
137+
/// `-Zpolonius=next`.
138+
pub(crate) struct LiveLoans {
139+
/// The set of loans that flow into a given region. When individual regions are marked as live
140+
/// in the CFG, these inflowing loans are recorded as live.
141+
pub(crate) inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
142+
143+
/// The set of loans that are live at a given point in the CFG.
144+
pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
145+
}
146+
147+
impl LiveLoans {
148+
pub(crate) fn new(num_loans: usize) -> Self {
149+
LiveLoans {
150+
live_loans: SparseBitMatrix::new(num_loans),
151+
inflowing_loans: SparseBitMatrix::new(num_loans),
152+
}
153+
}
125154
}
126155

127156
impl LivenessValues {
128157
/// Create an empty map of regions to locations where they're live.
129158
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
130-
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
159+
LivenessValues {
160+
points: SparseIntervalMatrix::new(elements.num_points),
161+
elements,
162+
loans: None,
163+
}
131164
}
132165

133166
/// Iterate through each region that has a value in this set.
@@ -140,12 +173,30 @@ impl LivenessValues {
140173
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
141174
let point = self.elements.point_from_location(location);
142175
self.points.insert(region, point);
176+
177+
// When available, record the loans flowing into this region as live at the given point.
178+
if let Some(loans) = self.loans.as_mut() {
179+
if let Some(inflowing) = loans.inflowing_loans.row(region) {
180+
loans.live_loans.union_row(point, inflowing);
181+
}
182+
}
143183
}
144184

145185
/// Records `region` as being live at all the given `points`.
146186
pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
147187
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
148188
self.points.union_row(region, points);
189+
190+
// When available, record the loans flowing into this region as live at the given points.
191+
if let Some(loans) = self.loans.as_mut() {
192+
if let Some(inflowing) = loans.inflowing_loans.row(region) {
193+
if !inflowing.is_empty() {
194+
for point in points.iter() {
195+
loans.live_loans.union_row(point, inflowing);
196+
}
197+
}
198+
}
199+
}
149200
}
150201

151202
/// Records `region` as being live at all the control-flow points.
@@ -185,6 +236,15 @@ impl LivenessValues {
185236
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
186237
self.elements.point_from_location(location)
187238
}
239+
240+
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
241+
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
242+
self.loans
243+
.as_ref()
244+
.expect("Accessing live loans requires `-Zpolonius=next`")
245+
.live_loans
246+
.contains(point, loan_idx)
247+
}
188248
}
189249

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

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

Lines changed: 13 additions & 51 deletions
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,
@@ -52,15 +51,12 @@ pub(super) fn trace<'mir, 'tcx>(
5251
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
5352

5453
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
55-
let num_loans = typeck.borrowck_context.borrow_set.len();
56-
let mut inflowing_loans = SparseBitMatrix::new(num_loans);
5754
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
58-
let borrowck_context = &typeck.borrowck_context;
55+
let borrowck_context = &mut typeck.borrowck_context;
5956
let borrow_set = &borrowck_context.borrow_set;
57+
let mut live_loans = LiveLoans::new(borrow_set.len());
6058
let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
61-
62-
let num_region_vars = typeck.infcx.num_region_vars();
63-
let graph = outlives_constraints.graph(num_region_vars);
59+
let graph = outlives_constraints.graph(typeck.infcx.num_region_vars());
6460
let region_graph =
6561
graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static);
6662

@@ -73,9 +69,13 @@ pub(super) fn trace<'mir, 'tcx>(
7369
continue;
7470
}
7571

76-
inflowing_loans.insert(succ, loan);
72+
live_loans.inflowing_loans.insert(succ, loan);
7773
}
7874
}
75+
76+
// Store the inflowing loans in the liveness constraints: they will be used to compute live
77+
// loans when liveness data is recorded there.
78+
borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
7979
};
8080

8181
let cx = LivenessContext {
@@ -86,7 +86,6 @@ pub(super) fn trace<'mir, 'tcx>(
8686
local_use_map,
8787
move_data,
8888
drop_data: FxIndexMap::default(),
89-
inflowing_loans,
9089
};
9190

9291
let mut results = LivenessResults::new(cx);
@@ -124,9 +123,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
124123
/// Index indicating where each variable is assigned, used, or
125124
/// dropped.
126125
local_use_map: &'me LocalUseMap,
127-
128-
/// Set of loans that flow into a given region, when using `-Zpolonius=next`.
129-
inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
130126
}
131127

132128
struct DropData<'tcx> {
@@ -517,14 +513,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
517513
live_at: &IntervalSet<PointIndex>,
518514
) {
519515
debug!("add_use_live_facts_for(value={:?})", value);
520-
521-
Self::make_all_regions_live(
522-
self.elements,
523-
self.typeck,
524-
value,
525-
live_at,
526-
&self.inflowing_loans,
527-
);
516+
Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
528517
}
529518

530519
/// Some variable with type `live_ty` is "drop live" at `location`
@@ -575,14 +564,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
575564
// All things in the `outlives` array may be touched by
576565
// the destructor and must be live at this point.
577566
for &kind in &drop_data.dropck_result.kinds {
578-
Self::make_all_regions_live(
579-
self.elements,
580-
self.typeck,
581-
kind,
582-
live_at,
583-
&self.inflowing_loans,
584-
);
585-
567+
Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
586568
polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind);
587569
}
588570
}
@@ -592,20 +574,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
592574
typeck: &mut TypeChecker<'_, 'tcx>,
593575
value: impl TypeVisitable<TyCtxt<'tcx>>,
594576
live_at: &IntervalSet<PointIndex>,
595-
inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
596577
) {
597578
debug!("make_all_regions_live(value={:?})", value);
598579
debug!(
599580
"make_all_regions_live: live_at={}",
600581
values::pretty_print_points(elements, live_at.iter()),
601582
);
602583

603-
// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
604-
// regions as being live at the given `live_at` points: this will be used to compute the
605-
// location where a loan goes out of scope.
606-
let num_loans = typeck.borrowck_context.borrow_set.len();
607-
let value_loans = &mut HybridBitSet::new_empty(num_loans);
608-
609584
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
610585
tcx: typeck.tcx(),
611586
param_env: typeck.param_env,
@@ -617,21 +592,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
617592
.constraints
618593
.liveness_constraints
619594
.add_points(live_region_vid, live_at);
620-
621-
// There can only be inflowing loans for this region when we are using
622-
// `-Zpolonius=next`.
623-
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
624-
value_loans.union(inflowing);
625-
}
626595
},
627596
});
628-
629-
// Record the loans reaching the value.
630-
if !value_loans.is_empty() {
631-
for point in live_at.iter() {
632-
typeck.borrowck_context.live_loans.union_row(point, value_loans);
633-
}
634-
}
635597
}
636598

637599
fn compute_drop_data(

0 commit comments

Comments
 (0)