Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 83ddc33

Browse files
committedAug 28, 2018
Auto merge of #53314 - nikomatsakis:nll-invert-liveness, r=pnkfelix
NLL: experiment with inverting liveness I got inspired to see what would happen here. Fixes #52460 r? @pnkfelix
2 parents 59e52b1 + 8d231ec commit 83ddc33

File tree

21 files changed

+1001
-608
lines changed

21 files changed

+1001
-608
lines changed
 

‎src/librustc/mir/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,12 @@ impl<'tcx> Mir<'tcx> {
194194
}
195195

196196
#[inline]
197-
pub fn predecessors(&self) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> {
197+
pub fn predecessors(&self) -> ReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> {
198198
self.cache.predecessors(self)
199199
}
200200

201201
#[inline]
202-
pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<Vec<BasicBlock>> {
202+
pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<'_, Vec<BasicBlock>> {
203203
ReadGuard::map(self.predecessors(), |p| &p[bb])
204204
}
205205

@@ -328,6 +328,14 @@ impl<'tcx> Mir<'tcx> {
328328
pub fn return_ty(&self) -> Ty<'tcx> {
329329
self.local_decls[RETURN_PLACE].ty
330330
}
331+
332+
/// Get the location of the terminator for the given block
333+
pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
334+
Location {
335+
block: bb,
336+
statement_index: self[bb].statements.len(),
337+
}
338+
}
331339
}
332340

333341
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]

‎src/librustc_data_structures/graph/dominators/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>(
3838

3939
// compute the post order index (rank) for each node
4040
let mut post_order_rank: IndexVec<G::Node, usize> =
41-
IndexVec::from_elem_n(usize::default(), graph.num_nodes());
41+
(0..graph.num_nodes()).map(|_| 0).collect();
4242
for (index, node) in rpo.iter().rev().cloned().enumerate() {
4343
post_order_rank[node] = index;
4444
}
4545

4646
let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
47-
IndexVec::from_elem_n(Option::default(), graph.num_nodes());
47+
(0..graph.num_nodes()).map(|_| None).collect();
4848
immediate_dominators[start_node] = Some(start_node);
4949

5050
let mut changed = true;

‎src/librustc_data_structures/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
2121
html_root_url = "https://doc.rust-lang.org/nightly/")]
2222

23+
#![feature(in_band_lifetimes)]
24+
#![feature(impl_header_lifetime_elision)]
2325
#![feature(unboxed_closures)]
2426
#![feature(fn_traits)]
2527
#![feature(unsize)]
@@ -86,6 +88,7 @@ pub mod thin_vec;
8688
pub mod transitive_relation;
8789
pub mod tuple_slice;
8890
pub use ena::unify;
91+
pub mod vec_linked_list;
8992
pub mod work_queue;
9093
pub mod fingerprint;
9194

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use indexed_vec::{Idx, IndexVec};
12+
13+
pub fn iter<Ls>(
14+
first: Option<Ls::LinkIndex>,
15+
links: &'a Ls,
16+
) -> impl Iterator<Item = Ls::LinkIndex> + 'a
17+
where
18+
Ls: Links,
19+
{
20+
VecLinkedListIterator {
21+
links: links,
22+
current: first,
23+
}
24+
}
25+
26+
pub struct VecLinkedListIterator<Ls>
27+
where
28+
Ls: Links,
29+
{
30+
links: Ls,
31+
current: Option<Ls::LinkIndex>,
32+
}
33+
34+
impl<Ls> Iterator for VecLinkedListIterator<Ls>
35+
where
36+
Ls: Links,
37+
{
38+
type Item = Ls::LinkIndex;
39+
40+
fn next(&mut self) -> Option<Ls::LinkIndex> {
41+
if let Some(c) = self.current {
42+
self.current = <Ls as Links>::next(&self.links, c);
43+
Some(c)
44+
} else {
45+
None
46+
}
47+
}
48+
}
49+
50+
pub trait Links {
51+
type LinkIndex: Copy;
52+
53+
fn next(links: &Self, index: Self::LinkIndex) -> Option<Self::LinkIndex>;
54+
}
55+
56+
impl<Ls> Links for &Ls
57+
where
58+
Ls: Links,
59+
{
60+
type LinkIndex = Ls::LinkIndex;
61+
62+
fn next(links: &Self, index: Ls::LinkIndex) -> Option<Ls::LinkIndex> {
63+
<Ls as Links>::next(links, index)
64+
}
65+
}
66+
67+
pub trait LinkElem {
68+
type LinkIndex: Copy;
69+
70+
fn next(elem: &Self) -> Option<Self::LinkIndex>;
71+
}
72+
73+
impl<L, E> Links for IndexVec<L, E>
74+
where
75+
E: LinkElem<LinkIndex = L>,
76+
L: Idx,
77+
{
78+
type LinkIndex = L;
79+
80+
fn next(links: &Self, index: L) -> Option<L> {
81+
<E as LinkElem>::next(&links[index])
82+
}
83+
}

‎src/librustc_mir/borrow_check/flows.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ impl<'b, 'gcx, 'tcx> FlowsAtLocation for Flows<'b, 'gcx, 'tcx> {
8989
each_flow!(self, reset_to_entry_of(bb));
9090
}
9191

92+
fn reset_to_exit_of(&mut self, bb: BasicBlock) {
93+
each_flow!(self, reset_to_exit_of(bb));
94+
}
95+
9296
fn reconstruct_statement_effect(&mut self, location: Location) {
9397
each_flow!(self, reconstruct_statement_effect(location));
9498
}

‎src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
1717
use rustc::mir::{Local, Location, Mir};
1818
use rustc::ty::{RegionVid, TyCtxt};
1919
use rustc_data_structures::fx::FxHashSet;
20-
use util::liveness::{self, DefUse, LivenessMode};
20+
use util::liveness::{self, DefUse};
2121

2222
crate fn find<'tcx>(
2323
mir: &Mir<'tcx>,
@@ -32,10 +32,6 @@ crate fn find<'tcx>(
3232
tcx,
3333
region_vid,
3434
start_point,
35-
liveness_mode: LivenessMode {
36-
include_regular_use: true,
37-
include_drops: true,
38-
},
3935
};
4036

4137
uf.find()
@@ -47,7 +43,6 @@ struct UseFinder<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
4743
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
4844
region_vid: RegionVid,
4945
start_point: Location,
50-
liveness_mode: LivenessMode,
5146
}
5247

5348
impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
@@ -108,7 +103,6 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
108103
mir: self.mir,
109104
tcx: self.tcx,
110105
region_vid: self.region_vid,
111-
liveness_mode: self.liveness_mode,
112106
def_use_result: None,
113107
};
114108

@@ -122,7 +116,6 @@ struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
122116
mir: &'cx Mir<'tcx>,
123117
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
124118
region_vid: RegionVid,
125-
liveness_mode: LivenessMode,
126119
def_use_result: Option<DefUseResult>,
127120
}
128121

@@ -146,23 +139,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'gcx, 'tcx> {
146139
});
147140

