integrate -Znll-dump-cause into borrowck

This commit is contained in:
Niko Matsakis 2017-12-07 11:21:29 -05:00
parent 741ef41e41
commit 0e64a756f8
5 changed files with 145 additions and 37 deletions

View file

@ -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();
}

View file

@ -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:

View file

@ -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();

View file

@ -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, 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<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.cause(r.to_region_vid(), p)
}
/// Returns access to the value of `r` for debugging purposes.

View file

@ -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}",