Skip to content

Commit 49d2274

Browse files
committed
constraint_generation: create liveness constraints more thoroughly
We now visit just the stuff in the CFG, and we add liveness constraints for all the random types, regions etc that appear within rvalues and statements.
1 parent 4de7336 commit 49d2274

File tree

5 files changed

+155
-110
lines changed

5 files changed

+155
-110
lines changed

src/librustc_mir/borrow_check/nll/constraint_generation.rs

Lines changed: 151 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@
99
// except according to those terms.
1010

1111
use rustc::hir;
12-
use rustc::mir::{Local, Location, Place, Mir, Rvalue};
12+
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
1313
use rustc::mir::visit::Visitor;
1414
use rustc::mir::Place::Projection;
15-
use rustc::mir::{PlaceProjection, ProjectionElem};
15+
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
16+
use rustc::mir::visit::TyContext;
1617
use rustc::infer::InferCtxt;
1718
use rustc::traits::{self, ObligationCause};
18-
use rustc::ty::{self, Ty};
19+
use rustc::ty::{self, ClosureSubsts, Ty};
20+
use rustc::ty::subst::Substs;
1921
use rustc::ty::fold::TypeFoldable;
2022
use rustc::util::common::ErrorReported;
2123
use rustc_data_structures::fx::FxHashSet;
2224
use syntax::codemap::DUMMY_SP;
2325
use borrow_check::FlowInProgress;
2426
use dataflow::MaybeInitializedLvals;
25-
use dataflow::move_paths::{MoveData, HasMoveData};
27+
use dataflow::move_paths::{HasMoveData, MoveData};
2628

2729
use super::LivenessResults;
2830
use super::ToRegionVid;
@@ -37,15 +39,19 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
3739
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
3840
move_data: &MoveData<'tcx>,
3941
) {
40-
ConstraintGeneration {
42+
let mut cg = ConstraintGeneration {
4143
infcx,
4244
regioncx,
4345
mir,
4446
liveness,
4547
param_env,
4648
flow_inits,
4749
move_data,
48-
}.add_constraints();
50+
};
51+
52+
for (bb, data) in mir.basic_blocks().iter_enumerated() {
53+
cg.visit_basic_block_data(bb, data);
54+
}
4955
}
5056

5157
/// 'cg = the duration of the constraint generation process itself.
@@ -59,75 +65,147 @@ struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
5965
move_data: &'cg MoveData<'tcx>,
6066
}
6167

62-
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
63-
fn add_constraints(&mut self) {
64-
self.add_liveness_constraints();
65-
self.add_borrow_constraints();
68+
69+
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
70+
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
71+
self.add_liveness_constraints(bb);
72+
self.super_basic_block_data(bb, data);
73+
}
74+
75+
/// We sometimes have `substs` within an rvalue, or within a
76+
/// call. Make them live at the location where they appear.
77+
fn visit_substs(&mut self, substs: &&'tcx Substs<'tcx>, location: Location) {
78+
self.add_regular_live_constraint(*substs, location);
79+
self.super_substs(substs);
80+
}
81+
82+
/// We sometimes have `region` within an rvalue, or within a
83+
/// call. Make them live at the location where they appear.
84+
fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) {
85+
self.add_regular_live_constraint(*region, location);
86+
self.super_region(region);
6687
}
6788

