Skip to content

Commit a94b01a

Browse files
committed
connect MIR borrowck with NLL
1 parent 8144917 commit a94b01a

File tree

6 files changed

+232
-10
lines changed

6 files changed

+232
-10
lines changed

src/librustc_mir/borrow_check.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use rustc::ty::maps::Providers;
1717
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local};
1818
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
1919
use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
20-
use rustc::mir::transform::{MirSource};
20+
use rustc::mir::transform::MirSource;
21+
use transform::nll;
2122

2223
use rustc_data_structures::indexed_set::{self, IdxSetBuf};
2324
use rustc_data_structures::indexed_vec::{Idx};
@@ -62,7 +63,7 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
6263
}
6364

6465
fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
65-
mir: &Mir<'gcx>,
66+
input_mir: &Mir<'gcx>,
6667
def_id: DefId,
6768
src: MirSource)
6869
{
@@ -72,7 +73,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
7273

7374
let id = src.item_id();
7475

75-
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx, param_env) {
76+
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
7677
Ok(move_data) => move_data,
7778
Err((move_data, move_errors)) => {
7879
for move_error in move_errors {
@@ -100,10 +101,23 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
100101
}
101102
};
102103

104+
// Make our own copy of the MIR. This copy will be modified (in place) to
105+
// contain non-lexical lifetimes. It will have a lifetime tied
106+
// to the inference context.
107+
let mut mir: Mir<'tcx> = input_mir.clone();
108+
let mir = &mut mir;
109+
110+
// If we are in non-lexical mode, compute the non-lexical lifetimes.
111+
let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
112+
None
113+
} else {
114+
Some(nll::compute_regions(infcx, src, mir))
115+
};
116+
103117
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
104118
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
105119
let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
106-
Borrows::new(tcx, mir),
120+
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
107121
|bd, i| bd.location(i));
108122
let flow_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
109123
MaybeInitializedLvals::new(tcx, mir, &mdpe),

src/librustc_mir/dataflow/impls/borrows.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use rustc_data_structures::indexed_vec::{IndexVec};
2121

2222
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
2323
pub use dataflow::indexes::BorrowIndex;
24+
use transform::nll::region_infer::RegionInferenceContext;
25+
use transform::nll::ToRegionIndex;
2426

2527
use syntax_pos::Span;
2628

@@ -36,6 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
3638
location_map: FxHashMap<Location, BorrowIndex>,
3739
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
3840
region_span_map: FxHashMap<RegionKind, Span>,
41+
nonlexical_regioncx: Option<&'a RegionInferenceContext>,
3942
}
4043

4144
// temporarily allow some dead fields: `kind` and `region` will be
@@ -64,7 +67,10 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
6467
}
6568

6669
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
67-
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
70+
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
71+
mir: &'a Mir<'tcx>,
72+
nonlexical_regioncx: Option<&'a RegionInferenceContext>)
73+
-> Self {
6874
let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
6975
location_map: FxHashMap(),
7076
region_map: FxHashMap(),
@@ -75,7 +81,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
7581
borrows: visitor.idx_vec,
7682
location_map: visitor.location_map,
7783
region_map: visitor.region_map,
78-
region_span_map: visitor.region_span_map};
84+
region_span_map: visitor.region_span_map,
85+
nonlexical_regioncx };
7986

8087
struct GatherBorrows<'tcx> {
8188
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
@@ -121,9 +128,26 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
121128
/// meaning there. Otherwise, it should return some.
122129
pub fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
123130
let opt_span = self.region_span_map.get(region);
124-
assert!(opt_span.is_some(), "end region not found for {:?}", region);
131+
assert!(self.nonlexical_regioncx.is_some() ||
132+
opt_span.is_some(), "end region not found for {:?}", region);
125133
opt_span.map(|s| s.end_point())
126134
}
135+
136+
/// Add all borrows to the kill set, if those borrows are out of scope at `location`.
137+
fn kill_loans_out_of_scope_at_location(&self,
138+
sets: &mut BlockSets<BorrowIndex>,
139+
location: Location) {
140+
if let Some(regioncx) = self.nonlexical_regioncx {
141+
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
142+
let borrow_region = regioncx.region_value(borrow_data.region.to_region_index());
143+
if !borrow_region.may_contain(location) && location != borrow_data.location {
144+
debug!("kill_loans_out_of_scope_at_location: kill{:?} \
145+
location={:?} borrow_data={:?}", borrow_index, location, borrow_data);
146+
sets.kill(&borrow_index);
147+
}
148+
}
149+
}
150+
}
127151
}
128152

