about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check.rs22
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs40
-rw-r--r--src/test/compile-fail/nll/loan_ends_mid_block_pair.rs50
-rw-r--r--src/test/compile-fail/nll/loan_ends_mid_block_vec.rs49
-rw-r--r--src/test/compile-fail/nll/region-ends-after-if-condition.rs32
-rw-r--r--src/test/compile-fail/nll/return_from_loop.rs49
6 files changed, 232 insertions, 10 deletions
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 5ff7bcc3c16..8b5f1539ac0 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -17,7 +17,8 @@ use rustc::ty::maps::Providers;
 use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local};
 use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
 use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
-use rustc::mir::transform::{MirSource};
+use rustc::mir::transform::MirSource;
+use transform::nll;
 
 use rustc_data_structures::indexed_set::{self, IdxSetBuf};
 use rustc_data_structures::indexed_vec::{Idx};
@@ -62,7 +63,7 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
 }
 
 fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                   mir: &Mir<'gcx>,
+                                   input_mir: &Mir<'gcx>,
                                    def_id: DefId,
                                    src: MirSource)
 {
@@ -72,7 +73,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 
     let id = src.item_id();
 
-    let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx, param_env) {
+    let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
         Ok(move_data) => move_data,
         Err((move_data, move_errors)) => {
             for move_error in move_errors {
@@ -100,10 +101,23 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
     };
 
+    // Make our own copy of the MIR. This copy will be modified (in place) to
+    // contain non-lexical lifetimes. It will have a lifetime tied
+    // to the inference context.
+    let mut mir: Mir<'tcx> = input_mir.clone();
+    let mir = &mut mir;
+
+    // If we are in non-lexical mode, compute the non-lexical lifetimes.
+    let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
+        None
+    } else {
+        Some(nll::compute_regions(infcx, src, mir))
+    };
+
     let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
     let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
     let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
-                                   Borrows::new(tcx, mir),
+                                   Borrows::new(tcx, mir, opt_regioncx.as_ref()),
                                    |bd, i| bd.location(i));
     let flow_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
                                  MaybeInitializedLvals::new(tcx, mir, &mdpe),
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 8079f64bf5d..17aa8c05418 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -21,6 +21,8 @@ use rustc_data_structures::indexed_vec::{IndexVec};
 
 use dataflow::{BitDenotation, BlockSets, DataflowOperator};
 pub use dataflow::indexes::BorrowIndex;
+use transform::nll::region_infer::RegionInferenceContext;
+use transform::nll::ToRegionIndex;
 
 use syntax_pos::Span;
 
@@ -36,6 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
     location_map: FxHashMap<Location, BorrowIndex>,
     region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
     region_span_map: FxHashMap<RegionKind, Span>,
+    nonlexical_regioncx: Option<&'a RegionInferenceContext>,
 }
 
 // temporarily allow some dead fields: `kind` and `region` will be
@@ -64,7 +67,10 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+               mir: &'a Mir<'tcx>,
+               nonlexical_regioncx: Option<&'a RegionInferenceContext>)
+               -> Self {
         let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
                                           location_map: FxHashMap(),
                                           region_map: FxHashMap(),
@@ -75,7 +81,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                          borrows: visitor.idx_vec,
                          location_map: visitor.location_map,
                          region_map: visitor.region_map,
-                         region_span_map: visitor.region_span_map};
+                         region_span_map: visitor.region_span_map,
+                         nonlexical_regioncx };
 
         struct GatherBorrows<'tcx> {
             idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
@@ -121,9 +128,26 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
     /// meaning there.  Otherwise, it should return some.
     pub fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
         let opt_span = self.region_span_map.get(region);
-        assert!(opt_span.is_some(), "end region not found for {:?}", region);
+        assert!(self.nonlexical_regioncx.is_some() ||
+                opt_span.is_some(), "end region not found for {:?}", region);
         opt_span.map(|s| s.end_point())
     }
