self.explain_span(scope_decorated_tag, span)
}
- ty::ReEarlyBound(_) | ty::ReFree(_) => self.msg_span_from_free_region(region),
-
- ty::ReStatic => ("the static lifetime".to_owned(), None),
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
+ self.msg_span_from_free_region(region)
+ }
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
}
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
+ match *region {
+ ty::ReEarlyBound(_) | ty::ReFree(_) => {
+ self.msg_span_from_early_bound_and_free_regions(region)
+ },
+ ty::ReStatic => ("the static lifetime".to_owned(), None),
+ _ => bug!(),
+ }
+ }
+
+ fn msg_span_from_early_bound_and_free_regions(
+ self,
+ region: ty::Region<'tcx>,
+ ) -> (String, Option<Span>) {
let scope = region.free_region_binding_scope(self);
let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
let unknown;
(place, span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
+ let tcx = self.tcx;
let value_msg = match self.describe_place(place) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
- let mut err = self.tcx.cannot_move_when_borrowed(
+ let mut err = tcx.cannot_move_when_borrowed(
span,
&self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir,
(place, span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
- let mut err = self.tcx.cannot_use_when_mutably_borrowed(
+ let tcx = self.tcx;
+ let mut err = tcx.cannot_use_when_mutably_borrowed(
span,
&self.describe_place(place).unwrap_or("_".to_owned()),
self.retrieve_borrow_span(borrow),
.unwrap_or(issued_span);
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
+ let tcx = self.tcx;
// FIXME: supply non-"" `opt_via` when appropriate
let mut err = match (
"mutable",
) {
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
- | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
+ | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
.cannot_reborrow_already_borrowed(
span,
&desc_place,
Origin::Mir,
),
- (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx
+ (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
.cannot_mutably_borrow_multiply(
span,
&desc_place,
Origin::Mir,
),
- (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
+ (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
.cannot_uniquely_borrow_by_two_closures(
span,
&desc_place,
Origin::Mir,
),
- (BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
+ (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
span,
&desc_place,
"",
Origin::Mir,
),
- (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
+ (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
.cannot_reborrow_already_uniquely_borrowed(
span,
&desc_place,
Origin::Mir,
),
- (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx
+ (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
.cannot_reborrow_already_uniquely_borrowed(
span,
&desc_place,
_proper_span: Span,
end_span: Option<Span>,
) {
- let mut err = self.tcx.path_does_not_live_long_enough(
+ let tcx = self.tcx;
+ let mut err = tcx.path_does_not_live_long_enough(
borrow_span,
&format!("`{}`", name),
Origin::Mir,
proper_span: Span,
end_span: Option<Span>,
) {
+ let tcx = self.tcx;
let mut err =
- self.tcx
- .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
+ tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(
drop_span,
context, name, scope_tree, borrow, drop_span, borrow_span
);
- let mut err = self.tcx.path_does_not_live_long_enough(
+ let tcx = self.tcx;
+ let mut err = tcx.path_does_not_live_long_enough(
borrow_span,
&format!("`{}`", name),
Origin::Mir,
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(drop_span, "borrowed value only lives until here");
- if !self.tcx.nll() {
- self.tcx.note_and_explain_region(
+ if !tcx.nll() {
+ tcx.note_and_explain_region(
scope_tree,
&mut err,
"borrowed value must be valid for ",
context, scope_tree, borrow, drop_span, proper_span
);
+ let tcx = self.tcx;
let mut err =
- self.tcx
- .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
+ tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(drop_span, "temporary value only lives until here");
- if !self.tcx.nll() {
- self.tcx.note_and_explain_region(
+ if !tcx.nll() {
+ tcx.note_and_explain_region(
scope_tree,
&mut err,
"borrowed value must be valid for ",
(place, span): (&Place<'tcx>, Span),
loan: &BorrowData<'tcx>,
) {
- let mut err = self.tcx.cannot_assign_to_borrowed(
+ let tcx = self.tcx;
+ let mut err = tcx.cannot_assign_to_borrowed(
span,
self.retrieve_borrow_span(loan),
&self.describe_place(place).unwrap_or("_".to_owned()),
//! This query borrow-checks the MIR to (further) ensure it is not broken.
-use borrow_check::nll::region_infer::RegionInferenceContext;
+use borrow_check::nll::region_infer::{RegionInferenceContext, RegionCausalInfo};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
nonlexical_regioncx: opt_regioncx.clone(),
+ nonlexical_cause_info: None,
};
let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
/// 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>>>,
+ nonlexical_cause_info: Option<RegionCausalInfo>,
}
// Check that:
use util::liveness::{self, DefUse, LivenessMode};
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+ /// Adds annotations to `err` explaining *why* the borrow contains the
+ /// point from `context`. This is key for the "3-point errors"
+ /// [described in the NLL RFC][d].
+ ///
+ /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
pub(in borrow_check) fn explain_why_borrow_contains_point(
- &self,
+ &mut self,
context: Context,
borrow: &BorrowData<'tcx>,
err: &mut DiagnosticBuilder<'_>,
) {
if let Some(regioncx) = &self.nonlexical_regioncx {
- if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
- let mir = self.mir;
+ let mir = self.mir;
+ if self.nonlexical_cause_info.is_none() {
+ self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
+ }
+
+ let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
+ if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
match *cause.root_cause() {
Cause::LiveVar(local, location) => {
match find_regular_use(&mir, regioncx, borrow, location, local) {
universal_regions: UniversalRegions<'tcx>,
}
+struct TrackCauses(bool);
+
struct RegionDefinition<'tcx> {
/// Why we created this variable. Mostly these will be
/// `RegionVariableOrigin::NLL`, but some variables get created
},
}
+pub(crate) struct RegionCausalInfo {
+ inferred_values: RegionValues,
+}
+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Constraint {
// NB. The ordering here is not significant for correctness, but
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.
pub(super) fn region_value_str(&self, r: RegionVid) -> String {
let inferred_values = self.inferred_values
}
}
+ /// Re-execute the region inference, this time tracking causal information.
+ /// This is significantly slower, so it is done only when an error is being reported.
+ pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
+ let inferred_values = self.compute_region_values(mir, TrackCauses(true));
+ RegionCausalInfo { inferred_values }
+ }
+
/// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
- debug!("propagate_constraints()");
- debug!("propagate_constraints: constraints={:#?}", {
+ let inferred_values = self.compute_region_values(mir, TrackCauses(false));
+ self.inferred_values = Some(inferred_values);
+ }
+
+ fn compute_region_values(&self, mir: &Mir<'tcx>, track_causes: TrackCauses) -> RegionValues {
+ debug!("compute_region_values()");
+ debug!("compute_region_values: constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort();
constraints
// The initial values for each region are derived from the liveness
// constraints we have accumulated.
- let mut inferred_values = self.liveness_constraints.clone();
+ let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
let dependency_map = self.build_dependency_map();
debug!("\n");
}
- self.inferred_values = Some(inferred_values);
+ inferred_values
}
/// Builds up a map from each region variable X to a vector with the
}
}
+impl RegionCausalInfo {
+ /// Returns the *reason* that the region `r` contains the given point.
+ pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
+ where
+ R: ToRegionVid,
+ {
+ self.inferred_values.cause(r.to_region_vid(), p)
+ }
+}
+
impl<'tcx> RegionDefinition<'tcx> {
fn new(origin: RegionVariableOrigin) -> Self {
// Create a new region definition. Note that, for free
use rustc::ty::RegionVid;
use syntax::codemap::Span;
-use super::{Cause, CauseExt};
+use super::{Cause, CauseExt, TrackCauses};
/// Maps between the various kinds of elements of a region value to
/// the internal indices that w use.
/// compact `SparseBitMatrix` representation, with one row per region
/// variable. The columns consist of either universal regions or
/// points in the CFG.
-#[derive(Clone)]
pub(super) struct RegionValues {
elements: Rc<RegionValueElements>,
matrix: SparseBitMatrix<RegionVid, RegionElementIndex>,
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
impl RegionValues {
+ /// Creates a new set of "region values" that tracks causal information.
+ /// Each of the regions in num_region_variables will be initialized with an
+ /// empty set of points and no causal information.
pub(super) fn new(
elements: &Rc<RegionValueElements>,
num_region_variables: usize,
}
}
+ /// Duplicates the region values. If track_causes is false, then the
+ /// resulting value will not track causal information (and any existing
+ /// causal information is dropped). Otherwise, the causal information is
+ /// preserved and maintained. Tracking the causal information makes region
+ /// propagation significantly slower, so we prefer not to do it until an
+ /// error is reported.
+ pub(super) fn duplicate(&self, track_causes: TrackCauses) -> Self {
+ Self {
+ elements: self.elements.clone(),
+ matrix: self.matrix.clone(),
+ causes: if track_causes.0 {
+ self.causes.clone()
+ } else {
+ None
+ },
+ }
+ }
+
/// Adds the given element to the value for the given region. Returns true if
/// the element is newly added (i.e., was not already present).
pub(super) fn add<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, cause: &Cause) -> bool {
...
LL | }
| - borrowed value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
error: aborting due to 2 previous errors