about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-04 00:56:06 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-06 00:34:01 +0200
commit243c5a5faaed0c34f0f236c1f168e10b4cc97d25 (patch)
treee52cbf68699754d80b28c88ecd9818fdd9b2703c
parentcbcae7f69414fd0e5de6bad771df12bfde4f2908 (diff)
downloadrust-243c5a5faaed0c34f0f236c1f168e10b4cc97d25.tar.gz
rust-243c5a5faaed0c34f0f236c1f168e10b4cc97d25.zip
fix handling of CallScopeData
This fixes the tests for issue #29793
-rw-r--r--src/librustc_mir/borrow_check/mod.rs9
-rw-r--r--src/librustc_mir/build/cfg.rs11
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs29
-rw-r--r--src/test/compile-fail/region-borrow-params-issue-29793-big.rs10
4 files changed, 53 insertions, 6 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 61e7eb59339..a8af5f5d32b 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -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;
@@ -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,
@@ -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),
     ));
 
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index d1bb1f39e22..932aad0bb1d 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -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),
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 2bba3e263f3..b3b06f7f6cd 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -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};
@@ -27,6 +30,7 @@ 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
@@ -34,6 +38,8 @@ use std::fmt;
 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>>,
@@ -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,
@@ -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,
@@ -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);
+                            }
+                        }
                     }
                 }
             }
diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-big.rs b/src/test/compile-fail/region-borrow-params-issue-29793-big.rs
index 887f7836ee1..a4dc00bd2b1 100644
--- a/src/test/compile-fail/region-borrow-params-issue-29793-big.rs
+++ b/src/test/compile-fail/region-borrow-params-issue-29793-big.rs
@@ -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> {
@@ -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