148141
if found_it {
149-
match liveness::categorize(context, self.liveness_mode) {
150-
Some(DefUse::Def) => {
151-
self.def_use_result = Some(DefUseResult::Def);
152-
}
153-
154-
Some(DefUse::Use) => {
155-
self.def_use_result = if context.is_drop() {
156-
Some(DefUseResult::UseDrop { local })
157-
} else {
158-
Some(DefUseResult::UseLive { local })
159-
};
160-
}
161-
162-
None => {
163-
self.def_use_result = None;
164-
}
165-
}
142+
self.def_use_result = match liveness::categorize(context) {
143+
Some(DefUse::Def) => Some(DefUseResult::Def),
144+
Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
145+
Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
146+
None => None,
147+
};
166148
}
167149
}
168150
}

‎src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use borrow_check::borrow_set::BorrowSet;
1212
use borrow_check::location::{LocationIndex, LocationTable};
1313
use borrow_check::nll::facts::AllFactsExt;
1414
use borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
15-
use borrow_check::nll::type_check::liveness::liveness_map::{NllLivenessMap, LocalWithRegion};
15+
use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
1616
use borrow_check::nll::region_infer::values::RegionValueElements;
1717
use dataflow::indexes::BorrowIndex;
1818
use dataflow::move_paths::MoveData;
@@ -22,22 +22,19 @@ use rustc::hir::def_id::DefId;
2222
use rustc::infer::InferCtxt;
2323
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir};
2424
use rustc::ty::{self, RegionKind, RegionVid};
25-
use rustc::util::nodemap::FxHashMap;
2625
use rustc_errors::Diagnostic;
27-
use std::collections::BTreeSet;
2826
use std::fmt::Debug;
2927
use std::env;
3028
use std::io;
3129
use std::path::PathBuf;
3230
use std::rc::Rc;
3331
use std::str::FromStr;
3432
use transform::MirSource;
35-
use util::liveness::{LivenessResults, LiveVarSet};
3633

3734
use self::mir_util::PassWhere;
3835
use polonius_engine::{Algorithm, Output};
3936
use util as mir_util;
40-
use util::pretty::{self, ALIGN};
37+
use util::pretty;
4138

4239
mod constraint_generation;
4340
pub mod explain_borrow;
@@ -111,8 +108,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
111108
let MirTypeckResults {
112109
constraints,
113110
universal_region_relations,
114-
liveness,
115-
liveness_map,
116111
} = type_check::type_check(
117112
infcx,
118113
param_env,
@@ -205,8 +200,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
205200
// write unit-tests, as well as helping with debugging.
206201
dump_mir_results(
207202
infcx,
208-
&liveness,
209-
&liveness_map,
210203
MirSource::item(def_id),
211204
&mir,
212205
&regioncx,
@@ -222,8 +215,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
222215

223216
fn dump_mir_results<'a, 'gcx, 'tcx>(
224217
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
225-
liveness: &LivenessResults<LocalWithRegion>,
226-
liveness_map: &NllLivenessMap,
227218
source: MirSource,
228219
mir: &Mir<'tcx>,
229220
regioncx: &RegionInferenceContext,
@@ -233,34 +224,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
233224
return;
234225
}
235226

236-
let regular_liveness_per_location: FxHashMap<_, _> = mir
237-
.basic_blocks()
238-
.indices()
239-
.flat_map(|bb| {
240-
let mut results = vec![];
241-
liveness
242-
.regular
243-
.simulate_block(&mir, bb, liveness_map, |location, local_set| {
244-
results.push((location, local_set.clone()));
245-
});
246-
results
247-
})
248-
.collect();
249-
250-
let drop_liveness_per_location: FxHashMap<_, _> = mir
251-
.basic_blocks()
252-
.indices()
253-
.flat_map(|bb| {
254-
let mut results = vec![];
255-
liveness
256-
.drop
257-
.simulate_block(&mir, bb, liveness_map, |location, local_set| {
258-
results.push((location, local_set.clone()));
259-
});
260-
results
261-
})
262-
.collect();
263-
264227
mir_util::dump_mir(
265228
infcx.tcx,
266229
None,
@@ -283,26 +246,10 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
283246
}
284247
}
285248