129153
impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
@@ -149,6 +173,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
149173
match stmt.kind {
150174
mir::StatementKind::EndRegion(region_scope) => {
151175
if let Some(borrow_indexes) = self.region_map.get(&ReScope(region_scope)) {
176+
assert!(self.nonlexical_regioncx.is_none());
152177
for idx in borrow_indexes { sets.kill(&idx); }
153178
} else {
154179
// (if there is no entry, then there are no borrows to be tracked)
@@ -175,11 +200,14 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
175200
mir::StatementKind::Nop => {}
176201

177202
}
203+
204+
self.kill_loans_out_of_scope_at_location(sets, location);
178205
}
206+
179207
fn terminator_effect(&self,
180-
_sets: &mut BlockSets<BorrowIndex>,
181-
_location: Location) {
182-
// no terminators start nor end region scopes.
208+
sets: &mut BlockSets<BorrowIndex>,
209+
location: Location) {
210+
self.kill_loans_out_of_scope_at_location(sets, location);
183211
}
184212

185213
fn propagate_call_return(&self,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2012 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+
12+
// compile-flags:-Zborrowck-mir -Znll
13+
14+
#![allow(warnings)]
15+
#![feature(rustc_attrs)]
16+
17+
18+
fn main() {
19+
}
20+
21+
fn nll_fail() {
22+
let mut data = ('a', 'b', 'c');
23+
let c = &mut data.0;
24+
capitalize(c);
25+
data.0 = 'e';
26+
//~^ ERROR (Ast) [E0506]
27+
//~| ERROR (Mir) [E0506]
28+
data.0 = 'f';
29+
//~^ ERROR (Ast) [E0506]
30+
//~| ERROR (Mir) [E0506]
31+
data.0 = 'g';
32+
//~^ ERROR (Ast) [E0506]
33+
//~| ERROR (Mir) [E0506]
34+
capitalize(c);
35+
}
36+
37+
fn nll_ok() {
38+
let mut data = ('a', 'b', 'c');
39+
let c = &mut data.0;
40+
capitalize(c);
41+
data.0 = 'e';
42+
//~^ ERROR (Ast) [E0506]
43+
data.0 = 'f';
44+
//~^ ERROR (Ast) [E0506]
45+
data.0 = 'g';
46+
//~^ ERROR (Ast) [E0506]
47+
}
48+
49+
fn capitalize(_: &mut char) {
50+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2012 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+
12+
// compile-flags:-Zborrowck-mir -Znll
13+
14+
#![allow(warnings)]
15+
#![feature(rustc_attrs)]
16+
17+
fn main() {
18+
}
19+
20+
fn nll_fail() {
21+
let mut data = vec!['a', 'b', 'c'];
22+
let slice = &mut data;
23+
capitalize(slice);
24+
data.push('d');
25+
//~^ ERROR (Ast) [E0499]
26+
//~| ERROR (Mir) [E0499]
27+
data.push('e');
28+
//~^ ERROR (Ast) [E0499]
29+
//~| ERROR (Mir) [E0499]
30+
data.push('f');
31+
//~^ ERROR (Ast) [E0499]
32+
//~| ERROR (Mir) [E0499]
33+
capitalize(slice);
34+
}
35+
36+
fn nll_ok() {
37+
let mut data = vec!['a', 'b', 'c'];
38+
let slice = &mut data;
39+
capitalize(slice);
40+
data.push('d');
41+
//~^ ERROR (Ast) [E0499]
42+
data.push('e');
43+
//~^ ERROR (Ast) [E0499]
44+
data.push('f');
45+
//~^ ERROR (Ast) [E0499]
46+
}
47+
48+
fn capitalize(_: &mut [char]) {
49+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012-2016 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+
// Basic test for liveness constraints: the region (`R1`) that appears
12+
// in the type of `p` includes the points after `&v[0]` up to (but not
13+
// including) the call to `use_x`. The `else` branch is not included.
14+
15+
// compile-flags:-Zborrowck-mir -Znll
16+
17+
#![allow(warnings)]
18+
#![feature(rustc_attrs)]
19+
20+
struct MyStruct {
21+
field: String
22+
}
23+
24+
fn main() {
25+
let mut my_struct = MyStruct { field: format!("Hello") };
26+
27+
let value = &my_struct.field;
28+
if value.is_empty() {
29+
my_struct.field.push_str("Hello, world!");
30+
//~^ ERROR cannot borrow (Ast)
31+
}
32+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2012-2016 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+
// Basic test for liveness constraints: the region (`R1`) that appears
12+
// in the type of `p` includes the points after `&v[0]` up to (but not
13+
// including) the call to `use_x`. The `else` branch is not included.
14+
15+
// compile-flags:-Zborrowck-mir -Znll
16+
17+
#![allow(warnings)]
18+
#![feature(rustc_attrs)]
19+
20+
struct MyStruct {
21+
field: String
22+
}
23+
24+
fn main() {
25+
}
26+
27+
fn nll_fail() {
28+
let mut my_struct = MyStruct { field: format!("Hello") };
29+
30+
let value = &mut my_struct.field;
31+
loop {
32+
my_struct.field.push_str("Hello, world!");
33+
//~^ ERROR (Ast) [E0499]
34+
//~| ERROR (Mir) [E0499]
35+
value.len();
36+
return;
37+
}
38+
}
39+
40+
fn nll_ok() {
41+
let mut my_struct = MyStruct { field: format!("Hello") };
42+
43+
let value = &mut my_struct.field;
44+
loop {
45+
my_struct.field.push_str("Hello, world!");
46+
//~^ ERROR (Ast) [E0499]
47+
return;
48+
}
49+
}

0 commit comments

Comments
 (0)