1
Fork 0

add subregion between borrow region and resulting reference

This commit is contained in:
Niko Matsakis 2017-10-24 18:28:39 -04:00
parent af09f720d6
commit 24442ffa66
4 changed files with 113 additions and 8 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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