286-
PassWhere::BeforeLocation(location) => {
287-
let s = live_variable_set(
288-
&regular_liveness_per_location[&location],
289-
&drop_liveness_per_location[&location],
290-
);
291-
writeln!(
292-
out,
293-
"{:ALIGN$} | Live variables on entry to {:?}: {}",
294-
"",
295-
location,
296-
s,
297-
ALIGN = ALIGN
298-
)?;
249+
PassWhere::BeforeLocation(_) => {
299250
}
300251

301-
// After each basic block, dump out the values
302-
// that are live on exit from the basic block.
303-
PassWhere::AfterTerminator(bb) => {
304-
let s = live_variable_set(&liveness.regular.outs[bb], &liveness.drop.outs[bb]);
305-
writeln!(out, " | Live variables on exit from {:?}: {}", bb, s)?;
252+
PassWhere::AfterTerminator(_) => {
306253
}
307254

308255
PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
@@ -420,33 +367,3 @@ impl ToRegionVid for RegionVid {
420367
self
421368
}
422369
}
423-
424-
fn live_variable_set(
425-
regular: &LiveVarSet<LocalWithRegion>,
426-
drops: &LiveVarSet<LocalWithRegion>
427-
) -> String {
428-
// sort and deduplicate:
429-
let all_locals: BTreeSet<_> = regular.iter().chain(drops.iter()).collect();
430-
431-
// construct a string with each local, including `(drop)` if it is
432-
// only dropped, versus a regular use.
433-
let mut string = String::new();
434-
for local in all_locals {
435-
string.push_str(&format!("{:?}", local));
436-
437-
if !regular.contains(&local) {
438-
assert!(drops.contains(&local));
439-
string.push_str(" (drop)");
440-
}
441-
442-
string.push_str(", ");
443-
}
444-
445-
let len = if string.is_empty() {
446-
0
447-
} else {
448-
string.len() - 2
449-
};
450-
451-
format!("[{}]", &string[..len])
452-
}

‎src/librustc_mir/borrow_check/nll/region_infer/values.rs

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use rustc::mir::{BasicBlock, Location, Mir};
1212
use rustc::ty::{self, RegionVid};
13-
use rustc_data_structures::bitvec::SparseBitMatrix;
13+
use rustc_data_structures::bitvec::{BitArray, SparseBitMatrix};
1414
use rustc_data_structures::indexed_vec::Idx;
1515
use rustc_data_structures::indexed_vec::IndexVec;
1616
use std::fmt::Debug;
@@ -20,13 +20,18 @@ use std::rc::Rc;
2020
crate struct RegionValueElements {
2121
/// For each basic block, how many points are contained within?
2222
statements_before_block: IndexVec<BasicBlock, usize>,
23+
24+
/// Map backward from each point to the basic block that it
25+
/// belongs to.
26+
basic_blocks: IndexVec<PointIndex, BasicBlock>,
27+
2328
num_points: usize,
2429
}
2530

2631
impl RegionValueElements {
2732
crate fn new(mir: &Mir<'_>) -> Self {
2833
let mut num_points = 0;
29-
let statements_before_block = mir
34+
let statements_before_block: IndexVec<BasicBlock, usize> = mir
3035
.basic_blocks()
3136
.iter()
3237
.map(|block_data| {
@@ -41,14 +46,25 @@ impl RegionValueElements {
4146
);
4247
debug!("RegionValueElements: num_points={:#?}", num_points);
4348

49+
let mut basic_blocks = IndexVec::with_capacity(num_points);
50+
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
51+
basic_blocks.extend((0 .. bb_data.statements.len() + 1).map(|_| bb));
52+
}
53+
4454
Self {
4555
statements_before_block,
56+
basic_blocks,
4657
num_points,
4758
}
4859
}
4960

61+
/// Total number of point indices
62+
crate fn num_points(&self) -> usize {
63+
self.num_points
64+
}
65+
5066
/// Converts a `Location` into a `PointIndex`. O(1).
51-
fn point_from_location(&self, location: Location) -> PointIndex {
67+
crate fn point_from_location(&self, location: Location) -> PointIndex {
5268
let Location {
5369
block,
5470
statement_index,
@@ -57,39 +73,50 @@ impl RegionValueElements {
5773
PointIndex::new(start_index + statement_index)
5874
}
5975

60-
/// Converts a `PointIndex` back to a location. O(N) where N is
61-
/// the number of blocks; could be faster if we ever cared.
62-
crate fn to_location(&self, i: PointIndex) -> Location {
63-
let point_index = i.index();
64-
65-
// Find the basic block. We have a vector with the
66-
// starting index of the statement in each block. Imagine
67-
// we have statement #22, and we have a vector like:
68-
//
69-
// [0, 10, 20]
70-
//
71-
// In that case, this represents point_index 2 of
72-
// basic block BB2. We know this because BB0 accounts for
73-
// 0..10, BB1 accounts for 11..20, and BB2 accounts for
74-
// 20...
75-
//
76-
// To compute this, we could do a binary search, but
77-
// because I am lazy we instead iterate through to find
78-
// the last point where the "first index" (0, 10, or 20)
79-
// was less than the statement index (22). In our case, this will
80-
// be (BB2, 20).
81-
//
82-
// Nit: we could do a binary search here but I'm too lazy.
83-
let (block, &first_index) = self
84-
.statements_before_block
85-
.iter_enumerated()
86-
.filter(|(_, first_index)| **first_index <= point_index)
87-
.last()
88-
.unwrap();
89-
90-
Location {
91-
block,
92-
statement_index: point_index - first_index,
76+
/// Converts a `Location` into a `PointIndex`. O(1).
77+
crate fn entry_point(&self, block: BasicBlock) -> PointIndex {
78+
let start_index = self.statements_before_block[block];
79+
PointIndex::new(start_index)
80+
}
81+
82+
/// Converts a `PointIndex` back to a location. O(1).
83+
crate fn to_location(&self, index: PointIndex) -> Location {
84+
assert!(index.index() < self.num_points);
85+
let block = self.basic_blocks[index];
86+
let start_index = self.statements_before_block[block];
87+
let statement_index = index.index() - start_index;
88+
Location { block, statement_index }
89+
}
90+
91+
/// Sometimes we get point-indices back from bitsets that may be
92+
/// out of range (because they round up to the nearest 2^N number
93+
/// of bits). Use this function to filter such points out if you
94+
/// like.
95+
crate fn point_in_range(&self, index: PointIndex) -> bool {
96+
index.index() < self.num_points
97+
}
98+
99+
/// Pushes all predecessors of `index` onto `stack`.
100+
crate fn push_predecessors(
101+
&self,
102+
mir: &Mir<'_>,
103+
index: PointIndex,
104+
stack: &mut Vec<PointIndex>,
105+
) {
106+
let Location { block, statement_index } = self.to_location(index);
107+
if statement_index == 0 {
108+
// If this is a basic block head, then the predecessors are
109+
// the the terminators of other basic blocks
110+
stack.extend(
111+
mir
112+
.predecessors_for(block)
113+
.iter()
114+
.map(|&pred_bb| mir.terminator_loc(pred_bb))
115+
.map(|pred_loc| self.point_from_location(pred_loc)),
116+
);
117+
} else {
118+
// Otherwise, the pred is just the previous statement
119+
stack.push(PointIndex::new(index.index() - 1));
93120
}
94121
}
95122
}
@@ -151,6 +178,13 @@ impl<N: Idx> LivenessValues<N> {
151178
self.points.add(row, index)
152179
}
153180

181+
/// Adds all the elements in the given bit array into the given
182+
/// region. Returns true if any of them are newly added.
183+
crate fn add_elements(&mut self, row: N, locations: &BitArray<PointIndex>) -> bool {
184+
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
185+
self.points.merge_into(row, locations)
186+
}
187+
154188
/// Adds all the control-flow points to the values for `r`.
155189
crate fn add_all_points(&mut self, row: N) {
156190
self.points.add_all(row);
@@ -169,6 +203,7 @@ impl<N: Idx> LivenessValues<N> {
169203
.row(r)
170204
.into_iter()
171205
.flat_map(|set| set.iter())
206+
.take_while(|&p| self.elements.point_in_range(p))
172207
.map(|p| self.elements.to_location(p))
173208
.map(RegionElement::Location),
174209
)
@@ -277,7 +312,11 @@ impl<N: Idx> RegionValues<N> {
277312
self.points
278313
.row(r)
279314
.into_iter()
280-
.flat_map(move |set| set.iter().map(move |p| self.elements.to_location(p)))
315+
.flat_map(move |set| {
316+
set.iter()
317+
.take_while(move |&p| self.elements.point_in_range(p))
318+
.map(move |p| self.elements.to_location(p))
319+
})
281320
}
282321

283322
/// Returns just the universal regions that are contained in a given region's value.
@@ -366,6 +405,19 @@ impl ToElementIndex for ty::UniverseIndex {
366405
}
367406
}
368407

408+
crate fn location_set_str(
409+
elements: &RegionValueElements,
410+
points: impl IntoIterator<Item = PointIndex>,
411+
) -> String {
412+
region_value_str(
413+
points
414+
.into_iter()
415+
.take_while(|&p| elements.point_in_range(p))
416+
.map(|p| elements.to_location(p))
417+
.map(RegionElement::Location),
418+
)
419+
}
420+
369421
fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
370422
let mut result = String::new();
371423
result.push_str("{");

‎src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
//! For the NLL computation, we need to compute liveness, but only for those
1212
//! local variables whose types contain regions. The others are not of interest
13-
//! to us. This file defines a new index type (LocalWithRegion) that indexes into
13+
//! to us. This file defines a new index type (LiveVar) that indexes into
1414
//! a list of "variables whose type contain regions". It also defines a map from
15-
//! Local to LocalWithRegion and vice versa -- this map can be given to the
15+
//! Local to LiveVar and vice versa -- this map can be given to the
1616
//! liveness code so that it only operates over variables with regions in their
1717
//! types, instead of all variables.
1818
@@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxHashSet;
2323
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
2424
use util::liveness::LiveVariableMap;
2525

26-
/// Map between Local and LocalWithRegion indices: the purpose of this
26+
/// Map between Local and LiveVar indices: the purpose of this
2727
/// map is to define the subset of local variables for which we need
2828
/// to do a liveness computation. We only need to compute whether a
2929
/// variable `X` is live if that variable contains some region `R` in
@@ -32,18 +32,18 @@ use util::liveness::LiveVariableMap;
3232
crate struct NllLivenessMap {
3333
/// For each local variable, contains `Some(i)` if liveness is
3434
/// needed for this variable.
35-
pub from_local: IndexVec<Local, Option<LocalWithRegion>>,
35+
pub from_local: IndexVec<Local, Option<LiveVar>>,
3636

37-
/// For each `LocalWithRegion`, maps back to the original `Local` index.
38-
pub to_local: IndexVec<LocalWithRegion, Local>,
37+
/// For each `LiveVar`, maps back to the original `Local` index.
38+
pub to_local: IndexVec<LiveVar, Local>,
3939
}
4040

4141
impl LiveVariableMap for NllLivenessMap {
4242
fn from_local(&self, local: Local) -> Option<Self::LiveVar> {
4343
self.from_local[local]
4444
}
4545

46-
type LiveVar = LocalWithRegion;
46+
type LiveVar = LiveVar;
4747

4848
fn from_live_var(&self, local: Self::LiveVar) -> Local {
4949
self.to_local[local]
@@ -93,5 +93,10 @@ impl NllLivenessMap {
9393
}
9494
}
9595

96-
/// Index given to each local variable whose type contains a region.
97-
newtype_index!(LocalWithRegion);
96+
/// Index given to each local variable for which we need to
97+
/// compute liveness information. For many locals, we are able to
98+
/// skip liveness information: for example, those variables whose
99+
/// types contain no regions.
100+
newtype_index!(
101+
LiveVar
102+
);
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
12+
use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap};
13+
use rustc::mir::visit::{PlaceContext, Visitor};
14+
use rustc::mir::{Local, Location, Mir};
15+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
16+
use rustc_data_structures::vec_linked_list as vll;
17+
use util::liveness::{categorize, DefUse, LiveVariableMap};
18+
19+
/// A map that cross references each local with the locations where it
20+
/// is defined (assigned), used, or dropped. Used during liveness
21+
/// computation.
22+
crate struct LocalUseMap<'me> {
23+
liveness_map: &'me NllLivenessMap,
24+
25+
/// Head of a linked list of **definitions** of each variable --
26+
/// definition in this context means assignment, e.g. `x` is
27+
/// defined in `x = y` but not `y`; that first def is the head of
28+
/// a linked list that lets you enumerate all places the variable
29+
/// is assigned.
30+
first_def_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
31+
32+
/// Head of a linked list of **uses** of each variable -- use in
33+
/// this context means that the existing value of the variable is
34+
/// read or modified. e.g., `y` is used in `x = y` but not `x`.
35+
/// Note that `DROP(x)` terminators are excluded from this list.
36+
first_use_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
37+
38+
/// Head of a linked list of **drops** of each variable -- these
39+
/// are a special category of uses corresponding to the drop that
40+
/// we add for each local variable.
41+
first_drop_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
42+
43+
appearances: IndexVec<AppearanceIndex, Appearance>,
44+
}
45+
46+
struct Appearance {
47+
point_index: PointIndex,
48+
next: Option<AppearanceIndex>,
49+
}
50+
51+
newtype_index!(AppearanceIndex);
52+
53+
impl vll::LinkElem for Appearance {
54+
type LinkIndex = AppearanceIndex;
55+
56+
fn next(elem: &Self) -> Option<AppearanceIndex> {
57+
elem.next
58+
}
59+
}
60+
61+
impl LocalUseMap<'me> {
62+
crate fn build(
63+
liveness_map: &'me NllLivenessMap,
64+
elements: &RegionValueElements,
65+
mir: &Mir<'_>,
66+
) -> Self {
67+
let nones = IndexVec::from_elem_n(None, liveness_map.num_variables());
68+
let mut local_use_map = LocalUseMap {
69+
liveness_map,
70+
first_def_at: nones.clone(),
71+
first_use_at: nones.clone(),
72+
first_drop_at: nones,
73+
appearances: IndexVec::new(),
74+
};
75+
76+
LocalUseMapBuild {
77+
local_use_map: &mut local_use_map,
78+
elements,
79+
}.visit_mir(mir);
80+
81+
local_use_map
82+
}
83+
84+
crate fn defs(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
85+
vll::iter(self.first_def_at[local], &self.appearances)
86+
.map(move |aa| self.appearances[aa].point_index)
87+
}
88+
89+
crate fn uses(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
90+
vll::iter(self.first_use_at[local], &self.appearances)
91+
.map(move |aa| self.appearances[aa].point_index)
92+
}
93+
94+
crate fn drops(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
95+
vll::iter(self.first_drop_at[local], &self.appearances)
96+
.map(move |aa| self.appearances[aa].point_index)
97+
}
98+
}
99+
100+
struct LocalUseMapBuild<'me, 'map: 'me> {
101+
local_use_map: &'me mut LocalUseMap<'map>,
102+
elements: &'me RegionValueElements,
103+
}
104+
105+
impl LocalUseMapBuild<'_, '_> {
106+
fn insert_def(&mut self, local: LiveVar, location: Location) {
107+
Self::insert(
108+
self.elements,
109+
&mut self.local_use_map.first_def_at[local],
110+
&mut self.local_use_map.appearances,
111+
location,
112+
);
113+
}
114+
115+
fn insert_use(&mut self, local: LiveVar, location: Location) {
116+
Self::insert(
117+
self.elements,
118+
&mut self.local_use_map.first_use_at[local],
119+
&mut self.local_use_map.appearances,
120+
location,
121+
);
122+
}
123+
124+
fn insert_drop(&mut self, local: LiveVar, location: Location) {
125+
Self::insert(
126+
self.elements,
127+
&mut self.local_use_map.first_drop_at[local],
128+
&mut self.local_use_map.appearances,
129+
location,
130+
);
131+
}
132+
133+
fn insert(
134+
elements: &RegionValueElements,
135+
first_appearance: &mut Option<AppearanceIndex>,
136+
appearances: &mut IndexVec<AppearanceIndex, Appearance>,
137+
location: Location,
138+
) {
139+
let point_index = elements.point_from_location(location);
140+
let appearance_index = appearances.push(Appearance {
141+
point_index,
142+
next: *first_appearance,
143+
});
144+
*first_appearance = Some(appearance_index);
145+
}
146+
}
147+
148+
impl Visitor<'tcx> for LocalUseMapBuild<'_, '_> {
149+
fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, location: Location) {
150+
if let Some(local_with_region) = self.local_use_map.liveness_map.from_local(local) {
151+
match categorize(context) {
152+
Some(DefUse::Def) => self.insert_def(local_with_region, location),
153+
Some(DefUse::Use) => self.insert_use(local_with_region, location),
154+
Some(DefUse::Drop) => self.insert_drop(local_with_region, location),
155+
_ => (),
156+
}
157+
}
158+
}
159+
}

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

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

11+
use borrow_check::nll::region_infer::values::RegionValueElements;
1112
use borrow_check::nll::constraints::ConstraintSet;
12-
use borrow_check::nll::type_check::AtLocation;
13-
use borrow_check::nll::{LocalWithRegion, NllLivenessMap};
13+
use borrow_check::nll::NllLivenessMap;
1414
use borrow_check::nll::universal_regions::UniversalRegions;
15-
use dataflow::move_paths::{HasMoveData, MoveData};
15+
use dataflow::move_paths::MoveData;
1616
use dataflow::MaybeInitializedPlaces;
17-
use dataflow::{FlowAtLocation, FlowsAtLocation};
18-
use rustc::infer::canonical::QueryRegionConstraint;
19-
use rustc::mir::{BasicBlock, Location, Mir};
20-
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
21-
use rustc::traits::query::type_op::outlives::DropckOutlives;
22-
use rustc::traits::query::type_op::TypeOp;
23-
use rustc::ty::{RegionVid, Ty, TypeFoldable};
24-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
17+
use dataflow::FlowAtLocation;
18+
use rustc::mir::Mir;
19+
use rustc::ty::RegionVid;
20+
use rustc_data_structures::fx::FxHashSet;
2521
use std::rc::Rc;
26-
use util::liveness::{LiveVariableMap, LivenessResults};
2722

2823
use super::TypeChecker;
2924

3025
crate mod liveness_map;
26+
mod local_use_map;
27+
mod trace;
3128

3229
/// Combines liveness analysis with initialization analysis to
3330
/// determine which variables are live at which points, both due to
@@ -38,40 +35,23 @@ crate mod liveness_map;
3835
/// NB. This computation requires normalization; therefore, it must be
3936
/// performed before
4037
pub(super) fn generate<'gcx, 'tcx>(
41-
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
38+
typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
4239
mir: &Mir<'tcx>,
40+
elements: &Rc<RegionValueElements>,
4341
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
4442
move_data: &MoveData<'tcx>,
45-
) -> (LivenessResults<LocalWithRegion>, NllLivenessMap) {
43+
) {
44+
debug!("liveness::generate");
4645
let free_regions = {
47-
let borrowck_context = cx.borrowck_context.as_ref().unwrap();
46+
let borrowck_context = typeck.borrowck_context.as_ref().unwrap();
4847
regions_that_outlive_free_regions(
49-
cx.infcx.num_region_vars(),
48+
typeck.infcx.num_region_vars(),
5049
&borrowck_context.universal_regions,
5150
&borrowck_context.constraints.outlives_constraints,
5251
)
5352
};
54-
let liveness_map = NllLivenessMap::compute(cx.tcx(), &free_regions, mir);
55-
let liveness = LivenessResults::compute(mir, &liveness_map);
56-
57-
// For everything else, it is only live where it is actually used.
58-
if !liveness_map.is_empty() {
59-
let mut generator = TypeLivenessGenerator {
60-
cx,
61-
mir,
62-
liveness: &liveness,
63-
flow_inits,
64-
move_data,
65-
drop_data: FxHashMap(),
66-
map: &liveness_map,
67-
};
68-
69-
for bb in mir.basic_blocks().indices() {
70-
generator.add_liveness_constraints(bb);
71-
}
72-
}
73-
74-
(liveness, liveness_map)
53+
let liveness_map = NllLivenessMap::compute(typeck.tcx(), &free_regions, mir);
54+
trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map);
7555
}
7656

7757
/// Compute all regions that are (currently) known to outlive free
@@ -112,198 +92,3 @@ fn regions_that_outlive_free_regions(
11292
// Return the final set of things we visited.
11393
outlives_free_region
11494
}
115-
116-
struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
117-
where
118-
'typeck: 'gen,
119-
'flow: 'gen,
120-
'tcx: 'typeck + 'flow,
121-
'gcx: 'tcx,
122-
{
123-
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
124-
mir: &'gen Mir<'tcx>,
125-
liveness: &'gen LivenessResults<LocalWithRegion>,
126-
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
127-
move_data: &'gen MoveData<'tcx>,
128-
drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
129-
map: &'gen NllLivenessMap,
130-
}
131-
132-
struct DropData<'tcx> {
133-
dropck_result: DropckOutlivesResult<'tcx>,
134-
region_constraint_data: Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>,
135-
}
136-
137-
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
138-
/// Liveness constraints:
139-
///
140-
/// > If a variable V is live at point P, then all regions R in the type of V
141-
/// > must include the point P.
142-
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
143-
debug!("add_liveness_constraints(bb={:?})", bb);
144-
145-
self.liveness
146-
.regular
147-
.simulate_block(self.mir, bb, self.map, |location, live_locals| {
148-
for live_local in live_locals.iter() {
149-
let local = self.map.from_live_var(live_local);
150-
let live_local_ty = self.mir.local_decls[local].ty;
151-
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
152-
}
153-
});
154-
155-
let mut all_live_locals: Vec<(Location, Vec<LocalWithRegion>)> = vec![];
156-
self.liveness
157-
.drop
158-
.simulate_block(self.mir, bb, self.map, |location, live_locals| {
159-
all_live_locals.push((location, live_locals.iter().collect()));
160-
});
161-
debug!(
162-
"add_liveness_constraints: all_live_locals={:#?}",
163-
all_live_locals
164-
);
165-
166-
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
167-
self.flow_inits.reset_to_entry_of(bb);
168-
while let Some((location, live_locals)) = all_live_locals.pop() {
169-
for live_local in live_locals {
170-
debug!(
171-
"add_liveness_constraints: location={:?} live_local={:?}",
172-
location, live_local
173-
);
174-
175-
if log_enabled!(::log::Level::Debug) {
176-
self.flow_inits.each_state_bit(|mpi_init| {
177-
debug!(
178-
"add_liveness_constraints: location={:?} initialized={:?}",
179-
location,
180-
&self.flow_inits.operator().move_data().move_paths[mpi_init]
181-
);
182-
});
183-
}
184-
185-
let local = self.map.from_live_var(live_local);
186-
let mpi = self.move_data.rev_lookup.find_local(local);
187-
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
188-
debug!(
189-
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
190-
self.move_data.move_paths[mpi],
191-
self.move_data.move_paths[initialized_child]
192-
);
193-
194-
let local = self.map.from_live_var(live_local);
195-
let live_local_ty = self.mir.local_decls[local].ty;
196-
self.add_drop_live_constraint(live_local, live_local_ty, location);
197-
}
198-
}
199-
200-
if location.statement_index == terminator_index {
201-
debug!(
202-
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
203-
location
204-
);
205-
self.flow_inits.reconstruct_terminator_effect(location);
206-
} else {
207-
debug!(
208-
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
209-
location
210-
);
211-
self.flow_inits.reconstruct_statement_effect(location);
212-
}
213-
self.flow_inits.apply_local_effect(location);
214-
}
215-
}
216-
217-
/// Some variable with type `live_ty` is "regular live" at
218-
/// `location` -- i.e., it may be used later. This means that all
219-
/// regions appearing in the type `live_ty` must be live at
220-
/// `location`.
221-
fn push_type_live_constraint<T>(
222-
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
223-
value: T,
224-
location: Location,
225-
) where
226-
T: TypeFoldable<'tcx>,
227-
{
228-
debug!(
229-
"push_type_live_constraint(live_ty={:?}, location={:?})",
230-
value, location
231-
);
232-
233-
cx.tcx().for_each_free_region(&value, |live_region| {
234-
if let Some(ref mut borrowck_context) = cx.borrowck_context {
235-
let region_vid = borrowck_context
236-
.universal_regions
237-
.to_region_vid(live_region);
238-
borrowck_context
239-
.constraints
240-
.liveness_constraints
241-
.add_element(region_vid, location);
242-
243-
if let Some(all_facts) = borrowck_context.all_facts {
244-
let start_index = borrowck_context.location_table.start_index(location);
245-
all_facts.region_live_at.push((region_vid, start_index));
246-
247-
let mid_index = borrowck_context.location_table.mid_index(location);
248-
all_facts.region_live_at.push((region_vid, mid_index));
249-
}
250-
}
251-
});
252-
}
253-
254-
/// Some variable with type `live_ty` is "drop live" at `location`
255-
/// -- i.e., it may be dropped later. This means that *some* of
256-
/// the regions in its type must be live at `location`. The
257-
/// precise set will depend on the dropck constraints, and in
258-
/// particular this takes `#[may_dangle]` into account.
259-
fn add_drop_live_constraint(
260-
&mut self,
261-
dropped_local: LocalWithRegion,
262-
dropped_ty: Ty<'tcx>,
263-
location: Location,
264-
) {
265-
debug!(
266-
"add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})",
267-
dropped_local, dropped_ty, location
268-
);
269-
270-
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
271-
let cx = &mut self.cx;
272-
move || Self::compute_drop_data(cx, dropped_ty)
273-
});
274-
275-
if let Some(data) = &drop_data.region_constraint_data {
276-
self.cx.push_region_constraints(location.boring(), data);
277-
}
278-
279-
drop_data.dropck_result.report_overflows(
280-
self.cx.infcx.tcx,
281-
self.mir.source_info(location).span,
282-
dropped_ty,
283-
);
284-
285-
// All things in the `outlives` array may be touched by
286-
// the destructor and must be live at this point.
287-
for &kind in &drop_data.dropck_result.kinds {
288-
Self::push_type_live_constraint(&mut self.cx, kind, location);
289-
}
290-
}
291-
292-
fn compute_drop_data(
293-
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
294-
dropped_ty: Ty<'tcx>,
295-
) -> DropData<'tcx> {
296-
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
297-
298-
let param_env = cx.param_env;
299-
let (dropck_result, region_constraint_data) = param_env
300-
.and(DropckOutlives::new(dropped_ty))
301-
.fully_perform(cx.infcx)
302-
.unwrap();
303-
304-
DropData {
305-
dropck_result,
306-
region_constraint_data,
307-
}
308-
}
309-
}

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

