Skip to content

Commit ac0a3d1

Browse files
author
Albin Stjerna
committed
polonius: add generation of liveneness-related facts
Notably contains an ugly hack to generate initialization information for variables that will go away when we have that functionality in Polonius.
1 parent e775bf3 commit ac0a3d1

File tree

7 files changed

+197
-20
lines changed

7 files changed

+197
-20
lines changed

src/librustc/mir/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::hir::def_id::DefId;
99
use crate::hir::{self, InlineAsm as HirInlineAsm};
1010
use crate::mir::interpret::{ConstValue, InterpError, Scalar};
1111
use crate::mir::visit::MirVisitable;
12+
use polonius_engine::Atom;
1213
use rustc_data_structures::bit_set::BitMatrix;
1314
use rustc_data_structures::fx::FxHashSet;
1415
use rustc_data_structures::graph::dominators::{dominators, Dominators};
@@ -600,6 +601,12 @@ newtype_index! {
600601
}
601602
}
602603

604+
impl Atom for Local {
605+
fn index(self) -> usize {
606+
Idx::index(self)
607+
}
608+
}
609+
603610
/// Classifies locals into categories. See `Body::local_kind`.
604611
#[derive(PartialEq, Eq, Debug, HashStable)]
605612
pub enum LocalKind {

src/librustc_mir/borrow_check/flows.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! FIXME: this might be better as a "generic" fixed-point combinator,
44
//! but is not as ugly as it is right now.
55
6-
use rustc::mir::{BasicBlock, Location};
6+
use rustc::mir::{BasicBlock, Local, Location};
77
use rustc::ty::RegionVid;
88
use rustc_data_structures::bit_set::BitIter;
99

@@ -21,22 +21,24 @@ use either::Either;
2121
use std::fmt;
2222
use std::rc::Rc;
2323

24+
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local>;
25+
2426
// (forced to be `pub` due to its use as an associated type below.)
2527
crate struct Flows<'b, 'tcx> {
2628
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
2729
pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>,
2830
pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>,
2931

3032
/// Polonius Output
31-
pub polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
33+
pub polonius_output: Option<Rc<PoloniusOutput>>,
3234
}
3335

3436
impl<'b, 'tcx> Flows<'b, 'tcx> {
3537
crate fn new(
3638
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
3739
uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>,
3840
ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>,
39-
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
41+
polonius_output: Option<Rc<PoloniusOutput>>,
4042
) -> Self {
4143
Flows {
4244
borrows,

src/librustc_mir/borrow_check/nll/facts.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::borrow_check::location::{LocationIndex, LocationTable};
22
use crate::dataflow::indexes::BorrowIndex;
33
use polonius_engine::AllFacts as PoloniusAllFacts;
44
use polonius_engine::Atom;
5+
use rustc::mir::Local;
56
use rustc::ty::{RegionVid, TyCtxt};
67
use rustc_data_structures::indexed_vec::Idx;
78
use std::error::Error;
@@ -10,7 +11,7 @@ use std::fs::{self, File};
1011
use std::io::Write;
1112
use std::path::Path;
1213

13-
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex>;
14+
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local>;
1415

1516
crate trait AllFactsExt {
1617
/// Returns `true` if there is a need to gather `AllFacts` given the
@@ -60,6 +61,12 @@ impl AllFactsExt for AllFacts {
6061
outlives,
6162
region_live_at,
6263
invalidates,
64+
var_used,
65+
var_defined,
66+
var_drop_used,
67+
var_uses_region,
68+
var_drops_region,
69+
var_initialized_on_exit,
6370
])
6471
}
6572
Ok(())

src/librustc_mir/borrow_check/nll/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::transform::MirSource;
1111
use crate::borrow_check::Upvar;
1212
use rustc::hir::def_id::DefId;
1313
use rustc::infer::InferCtxt;
14-
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Body};
14+
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body};
1515
use rustc::ty::{self, RegionKind, RegionVid};
1616
use rustc_errors::Diagnostic;
1717
use std::fmt::Debug;
@@ -84,7 +84,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
8484
errors_buffer: &mut Vec<Diagnostic>,
8585
) -> (
8686
RegionInferenceContext<'tcx>,
87-
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
87+
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local>>>,
8888
Option<ClosureRegionRequirements<'tcx>>,
8989
) {
9090
let mut all_facts = if AllFacts::enabled(infcx.tcx) {

src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::rc::Rc;
1515
use super::TypeChecker;
1616

1717
mod local_use_map;
18+
mod polonius;
1819
mod trace;
1920

2021
/// Combines liveness analysis with initialization analysis to
@@ -57,15 +58,9 @@ pub(super) fn generate<'tcx>(
5758
};
5859

5960
if !live_locals.is_empty() {
60-
trace::trace(
61-
typeck,
62-
body,
63-
elements,
64-
flow_inits,
65-
move_data,
66-
live_locals,
67-
location_table,
68-
);
61+
trace::trace(typeck, body, elements, flow_inits, move_data, live_locals, location_table);
62+
63+
polonius::populate_var_liveness_facts(typeck, body, location_table);
6964
}
7065
}
7166

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use crate::borrow_check::location::{LocationIndex, LocationTable};
2+
use crate::util::liveness::{categorize, DefUse};
3+
use rustc::mir::visit::{PlaceContext, Visitor};
4+
use rustc::mir::{Body, Local, Location};
5+
use rustc::ty::subst::Kind;
6+
use rustc::ty::Ty;
7+
8+
use super::TypeChecker;
9+
10+
type VarPointRelations = Vec<(Local, LocationIndex)>;
11+
12+
struct LivenessPointFactsExtractor<'me> {
13+
var_defined: &'me mut VarPointRelations,
14+
var_used: &'me mut VarPointRelations,
15+
location_table: &'me LocationTable,
16+
}
17+
18+
// A Visitor to walk through the MIR and extract point-wise facts
19+
impl LivenessPointFactsExtractor<'_> {
20+
fn location_to_index(&self, location: Location) -> LocationIndex {
21+
self.location_table.mid_index(location)
22+
}
23+
24+
fn insert_def(&mut self, local: Local, location: Location) {
25+
debug!("LivenessFactsExtractor::insert_def()");
26+
self.var_defined.push((local, self.location_to_index(location)));
27+
}
28+
29+
fn insert_use(&mut self, local: Local, location: Location) {
30+
debug!("LivenessFactsExtractor::insert_use()");
31+
self.var_used.push((local, self.location_to_index(location)));
32+
}
33+
}
34+
35+
impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
36+
fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
37+
match categorize(context) {
38+
Some(DefUse::Def) => self.insert_def(local, location),
39+
Some(DefUse::Use) => self.insert_use(local, location),
40+
_ => (),
41+
// NOTE: Drop handling is now done in trace()
42+
}
43+
}
44+
}
45+
46+
fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty<'tcx>) {
47+
debug!("add_regions(local={:?}, type={:?})", local, ty);
48+
typeck.tcx().for_each_free_region(&ty, |region| {
49+
let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(region);
50+
debug!("add_regions for region {:?}", region_vid);
51+
if let Some(facts) = typeck.borrowck_context.all_facts {
52+
facts.var_uses_region.push((local, region_vid));
53+
}
54+
});
55+
}
56+
57+
pub(super) fn populate_var_liveness_facts(
58+
typeck: &mut TypeChecker<'_, 'tcx>,
59+
mir: &Body<'tcx>,
60+
location_table: &LocationTable,
61+
) {
62+
debug!("populate_var_liveness_facts()");
63+
64+
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
65+
LivenessPointFactsExtractor {
66+
var_defined: &mut facts.var_defined,
67+
var_used: &mut facts.var_used,
68+
location_table,
69+
}
70+
.visit_body(mir);
71+
}
72+
73+
for (local, local_decl) in mir.local_decls.iter_enumerated() {
74+
add_var_uses_regions(typeck, local, local_decl.ty);
75+
}
76+
}
77+
78+
// For every potentially drop()-touched region `region` in `local`'s type
79+
// (`kind`), emit a Polonius `var_drops_region(local, region)` fact.
80+
pub(super) fn add_var_drops_regions(
81+
typeck: &mut TypeChecker<'_, 'tcx>,
82+
local: Local,
83+
kind: &Kind<'tcx>,
84+
) {
85+
debug!("add_var_drops_region(local={:?}, kind={:?}", local, kind);
86+
let tcx = typeck.tcx();
87+
88+
tcx.for_each_free_region(kind, |drop_live_region| {
89+
let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(drop_live_region);
90+
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
91+
facts.var_drops_region.push((local, region_vid));
92+
};
93+
});
94+
}

