From 24442ffa666925b7c98fb9e9197811700bc36d26 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 24 Oct 2017 18:28:39 -0400 Subject: [PATCH] add subregion between borrow region and resulting reference --- src/librustc/mir/mod.rs | 8 +++ .../transform/nll/constraint_generation.rs | 63 ++++++++++++++++--- src/test/mir-opt/nll/region-liveness-basic.rs | 1 + .../nll/region-liveness-two-disjoint-uses.rs | 49 +++++++++++++++ 4 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f5a3c1989cf8..307637b2f1d6 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) -> 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 1e008ec38f22..1acbd72a47df 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 67e16c2fe6fc..3ab83a8eec32 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 000000000000..eb904af39ac0 --- /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 or the MIT license +// , 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