Lines changed: 553 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ use borrow_check::nll::facts::AllFacts;
1818
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
1919
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
2020
use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
21-
use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
2221
use borrow_check::nll::universal_regions::UniversalRegions;
23-
use borrow_check::nll::LocalWithRegion;
2422
use borrow_check::nll::ToRegionVid;
2523
use dataflow::move_paths::MoveData;
2624
use dataflow::FlowAtLocation;
@@ -43,7 +41,6 @@ use std::fmt;
4341
use std::rc::Rc;
4442
use syntax_pos::{Span, DUMMY_SP};
4543
use transform::{MirPass, MirSource};
46-
use util::liveness::LivenessResults;
4744

4845
use rustc_data_structures::fx::FxHashSet;
4946
use rustc_data_structures::indexed_vec::Idx;
@@ -143,7 +140,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
143140
all_facts,
144141
);
145142

146-
let (liveness, liveness_map) = {
143+
{
147144
let mut borrowck_context = BorrowCheckContext {
148145
universal_regions,
149146
location_table,
@@ -169,16 +166,14 @@ pub(crate) fn type_check<'gcx, 'tcx>(
169166
&universal_region_relations,
170167
&normalized_inputs_and_output,
171168
);
172-
liveness::generate(cx, mir, flow_inits, move_data)
169+
liveness::generate(cx, mir, elements, flow_inits, move_data);
173170
},
174-
)
175-
};
171+
);
172+
}
176173

