Skip to content

Commit

Permalink
fix handling of CallScopeData
Browse files Browse the repository at this point in the history
This fixes the tests for issue rust-lang#29793
  • Loading branch information
arielb1 committed Dec 5, 2017
1 parent cbcae7f commit 243c5a5
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
9 changes: 8 additions & 1 deletion src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::maps::Providers;
Expand Down Expand Up @@ -131,6 +132,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
move_data: move_data,
param_env: param_env,
};
let body_id = match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::StructCtor |
DefPathData::EnumVariant(_) => None,
_ => Some(tcx.hir.body_owned_by(id))
};

let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let mut flow_inits = FlowInProgress::new(do_dataflow(
tcx,
Expand Down Expand Up @@ -206,7 +213,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx),
Borrows::new(tcx, mir, opt_regioncx, def_id, body_id),
|bd, i| bd.location(i),
));

Expand Down
11 changes: 11 additions & 0 deletions src/librustc_mir/build/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ impl<'tcx> CFG<'tcx> {
source_info: SourceInfo,
region_scope: region::Scope) {
if tcx.sess.emit_end_regions() {
if let region::ScopeData::CallSite(_) = region_scope.data() {
// The CallSite scope (aka the root scope) is sort of weird, in that it is
// supposed to "separate" the "interior" and "exterior" of a closure. Being
// that, it is not really a part of the region hierarchy, but for some
// reason it *is* considered a part of it.
//
// It should die a hopefully painful death with NLL, so let's leave this hack
// for now so that nobody can complain about soundness.
return
}

self.push(block, Statement {
source_info,
kind: StatementKind::EndRegion(region_scope),
Expand Down
29 changes: 26 additions & 3 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::{self, Location, Mir};
use rustc::mir::visit::Visitor;
use rustc::ty::{self, Region, TyCtxt};
Expand All @@ -27,13 +30,16 @@ use borrow_check::nll::ToRegionVid;
use syntax_pos::Span;

use std::fmt;
use std::rc::Rc;

// `Borrows` maps each dataflow bit to an `Rvalue::Ref`, which can be
// uniquely identified in the MIR by the `Location` of the assigment
// statement in which it appears on the right hand side.
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>,
scope_tree: Rc<region::ScopeTree>,
root_scope: Option<region::Scope>,
borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
location_map: FxHashMap<Location, BorrowIndex>,
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
Expand Down Expand Up @@ -69,8 +75,14 @@ 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<RegionInferenceContext<'tcx>>)
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>,
def_id: DefId,
body_id: Option<hir::BodyId>)
-> Self {
let scope_tree = tcx.region_scope_tree(def_id);
let root_scope = body_id.map(|body_id| {
region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
});
let mut visitor = GatherBorrows {
tcx,
mir,
Expand All @@ -83,6 +95,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
return Borrows { tcx: tcx,
mir: mir,
borrows: visitor.idx_vec,
scope_tree,
root_scope,
location_map: visitor.location_map,
region_map: visitor.region_map,
region_span_map: visitor.region_span_map,
Expand Down Expand Up @@ -253,8 +267,17 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
// like unwind paths, we do not always emit `EndRegion` statements, so we
// add some kills here as a "backup" and to avoid spurious error messages.
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
if let ReScope(..) = borrow_data.region {
sets.kill(&borrow_index);
if let ReScope(scope) = borrow_data.region {
// Check that the scope is not actually a scope from a function that is
// a parent of our closure. Note that the CallSite scope itself is
// *outside* of the closure, for some weird reason.
if let Some(root_scope) = self.root_scope {
if *scope != root_scope &&
self.scope_tree.is_subscope_of(*scope, root_scope)
{
sets.kill(&borrow_index);
}
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/test/compile-fail/region-borrow-params-issue-29793-big.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
// behavior (because the improperly accepted closure was actually
// able to be invoked).

// ignore-tidy-linelength
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

struct WrapA<F>(Option<F>);

impl<F> WrapA<F> {
Expand Down Expand Up @@ -75,9 +79,11 @@ impl<F, T> WrapA<F>
fn main() {
let mut w = WrapA::new().set(|x: usize, y: usize| {
WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`)
//~^ ERROR `x` does not live long enough
//~| ERROR `y` does not live long enough
//[ast]~^ ERROR `x` does not live long enough
//[ast]~| ERROR `y` does not live long enough
});
//[mir]~^ ERROR borrowed value does not live long enough
//[mir]~| ERROR borrowed value does not live long enough

w.handle(); // This works
// w.handle_ref(); // This doesn't
Expand Down

0 comments on commit 243c5a5

Please sign in to comment.