Skip to content

Commit e79656c

Browse files
committed
support X = &*Y reborrows
1 parent 341a07c commit e79656c

File tree

3 files changed

+47
-16
lines changed

3 files changed

+47
-16
lines changed

src/librustc_mir/borrow_check/nll/escaping_locals.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
1414
use rustc::mir::visit::Visitor;
1515
use rustc::mir::*;
16+
use rustc::ty::{self, TyCtxt};
1617

1718
use rustc_data_structures::indexed_vec::Idx;
1819
use rustc_data_structures::unify as ut;
@@ -22,11 +23,13 @@ crate struct EscapingLocals {
2223
}
2324

2425
impl EscapingLocals {
25-
crate fn compute(mir: &Mir<'_>) -> Self {
26-
let mut visitor = GatherAssignedLocalsVisitor::new();
26+
crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
27+
let mut visitor = GatherAssignedLocalsVisitor::new(tcx, mir);
2728
visitor.visit_mir(mir);
2829

29-
EscapingLocals { unification_table: visitor.unification_table }
30+
EscapingLocals {
31+
unification_table: visitor.unification_table,
32+
}
3033
}
3134

3235
/// True if `local` is known to escape into static
@@ -40,8 +43,10 @@ impl EscapingLocals {
4043

4144
/// The MIR visitor gathering the union-find of the locals used in
4245
/// assignments.
43-
struct GatherAssignedLocalsVisitor {
46+
struct GatherAssignedLocalsVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
4447
unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>,
48+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
49+
mir: &'cx Mir<'tcx>,
4550
}
4651

4752
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -71,17 +76,20 @@ impl From<Local> for AssignedLocal {
7176
}
7277
}
7378

74-
impl GatherAssignedLocalsVisitor {
75-
fn new() -> Self {
79+
impl GatherAssignedLocalsVisitor<'cx, 'gcx, 'tcx> {
80+
fn new(tcx: TyCtxt<'cx, 'gcx, 'tcx>, mir: &'cx Mir<'tcx>) -> Self {
7681
Self {
7782
unification_table: ut::UnificationTable::new(),
83+
tcx,
84+
mir,
7885
}
7986
}
8087

8188
fn union_locals_if_needed(&mut self, lvalue: Option<Local>, rvalue: Option<Local>) {
8289
if let Some(lvalue) = lvalue {
8390
if let Some(rvalue) = rvalue {
8491
if lvalue != rvalue {
92+
debug!("EscapingLocals: union {:?} and {:?}", lvalue, rvalue);
8593
self.unification_table
8694
.union(AssignedLocal::from(lvalue), AssignedLocal::from(rvalue));
8795
}
@@ -115,7 +123,7 @@ fn find_local_in_operand(op: &Operand) -> Option<Local> {
115123
}
116124
}
117125

118-
impl<'tcx> Visitor<'tcx> for GatherAssignedLocalsVisitor {
126+
impl Visitor<'tcx> for GatherAssignedLocalsVisitor<'_, '_, 'tcx> {
119127
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
120128
// We need as many union-find keys as there are locals
121129
for _ in 0..mir.local_decls.len() {
@@ -139,6 +147,19 @@ impl<'tcx> Visitor<'tcx> for GatherAssignedLocalsVisitor {
139147
match rvalue {
140148
Rvalue::Use(op) => self.union_locals_if_needed(local, find_local_in_operand(op)),
141149
Rvalue::Ref(_, _, place) => {
150+
// Special case: if you have `X = &*Y` where `Y` is a
151+
// reference, then the outlives relationships should
152+
// ensure that all regions in `Y` are constrained by
153+
// regions in `X`.
154+
if let Place::Projection(proj) = place {
155+
if let ProjectionElem::Deref = proj.elem {
156+
if let ty::TyRef(..) = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx).sty
157+
{
158+
self.union_locals_if_needed(local, find_local_in_place(&proj.base));
159+
}
160+
}
161+
}
162+
142163
self.union_locals_if_needed(local, find_local_in_place(place))
143164
}
144165

src/librustc_mir/borrow_check/nll/liveness_map.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
1919
use borrow_check::nll::escaping_locals::EscapingLocals;
2020
use rustc::mir::{Local, Mir};
21-
use rustc::ty::TypeFoldable;
21+
use rustc::ty::{TyCtxt, TypeFoldable};
2222
use rustc_data_structures::indexed_vec::IndexVec;
2323
use util::liveness::LiveVariableMap;
2424

@@ -55,10 +55,12 @@ impl LiveVariableMap for NllLivenessMap {
5555
impl NllLivenessMap {
5656
/// Iterates over the variables in Mir and assigns each Local whose type contains
5757
/// regions a LocalWithRegion index. Returns a map for converting back and forth.
58-
crate fn compute(mir: &Mir<'_>) -> Self {
59-
let mut escaping_locals = EscapingLocals::compute(mir);
58+
crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
59+
let mut escaping_locals = EscapingLocals::compute(tcx, mir);
6060

6161
let mut to_local = IndexVec::default();
62+
let mut escapes_into_return = 0;
63+
let mut no_regions = 0;
6264
let from_local: IndexVec<Local, Option<_>> = mir
6365
.local_decls
6466
.iter_enumerated()
@@ -70,14 +72,22 @@ impl NllLivenessMap {
7072
// (e.g., `'static`) and hence liveness is not
7173
// needed. This is particularly important for big
7274
// statics.
75+
escapes_into_return += 1;
7376
None
7477
} else if local_decl.ty.has_free_regions() {
75-
Some(to_local.push(local))
78+
let l = to_local.push(local);
79+
debug!("liveness_map: {:?} = {:?}", local, l);
80+
Some(l)
7681
} else {
82+
no_regions += 1;
7783
None
7884
}
7985
}).collect();
8086

87+
debug!("liveness_map: {} variables need liveness", to_local.len());
88+
debug!("liveness_map: {} escapes into return", escapes_into_return);
89+
debug!("liveness_map: {} no regions", no_regions);
90+
8191
Self {
8292
from_local,
8393
to_local,

src/librustc_mir/borrow_check/nll/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
109109
let elements = &Rc::new(RegionValueElements::new(mir));
110110

111111
// Run the MIR type-checker.
112-
let liveness_map = NllLivenessMap::compute(&mir);
112+
let liveness_map = NllLivenessMap::compute(infcx.tcx, &mir);
113113
let liveness = LivenessResults::compute(mir, &liveness_map);
114114
let (constraint_sets, universal_region_relations) = type_check::type_check(
115115
infcx,
@@ -206,6 +206,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
206206
dump_mir_results(
207207
infcx,
208208
&liveness,
209+
&liveness_map,
209210
MirSource::item(def_id),
210211
&mir,
211212
&regioncx,
@@ -222,6 +223,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
222223
fn dump_mir_results<'a, 'gcx, 'tcx>(
223224
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
224225
liveness: &LivenessResults<LocalWithRegion>,
226+
liveness_map: &NllLivenessMap,
225227
source: MirSource,
226228
mir: &Mir<'tcx>,
227229
regioncx: &RegionInferenceContext,
@@ -231,16 +233,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
231233
return;
232234
}
233235

234-
let map = &NllLivenessMap::compute(mir);
235-
236236
let regular_liveness_per_location: FxHashMap<_, _> = mir
237237
.basic_blocks()
238238
.indices()
239239
.flat_map(|bb| {
240240
let mut results = vec![];
241241
liveness
242242
.regular
243-
.simulate_block(&mir, bb, map, |location, local_set| {
243+
.simulate_block(&mir, bb, liveness_map, |location, local_set| {
244244
results.push((location, local_set.clone()));
245245
});
246246
results
@@ -254,7 +254,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
254254
let mut results = vec![];
255255
liveness
256256
.drop
257-
.simulate_block(&mir, bb, map, |location, local_set| {
257+
.simulate_block(&mir, bb, liveness_map, |location, local_set| {
258258
results.push((location, local_set.clone()));
259259
});
260260
results

0 commit comments

Comments
 (0)