177174
MirTypeckResults {
178175
constraints,
179176
universal_region_relations,
180-
liveness,
181-
liveness_map,
182177
}
183178
}
184179

@@ -672,8 +667,6 @@ struct BorrowCheckContext<'a, 'tcx: 'a> {
672667
crate struct MirTypeckResults<'tcx> {
673668
crate constraints: MirTypeckRegionConstraints<'tcx>,
674669
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
675-
crate liveness: LivenessResults<LocalWithRegion>,
676-
crate liveness_map: NllLivenessMap,
677670
}
678671

679672
/// A collection of region constraints that must be satisfied for the

‎src/librustc_mir/dataflow/at_location.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ pub trait FlowsAtLocation {
2828
/// Reset the state bitvector to represent the entry to block `bb`.
2929
fn reset_to_entry_of(&mut self, bb: BasicBlock);
3030

31+
/// Reset the state bitvector to represent the exit of the
32+
/// terminator of block `bb`.
33+
///
34+
/// **Important:** In the case of a `Call` terminator, these
35+
/// effects do *not* include the result of storing the destination
36+
/// of the call, since that is edge-dependent (in other words, the
37+
/// effects don't apply to the unwind edge).
38+
fn reset_to_exit_of(&mut self, bb: BasicBlock);
39+
3140
/// Build gen + kill sets for statement at `loc`.
3241
///
3342
/// Note that invoking this method alone does not change the
@@ -142,6 +151,12 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
142151
self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
143152
}
144153

