Skip to content

Commit eaac10e

Browse files
committed
add -Znll-facts switch that dumps facts for new analysis
1 parent 74bb917 commit eaac10e

File tree

7 files changed

+441
-54
lines changed

7 files changed

+441
-54
lines changed

src/librustc/session/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12501250
"choose which RELRO level to use"),
12511251
nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED],
12521252
"when tracking region error causes, accept subminimal results for faster execution."),
1253+
nll_facts: bool = (false, parse_bool, [UNTRACKED],
1254+
"dump facts from NLL analysis into side files"),
12531255
disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
12541256
"disable user provided type assertion in NLL"),
12551257
trans_time_graph: bool = (false, parse_bool, [UNTRACKED],

src/librustc_mir/borrow_check/location.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![allow(dead_code)] // TODO -- will be used in a later commit, remove then
12-
1311
use rustc::mir::{BasicBlock, Location, Mir};
1412
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1513

src/librustc_mir/borrow_check/nll/constraint_generation.rs

Lines changed: 151 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,37 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use borrow_check::borrow_set::BorrowSet;
12+
use borrow_check::location::LocationTable;
13+
use borrow_check::nll::facts::AllFacts;
1114
use rustc::hir;
12-
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
15+
use rustc::infer::InferCtxt;
16+
use rustc::mir::visit::TyContext;
1317
use rustc::mir::visit::Visitor;
1418
use rustc::mir::Place::Projection;
15-
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
16-
use rustc::mir::visit::TyContext;
17-
use rustc::infer::InferCtxt;
18-
use rustc::ty::{self, CanonicalTy, ClosureSubsts};
19-
use rustc::ty::subst::Substs;
19+
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
20+
use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator};
2021
use rustc::ty::fold::TypeFoldable;
22+
use rustc::ty::subst::Substs;
23+
use rustc::ty::{self, CanonicalTy, ClosureSubsts};
2124

25+
use super::region_infer::{Cause, RegionInferenceContext};
2226
use super::ToRegionVid;
23-
use super::region_infer::{RegionInferenceContext, Cause};
2427

2528
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
2629
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
2730
regioncx: &mut RegionInferenceContext<'tcx>,
31+
all_facts: &mut Option<AllFacts>,
32+
location_table: &LocationTable,
2833
mir: &Mir<'tcx>,
34+
borrow_set: &BorrowSet<'tcx>,
2935
) {
3036
let mut cg = ConstraintGeneration {
37+
borrow_set,
3138
infcx,
3239
regioncx,
40+
location_table,
41+
all_facts,
3342
mir,
3443
};
3544

@@ -41,8 +50,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
4150
/// 'cg = the duration of the constraint generation process itself.
4251
struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
4352
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
53+
all_facts: &'cg mut Option<AllFacts>,
54+
location_table: &'cg LocationTable,
4455
regioncx: &'cg mut RegionInferenceContext<'tcx>,
4556
mir: &'cg Mir<'tcx>,
57+
borrow_set: &'cg BorrowSet<'tcx>,
4658
}
4759

4860
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
@@ -68,12 +80,14 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
6880
/// call. Make them live at the location where they appear.
6981
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
7082
match ty_context {
71-
TyContext::ReturnTy(source_info) |
72-
TyContext::YieldTy(source_info) |
73-
TyContext::LocalDecl { source_info, .. } => {
74-
span_bug!(source_info.span,
75-
"should not be visiting outside of the CFG: {:?}",
76-
ty_context);
83+
TyContext::ReturnTy(source_info)
84+
| TyContext::YieldTy(source_info)
85+
| TyContext::LocalDecl { source_info, .. } => {
86+
span_bug!(
87+
source_info.span,
88+
"should not be visiting outside of the CFG: {:?}",
89+
ty_context
90+
);
7791
}
7892
TyContext::Location(location) => {
7993
self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location));
@@ -90,25 +104,117 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
90104
self.super_closure_substs(substs);
91105
}
92106

107+
fn visit_statement(
108+
&mut self,
109+
block: BasicBlock,
110+
statement: &Statement<'tcx>,
111+
location: Location,
112+
) {
113+
if let Some(all_facts) = self.all_facts {
114+
all_facts.cfg_edge.push((
115+
self.location_table.start_index(location),
116+
self.location_table.mid_index(location),
117+
));
118+
119+
all_facts.cfg_edge.push((
120+
self.location_table.mid_index(location),
121+
self.location_table
122+
.start_index(location.successor_within_block()),
123+
));
124+
}
125+
126+
self.super_statement(block, statement, location);
127+
}
128+
129+
fn visit_assign(
130+
&mut self,
131+
block: BasicBlock,
132+
place: &Place<'tcx>,
133+
rvalue: &Rvalue<'tcx>,
134+
location: Location,
135+
) {
136+
// When we see `X = ...`, then kill borrows of
137+
// `(*X).foo` and so forth.
138+
if let Some(all_facts) = self.all_facts {
139+
if let Place::Local(temp) = place {
140+
if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
141+
for &borrow_index in borrow_indices {
142+
let location_index = self.location_table.mid_index(location);
143+
all_facts.killed.push((borrow_index, location_index));
144+
}
145+
}
146+
}
147+
}
148+
149+
self.super_assign(block, place, rvalue, location);
150+
}
151+
152+
fn visit_terminator(
153+
&mut self,
154+
block: BasicBlock,
155+
terminator: &Terminator<'tcx>,
156+
location: Location,
157+
) {
158+
if let Some(all_facts) = self.all_facts {
159+
all_facts.cfg_edge.push((
160+
self.location_table.start_index(location),
161+
self.location_table.mid_index(location),
162+
));
163+
164+
for successor_block in terminator.successors() {
165+
all_facts.cfg_edge.push((
166+
self.location_table.mid_index(location),
167+
self.location_table
168+
.start_index(successor_block.start_location()),
169+
));
170+
}
171+
}
172+
173+
self.super_terminator(block, terminator, location);
174+
}
175+
93176
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
94177
debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
95178

