]> git.lizzy.rs Git - rust.git/commitdiff
Port borrows across yield check to MIR borrowck
authorJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Thu, 11 Jan 2018 18:50:40 +0000 (19:50 +0100)
committerJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Tue, 23 Jan 2018 04:10:39 +0000 (05:10 +0100)
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/mod.rs
src/test/ui/generator/generator-with-nll.rs [new file with mode: 0644]
src/test/ui/generator/generator-with-nll.stderr [new file with mode: 0644]

index 520febca938f098dcba9d4fd89f259602fe2f415..7bd3b6e39f053b46ca7ab2ce3558049c6ede6ee6 100644 (file)
@@ -769,7 +769,7 @@ fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
     }
 
     // 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
     }
 
index b5836c65d675b515c85e95d11fcac984106b7507..d6937c405f961d91c95a64834f0edc26d2b950e5 100644 (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 @@ fn visit_terminator_entry(
                 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 @@ fn check_for_invalidation_at_exit(
         }
     }
 
+    /// 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,
diff --git a/src/test/ui/generator/generator-with-nll.rs b/src/test/ui/generator/generator-with-nll.rs
new file mode 100644 (file)
index 0000000..3223ff4
--- /dev/null
@@ -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);
+    };
+}
diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr
new file mode 100644 (file)
index 0000000..0a52a92
--- /dev/null
@@ -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
+