154+
fn reset_to_exit_of(&mut self, bb: BasicBlock) {
155+
self.reset_to_entry_of(bb);
156+
self.curr_state.union(self.base_results.sets().gen_set_for(bb.index()));
157+
self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index()));
158+
}
159+
145160
fn reconstruct_statement_effect(&mut self, loc: Location) {
146161
self.stmt_gen.clear();
147162
self.stmt_kill.clear();

‎src/librustc_mir/dataflow/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,18 @@ pub struct AllSets<E: Idx> {
454454
/// For each block, bits valid on entry to the block.
455455
on_entry_sets: Vec<IdxSet<E>>,
456456

457-
/// For each block, bits generated by executing the statements in
458-
/// the block. (For comparison, the Terminator for each block is
459-
/// handled in a flow-specific manner during propagation.)
457+
/// For each block, bits generated by executing the statements +
458+
/// terminator in the block -- with one caveat. In particular, for
459+
/// *call terminators*, the effect of storing the destination is
460+
/// not included, since that only takes effect on the **success**
461+
/// edge (and not the unwind edge).
460462
gen_sets: Vec<HybridIdxSet<E>>,
461463

462-
/// For each block, bits killed by executing the statements in the
463-
/// block. (For comparison, the Terminator for each block is
464-
/// handled in a flow-specific manner during propagation.)
464+
/// For each block, bits killed by executing the statements +
465+
/// terminator in the block -- with one caveat. In particular, for
466+
/// *call terminators*, the effect of storing the destination is
467+
/// not included, since that only takes effect on the **success**
468+
/// edge (and not the unwind edge).
465469
kill_sets: Vec<HybridIdxSet<E>>,
466470
}
467471

‎src/librustc_mir/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
1717
#![cfg_attr(not(stage0), feature(nll))]
1818
#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
1919
#![feature(in_band_lifetimes)]
20+
#![feature(impl_header_lifetime_elision)]
2021
#![feature(slice_patterns)]
2122
#![feature(slice_sort_by_cached_key)]
2223
#![feature(box_patterns)]

‎src/librustc_mir/transform/generator.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
6666
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
6767
use rustc::ty::subst::Substs;
6868
use util::dump_mir;
69-
use util::liveness::{self, IdentityMap, LivenessMode};
69+
use util::liveness::{self, IdentityMap};
7070
use rustc_data_structures::indexed_vec::Idx;
7171
use rustc_data_structures::indexed_set::IdxSet;
7272
use std::collections::HashMap;
@@ -402,10 +402,6 @@ fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
402402
let mut set = liveness::LiveVarSet::new_empty(mir.local_decls.len());
403403
let mut liveness = liveness::liveness_of_locals(
404404
mir,
405-
LivenessMode {
406-
include_regular_use: true,
407-
include_drops: true,
408-
},
409405
&IdentityMap::new(mir),
410406
);
411407
liveness::dump_mir(

‎src/librustc_mir/util/liveness.rs

Lines changed: 14 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
//! generator yield points, all pre-existing references are invalidated, so this
3434
//! doesn't matter).
3535
36-
use rustc::mir::visit::MirVisitable;
3736
use rustc::mir::visit::{PlaceContext, Visitor};
3837
use rustc::mir::Local;
3938
use rustc::mir::*;
@@ -50,17 +49,13 @@ use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
5049
pub type LiveVarSet<V> = IdxSet<V>;
5150

5251
/// This gives the result of the liveness analysis at the boundary of
53-
/// basic blocks. You can use `simulate_block` to obtain the
54-
/// intra-block results.
52+
/// basic blocks.
5553
///
5654
/// The `V` type defines the set of variables that we computed
5755
/// liveness for. This is often `Local`, in which case we computed
5856
/// liveness for all variables -- but it can also be some other type,
5957
/// which indicates a subset of the variables within the graph.
6058
pub struct LivenessResult<V: Idx> {
61-
/// Liveness mode in use when these results were computed.
62-
pub mode: LivenessMode,
63-
6459
/// Live variables on exit to each basic block. This is equal to
6560
/// the union of the `ins` for each successor.
6661
pub outs: IndexVec<BasicBlock, LiveVarSet<V>>,
@@ -104,76 +99,19 @@ impl<'a, 'tcx> LiveVariableMap for IdentityMap<'a, 'tcx> {
10499
}
105100
}
106101

107-
#[derive(Copy, Clone, Debug)]
108-
pub struct LivenessMode {
109-
/// If true, then we will consider "regular uses" of a variable to be live.
110-
/// For example, if the user writes `foo(x)`, then this is a regular use of
111-
/// the variable `x`.
112-
pub include_regular_use: bool,
113-
114-
/// If true, then we will consider (implicit) drops of a variable
115-
/// to be live. For example, if the user writes `{ let x =
116-
/// vec![...]; .. }`, then the drop at the end of the block is an
117-
/// implicit drop.
118-
///
119-
/// NB. Despite its name, a call like `::std::mem::drop(x)` is
120-
/// **not** considered a drop for this purposes, but rather a
121-
/// regular use.
122-
pub include_drops: bool,
123-
}
124-
125-
/// A combination of liveness results, used in NLL.
126-
pub struct LivenessResults<V: Idx> {
127-
/// Liveness results where a regular use makes a variable X live,
128-
/// but not a drop.
129-
pub regular: LivenessResult<V>,
130-
131-
/// Liveness results where a drop makes a variable X live,
132-
/// but not a regular use.
133-
pub drop: LivenessResult<V>,
134-
}
135-
136-
impl<V: Idx> LivenessResults<V> {
137-
pub fn compute<'tcx>(
138-
mir: &Mir<'tcx>,
139-
map: &impl LiveVariableMap<LiveVar = V>,
140-
) -> LivenessResults<V> {
141-
LivenessResults {
142-
regular: liveness_of_locals(
143-
&mir,
144-
LivenessMode {
145-
include_regular_use: true,
146-
include_drops: false,
147-
},
148-
map,
149-
),
150-
151-
drop: liveness_of_locals(
152-
&mir,
153-
LivenessMode {
154-
include_regular_use: false,
155-
include_drops: true,
156-
},
157-
map,
158-
),
159-
}
160-
}
161-
}
162-
163102
/// Compute which local variables are live within the given function
164103
/// `mir`. The liveness mode `mode` determines what sorts of uses are
165104
/// considered to make a variable live (e.g., do drops count?).
166105
pub fn liveness_of_locals<'tcx, V: Idx>(
167106
mir: &Mir<'tcx>,
168-
mode: LivenessMode,
169107
map: &impl LiveVariableMap<LiveVar = V>,
170108
) -> LivenessResult<V> {
171109
let num_live_vars = map.num_variables();
172110

173111
let def_use: IndexVec<_, DefsUses<V>> = mir
174112
.basic_blocks()
175113
.iter()
176-
.map(|b| block(mode, map, b, num_live_vars))
114+
.map(|b| block(map, b, num_live_vars))
177115
.collect();
178116

179117
let mut outs: IndexVec<_, LiveVarSet<V>> = mir
@@ -208,80 +146,17 @@ pub fn liveness_of_locals<'tcx, V: Idx>(
208146
}
209147
}
210148

