Skip to content

Commit 55c6c88

Browse files
committed
Port borrows across yield check to MIR borrowck
1 parent 410d27b commit 55c6c88

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
769769
}
770770

771771
// Retrieve span of given borrow from the current MIR representation
772-
fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
772+
pub fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
773773
self.mir.source_info(borrow.location).span
774774
}
775775

src/librustc_mir/borrow_check/mod.rs

+61
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
209209
};
210210
let flow_inits = flow_inits; // remove mut
211211

212+
let movable_generator = !match tcx.hir.get(id) {
213+
hir::map::Node::NodeExpr(&hir::Expr {
214+
node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
215+
..
216+
}) => true,
217+
_ => false,
218+
};
219+
212220
let mut mbcx = MirBorrowckCtxt {
213221
tcx: tcx,
214222
mir: mir,
215223
node_id: id,
216224
move_data: &mdpe.move_data,
217225
param_env: param_env,
226+
movable_generator,
218227
locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
219228
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
220229
hir::BodyOwnerKind::Fn => true,
@@ -277,6 +286,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
277286
node_id: ast::NodeId,
278287
move_data: &'cx MoveData<'tcx>,
279288
param_env: ParamEnv<'gcx>,
289+
movable_generator: bool,
280290
/// This keeps track of whether local variables are free-ed when the function
281291
/// exits even without a `StorageDead`, which appears to be the case for
282292
/// constants.
@@ -534,6 +544,18 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
534544
drop: _,
535545
} => {
536546
self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state);
547+
548+
if self.movable_generator {
549+
// Look for any active borrows to locals
550+
let domain = flow_state.borrows.operator();
551+
let data = domain.borrows();
552+
flow_state.borrows.with_elems_outgoing(|borrows| {
553+
for i in borrows {
554+
let borrow = &data[i.borrow_index()];
555+
self.check_for_local_borrow(borrow, span);
556+
}
557+
});
558+
}
537559
}
538560

539561
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
@@ -1099,6 +1121,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10991121
}
11001122
}
11011123

1124+
/// Reports an error if this is a borrow of local data.
1125+
/// This is called for all Yield statements on movable generators
1126+
fn check_for_local_borrow(
1127+
&mut self,
1128+
borrow: &BorrowData<'tcx>,
1129+
yield_span: Span)
1130+
{
1131+
fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
1132+
match place {
1133+
Place::Static(..) => false,
1134+
Place::Local(..) => true,
1135+
Place::Projection(box proj) => {
1136+
match proj.elem {
1137+
// Reborrow of already borrowed data is ignored
1138+
// Any errors will be caught on the initial borrow
1139+
ProjectionElem::Deref => false,
1140+
1141+
// For interior references and downcasts, find out if the base is local
1142+
ProjectionElem::Field(..) |
1143+
ProjectionElem::Index(..) |
1144+
ProjectionElem::ConstantIndex { .. } |
1145+
ProjectionElem::Subslice { .. } |
1146+
ProjectionElem::Downcast(..) => {
1147+
borrow_of_local_data(&proj.base)
1148+
}
1149+
}
1150+
}
1151+
}
1152+
}
1153+
1154+
debug!("check_for_local_borrow({:?})", borrow);
1155+
1156+
if borrow_of_local_data(&borrow.borrowed_place) {
1157+
self.tcx.cannot_borrow_across_generator_yield(self.retrieve_borrow_span(borrow),
1158+
yield_span,
1159+
Origin::Mir).emit();
1160+
}
1161+
}
1162+
11021163
fn check_activations(
11031164
&mut self,
11041165
location: Location,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
// compile-flags: -Z borrowck=compare
12+
13+
#![feature(generators)]
14+
#![feature(nll)]
15+
16+
fn main() {
17+
|| {
18+
// The reference in `_a` is a Legal with NLL since it ends before the yield
19+
let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
20+
let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
21+
//~^ borrow may still be in use when generator yields (Mir)
22+
yield ();
23+
println!("{}", b);
24+
};
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0626]: borrow may still be in use when generator yields (Mir)
2+
--> $DIR/generator-with-nll.rs:20:17
3+
|
4+
20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
5+
| ^^^^^^^^^
6+
21 | //~^ borrow may still be in use when generator yields (Mir)
7+
22 | yield ();
8+
| -------- possible yield occurs here
9+
10+
error[E0626]: borrow may still be in use when generator yields (Ast)
11+
--> $DIR/generator-with-nll.rs:19:23
12+
|
13+
19 | let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
14+
| ^^^^
15+
...
16+
22 | yield ();
17+
| -------- possible yield occurs here
18+
19+
error[E0626]: borrow may still be in use when generator yields (Ast)
20+
--> $DIR/generator-with-nll.rs:20:22
21+
|
22+
20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
23+
| ^^^^
24+
21 | //~^ borrow may still be in use when generator yields (Mir)
25+
22 | yield ();
26+
| -------- possible yield occurs here
27+
28+
error: aborting due to 3 previous errors
29+

0 commit comments

Comments
 (0)