Skip to content

Commit 73ccebe

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 868e35f commit 73ccebe

File tree

5 files changed

+96
-97
lines changed

5 files changed

+96
-97
lines changed

compiler/rustc_borrowck/src/nll.rs

Lines changed: 16 additions & 21 deletions
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

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<RegionVid>,
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: 63 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,16 +122,47 @@ pub(crate) enum RegionElement {
120122
/// When we initially compute liveness, we use an interval matrix storing
121123
/// liveness ranges for each region-vid.
122124
pub(crate) struct LivenessValues<N: Idx> {
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<N, 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<N>>,
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<N: Idx> {
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<N, 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<N: Idx> LiveLoans<N> {
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<N: Idx> LivenessValues<N> {
128157
/// Creates a new set of "region values" that tracks causal information.
129158
/// Each of the regions in num_region_variables will be initialized with an
130159
/// empty set of points and no causal information.
131160
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
132-
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
161+
LivenessValues {
162+
points: SparseIntervalMatrix::new(elements.num_points),
163+
elements,
164+
loans: None,
165+
}
133166
}
134167

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

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

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

187249
/// 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::location_set_str(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_elements(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)