211-
LivenessResult { mode, outs }
212-
}
213-
214-
impl<V: Idx> LivenessResult<V> {
215-
/// Walks backwards through the statements/terminator in the given
216-
/// basic block `block`. At each point within `block`, invokes
217-
/// the callback `op` with the current location and the set of
218-
/// variables that are live on entry to that location.
219-
pub fn simulate_block<'tcx, OP>(
220-
&self,
221-
mir: &Mir<'tcx>,
222-
block: BasicBlock,
223-
map: &impl LiveVariableMap<LiveVar = V>,
224-
mut callback: OP,
225-
) where
226-
OP: FnMut(Location, &LiveVarSet<V>),
227-
{
228-
let data = &mir[block];
229-
230-
// Get a copy of the bits on exit from the block.
231-
let mut bits = self.outs[block].clone();
232-
233-
// Start with the maximal statement index -- i.e., right before
234-
// the terminator executes.
235-
let mut statement_index = data.statements.len();
236-
237-
// Compute liveness right before terminator and invoke callback.
238-
let terminator_location = Location {
239-
block,
240-
statement_index,
241-
};
242-
let num_live_vars = map.num_variables();
243-
let mut visitor = DefsUsesVisitor {
244-
mode: self.mode,
245-
map,
246-
defs_uses: DefsUses {
247-
defs: LiveVarSet::new_empty(num_live_vars),
248-
uses: LiveVarSet::new_empty(num_live_vars),
249-
},
250-
};
251-
// Visit the various parts of the basic block in reverse. If we go
252-
// forward, the logic in `add_def` and `add_use` would be wrong.
253-
visitor.update_bits_and_do_callback(
254-
terminator_location,
255-
&data.terminator,
256-
&mut bits,
257-
&mut callback,
258-
);
259-
260-
// Compute liveness before each statement (in rev order) and invoke callback.
261-
for statement in data.statements.iter().rev() {
262-
statement_index -= 1;
263-
let statement_location = Location {
264-
block,
265-
statement_index,
266-
};
267-
visitor.defs_uses.clear();
268-
visitor.update_bits_and_do_callback(
269-
statement_location,
270-
statement,
271-
&mut bits,
272-
&mut callback,
273-
);
274-
}
275-
}
149+
LivenessResult { outs }
276150
}
277151