89+
/// We sometimes have `ty` within an rvalue, or within a
90+
/// call. Make them live at the location where they appear.
91+
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
92+
match ty_context {
93+
TyContext::ReturnTy(source_info) |
94+
TyContext::LocalDecl { source_info, .. } => {
95+
span_bug!(source_info.span,
96+
"should not be visiting outside of the CFG: {:?}",
97+
ty_context);
98+
}
99+
TyContext::Location(location) => {
100+
self.add_regular_live_constraint(*ty, location);
101+
}
102+
}
103+
104+
self.super_ty(ty);
105+
}
106+
107+
/// We sometimes have `closure_substs` within an rvalue, or within a
108+
/// call. Make them live at the location where they appear.
109+
fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, location: Location) {
110+
self.add_regular_live_constraint(*substs, location);
111+
self.super_closure_substs(substs);
112+
}
113+
114+
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
115+
debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
116+
117+
// Look for an rvalue like:
118+
//
119+
// & L
120+
//
121+
// where L is the path that is borrowed. In that case, we have
122+
// to add the reborrow constraints (which don't fall out
123+
// naturally from the type-checker).
124+
if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue {
125+
self.add_reborrow_constraint(location, region, borrowed_lv);
126+
}
127+
128+
self.super_rvalue(rvalue, location);
129+
}
130+
}
131+
132+
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
68133
/// Liveness constraints:
69134
///
70135
/// > If a variable V is live at point P, then all regions R in the type of V
71136
/// > must include the point P.
72-
fn add_liveness_constraints(&mut self) {
73-
debug!("add_liveness_constraints()");
74-
for bb in self.mir.basic_blocks().indices() {
75-
debug!("add_liveness_constraints: bb={:?}", bb);
76-
77-
self.liveness
78-
.regular
79-
.simulate_block(self.mir, bb, |location, live_locals| {
80-
for live_local in live_locals.iter() {
81-
let live_local_ty = self.mir.local_decls[live_local].ty;
82-
self.add_regular_live_constraint(live_local_ty, location);
83-
}
84-
});
137+
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
138+
debug!("add_liveness_constraints(bb={:?})", bb);
85139

86-
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
87-
self.liveness.drop.simulate_block(self.mir, bb, |location, live_locals| {
140+
self.liveness
141+
.regular
142+
.simulate_block(self.mir, bb, |location, live_locals| {
143+
for live_local in live_locals.iter() {
144+
let live_local_ty = self.mir.local_decls[live_local].ty;
145+
self.add_regular_live_constraint(live_local_ty, location);
146+
}
147+
});
148+
149+
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
150+
self.liveness
151+
.drop
152+
.simulate_block(self.mir, bb, |location, live_locals| {
88153
all_live_locals.push((location, live_locals.iter().collect()));
89154
});
90-
debug!("add_liveness_constraints: all_live_locals={:#?}", all_live_locals);
91-
92-
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
93-
self.flow_inits.reset_to_entry_of(bb);
94-
while let Some((location, live_locals)) = all_live_locals.pop() {
95-
for live_local in live_locals {
96-
debug!("add_liveness_constraints: location={:?} live_local={:?}", location,
97-
live_local);
98-
99-
self.flow_inits.each_state_bit(|mpi_init| {
100-
debug!("add_liveness_constraints: location={:?} initialized={:?}",
101-
location,
102-
&self.flow_inits
103-
.base_results
104-
.operator()
105-
.move_data()
106-
.move_paths[mpi_init]);
107-
});
108-
109-
let mpi = self.move_data.rev_lookup.find_local(live_local);
110-
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
111-
debug!("add_liveness_constraints: mpi={:?} has initialized child {:?}",
112-
self.move_data.move_paths[mpi],
113-
self.move_data.move_paths[initialized_child]);
114-
115-
let live_local_ty = self.mir.local_decls[live_local].ty;
116-
self.add_drop_live_constraint(live_local_ty, location);
117-
}
118-
}
155+
debug!(
156+
"add_liveness_constraints: all_live_locals={:#?}",
157+
all_live_locals
158+
);
119159

120-
if location.statement_index == terminator_index {
121-
debug!("add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
122-
location);
123-
self.flow_inits.reconstruct_terminator_effect(location);
124-
} else {
125-
debug!("add_liveness_constraints: reconstruct_statement_effect from {:#?}",
126-
location);
127-
self.flow_inits.reconstruct_statement_effect(location);
160+
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
161+
self.flow_inits.reset_to_entry_of(bb);
162+
while let Some((location, live_locals)) = all_live_locals.pop() {
163+
for live_local in live_locals {
164+
debug!(
165+
"add_liveness_constraints: location={:?} live_local={:?}",
166+
location,
167+
live_local
168+
);
169+
170+
self.flow_inits.each_state_bit(|mpi_init| {
171+
debug!(
172+
"add_liveness_constraints: location={:?} initialized={:?}",
173+
location,
174+
&self.flow_inits
175+
.base_results
176+
.operator()
177+
.move_data()
178+
.move_paths[mpi_init]
179+
);
180+
});
181+
182+
let mpi = self.move_data.rev_lookup.find_local(live_local);
183+
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
184+
debug!(
185+
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
186+
self.move_data.move_paths[mpi],
187+
self.move_data.move_paths[initialized_child]
188+
);
189+
190+
let live_local_ty = self.mir.local_decls[live_local].ty;
191+
self.add_drop_live_constraint(live_local_ty, location);
128192
}
129-
self.flow_inits.apply_local_effect();
130193
}
194+
195+
if location.statement_index == terminator_index {
196+
debug!(
197+
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
198+
location
199+
);
200+
self.flow_inits.reconstruct_terminator_effect(location);
201+
} else {
202+
debug!(
203+
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
204+
location
205+
);
206+
self.flow_inits.reconstruct_statement_effect(location);
207+
}
208+
self.flow_inits.apply_local_effect();
131209
}
132210
}
133211

@@ -185,13 +263,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
185263
// All things in the `outlives` array may be touched by
186264
// the destructor and must be live at this point.
187265
for outlive in outlives {
188-
if let Some(ty) = outlive.as_type() {
189-
self.add_regular_live_constraint(ty, location);
190-
} else if let Some(r) = outlive.as_region() {
191-
self.add_regular_live_constraint(r, location);
192-
} else {
193-
bug!()
194-
}
266+
self.add_regular_live_constraint(outlive, location);
195267
}
196268

197269
// However, there may also be some types that
@@ -228,10 +300,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
228300
}
229301
}
230302

231-
fn add_borrow_constraints(&mut self) {
232-
self.visit_mir(self.mir);
233-
}
234-
235303
fn add_reborrow_constraint(
236304
&mut self,
237305
location: Location,
@@ -246,43 +314,24 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
246314
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
247315
let base_sty = &base_ty.sty;
248316

249-
if let ty::TyRef(base_region, ty::TypeAndMut{ ty: _, mutbl }) = *base_sty {
317+
if let ty::TyRef(base_region, ty::TypeAndMut { ty: _, mutbl }) = *base_sty {
250318
match mutbl {
251-
hir::Mutability::MutImmutable => { },
319+
hir::Mutability::MutImmutable => {}
252320

253321
hir::Mutability::MutMutable => {
254322
self.add_reborrow_constraint(location, borrow_region, base);
255-
},
323+
}
256324
}
257325

258326
let span = self.mir.source_info(location).span;
259-
self.regioncx.add_outlives(span,
260-
base_region.to_region_vid(),
261-
borrow_region.to_region_vid(),
262-
location.successor_within_block());
327+
self.regioncx.add_outlives(
328+
span,
329+
base_region.to_region_vid(),
330+
borrow_region.to_region_vid(),
331+
location.successor_within_block(),
332+
);
263333
}
264334
}
265335
}
266336
}
267337
}
268-
269-
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
270-
fn visit_rvalue(&mut self,
271-
rvalue: &Rvalue<'tcx>,
272-
location: Location) {
273-
debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
274-
275-
// Look for an rvalue like:
276-
//
277-
// & L
278-
//
279-
// where L is the path that is borrowed. In that case, we have
280-
// to add the reborrow constraints (which don't fall out
281-
// naturally from the type-checker).
282-
if let Rvalue::Ref(region, _bk, ref borrowed_place) = *rvalue {
283-
self.add_reborrow_constraint(location, region, borrowed_place);
284-
}
285-
286-
self.super_rvalue(rvalue, location);
287-
}
288-
}

