Skip to content

extend NLL with preliminary support for free regions on functions #45668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 7, 2017
Merged
21 changes: 21 additions & 0 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
errors: &Vec<RegionResolutionError<'tcx>>) {
debug!("report_region_errors(): {} errors to start", errors.len());

if self.tcx.sess.opts.debugging_opts.nll {
for error in errors {
match *error {
RegionResolutionError::ConcreteFailure(ref origin, ..) |
RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
self.tcx.sess.span_warn(
origin.span(),
"not reporting region error due to -Znll");
}

RegionResolutionError::SubSupConflict(ref rvo, ..) => {
self.tcx.sess.span_warn(
rvo.span(),
"not reporting region error due to -Znll");
}
}
}

return;
}

// try to pre-process the errors, which will group some of them
// together into a `ProcessedErrors` group:
let errors = self.process_errors(errors);
Expand Down
13 changes: 13 additions & 0 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@ impl<'tcx> FreeRegionMap<'tcx> {
debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
result
}

/// Returns all regions that are known to outlive `r_a`. For
/// example, in a function:
///
/// ```
/// fn foo<'a, 'b: 'a, 'c: 'b>() { .. }
/// ```
///
/// if `r_a` represents `'a`, this function would return `{'b, 'c}`.
pub fn regions_that_outlive<'a, 'gcx>(&self, r_a: Region<'tcx>) -> Vec<&Region<'tcx>> {
assert!(is_free(r_a));
self.relation.greater_than(&r_a)
}
}