278152
#[derive(Eq, PartialEq, Clone)]
279153
pub enum DefUse {
280154
Def,
281155
Use,
156+
Drop,
282157
}
283158

284-
pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Option<DefUse> {
159+
pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
285160
match context {
286161
///////////////////////////////////////////////////////////////////////////
287162
// DEFS
@@ -322,13 +197,8 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Opti
322197
PlaceContext::Inspect |
323198
PlaceContext::Copy |
324199
PlaceContext::Move |
325-
PlaceContext::Validate => {
326-
if mode.include_regular_use {
327-
Some(DefUse::Use)
328-
} else {
329-
None
330-
}
331-
}
200+
PlaceContext::Validate =>
201+
Some(DefUse::Use),
332202

333203
///////////////////////////////////////////////////////////////////////////
334204
// DROP USES
@@ -338,13 +208,8 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Opti
338208
// uses in drop are special because `#[may_dangle]`
339209
// attributes can affect whether lifetimes must be live.
340210

341-
PlaceContext::Drop => {
342-
if mode.include_drops {
343-
Some(DefUse::Use)
344-
} else {
345-
None
346-
}
347-
}
211+
PlaceContext::Drop =>
212+
Some(DefUse::Drop),
348213
}
349214
}
350215

@@ -353,7 +218,6 @@ where
353218
V: Idx,
354219
M: LiveVariableMap<LiveVar = V> + 'lv,
355220
{
356-
mode: LivenessMode,
357221
map: &'lv M,
358222
defs_uses: DefsUses<V>,
359223
}
@@ -365,11 +229,6 @@ struct DefsUses<V: Idx> {
365229
}
366230

367231
impl<V: Idx> DefsUses<V> {
368-
fn clear(&mut self) {
369-
self.uses.clear();
370-
self.defs.clear();
371-
}
372-
373232
fn apply(&self, bits: &mut LiveVarSet<V>) -> bool {
374233
bits.subtract(&self.defs) | bits.union(&self.uses)
375234
}
@@ -404,53 +263,28 @@ impl<V: Idx> DefsUses<V> {
404263
}
405264
}
406265

407-
impl<'lv, V, M> DefsUsesVisitor<'lv, V, M>
408-
where
409-
V: Idx,
410-
M: LiveVariableMap<LiveVar = V>,
411-
{
412-
/// Update `bits` with the effects of `value` and call `callback`. We
413-
/// should always visit in reverse order. This method assumes that we have
414-
/// not visited anything before; if you have, clear `bits` first.
415-
fn update_bits_and_do_callback<'tcx, OP>(
416-
&mut self,
417-
location: Location,
418-
value: &impl MirVisitable<'tcx>,
419-
bits: &mut LiveVarSet<V>,
420-
callback: &mut OP,
421-
) where
422-
OP: FnMut(Location, &LiveVarSet<V>),
423-
{
424-
value.apply(location, self);
425-
self.defs_uses.apply(bits);
426-
callback(location, bits);
427-
}
428-
}
429-
430266
impl<'tcx, 'lv, V, M> Visitor<'tcx> for DefsUsesVisitor<'lv, V, M>
431267
where
432268
V: Idx,
433269
M: LiveVariableMap<LiveVar = V>,
434270
{
435271
fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
436272
if let Some(v_index) = self.map.from_local(local) {
437-
match categorize(context, self.mode) {
273+
match categorize(context) {
438274
Some(DefUse::Def) => self.defs_uses.add_def(v_index),
439-
Some(DefUse::Use) => self.defs_uses.add_use(v_index),
440-
None => (),
275+
Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(v_index),
276+
_ => (),
441277
}
442278
}
443279
}
444280
}
445281

446282
fn block<'tcx, V: Idx>(
447-
mode: LivenessMode,
448283
map: &impl LiveVariableMap<LiveVar = V>,
449284
b: &BasicBlockData<'tcx>,
450285
locals: usize,
451286
) -> DefsUses<V> {
452287
let mut visitor = DefsUsesVisitor {
453-
mode,
454288
map,
455289
defs_uses: DefsUses {
456290
defs: LiveVarSet::new_empty(locals),
@@ -526,7 +360,8 @@ pub fn write_mir_fn<'a, 'tcx, V: Idx>(
526360
write_mir_intro(tcx, src, mir, w)?;
527361
for block in mir.basic_blocks().indices() {
528362
let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet<V>>| {
529-
let live: Vec<String> = result[block].iter()
363+
let live: Vec<String> = result[block]
364+
.iter()
530365
.map(|v| map.from_live_var(v))
531366
.map(|local| format!("{:?}", local))
532367
.collect();

‎src/test/mir-opt/nll/named-lifetimes-basic.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ fn main() {
3434
// | '_#4r | Local | ['_#4r]
3535
// |
3636
// | Inferred Region Values
37-
// | '_#0r | U0 | {bb0[0..=127], '_#0r}
38-
// | '_#1r | U0 | {bb0[0..=127], '_#1r}
39-
// | '_#2r | U0 | {bb0[0..=127], '_#2r}
40-
// | '_#3r | U0 | {bb0[0..=127], '_#3r}
41-
// | '_#4r | U0 | {bb0[0..=127], '_#4r}
42-
// | '_#5r | U0 | {bb0[0..=127], '_#1r}
43-
// | '_#6r | U0 | {bb0[0..=127], '_#2r}
44-
// | '_#7r | U0 | {bb0[0..=127], '_#1r}
45-
// | '_#8r | U0 | {bb0[0..=127], '_#3r}
37+
// | '_#0r | U0 | {bb0[0..=1], '_#0r}
38+
// | '_#1r | U0 | {bb0[0..=1], '_#1r}
39+
// | '_#2r | U0 | {bb0[0..=1], '_#2r}
40+
// | '_#3r | U0 | {bb0[0..=1], '_#3r}
41+
// | '_#4r | U0 | {bb0[0..=1], '_#4r}
42+
// | '_#5r | U0 | {bb0[0..=1], '_#1r}
43+
// | '_#6r | U0 | {bb0[0..=1], '_#2r}
44+
// | '_#7r | U0 | {bb0[0..=1], '_#1r}
45+
// | '_#8r | U0 | {bb0[0..=1], '_#3r}
4646
// |
4747
// ...
4848
// fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {

‎src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs

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

11-
//compile-flags: -Z emit-end-regions -Zborrowck=mir
12-
13-
1411
#![allow(warnings)]
12+
#![feature(nll)]
1513

1614
struct Wrap<'p> { p: &'p mut i32 }
1715

‎src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0506]: cannot assign to `x` because it is borrowed
2-
--> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:32:5
2+
--> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:30:5
33
|
44
LL | let wrap = Wrap { p: &mut x };
55
| ------ borrow of `x` occurs here

0 commit comments

Comments
 (0)
Please sign in to comment.