Port borrows across yield check to MIR borrowck
This commit is contained in:
parent
410d27bb97
commit
55c6c88782
4 changed files with 116 additions and 1 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
25
src/test/ui/generator/generator-with-nll.rs
Normal file
25
src/test/ui/generator/generator-with-nll.rs
Normal 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);
|
||||
};
|
||||
}
|
29
src/test/ui/generator/generator-with-nll.stderr
Normal file
29
src/test/ui/generator/generator-with-nll.stderr
Normal 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
|
||||
|
Loading…
Add table
Reference in a new issue