fn is_free(r: Region) -> bool {
Expand Down
51 changes: 34 additions & 17 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ macro_rules! make_mir_visitor {

fn visit_ty(&mut self,
ty: & $($mutability)* Ty<'tcx>,
_: Lookup) {
_: TyContext) {
self.super_ty(ty);
}

Expand Down Expand Up @@ -256,8 +256,9 @@ macro_rules! make_mir_visitor {
}

fn visit_local_decl(&mut self,
local: Local,
local_decl: & $($mutability)* LocalDecl<'tcx>) {
self.super_local_decl(local_decl);
self.super_local_decl(local, local_decl);
}

fn visit_local(&mut self,
Expand Down Expand Up @@ -291,14 +292,14 @@ macro_rules! make_mir_visitor {
self.visit_visibility_scope_data(scope);
}

let lookup = Lookup::Src(SourceInfo {
let lookup = TyContext::SourceInfo(SourceInfo {
span: mir.span,
scope: ARGUMENT_VISIBILITY_SCOPE,
});
self.visit_ty(&$($mutability)* mir.return_ty, lookup);

for local_decl in &$($mutability)* mir.local_decls {
self.visit_local_decl(local_decl);
for local in mir.local_decls.indices() {
self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
}

self.visit_span(&$($mutability)* mir.span);
Expand Down Expand Up @@ -359,7 +360,8 @@ macro_rules! make_mir_visitor {
for operand in lvalues {
self.visit_lvalue(& $($mutability)* operand.lval,
LvalueContext::Validate, location);
self.visit_ty(& $($mutability)* operand.ty, Lookup::Loc(location));
self.visit_ty(& $($mutability)* operand.ty,
TyContext::Location(location));
}
}
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
Expand Down Expand Up @@ -421,7 +423,7 @@ macro_rules! make_mir_visitor {
ref values,
ref targets } => {
self.visit_operand(discr, source_location);
self.visit_ty(switch_ty, Lookup::Loc(source_location));
self.visit_ty(switch_ty, TyContext::Location(source_location));
for value in &values[..] {
self.visit_const_int(value, source_location);
}
Expand Down Expand Up @@ -538,7 +540,7 @@ macro_rules! make_mir_visitor {
ref $($mutability)* operand,
ref $($mutability)* ty) => {
self.visit_operand(operand, location);
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
}

Rvalue::BinaryOp(_bin_op,
Expand All @@ -560,15 +562,15 @@ macro_rules! make_mir_visitor {
}

Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
}

Rvalue::Aggregate(ref $($mutability)* kind,
ref $($mutability)* operands) => {
let kind = &$($mutability)* **kind;
match *kind {
AggregateKind::Array(ref $($mutability)* ty) => {
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
}
AggregateKind::Tuple => {
}
Expand Down Expand Up @@ -638,7 +640,7 @@ macro_rules! make_mir_visitor {
ref $($mutability)* ty,
} = *static_;
self.visit_def_id(def_id, location);
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
}

fn super_projection(&mut self,
Expand Down Expand Up @@ -668,7 +670,7 @@ macro_rules! make_mir_visitor {
ProjectionElem::Subslice { from: _, to: _ } => {
}
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(ref $($mutability)* local) => {
self.visit_local(local, LvalueContext::Consume, location);
Expand All @@ -683,6 +685,7 @@ macro_rules! make_mir_visitor {
}

fn super_local_decl(&mut self,
local: Local,
local_decl: & $($mutability)* LocalDecl<'tcx>) {
let LocalDecl {
mutability: _,
Expand All @@ -694,7 +697,10 @@ macro_rules! make_mir_visitor {
is_user_variable: _,
} = *local_decl;

self.visit_ty(ty, Lookup::Src(*source_info));
self.visit_ty(ty, TyContext::LocalDecl {
local,
source_info: *source_info,
});
self.visit_source_info(source_info);
self.visit_visibility_scope(lexical_scope);
}
Expand All @@ -718,7 +724,7 @@ macro_rules! make_mir_visitor {
} = *constant;

self.visit_span(span);
self.visit_ty(ty, Lookup::Loc(location));
self.visit_ty(ty, TyContext::Location(location));
self.visit_literal(literal, location);
}

Expand Down Expand Up @@ -796,10 +802,21 @@ macro_rules! make_mir_visitor {
make_mir_visitor!(Visitor,);
make_mir_visitor!(MutVisitor,mut);

/// Extra information passed to `visit_ty` and friends to give context
/// about where the type etc appears.
#[derive(Copy, Clone, Debug)]
pub enum Lookup {
Loc(Location),
Src(SourceInfo),
pub enum TyContext {
LocalDecl {
/// The index of the local variable we are visiting.
local: Local,

/// The source location where this local variable was declared.
source_info: SourceInfo,
},

Location(Location),

SourceInfo(SourceInfo),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down
36 changes: 21 additions & 15 deletions src/librustc_data_structures/bitvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ pub struct BitMatrix {
}

impl BitMatrix {
// Create a new `rows x columns` matrix, initially empty.
/// Create a new `rows x columns` matrix, initially empty.
pub fn new(rows: usize, columns: usize) -> BitMatrix {
// For every element, we need one bit for every other
// element. Round up to an even number of u64s.
Expand All @@ -163,29 +163,33 @@ impl BitMatrix {
(start, start + u64s_per_row)
}

pub fn add(&mut self, source: usize, target: usize) -> bool {
let (start, _) = self.range(source);
let (word, mask) = word_mask(target);
/// Sets the cell at `(row, column)` to true. Put another way, add
/// `column` to the bitset for `row`.
///
/// Returns true if this changed the matrix, and false otherwies.
pub fn add(&mut self, row: usize, column: usize) -> bool {
let (start, _) = self.range(row);
let (word, mask) = word_mask(column);
let vector = &mut self.vector[..];
let v1 = vector[start + word];
let v2 = v1 | mask;
vector[start + word] = v2;
v1 != v2
}

/// Do the bits from `source` contain `target`?
///
/// Put another way, if the matrix represents (transitive)
/// reachability, can `source` reach `target`?
pub fn contains(&self, source: usize, target: usize) -> bool {
let (start, _) = self.range(source);
let (word, mask) = word_mask(target);
/// Do the bits from `row` contain `column`? Put another way, is
/// the matrix cell at `(row, column)` true? Put yet another way,
/// if the matrix represents (transitive) reachability, can
/// `row` reach `column`?
pub fn contains(&self, row: usize, column: usize) -> bool {
let (start, _) = self.range(row);
let (word, mask) = word_mask(column);
(self.vector[start + word] & mask) != 0
}

/// Returns those indices that are reachable from both `a` and
/// `b`. This is an O(n) operation where `n` is the number of
/// elements (somewhat independent from the actual size of the
/// Returns those indices that are true in rows `a` and `b`. This
/// is an O(n) operation where `n` is the number of elements
/// (somewhat independent from the actual size of the
/// intersection, in particular).
pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> {
let (a_start, a_end) = self.range(a);
Expand All @@ -206,7 +210,7 @@ impl BitMatrix {
result
}

/// Add the bits from `read` to the bits from `write`,
/// Add the bits from row `read` to the bits from row `write`,
/// return true if anything changed.
///
/// This is used when computing transitive reachability because if
Expand All @@ -227,6 +231,8 @@ impl BitMatrix {
changed
}

/// Iterates through all the columns set to true in a given row of
/// the matrix.
pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> {
let (start, end) = self.range(row);
BitVectorIter {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_data_structures/transitive_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,12 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
}
}

/// Returns a vector of all things less than `a`.
/// Returns a vector of all things greater than `a`.
///
/// Really this probably ought to be `impl Iterator<Item=&T>`, but
/// I'm too lazy to make that work, and -- given the caching
/// strategy -- it'd be a touch tricky anyhow.
pub fn less_than(&self, a: &T) -> Vec<&T> {
pub fn greater_than(&self, a: &T) -> Vec<&T> {
match self.index(a) {
Some(a) => self.with_closure(|closure| {
closure.iter(a.0).map(|i| &self.elements[i]).collect()
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
Expand Down Expand Up @@ -165,7 +165,7 @@ struct GlobalizeMir<'a, 'gcx: 'a> {
}

impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
if let Some(lifted) = self.tcx.lift(ty) {
*ty = lifted;
} else {
Expand Down
24 changes: 17 additions & 7 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +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>,
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>,
}

// temporarily allow some dead fields: `kind` and `region` will be
Expand Down Expand Up @@ -69,7 +69,7 @@ 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>,
nonlexical_regioncx: Option<&'a RegionInferenceContext>)
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>)
-> Self {
let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
location_map: FxHashMap(),
Expand Down Expand Up @@ -139,11 +139,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
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);
let borrow_region = borrow_data.region.to_region_index();
if !regioncx.region_contains_point(borrow_region, location) {
// The region checker really considers the borrow
// to start at the point **after** the location of
// the borrow, but the borrow checker puts the gen
// directly **on** the location of the
// borrow. This results in a gen/kill both being
// generated for same point if we are not
// careful. Probably we should change the point of
// the gen, but for now we hackily account for the
// mismatch here by not generating a kill for the
// location on the borrow itself.
if location != borrow_data.location {
sets.kill(&borrow_index);
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/transform/clean_end_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc::middle::region;
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, Visitor, Lookup};
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
use rustc::ty::{Ty, RegionKind, TyCtxt};

pub struct CleanEndRegions;
Expand Down Expand Up @@ -67,7 +67,7 @@ impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions {
self.super_rvalue(rvalue, location);
}

fn visit_ty(&mut self, ty: &Ty<'tcx>, _: Lookup) {
fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
// Gather regions that occur in types
for re in ty.walk().flat_map(|t| t.regions()) {
match *re {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/transform/erase_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::mir::transform::{MirPass, MirSource};

struct EraseRegionsVisitor<'a, 'tcx: 'a> {
Expand All @@ -35,7 +35,7 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
}

impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
if !self.in_validation_statement {
*ty = self.tcx.erase_regions(ty);
}
Expand Down
Loading