about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-10-24 18:28:39 -0400
committerNiko Matsakis <niko@alum.mit.edu>2017-10-31 12:41:39 -0400
commit24442ffa666925b7c98fb9e9197811700bc36d26 (patch)
tree555eaac91cd6b64f81cbaa64b0a1392f5a21c042
parentaf09f720d60c1226b5d42aaee3cc0c0e67ebe5cc (diff)
downloadrust-24442ffa666925b7c98fb9e9197811700bc36d26.tar.gz
rust-24442ffa666925b7c98fb9e9197811700bc36d26.zip
add subregion between borrow region and resulting reference
-rw-r--r--src/librustc/mir/mod.rs8
-rw-r--r--src/librustc_mir/transform/nll/constraint_generation.rs63
-rw-r--r--src/test/mir-opt/nll/region-liveness-basic.rs1
-rw-r--r--src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs49
4 files changed, 113 insertions, 8 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index f5a3c1989cf..307637b2f1d 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1637,6 +1637,14 @@ impl fmt::Debug for Location {
 }
 
 impl Location {
+    /// Returns the location immediately after this one within the enclosing block.
+    ///
+    /// Note that if this location represents a terminator, then the
+    /// resulting location would be out of bounds and invalid.
+    pub fn successor_within_block(&self) -> Location {
+        Location { block: self.block, statement_index: self.statement_index + 1 }
+    }
+
     pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool {
         if self.block == other.block {
             self.statement_index <= other.statement_index
diff --git a/src/librustc_mir/transform/nll/constraint_generation.rs b/src/librustc_mir/transform/nll/constraint_generation.rs
index 1e008ec38f2..1acbd72a47d 100644
--- a/src/librustc_mir/transform/nll/constraint_generation.rs
+++ b/src/librustc_mir/transform/nll/constraint_generation.rs
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::mir::{Location, Mir};
+use rustc::mir::{BasicBlock, BorrowKind, Location, Lvalue, Mir, Rvalue, Statement, StatementKind};
 use rustc::mir::transform::MirSource;
+use rustc::mir::visit::Visitor;
 use rustc::infer::InferCtxt;
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty};
@@ -38,18 +39,18 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
     }.add_constraints();
 }
 
-struct ConstraintGeneration<'constrain, 'gcx: 'tcx, 'tcx: 'constrain> {
-    infcx: &'constrain InferCtxt<'constrain, 'gcx, 'tcx>,
-    regioncx: &'constrain mut RegionInferenceContext,
-    mir: &'constrain Mir<'tcx>,
-    liveness: &'constrain LivenessResults,
+struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
+    infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
+    regioncx: &'cx mut RegionInferenceContext,
+    mir: &'cx Mir<'tcx>,
+    liveness: &'cx LivenessResults,
     mir_source: MirSource,
 }
 
-impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> {
+impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
     fn add_constraints(&mut self) {
-        // To start, add the liveness constraints.
         self.add_liveness_constraints();
+        self.add_borrow_constraints();
     }
 
     /// Liveness constraints:
@@ -172,4 +173,50 @@ impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> {
             }
         }
     }
+
+    fn add_borrow_constraints(&mut self) {
+        self.visit_mir(self.mir);
+    }
+
+    fn add_borrow_constraint(
+        &mut self,
+        location: Location,
+        destination_lv: &Lvalue<'tcx>,
+        borrow_region: ty::Region<'tcx>,
+        _borrow_kind: BorrowKind,
+        _borrowed_lv: &Lvalue<'tcx>,
+    ) {
+        let tcx = self.infcx.tcx;
+        let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx);
+
+        let destination_region = match destination_ty.sty {
+            ty::TyRef(r, _) => r,
+            _ => bug!()
+        };
+
+        self.regioncx.add_outlives(borrow_region.to_region_index(),
+                                   destination_region.to_region_index(),
+                                   location.successor_within_block());
+    }
+}
+
+impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
+    fn visit_statement(&mut self,
+                       block: BasicBlock,
+                       statement: &Statement<'tcx>,
+                       location: Location) {
+        // Look for a statement like:
+        //
+        //     D = & L
+        //
+        // where D is the path to which we are assigning, and
+        // L is the path that is borrowed.
+        if let StatementKind::Assign(ref destination_lv, ref rv) = statement.kind {
+            if let Rvalue::Ref(region, bk, ref borrowed_lv) = *rv {
+                self.add_borrow_constraint(location, destination_lv, region, bk, borrowed_lv);
+            }
+        }
+
+        self.super_statement(block, statement, location);
+    }
 }
diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs
index 67e16c2fe6f..3ab83a8eec3 100644
--- a/src/test/mir-opt/nll/region-liveness-basic.rs
+++ b/src/test/mir-opt/nll/region-liveness-basic.rs
@@ -31,6 +31,7 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.node12.nll.0.mir
+// | R0: {bb1[1], bb2[0], bb2[1]}
 // | R1: {bb1[1], bb2[0], bb2[1]}
 // ...
 //             let _2: &'_#1r usize;
diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
new file mode 100644
index 00000000000..eb904af39ac
--- /dev/null
+++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.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.
+
+// Test for the subregion constraints. In this case, the region R3 on
+// `p` includes two disjoint regions of the control-flow graph. The
+// borrows in `&v[0]` and `&v[1]` each (in theory) have to outlive R3,
+// but only at a particular point, and hence they wind up including
+// distinct regions.
+
+// compile-flags:-Znll -Zverbose
+//                     ^^^^^^^^^ force compiler to dump more region information
+
+#![allow(warnings)]
+
+fn use_x(_: usize) -> bool { true }
+
+fn main() {
+    let mut v = [1, 2, 3];
+    let mut p = &v[0];
+    if true {
+        use_x(*p);
+    } else {
+        use_x(22);
+    }
+
+    p = &v[1];
+    use_x(*p);
+}
+
+// END RUST SOURCE
+// START rustc.node12.nll.0.mir
+// | R0: {bb1[1], bb2[0], bb2[1]}
+// ...
+// | R2: {bb7[2], bb7[3], bb7[4]}
+// | R3: {bb1[1], bb2[0], bb2[1], bb7[2], bb7[3], bb7[4]}
+// ...
+// let mut _2: &'_#3r usize;
+// ...
+// _2 = &'_#0r _1[_3];
+// ...
+// _2 = &'_#2r (*_10);
+// END rustc.node12.nll.0.mir