about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-12-07 11:21:29 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-12-20 14:04:51 -0500
commit0e64a756f84041e7c33acb052db9df9c9576e6d4 (patch)
tree3d6bd561cf157588aeea08a0a5a77047d6594b6e
parent741ef41e41e61ae107145d03ffcb263ffec5ca1f (diff)
downloadrust-0e64a756f84041e7c33acb052db9df9c9576e6d4.tar.gz
rust-0e64a756f84041e7c33acb052db9df9c9576e6d4.zip
integrate -Znll-dump-cause into borrowck
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs136
-rw-r--r--src/librustc_mir/borrow_check/mod.rs6
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs16
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs20
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs4
5 files changed, 145 insertions, 37 deletions
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index c144962fb2d..971b5eb2275 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -14,6 +14,7 @@ use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
 use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind};
 use rustc::ty::{self, RegionKind};
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_errors::DiagnosticBuilder;
 
 use std::rc::Rc;
 
@@ -88,7 +89,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     pub(super) fn report_move_out_while_borrowed(
         &mut self,
-        _context: Context,
+        context: Context,
         (place, span): (&Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
     ) {
@@ -100,23 +101,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Some(name) => format!("`{}`", name),
             None => "value".to_owned(),
         };
-        self.tcx
-            .cannot_move_when_borrowed(
-                span,
-                &self.describe_place(place).unwrap_or("_".to_owned()),
-                Origin::Mir,
-            )
-            .span_label(
-                self.retrieve_borrow_span(borrow),
-                format!("borrow of {} occurs here", borrow_msg),
-            )
-            .span_label(span, format!("move out of {} occurs here", value_msg))
-            .emit();
+        let mut err = self.tcx.cannot_move_when_borrowed(
+            span,
+            &self.describe_place(place).unwrap_or("_".to_owned()),
+            Origin::Mir,
+        );
+        err.span_label(
+            self.retrieve_borrow_span(borrow),
+            format!("borrow of {} occurs here", borrow_msg),
+        );
+        err.span_label(span, format!("move out of {} occurs here", value_msg));
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
+        err.emit();
     }
 
     pub(super) fn report_use_while_mutably_borrowed(
         &mut self,
-        _context: Context,
+        context: Context,
         (place, span): (&Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
     ) {
@@ -128,9 +129,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Origin::Mir,
         );
 
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
+
         err.emit();
     }
 
+    fn explain_why_borrow_contains_point(
+        &self,
+        context: Context,
+        borrow: &BorrowData<'_>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let Some(regioncx) = &self.nonlexical_regioncx {
+            if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
+                cause.label_diagnostic(self.mir, err);
+            }
+        }
+    }
+
     /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
     /// the local assigned at `location`.
     /// This is done by searching in statements succeeding `location`
@@ -313,12 +329,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             );
         }
 
