Port borrows across yield check to MIR borrowck

This commit is contained in:
John Kåre Alsaker 2018-01-11 19:50:40 +01:00
parent 410d27bb97
commit 55c6c88782
4 changed files with 116 additions and 1 deletions

View file

@ -769,7 +769,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
// Retrieve span of given borrow from the current MIR representation
fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
pub fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
self.mir.source_info(borrow.location).span
}

View file

@ -209,12 +209,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
};
let flow_inits = flow_inits; // remove mut
let movable_generator = !match tcx.hir.get(id) {
hir::map::Node::NodeExpr(&hir::Expr {
node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
..
}) => true,
_ => false,
};
let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
mir: mir,
node_id: id,
move_data: &mdpe.move_data,
param_env: param_env,
movable_generator,
locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
hir::BodyOwnerKind::Fn => true,
@ -277,6 +286,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
node_id: ast::NodeId,
move_data: &'cx MoveData<'tcx>,
param_env: ParamEnv<'gcx>,
movable_generator: bool,
/// This keeps track of whether local variables are free-ed when the function
/// exits even without a `StorageDead`, which appears to be the case for
/// constants.
@ -534,6 +544,18 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
drop: _,
} => {
self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state);
if self.movable_generator {
// Look for any active borrows to locals
let domain = flow_state.borrows.operator();
let data = domain.borrows();
flow_state.borrows.with_elems_outgoing(|borrows| {
for i in borrows {
let borrow = &data[i.borrow_index()];
self.check_for_local_borrow(borrow, span);
}
});
}
}
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
@ -1099,6 +1121,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
/// Reports an error if this is a borrow of local data.
/// This is called for all Yield statements on movable generators
fn check_for_local_borrow(
&mut self,
borrow: &BorrowData<'tcx>,
yield_span: Span)
{
fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
match place {
Place::Static(..) => false,
Place::Local(..) => true,
Place::Projection(box proj) => {
match proj.elem {
// Reborrow of already borrowed data is ignored
// Any errors will be caught on the initial borrow
ProjectionElem::Deref => false,
// For interior references and downcasts, find out if the base is local
ProjectionElem::Field(..) |
ProjectionElem::Index(..) |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } |
ProjectionElem::Downcast(..) => {
borrow_of_local_data(&proj.base)
}
}
}
}
}
debug!("check_for_local_borrow({:?})", borrow);
if borrow_of_local_data(&borrow.borrowed_place) {
self.tcx.cannot_borrow_across_generator_yield(self.retrieve_borrow_span(borrow),
yield_span,
Origin::Mir).emit();
}
}
fn check_activations(
&mut self,
location: Location,

View file

@ -0,0 +1,25 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z borrowck=compare
#![feature(generators)]
#![feature(nll)]
fn main() {
|| {
// The reference in `_a` is a Legal with NLL since it ends before the yield
let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
//~^ borrow may still be in use when generator yields (Mir)
yield ();
println!("{}", b);
};
}

View file

@ -0,0 +1,29 @@
error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/generator-with-nll.rs:20:17
|
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 ();
| -------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/generator-with-nll.rs:19:23
|
19 | let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
| ^^^^
...
22 | yield ();
| -------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/generator-with-nll.rs:20:22
|
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 ();
| -------- possible yield occurs here
error: aborting due to 3 previous errors