From 0e64a756f84041e7c33acb052db9df9c9576e6d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 7 Dec 2017 11:21:29 -0500 Subject: [PATCH] integrate -Znll-dump-cause into borrowck --- .../borrow_check/error_reporting.rs | 136 ++++++++++++++---- src/librustc_mir/borrow_check/mod.rs | 6 + src/librustc_mir/borrow_check/nll/mod.rs | 16 ++- .../borrow_check/nll/region_infer/mod.rs | 20 ++- src/librustc_mir/util/borrowck_errors.rs | 4 +- 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 c144962fb2d8..971b5eb22752 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, _borrow: &BorrowData<'tcx>, - drop_span: Span, borrow_span: Span, _proper_span: Span, end_span: Option + &mut self, + context: Context, + name: &String, + _scope_tree: &Rc, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_span: Span, + _proper_span: Span, + end_span: Option, ) { 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, _borrow: &BorrowData<'tcx>, - drop_span: Span, _borrow_span: Span, proper_span: Span, end_span: Option + &mut self, + context: Context, + _scope_tree: &Rc, + borrow: &BorrowData<'tcx>, + drop_span: Span, + _borrow_span: Span, + proper_span: Span, + end_span: Option, ) { 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, borrow: &BorrowData<'tcx>, - drop_span: Span, borrow_span: Span, _proper_span: Span, _end_span: Option + &mut self, + context: Context, + name: &String, + scope_tree: &Rc, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_span: Span, + _proper_span: Span, + _end_span: Option, ) { 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, borrow: &BorrowData<'tcx>, - drop_span: Span, _borrow_span: Span, proper_span: Span, _end_span: Option + &mut self, + context: Context, + scope_tree: &Rc, + borrow: &BorrowData<'tcx>, + drop_span: Span, + _borrow_span: Span, + proper_span: Span, + _end_span: Option ) { 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 7df745bb2f45..46e97d95f493 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>, + /// 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>>, } // Check that: diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 6977d91d25a5..33a6c9e2d1cb 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 384be3d79d12..9f7219b1f550 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(&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, p) + 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(&self, r: R, p: Location) -> Option> + where + R: ToRegionVid, + { + let inferred_values = self.inferred_values + .as_ref() + .expect("region values not yet inferred"); + 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 00248400c553..7cd92de88ee5 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}",