integrate -Znll-dump-cause into borrowck
This commit is contained in:
parent
741ef41e41
commit
0e64a756f8
5 changed files with 145 additions and 37 deletions
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue