Skip to content

Commit 9776723

Browse files
committed
Auto merge of #62800 - albins:polonius-initialization-1, r=nikomatsakis
Extend Polonius fact generation for (some) move tracking This PR will extend rustc to emit facts used for tracking moves and initialization in Polonius. It is most likely the final part of my master's thesis work.
2 parents a24f636 + 28312b5 commit 9776723

File tree

13 files changed

+323
-273
lines changed

13 files changed

+323
-273
lines changed

Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -2324,9 +2324,9 @@ checksum = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
23242324

23252325
[[package]]
23262326
name = "polonius-engine"
2327-
version = "0.9.0"
2327+
version = "0.10.0"
23282328
source = "registry+https://github.com/rust-lang/crates.io-index"
2329-
checksum = "f6b8a5defa2aef9ba4999aaa745fbc01c622ecea35964a306adc3e44be4f3b5b"
2329+
checksum = "50fa9dbfd0d3d60594da338cfe6f94028433eecae4b11b7e83fd99759227bbfe"
23302330
dependencies = [
23312331
"datafrog",
23322332
"log",

src/librustc/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ scoped-tls = "1.0"
2121
log = { version = "0.4", features = ["release_max_level_info", "std"] }
2222
rustc-rayon = "0.2.0"
2323
rustc-rayon-core = "0.2.0"
24-
polonius-engine = "0.9.0"
24+
polonius-engine = "0.10.0"
2525
rustc_apfloat = { path = "../librustc_apfloat" }
2626
rustc_target = { path = "../librustc_target" }
2727
rustc_macros = { path = "../librustc_macros" }

src/librustc_mir/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ either = "1.5.0"
1515
dot = { path = "../libgraphviz", package = "graphviz" }
1616
log = "0.4"
1717
log_settings = "0.1.1"
18-
polonius-engine = "0.9.0"
18+
polonius-engine = "0.10.0"
1919
rustc = { path = "../librustc" }
2020
rustc_target = { path = "../librustc_target" }
2121
rustc_data_structures = { path = "../librustc_data_structures" }

src/librustc_mir/borrow_check/flows.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::borrow_check::location::LocationIndex;
1212
use polonius_engine::Output;
1313

1414
use crate::dataflow::indexes::BorrowIndex;
15-
use crate::dataflow::move_paths::HasMoveData;
15+
use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
1616
use crate::dataflow::Borrows;
1717
use crate::dataflow::EverInitializedPlaces;
1818
use crate::dataflow::MaybeUninitializedPlaces;
@@ -21,7 +21,7 @@ use either::Either;
2121
use std::fmt;
2222
use std::rc::Rc;
2323

24-
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local>;
24+
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
2525

2626
// (forced to be `pub` due to its use as an associated type below.)
2727
crate struct Flows<'b, 'tcx> {

src/librustc_mir/borrow_check/nll/facts.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::borrow_check::location::{LocationIndex, LocationTable};
2-
use crate::dataflow::indexes::BorrowIndex;
2+
use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
33
use polonius_engine::AllFacts as PoloniusAllFacts;
44
use polonius_engine::Atom;
55
use rustc::mir::Local;
@@ -11,7 +11,7 @@ use std::fs::{self, File};
1111
use std::io::Write;
1212
use std::path::Path;
1313

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

1616
crate trait AllFactsExt {
1717
/// Returns `true` if there is a need to gather `AllFacts` given the
@@ -58,14 +58,17 @@ impl AllFactsExt for AllFacts {
5858
cfg_edge,
5959
killed,
6060
outlives,
61-
region_live_at,
6261
invalidates,
6362
var_used,
6463
var_defined,
6564
var_drop_used,
6665
var_uses_region,
6766
var_drops_region,
68-
var_initialized_on_exit,
67+
child,
68+
path_belongs_to_var,
69+
initialized_at,
70+
moved_out_at,
71+
path_accessed_at,
6972
])
7073
}
7174
Ok(())
@@ -84,6 +87,12 @@ impl Atom for LocationIndex {
8487
}
8588
}
8689

90+
impl Atom for MovePathIndex {
91+
fn index(self) -> usize {
92+
Idx::index(self)
93+
}
94+
}
95+
8796
struct FactWriter<'w> {
8897
location_table: &'w LocationTable,
8998
dir: &'w Path,

src/librustc_mir/borrow_check/nll/mod.rs

+84-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ use crate::borrow_check::nll::facts::AllFactsExt;
44
use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
55
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
66
use crate::dataflow::indexes::BorrowIndex;
7-
use crate::dataflow::move_paths::MoveData;
7+
use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind};
88
use crate::dataflow::FlowAtLocation;
99
use crate::dataflow::MaybeInitializedPlaces;
1010
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, Local, Body, Promoted};
14+
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
15+
Local, Location, Body, LocalKind, BasicBlock, Promoted};
1516
use rustc::ty::{self, RegionKind, RegionVid};
1617
use rustc_data_structures::indexed_vec::IndexVec;
1718
use rustc_errors::Diagnostic;
@@ -69,6 +70,85 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
6970
universal_regions
7071
}
7172

73+
74+
// This function populates an AllFacts instance with base facts related to
75+
// MovePaths and needed for the move analysis.
76+
fn populate_polonius_move_facts(
77+
all_facts: &mut AllFacts,
78+
move_data: &MoveData<'_>,
79+
location_table: &LocationTable,
80+
body: &Body<'_>) {
81+
all_facts
82+
.path_belongs_to_var
83+
.extend(
84+
move_data
85+
.rev_lookup
86+
.iter_locals_enumerated()
87+
.map(|(v, &m)| (m, v)));
88+
89+
for (child, move_path) in move_data.move_paths.iter_enumerated() {
90+
all_facts
91+
.child
92+
.extend(
93+
move_path
94+
.parents(&move_data.move_paths)
95+
.iter()
96+
.map(|&parent| (child, parent)));
97+
}
98+
99+
// initialized_at
100+
for init in move_data.inits.iter() {
101+
102+
match init.location {
103+
InitLocation::Statement(location) => {
104+
let block_data = &body[location.block];
105+
let is_terminator = location.statement_index == block_data.statements.len();
106+
107+
if is_terminator && init.kind == InitKind::NonPanicPathOnly {
108+
// We are at the terminator of an init that has a panic path,
109+
// and where the init should not happen on panic
110+
111+
for &successor in block_data.terminator().successors() {
112+
if body[successor].is_cleanup {
113+
continue;
114+
}
115+
116+
// The initialization happened in (or rather, when arriving at)
117+
// the successors, but not in the unwind block.
118+
let first_statement = Location { block: successor, statement_index: 0};
119+
all_facts
120+
.initialized_at
121+
.push((init.path, location_table.start_index(first_statement)));
122+
}
123+
124+
} else {
125+
// In all other cases, the initialization just happens at the
126+
// midpoint, like any other effect.
127+
all_facts.initialized_at.push((init.path, location_table.mid_index(location)));
128+
}
129+
},
130+
// Arguments are initialized on function entry
131+
InitLocation::Argument(local) => {
132+
assert!(body.local_kind(local) == LocalKind::Arg);
133+
let fn_entry = Location {block: BasicBlock::from_u32(0u32), statement_index: 0 };
134+
all_facts.initialized_at.push((init.path, location_table.start_index(fn_entry)));
135+
136+
}
137+
}
138+
}
139+
140+
141+
// moved_out_at
142+
// deinitialisation is assumed to always happen!
143+
all_facts
144+
.moved_out_at
145+
.extend(
146+
move_data
147+
.moves
148+
.iter()
149+
.map(|mo| (mo.path, location_table.mid_index(mo.source))));
150+
}
151+
72152
/// Computes the (non-lexical) regions from the input MIR.
73153
///
74154
/// This may result in errors being reported.
@@ -87,7 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
87167
errors_buffer: &mut Vec<Diagnostic>,
88168
) -> (
89169
RegionInferenceContext<'tcx>,
90-
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local>>>,
170+
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>>>,
91171
Option<ClosureRegionRequirements<'tcx>>,
92172
) {
93173
let mut all_facts = if AllFacts::enabled(infcx.tcx) {
@@ -123,6 +203,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
123203
all_facts
124204
.universal_region
125205
.extend(universal_regions.universal_regions());
206+
populate_polonius_move_facts(all_facts, move_data, location_table, body);
126207
}
127208

128209
// Create the region inference context, taking ownership of the

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

+7-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
22
use crate::util::liveness::{categorize, DefUse};
33
use rustc::mir::visit::{PlaceContext, Visitor};
4-
use rustc::mir::{Local, Location, Body};
4+
use rustc::mir::{Body, Local, Location};
55
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
66
use rustc_data_structures::vec_linked_list as vll;
77

@@ -72,16 +72,10 @@ impl LocalUseMap {
7272

7373
let mut locals_with_use_data: IndexVec<Local, bool> =
7474
IndexVec::from_elem_n(false, body.local_decls.len());
75-
live_locals
76-
.iter()
77-
.for_each(|&local| locals_with_use_data[local] = true);
78-
79-
LocalUseMapBuild {
80-
local_use_map: &mut local_use_map,
81-
elements,
82-
locals_with_use_data,
83-
}
84-
.visit_body(body);
75+
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
76+
77+
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }
78+
.visit_body(body);
8579

8680
local_use_map
8781
}
@@ -151,10 +145,8 @@ impl LocalUseMapBuild<'_> {
151145
location: Location,
152146
) {
153147
let point_index = elements.point_from_location(location);
154-
let appearance_index = appearances.push(Appearance {
155-
point_index,
156-
next: *first_appearance,
157-
});
148+
let appearance_index =
149+
appearances.push(Appearance { point_index, next: *first_appearance });
158150
*first_appearance = Some(appearance_index);
159151
}
160152
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ pub(super) fn generate<'tcx>(
5858
};
5959

6060
if !live_locals.is_empty() {
61-
trace::trace(typeck, body, elements, flow_inits, move_data, live_locals, location_table);
61+
trace::trace(typeck, body, elements, flow_inits, move_data, live_locals);
6262

63-
polonius::populate_var_liveness_facts(typeck, body, location_table);
63+
polonius::populate_access_facts(typeck, body, location_table, move_data);
6464
}
6565
}
6666

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

+56-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
use crate::borrow_check::location::{LocationIndex, LocationTable};
2+
use crate::dataflow::indexes::MovePathIndex;
3+
use crate::dataflow::move_paths::{LookupResult, MoveData};
24
use crate::util::liveness::{categorize, DefUse};
3-
use rustc::mir::visit::{PlaceContext, Visitor};
4-
use rustc::mir::{Body, Local, Location};
5+
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
6+
use rustc::mir::{Body, Local, Location, Place};
57
use rustc::ty::subst::Kind;
68
use rustc::ty::Ty;
79

810
use super::TypeChecker;
911

1012
type VarPointRelations = Vec<(Local, LocationIndex)>;
13+
type MovePathPointRelations = Vec<(MovePathIndex, LocationIndex)>;
1114

12-
struct LivenessPointFactsExtractor<'me> {
15+
struct UseFactsExtractor<'me> {
1316
var_defined: &'me mut VarPointRelations,
1417
var_used: &'me mut VarPointRelations,
1518
location_table: &'me LocationTable,
19+
var_drop_used: &'me mut VarPointRelations,
20+
move_data: &'me MoveData<'me>,
21+
path_accessed_at: &'me mut MovePathPointRelations,
1622
}
1723

1824
// A Visitor to walk through the MIR and extract point-wise facts
19-
impl LivenessPointFactsExtractor<'_> {
25+
impl UseFactsExtractor<'_> {
2026
fn location_to_index(&self, location: Location) -> LocationIndex {
2127
self.location_table.mid_index(location)
2228
}
@@ -30,15 +36,50 @@ impl LivenessPointFactsExtractor<'_> {
3036
debug!("LivenessFactsExtractor::insert_use()");
3137
self.var_used.push((local, self.location_to_index(location)));
3238
}
39+
40+
fn insert_drop_use(&mut self, local: Local, location: Location) {
41+
debug!("LivenessFactsExtractor::insert_drop_use()");
42+
self.var_drop_used.push((local, self.location_to_index(location)));
43+
}
44+
45+
fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
46+
debug!("LivenessFactsExtractor::insert_path_access({:?}, {:?})", path, location);
47+
self.path_accessed_at.push((path, self.location_to_index(location)));
48+
}
49+
50+
fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
51+
match self.move_data.rev_lookup.find(place.as_ref()) {
52+
LookupResult::Exact(mpi) => Some(mpi),
53+
LookupResult::Parent(mmpi) => mmpi,
54+
}
55+
}
3356
}
3457

35-
impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
58+
impl Visitor<'tcx> for UseFactsExtractor<'_> {
3659
fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
3760
match categorize(context) {
3861
Some(DefUse::Def) => self.insert_def(local, location),
3962
Some(DefUse::Use) => self.insert_use(local, location),
63+
Some(DefUse::Drop) => self.insert_drop_use(local, location),
64+
_ => (),
65+
}
66+
}
67+
68+
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
69+
self.super_place(place, context, location);
70+
match context {
71+
PlaceContext::NonMutatingUse(_) => {
72+
if let Some(mpi) = self.place_to_mpi(place) {
73+
self.insert_path_access(mpi, location);
74+
}
75+
}
76+
77+
PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
78+
if let Some(mpi) = self.place_to_mpi(place) {
79+
self.insert_path_access(mpi, location);
80+
}
81+
}
4082
_ => (),
41-
// NOTE: Drop handling is now done in trace()
4283
}
4384
}
4485
}
@@ -54,23 +95,27 @@ fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty
5495
});
5596
}
5697

57-
pub(super) fn populate_var_liveness_facts(
98+
pub(super) fn populate_access_facts(
5899
typeck: &mut TypeChecker<'_, 'tcx>,
59-
mir: &Body<'tcx>,
100+
body: &Body<'tcx>,
60101
location_table: &LocationTable,
102+
move_data: &MoveData<'_>,
61103
) {
62104
debug!("populate_var_liveness_facts()");
63105

64106
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
65-
LivenessPointFactsExtractor {
107+
UseFactsExtractor {
66108
var_defined: &mut facts.var_defined,
67109
var_used: &mut facts.var_used,
110+
var_drop_used: &mut facts.var_drop_used,
111+
path_accessed_at: &mut facts.path_accessed_at,
68112
location_table,
113+
move_data,
69114
}
70-
.visit_body(mir);
115+
.visit_body(body);
71116
}
72117

73-
for (local, local_decl) in mir.local_decls.iter_enumerated() {
118+
for (local, local_decl) in body.local_decls.iter_enumerated() {
74119
add_var_uses_regions(typeck, local, local_decl.ty);
75120
}
76121
}

0 commit comments

Comments
 (0)