+
+    /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
+    fn kill_loans_out_of_scope_at_location(&self,
+                                           sets: &mut BlockSets<BorrowIndex>,
+                                           location: Location) {
+        if let Some(regioncx) = self.nonlexical_regioncx {
+            for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
+                let borrow_region = regioncx.region_value(borrow_data.region.to_region_index());
+                if !borrow_region.may_contain(location) && location != borrow_data.location {
+                    debug!("kill_loans_out_of_scope_at_location: kill{:?} \
+                           location={:?} borrow_data={:?}", borrow_index, location, borrow_data);
+                    sets.kill(&borrow_index);
+                }
+            }
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
@@ -149,6 +173,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
         match stmt.kind {
             mir::StatementKind::EndRegion(region_scope) => {
                 if let Some(borrow_indexes) = self.region_map.get(&ReScope(region_scope)) {
+                    assert!(self.nonlexical_regioncx.is_none());
                     for idx in borrow_indexes { sets.kill(&idx); }
                 } else {
                     // (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> {
             mir::StatementKind::Nop => {}
 
         }
+
+        self.kill_loans_out_of_scope_at_location(sets, location);
     }
+
     fn terminator_effect(&self,
-                         _sets: &mut BlockSets<BorrowIndex>,
-                         _location: Location) {
-        // no terminators start nor end region scopes.
+                         sets: &mut BlockSets<BorrowIndex>,
+                         location: Location) {
+        self.kill_loans_out_of_scope_at_location(sets, location);
     }
 
     fn propagate_call_return(&self,
diff --git a/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs b/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs
new file mode 100644
index 00000000000..c02977f22ea
--- /dev/null
+++ b/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs
@@ -0,0 +1,50 @@
+// Copyright 2012 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:-Zborrowck-mir -Znll
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+
+fn main() {
+}
+
+fn nll_fail() {
+    let mut data = ('a', 'b', 'c');
+    let c = &mut data.0;
+    capitalize(c);
+    data.0 = 'e';
+    //~^ ERROR (Ast) [E0506]
+    //~| ERROR (Mir) [E0506]
+    data.0 = 'f';
+    //~^ ERROR (Ast) [E0506]
+    //~| ERROR (Mir) [E0506]
+    data.0 = 'g';
+    //~^ ERROR (Ast) [E0506]
+    //~| ERROR (Mir) [E0506]
+    capitalize(c);
+}
+
+fn nll_ok() {
+    let mut data = ('a', 'b', 'c');
+    let c = &mut data.0;
+    capitalize(c);
+    data.0 = 'e';
+    //~^ ERROR (Ast) [E0506]
+    data.0 = 'f';
+    //~^ ERROR (Ast) [E0506]
+    data.0 = 'g';
+    //~^ ERROR (Ast) [E0506]
+}
+
+fn capitalize(_: &mut char) {
+}
diff --git a/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs b/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs
new file mode 100644
index 00000000000..5e3a003b54e
--- /dev/null
+++ b/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs
@@ -0,0 +1,49 @@
+// Copyright 2012 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:-Zborrowck-mir -Znll
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+fn main() {
+}
+
+fn nll_fail() {
+    let mut data = vec!['a', 'b', 'c'];
+    let slice = &mut data;
+    capitalize(slice);
+    data.push('d');
+    //~^ ERROR (Ast) [E0499]
+    //~| ERROR (Mir) [E0499]
+    data.push('e');
+    //~^ ERROR (Ast) [E0499]
+    //~| ERROR (Mir) [E0499]
+    data.push('f');
+    //~^ ERROR (Ast) [E0499]
+    //~| ERROR (Mir) [E0499]
+    capitalize(slice);
+}
+
+fn nll_ok() {
+    let mut data = vec!['a', 'b', 'c'];
+    let slice = &mut data;
+    capitalize(slice);
+    data.push('d');
+    //~^ ERROR (Ast) [E0499]
+    data.push('e');
+    //~^ ERROR (Ast) [E0499]
+    data.push('f');
+    //~^ ERROR (Ast) [E0499]
+}
+
+fn capitalize(_: &mut [char]) {
+}
diff --git a/src/test/compile-fail/nll/region-ends-after-if-condition.rs b/src/test/compile-fail/nll/region-ends-after-if-condition.rs
new file mode 100644
index 00000000000..dbc35fa99b0
--- /dev/null
+++ b/src/test/compile-fail/nll/region-ends-after-if-condition.rs
@@ -0,0 +1,32 @@
+// Copyright 2012-2016 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.
+
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+// compile-flags:-Zborrowck-mir -Znll
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+struct MyStruct {
+    field: String
+}
+
+fn main() {
+    let mut my_struct = MyStruct { field: format!("Hello") };
+
+    let value = &my_struct.field;
+    if value.is_empty() {
+        my_struct.field.push_str("Hello, world!");
+        //~^ ERROR cannot borrow (Ast)
+    }
+}
diff --git a/src/test/compile-fail/nll/return_from_loop.rs b/src/test/compile-fail/nll/return_from_loop.rs
new file mode 100644
index 00000000000..6b287fd2272
--- /dev/null
+++ b/src/test/compile-fail/nll/return_from_loop.rs
@@ -0,0 +1,49 @@
+// Copyright 2012-2016 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.
+
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+// compile-flags:-Zborrowck-mir -Znll
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+struct MyStruct {
+    field: String
+}
+
+fn main() {
+}
+
+fn nll_fail() {
+    let mut my_struct = MyStruct { field: format!("Hello") };
+
+    let value = &mut my_struct.field;
+    loop {
+        my_struct.field.push_str("Hello, world!");
+        //~^ ERROR (Ast) [E0499]
+        //~| ERROR (Mir) [E0499]
+        value.len();
+        return;
+    }
+}
+
+fn nll_ok() {
+    let mut my_struct = MyStruct { field: format!("Hello") };
+
+    let value = &mut my_struct.field;
+    loop {
+        my_struct.field.push_str("Hello, world!");
+        //~^ ERROR (Ast) [E0499]
+        return;
+    }
+}