96-
// Look for an rvalue like:
97-
//
98-
// & L
99-
//
100-
// where L is the path that is borrowed. In that case, we have
101-
// to add the reborrow constraints (which don't fall out
102-
// naturally from the type-checker).
103-
if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue {
104-
self.add_reborrow_constraint(location, region, borrowed_lv);
179+
match rvalue {
180+
Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
181+
// In some cases, e.g. when borrowing from an unsafe
182+
// place, we don't bother to create a loan, since
183+
// there are no conditions to validate.
184+
if let Some(all_facts) = self.all_facts {
185+
if let Some(borrow_index) = self.borrow_set.location_map.get(&location) {
186+
let region_vid = region.to_region_vid();
187+
all_facts.borrow_region.push((
188+
region_vid,
189+
*borrow_index,
190+
self.location_table.mid_index(location),
191+
));
192+
}
193+
}
194+
195+
// Look for an rvalue like:
196+
//
197+
// & L
198+
//
199+
// where L is the path that is borrowed. In that case, we have
200+
// to add the reborrow constraints (which don't fall out
201+
// naturally from the type-checker).
202+
self.add_reborrow_constraint(location, region, borrowed_place);
203+
}
204+
205+
_ => { }
105206
}
106207

107208
self.super_rvalue(rvalue, location);
108209
}
109210

110-
fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>,
111-
_local: &Local, _location: Location) { }
211+
fn visit_user_assert_ty(
212+
&mut self,
213+
_c_ty: &CanonicalTy<'tcx>,
214+
_local: &Local,
215+
_location: Location,
216+
) {
217+
}
112218
}
113219

114220
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
@@ -122,8 +228,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
122228
{
123229
debug!(
124230
"add_regular_live_constraint(live_ty={:?}, location={:?})",
125-
live_ty,
126-
location
231+
live_ty, location
127232
);
128233

129234
self.infcx
@@ -144,8 +249,10 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
144249
) {
145250
let mut borrowed_place = borrowed_place;
146251

147-
debug!("add_reborrow_constraint({:?}, {:?}, {:?})",
148-
location, borrow_region, borrowed_place);
252+
debug!(
253+
"add_reborrow_constraint({:?}, {:?}, {:?})",
254+
location, borrow_region, borrowed_place
255+
);
149256
while let Projection(box PlaceProjection { base, elem }) = borrowed_place {
150257
debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
151258

@@ -165,12 +272,20 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
165272
location.successor_within_block(),
166273
);
167274

275+
if let Some(all_facts) = self.all_facts {
276+
all_facts.outlives.push((
277+
ref_region.to_region_vid(),
278+
borrow_region.to_region_vid(),
279+
self.location_table.mid_index(location),
280+
));
281+
}
282+
168283
match mutbl {
169284
hir::Mutability::MutImmutable => {
170285
// Immutable reference. We don't need the base
171286
// to be valid for the entire lifetime of
172287
// the borrow.
173-
break
288+
break;
174289
}
175290
hir::Mutability::MutMutable => {
176291
// Mutable reference. We *do* need the base
@@ -199,19 +314,19 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
199314
}
200315
ty::TyRawPtr(..) => {
201316
// deref of raw pointer, guaranteed to be valid
202-
break
317+
break;
203318
}
204319
ty::TyAdt(def, _) if def.is_box() => {
205320
// deref of `Box`, need the base to be valid - propagate
206321
}
207-
_ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place)
322+
_ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place),
208323
}
209324
}
210-
ProjectionElem::Field(..) |
211-
ProjectionElem::Downcast(..) |
212-
ProjectionElem::Index(..) |
213-
ProjectionElem::ConstantIndex { .. } |
214-
ProjectionElem::Subslice { .. } => {
325+
ProjectionElem::Field(..)
326+
| ProjectionElem::Downcast(..)
327+
| ProjectionElem::Index(..)
328+
| ProjectionElem::ConstantIndex { .. }
329+
| ProjectionElem::Subslice { .. } => {
215330
// other field access
216331
}
217332
}

0 commit comments

Comments
 (0)