+        self.explain_why_borrow_contains_point(context, issued_borrow, &mut err);
+
         err.emit();
     }
 
     pub(super) fn report_borrowed_value_does_not_live_long_enough(
         &mut self,
-        _: Context,
+        context: Context,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
         borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>
@@ -357,11 +375,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
             (RegionKind::ReScope(_), Some(name)) => {
                 self.report_scoped_local_value_does_not_live_long_enough(
-                    name, &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
+                    context,
+                    name,
+                    &scope_tree,
+                    &borrow,
+                    drop_span,
+                    borrow_span,
+                    proper_span,
+                    end_span
+                );
             },
             (RegionKind::ReScope(_), None) => {
                 self.report_scoped_temporary_value_does_not_live_long_enough(
-                    &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
+                    context,
+                    &scope_tree,
+                    &borrow,
+                    drop_span,
+                    borrow_span,
+                    proper_span,
+                    end_span
+                );
             },
             (RegionKind::ReEarlyBound(_), Some(name)) |
             (RegionKind::ReFree(_), Some(name)) |
@@ -369,7 +402,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             (RegionKind::ReEmpty, Some(name)) |
             (RegionKind::ReVar(_), Some(name)) => {
                 self.report_unscoped_local_value_does_not_live_long_enough(
-                    name, &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
+                    context,
+                    name,
+                    &scope_tree,
+                    &borrow,
+                    drop_span,
+                    borrow_span,
+                    proper_span,
+                    end_span,
+                );
             },
             (RegionKind::ReEarlyBound(_), None) |
             (RegionKind::ReFree(_), None) |
@@ -377,7 +418,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             (RegionKind::ReEmpty, None) |
             (RegionKind::ReVar(_), None) => {
                 self.report_unscoped_temporary_value_does_not_live_long_enough(
-                    &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
+                    context,
+                    &scope_tree,
+                    &borrow,
+                    drop_span,
+                    borrow_span,
+                    proper_span,
+                    end_span,
+                );
             },
             (RegionKind::ReLateBound(_, _), _) |
             (RegionKind::ReSkolemized(_, _), _) |
@@ -389,8 +437,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     }
 
     fn report_scoped_local_value_does_not_live_long_enough(
-        &mut self, name: &String, _scope_tree: &Rc<ScopeTree>, _borrow: &BorrowData<'tcx>,
-        drop_span: Span, borrow_span: Span, _proper_span: Span, end_span: Option<Span>
+        &mut self,
+        context: Context,
+        name: &String,
+        _scope_tree: &Rc<ScopeTree>,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_span: Span,
+        _proper_span: Span,
+        end_span: Option<Span>,
     ) {
         let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
                                                               &format!("`{}`", name),
@@ -400,12 +455,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         if let Some(end) = end_span {
             err.span_label(end, "borrowed value needs to live until here");
         }
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
 
     fn report_scoped_temporary_value_does_not_live_long_enough(
-        &mut self, _scope_tree: &Rc<ScopeTree>, _borrow: &BorrowData<'tcx>,
-        drop_span: Span, _borrow_span: Span, proper_span: Span, end_span: Option<Span>
+        &mut self,
+        context: Context,
+        _scope_tree: &Rc<ScopeTree>,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        _borrow_span: Span,
+        proper_span: Span,
+        end_span: Option<Span>,
     ) {
         let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
                                                               "borrowed value",
@@ -416,12 +478,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         if let Some(end) = end_span {
             err.span_label(end, "temporary value needs to live until here");
         }
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
 
     fn report_unscoped_local_value_does_not_live_long_enough(
-        &mut self, name: &String, scope_tree: &Rc<ScopeTree>, borrow: &BorrowData<'tcx>,
-        drop_span: Span, borrow_span: Span, _proper_span: Span, _end_span: Option<Span>
+        &mut self,
+        context: Context,
+        name: &String,
+        scope_tree: &Rc<ScopeTree>,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_span: Span,
+        _proper_span: Span,
+        _end_span: Option<Span>,
     ) {
         let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
                                                               &format!("`{}`", name),
@@ -431,12 +501,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         self.tcx.note_and_explain_region(scope_tree, &mut err,
                                          "borrowed value must be valid for ",
                                          borrow.region, "...");
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
 
     fn report_unscoped_temporary_value_does_not_live_long_enough(
-        &mut self, scope_tree: &Rc<ScopeTree>, borrow: &BorrowData<'tcx>,
-        drop_span: Span, _borrow_span: Span, proper_span: Span, _end_span: Option<Span>
+        &mut self,
+        context: Context,
+        scope_tree: &Rc<ScopeTree>,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        _borrow_span: Span,
+        proper_span: Span,
+        _end_span: Option<Span>
     ) {
         let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
                                                               "borrowed value",
@@ -446,12 +523,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         self.tcx.note_and_explain_region(scope_tree, &mut err,
                                          "borrowed value must be valid for ",
                                          borrow.region, "...");
+        self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
 
     pub(super) fn report_illegal_mutation_of_borrowed(
         &mut self,
-        _: Context,
+        context: Context,
         (place, span): (&Place<'tcx>, Span),
         loan: &BorrowData,
     ) {
@@ -462,6 +540,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Origin::Mir,
         );
 
+        self.explain_why_borrow_contains_point(context, loan, &mut err);
+
         err.emit();
     }
 
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 7df745bb2f4..46e97d95f49 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,6 +10,7 @@
 
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
+use borrow_check::nll::region_infer::RegionInferenceContext;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::definitions::DefPathData;
@@ -224,6 +225,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         storage_dead_or_drop_error_reported_l: FxHashSet(),
         storage_dead_or_drop_error_reported_s: FxHashSet(),
         reservation_error_reported: FxHashSet(),
+        nonlexical_regioncx: opt_regioncx.clone(),
     };
 
     let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
@@ -299,6 +301,10 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     /// but it is currently inconvenient to track down the BorrowIndex
     /// at the time we detect and report a reservation error.
     reservation_error_reported: FxHashSet<Place<'tcx>>,
+    /// Non-lexical region inference context, if NLL is enabled.  This
+    /// contains the results from region inference and lets us e.g.
+    /// find out which CFG points are contained in each borrow region.
+    nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
 }
 
 // Check that:
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 6977d91d25a..33a6c9e2d1c 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -285,19 +285,25 @@ fn for_each_region_constraint(
 /// This is reasonable because in our MIR we replace all universal regions
 /// with inference variables.
 pub trait ToRegionVid {
-    fn to_region_vid(&self) -> RegionVid;
+    fn to_region_vid(self) -> RegionVid;
 }
 
-impl ToRegionVid for RegionKind {
-    fn to_region_vid(&self) -> RegionVid {
-        if let &ty::ReVar(vid) = self {
-            vid
+impl<'tcx> ToRegionVid for &'tcx RegionKind {
+    fn to_region_vid(self) -> RegionVid {
+        if let ty::ReVar(vid) = self {
+            *vid
         } else {
             bug!("region is not an ReVar: {:?}", self)
         }
     }
 }
 
+impl ToRegionVid for RegionVid {
+    fn to_region_vid(self) -> RegionVid {
+        self
+    }
+}
+
 fn live_variable_set(regular: &LocalSet, drops: &LocalSet) -> String {
     // sort and deduplicate:
     let all_locals: BTreeSet<_> = regular.iter().chain(drops.iter()).collect();
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 384be3d79d1..9f7219b1f55 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -35,6 +35,8 @@ mod graphviz;
 mod values;
 use self::values::{RegionValueElements, RegionValues};
 
+use super::ToRegionVid;
+
 pub struct RegionInferenceContext<'tcx> {
     /// Contains the definition for every region variable.  Region
     /// variables are identified by their index (`RegionVid`). The
@@ -330,11 +332,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Returns true if the region `r` contains the point `p`.
     ///
     /// Panics if called before `solve()` executes,
-    pub fn region_contains_point(&self, r: RegionVid, p: Location) -> bool {
+    pub fn region_contains_point<R>(&self, r: R, p: Location) -> bool
+    where
+        R: ToRegionVid,
+    {
+        let inferred_values = self.inferred_values
+            .as_ref()
+            .expect("region values not yet inferred");
+        inferred_values.contains(r.to_region_vid(), p)
+    }
+
+    /// Returns the *reason* that the region `r` contains the given point.
+    pub(crate) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
+    where
+        R: ToRegionVid,
+    {
         let inferred_values = self.inferred_values
             .as_ref()
             .expect("region values not yet inferred");
-        inferred_values.contains(r, p)
+        inferred_values.cause(r.to_region_vid(), p)
     }
 
     /// Returns access to the value of `r` for debugging purposes.
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 00248400c55..7cd92de88ee 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -75,7 +75,7 @@ pub trait BorrowckErrors {
                                 -> DiagnosticBuilder<'a>;
 
     fn cannot_move_when_borrowed(&self, span: Span, desc: &str, o: Origin)
-                                 -> DiagnosticBuilder
+                                 -> DiagnosticBuilder<'_>
     {
         let err = struct_span_err!(self, span, E0505,
                                    "cannot move out of `{}` because it is borrowed{OGN}",
@@ -89,7 +89,7 @@ pub trait BorrowckErrors {
                                         borrow_span: Span,
                                         borrow_desc: &str,
                                         o: Origin)
-                                        -> DiagnosticBuilder
+                                        -> DiagnosticBuilder<'_>
     {
         let mut err = struct_span_err!(self, span, E0503,
                          "cannot use `{}` because it was mutably borrowed{OGN}",