src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs

+77-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use crate::borrow_check::location::LocationTable;
22
use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
33
use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
4+
use crate::borrow_check::nll::type_check::liveness::polonius;
45
use crate::borrow_check::nll::type_check::NormalizeLocation;
56
use crate::borrow_check::nll::type_check::TypeChecker;
67
use crate::dataflow::indexes::MovePathIndex;
78
use crate::dataflow::move_paths::MoveData;
89
use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
910
use rustc::infer::canonical::QueryRegionConstraints;
10-
use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, Body};
11+
use rustc::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
1112
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
1213
use rustc::traits::query::type_op::outlives::DropckOutlives;
1314
use rustc::traits::query::type_op::TypeOp;
@@ -130,6 +131,12 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
130131
for local in live_locals {
131132
self.reset_local_state();
132133
self.add_defs_for(local);
134+
135+
// FIXME: this is temporary until we can generate our own initialization
136+
if self.cx.typeck.borrowck_context.all_facts.is_some() {
137+
self.add_polonius_var_initialized_on_exit_for(local)
138+
}
139+
133140
self.compute_use_live_points_for(local);
134141
self.compute_drop_live_points_for(local);
135142

@@ -150,6 +157,63 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
150157
}
151158
}
152159

160+
// WARNING: panics if self.cx.typeck.borrowck_context.all_facts != None
161+
//
162+
// FIXME: this analysis (the initialization tracking) should be
163+
// done in Polonius, but isn't yet.
164+
fn add_polonius_var_initialized_on_exit_for(&mut self, local: Local) {
165+
let move_path = self.cx.move_data.rev_lookup.find_local(local);
166+
let facts = self.cx.typeck.borrowck_context.all_facts.as_mut().unwrap();
167+
for block in self.cx.body.basic_blocks().indices() {
168+
debug!("polonius: generating initialization facts for {:?} in {:?}", local, block);
169+
170+
// iterate through the block, applying the effects of each statement
171+
// up to and including location, and populate `var_initialized_on_exit`
172+
self.cx.flow_inits.reset_to_entry_of(block);
173+
let start_location = Location { block, statement_index: 0 };
174+
self.cx.flow_inits.apply_local_effect(start_location);
175+
176+
for statement_index in 0..self.cx.body[block].statements.len() {
177+
let current_location = Location { block, statement_index };
178+
179+
self.cx.flow_inits.reconstruct_statement_effect(current_location);
180+
181+
// statement has not yet taken effect:
182+
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
183+
facts
184+
.var_initialized_on_exit
185+
.push((local, self.cx.location_table.start_index(current_location)));
186+
}
187+
188+
// statement has now taken effect
189+
self.cx.flow_inits.apply_local_effect(current_location);
190+
191+
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
192+
facts
193+
.var_initialized_on_exit
194+
.push((local, self.cx.location_table.mid_index(current_location)));
195+
}
196+
}
197+
198+
let terminator_location = self.cx.body.terminator_loc(block);
199+
200+
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
201+
facts
202+
.var_initialized_on_exit
203+
.push((local, self.cx.location_table.start_index(terminator_location)));
204+
}
205+
206+
// apply the effects of the terminator and push it if needed
207+
self.cx.flow_inits.reset_to_exit_of(block);
208+
209+
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
210+
facts
211+
.var_initialized_on_exit
212+
.push((local, self.cx.location_table.mid_index(terminator_location)));
213+
}
214+
}
215+
}
216+
153217
/// Clear the value of fields that are "per local variable".
154218
fn reset_local_state(&mut self) {
155219
self.defs.clear();
@@ -211,6 +275,11 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
211275
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
212276

213277
if self.cx.initialized_at_terminator(location.block, mpi) {
278+
// FIXME: this analysis (the initialization tracking) should be
279+
// done in Polonius, but isn't yet.
280+
if let Some(facts) = self.cx.typeck.borrowck_context.all_facts {
281+
facts.var_drop_used.push((local, self.cx.location_table.mid_index(location)));
282+
}
214283
if self.drop_live_at.insert(drop_point) {
215284
self.drop_locations.push(location);
216285
self.stack.push(drop_point);
@@ -487,6 +556,8 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
487556
live_at,
488557
self.location_table,
489558
);
559+
560+
polonius::add_var_drops_regions(&mut self.typeck, dropped_local, &kind);
490561
}
491562
}
492563

@@ -505,14 +576,15 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
505576

506577
let tcx = typeck.tcx();
507578
tcx.for_each_free_region(&value, |live_region| {
508-
let live_region_vid = typeck.borrowck_context
509-
.universal_regions
510-
.to_region_vid(live_region);
511-
typeck.borrowck_context
579+
let live_region_vid =
580+
typeck.borrowck_context.universal_regions.to_region_vid(live_region);
581+
typeck
582+
.borrowck_context
512583
.constraints
513584
.liveness_constraints
514585
.add_elements(live_region_vid, live_at);
515586

587+
// FIXME: remove this when we can generate our own region-live-at reliably
516588
if let Some(facts) = typeck.borrowck_context.all_facts {
517589
for point in live_at.iter() {
518590
let loc = elements.to_location(point);

0 commit comments

Comments
 (0)