src/librustc_mir/dataflow/impls/borrows.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
132132
&self.borrows[idx].location
133133
}
134134

135-
pub fn nonlexical_regioncx(&self) -> Option<&'a RegionInferenceContext<'tcx>> {
136-
self.nonlexical_regioncx
137-
}
138-
139135
/// Returns the span for the "end point" given region. This will
140136
/// return `None` if NLL is enabled, since that concept has no
141137
/// meaning there. Otherwise, return region span if it exists and

src/test/mir-opt/nll/region-liveness-basic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn main() {
3131

3232
// END RUST SOURCE
3333
// START rustc.main.nll.0.mir
34-
// | '_#1r: {bb2[1], bb3[0], bb3[1]}
34+
// | '_#1r: {bb2[0], bb2[1], bb3[0], bb3[1]}
3535
// | '_#2r: {bb2[1], bb3[0], bb3[1]}
3636
// ...
3737
// let _2: &'_#2r usize;

src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ fn main() {
3636

3737
// END RUST SOURCE
3838
// START rustc.main.nll.0.mir
39-
// | '_#1r: {bb2[1], bb3[0], bb3[1]}
39+
// | '_#1r: {bb2[0], bb2[1], bb3[0], bb3[1]}
4040
// ...
41-
// | '_#3r: {bb8[2], bb8[3], bb8[4]}
41+
// | '_#3r: {bb8[1], bb8[2], bb8[3], bb8[4]}
4242
// | '_#4r: {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]}
4343
// ...
4444
// let mut _2: &'_#4r usize;

src/test/mir-opt/nll/region-subtyping-basic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn main() {
3232

3333
// END RUST SOURCE
3434
// START rustc.main.nll.0.mir
35-
// | '_#1r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
35+
// | '_#1r: {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
3636
// | '_#2r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
3737
// | '_#3r: {bb2[5], bb2[6], bb3[0], bb3[1]}
3838
// END rustc.main.nll.0.mir

0 commit comments

Comments
 (0)