Auto merge of #51889 - spastorino:make-causal-tracking-lazy, r=nikomatsakis
Make causal tracking lazy Closes #51710 r? @nikomatsakis
This commit is contained in:
commit
64f8ae08fd
@ -1000,6 +1000,10 @@ impl<'tcx> Terminator<'tcx> {
|
||||
self.kind.successors_mut()
|
||||
}
|
||||
|
||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
||||
self.kind.unwind()
|
||||
}
|
||||
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
||||
self.kind.unwind_mut()
|
||||
}
|
||||
@ -1195,6 +1199,31 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::FalseEdges { .. } => None,
|
||||
TerminatorKind::Call {
|
||||
cleanup: ref unwind,
|
||||
..
|
||||
}
|
||||
| TerminatorKind::Assert {
|
||||
cleanup: ref unwind,
|
||||
..
|
||||
}
|
||||
| TerminatorKind::DropAndReplace { ref unwind, .. }
|
||||
| TerminatorKind::Drop { ref unwind, .. }
|
||||
| TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
|
@ -12,7 +12,7 @@ use borrow_check::borrow_set::BorrowSet;
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::type_check::AtLocation;
|
||||
use rustc::hir;
|
||||
use rustc::infer::InferCtxt;
|
||||
@ -33,7 +33,7 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
|
||||
location_table: &LocationTable,
|
||||
mir: &Mir<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness_set_from_typeck: &[(ty::Region<'tcx>, Location, Cause)],
|
||||
liveness_set_from_typeck: &[(ty::Region<'tcx>, Location)],
|
||||
) {
|
||||
let mut cg = ConstraintGeneration {
|
||||
borrow_set,
|
||||
@ -69,14 +69,14 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
||||
/// We sometimes have `substs` within an rvalue, or within a
|
||||
/// call. Make them live at the location where they appear.
|
||||
fn visit_substs(&mut self, substs: &&'tcx Substs<'tcx>, location: Location) {
|
||||
self.add_regular_live_constraint(*substs, location, Cause::LiveOther(location));
|
||||
self.add_regular_live_constraint(*substs, location);
|
||||
self.super_substs(substs);
|
||||
}
|
||||
|
||||
/// We sometimes have `region` within an rvalue, or within a
|
||||
/// call. Make them live at the location where they appear.
|
||||
fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) {
|
||||
self.add_regular_live_constraint(*region, location, Cause::LiveOther(location));
|
||||
self.add_regular_live_constraint(*region, location);
|
||||
self.super_region(region);
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
||||
);
|
||||
}
|
||||
TyContext::Location(location) => {
|
||||
self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location));
|
||||
self.add_regular_live_constraint(*ty, location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,14 +104,14 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
||||
/// We sometimes have `generator_substs` within an rvalue, or within a
|
||||
/// call. Make them live at the location where they appear.
|
||||
fn visit_generator_substs(&mut self, substs: &GeneratorSubsts<'tcx>, location: Location) {
|
||||
self.add_regular_live_constraint(*substs, location, Cause::LiveOther(location));
|
||||
self.add_regular_live_constraint(*substs, location);
|
||||
self.super_generator_substs(substs);
|
||||
}
|
||||
|
||||
/// We sometimes have `closure_substs` within an rvalue, or within a
|
||||
/// call. Make them live at the location where they appear.
|
||||
fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, location: Location) {
|
||||
self.add_regular_live_constraint(*substs, location, Cause::LiveOther(location));
|
||||
self.add_regular_live_constraint(*substs, location);
|
||||
self.super_closure_substs(substs);
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
/// that we also have to respect.
|
||||
fn add_region_liveness_constraints_from_type_check(
|
||||
&mut self,
|
||||
liveness_set: &[(ty::Region<'tcx>, Location, Cause)],
|
||||
liveness_set: &[(ty::Region<'tcx>, Location)],
|
||||
) {
|
||||
debug!(
|
||||
"add_region_liveness_constraints_from_type_check(liveness_set={} items)",
|
||||
@ -247,16 +247,16 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
..
|
||||
} = self;
|
||||
|
||||
for (region, location, cause) in liveness_set {
|
||||
for (region, location) in liveness_set {
|
||||
debug!("generate: {:#?} is live at {:#?}", region, location);
|
||||
let region_vid = regioncx.to_region_vid(region);
|
||||
regioncx.add_live_point(region_vid, *location, &cause);
|
||||
regioncx.add_live_point(region_vid, *location);
|
||||
}
|
||||
|
||||
if let Some(all_facts) = all_facts {
|
||||
all_facts
|
||||
.region_live_at
|
||||
.extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
|
||||
.extend(liveness_set.into_iter().flat_map(|(region, location)| {
|
||||
let r = regioncx.to_region_vid(region);
|
||||
let p1 = location_table.start_index(*location);
|
||||
let p2 = location_table.mid_index(*location);
|
||||
@ -269,7 +269,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
/// `location` -- i.e., it may be used later. This means that all
|
||||
/// regions appearing in the type `live_ty` must be live at
|
||||
/// `location`.
|
||||
fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location, cause: Cause)
|
||||
fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
@ -282,7 +282,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
.tcx
|
||||
.for_each_free_region(&live_ty, |live_region| {
|
||||
let vid = live_region.to_region_vid();
|
||||
self.regioncx.add_live_point(vid, location, &cause);
|
||||
self.regioncx.add_live_point(vid, location);
|
||||
});
|
||||
}
|
||||
|
||||
|
168
src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
Normal file
168
src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||
use rustc::mir::{Local, Location, Mir};
|
||||
use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use util::liveness::{self, DefUse, LivenessMode};
|
||||
|
||||
crate fn find<'cx, 'gcx: 'tcx, 'tcx: 'cx>(
|
||||
mir: &'cx Mir<'tcx>,
|
||||
regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
) -> Option<Cause> {
|
||||
let mut uf = UseFinder {
|
||||
mir,
|
||||
regioncx,
|
||||
tcx,
|
||||
region_vid,
|
||||
start_point,
|
||||
liveness_mode: LivenessMode {
|
||||
include_regular_use: true,
|
||||
include_drops: true,
|
||||
},
|
||||
};
|
||||
|
||||
uf.find()
|
||||
}
|
||||
|
||||
struct UseFinder<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
mir: &'cx Mir<'tcx>,
|
||||
regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
liveness_mode: LivenessMode,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
|
||||
fn find(&mut self) -> Option<Cause> {
|
||||
let mut queue = VecDeque::new();
|
||||
let mut visited = FxHashSet();
|
||||
|
||||
queue.push_back(self.start_point);
|
||||
while let Some(p) = queue.pop_front() {
|
||||
if !self.regioncx.region_contains_point(self.region_vid, p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !visited.insert(p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let block_data = &self.mir[p.block];
|
||||
|
||||
match self.def_use(p, block_data.visitable(p.statement_index)) {
|
||||
Some(DefUseResult::Def) => {}
|
||||
|
||||
Some(DefUseResult::UseLive { local }) => {
|
||||
return Some(Cause::LiveVar(local, p));
|
||||
}
|
||||
|
||||
Some(DefUseResult::UseDrop { local }) => {
|
||||
return Some(Cause::DropVar(local, p));
|
||||
}
|
||||
|
||||
None => {
|
||||
if p.statement_index < block_data.statements.len() {
|
||||
queue.push_back(Location {
|
||||
statement_index: p.statement_index + 1,
|
||||
..p
|
||||
});
|
||||
} else {
|
||||
queue.extend(
|
||||
block_data
|
||||
.terminator()
|
||||
.successors()
|
||||
.filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
|
||||
.map(|&bb| Location {
|
||||
statement_index: 0,
|
||||
block: bb,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
|
||||
let mut visitor = DefUseVisitor {
|
||||
mir: self.mir,
|
||||
tcx: self.tcx,
|
||||
region_vid: self.region_vid,
|
||||
liveness_mode: self.liveness_mode,
|
||||
def_use_result: None,
|
||||
};
|
||||
|
||||
thing.apply(location, &mut visitor);
|
||||
|
||||
visitor.def_use_result
|
||||
}
|
||||
}
|
||||
|
||||
struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
mir: &'cx Mir<'tcx>,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_vid: RegionVid,
|
||||
liveness_mode: LivenessMode,
|
||||
def_use_result: Option<DefUseResult>,
|
||||
}
|
||||
|
||||
enum DefUseResult {
|
||||
Def,
|
||||
|
||||
UseLive { local: Local },
|
||||
|
||||
UseDrop { local: Local },
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'gcx, 'tcx> {
|
||||
fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
|
||||
let local_ty = self.mir.local_decls[local].ty;
|
||||
|
||||
let mut found_it = false;
|
||||
self.tcx.for_each_free_region(&local_ty, |r| {
|
||||
if r.to_region_vid() == self.region_vid {
|
||||
found_it = true;
|
||||
}
|
||||
});
|
||||
|
||||
if found_it {
|
||||
match liveness::categorize(context, self.liveness_mode) {
|
||||
Some(DefUse::Def) => {
|
||||
self.def_use_result = Some(DefUseResult::Def);
|
||||
}
|
||||
|
||||
Some(DefUse::Use) => {
|
||||
self.def_use_result = if context.is_drop() {
|
||||
Some(DefUseResult::UseDrop { local })
|
||||
} else {
|
||||
Some(DefUseResult::UseLive { local })
|
||||
};
|
||||
}
|
||||
|
||||
None => {
|
||||
self.def_use_result = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,13 +9,12 @@
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::borrow_set::BorrowData;
|
||||
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
|
||||
use borrow_check::nll::region_infer::Cause;
|
||||
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
|
||||
use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||
use rustc::mir::{Local, Location, Mir, Place};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc::mir::Place;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use util::liveness::{self, DefUse, LivenessMode};
|
||||
|
||||
mod find_use;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Adds annotations to `err` explaining *why* the borrow contains the
|
||||
@ -39,214 +38,73 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
kind_place: Option<(WriteKind, &Place<'tcx>)>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
let regioncx = &&self.nonlexical_regioncx;
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
|
||||
context, borrow, kind_place,
|
||||
);
|
||||
|
||||
let regioncx = &self.nonlexical_regioncx;
|
||||
let mir = self.mir;
|
||||
let tcx = self.tcx;
|
||||
|
||||
let borrow_region_vid = regioncx.to_region_vid(borrow.region);
|
||||
if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) {
|
||||
match cause {
|
||||
Cause::LiveVar(local, location) => match find_regular_use(
|
||||
mir, regioncx, borrow, location, local,
|
||||
) {
|
||||
Some(p) => {
|
||||
err.span_label(mir.source_info(p).span, format!("borrow later used here"));
|
||||
}
|
||||
|
||||
None => {
|
||||
span_bug!(
|
||||
mir.source_info(context.loc).span,
|
||||
"Cause should end in a LiveVar"
|
||||
);
|
||||
}
|
||||
},
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point: borrow_region_vid={:?}",
|
||||
borrow_region_vid
|
||||
);
|
||||
|
||||
Cause::DropVar(local, location) => match find_drop_use(
|
||||
mir, regioncx, borrow, location, local,
|
||||
) {
|
||||
Some(p) => match &mir.local_decls[local].name {
|
||||
Some(local_name) => {
|
||||
err.span_label(
|
||||
mir.source_info(p).span,
|
||||
format!("borrow later used here, when `{}` is dropped", local_name),
|
||||
);
|
||||
let region_sub = regioncx.find_constraint(borrow_region_vid, context.loc);
|
||||
|
||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||
if let Place::Local(borrowed_local) = place {
|
||||
let dropped_local_scope =
|
||||
mir.local_decls[local].visibility_scope;
|
||||
let borrowed_local_scope =
|
||||
mir.local_decls[*borrowed_local].visibility_scope;
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point: region_sub={:?}",
|
||||
region_sub
|
||||
);
|
||||
|
||||
if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
|
||||
err.note(
|
||||
"values in a scope are dropped \
|
||||
in the opposite order they are defined",
|
||||
);
|
||||
}
|
||||
}
|
||||
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
|
||||
Some(Cause::LiveVar(_local, location)) => {
|
||||
err.span_label(
|
||||
mir.source_info(location).span,
|
||||
format!("borrow later used here"),
|
||||
);
|
||||
}
|
||||
|
||||
Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
|
||||
Some(local_name) => {
|
||||
err.span_label(
|
||||
mir.source_info(location).span,
|
||||
format!("borrow later used here, when `{}` is dropped", local_name),
|
||||
);
|
||||
|
||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||
if let Place::Local(borrowed_local) = place {
|
||||
let dropped_local_scope = mir.local_decls[local].visibility_scope;
|
||||
let borrowed_local_scope =
|
||||
mir.local_decls[*borrowed_local].visibility_scope;
|
||||
|
||||
if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
|
||||
err.note(
|
||||
"values in a scope are dropped \
|
||||
in the opposite order they are defined",
|
||||
);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
err.span_label(
|
||||
mir.local_decls[local].source_info.span,
|
||||
"borrow may end up in a temporary, created here",
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
mir.source_info(p).span,
|
||||
"temporary later dropped here, \
|
||||
potentially using the reference",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
None => {
|
||||
span_bug!(
|
||||
mir.source_info(context.loc).span,
|
||||
"Cause should end in a DropVar"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
Cause::UniversalRegion(region_vid) => {
|
||||
if let Some(region) = regioncx.to_error_region(region_vid) {
|
||||
self.tcx.note_and_explain_free_region(
|
||||
err,
|
||||
"borrowed value must be valid for ",
|
||||
region,
|
||||
"...",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
},
|
||||
|
||||
fn find_regular_use<'gcx, 'tcx>(
|
||||
mir: &'gcx Mir,
|
||||
regioncx: &'tcx RegionInferenceContext,
|
||||
borrow: &'tcx BorrowData,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
) -> Option<Location> {
|
||||
let mut uf = UseFinder {
|
||||
mir,
|
||||
regioncx,
|
||||
borrow,
|
||||
start_point,
|
||||
local,
|
||||
liveness_mode: LivenessMode {
|
||||
include_regular_use: true,
|
||||
include_drops: false,
|
||||
},
|
||||
};
|
||||
|
||||
uf.find()
|
||||
}
|
||||
|
||||
fn find_drop_use<'gcx, 'tcx>(
|
||||
mir: &'gcx Mir,
|
||||
regioncx: &'tcx RegionInferenceContext,
|
||||
borrow: &'tcx BorrowData,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
) -> Option<Location> {
|
||||
let mut uf = UseFinder {
|
||||
mir,
|
||||
regioncx,
|
||||
borrow,
|
||||
start_point,
|
||||
local,
|
||||
liveness_mode: LivenessMode {
|
||||
include_regular_use: false,
|
||||
include_drops: true,
|
||||
},
|
||||
};
|
||||
|
||||
uf.find()
|
||||
}
|
||||
|
||||
struct UseFinder<'gcx, 'tcx> {
|
||||
mir: &'gcx Mir<'gcx>,
|
||||
regioncx: &'tcx RegionInferenceContext<'tcx>,
|
||||
borrow: &'tcx BorrowData<'tcx>,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
liveness_mode: LivenessMode,
|
||||
}
|
||||
|
||||
impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> {
|
||||
fn find(&mut self) -> Option<Location> {
|
||||
let mut stack = vec![];
|
||||
let mut visited = FxHashSet();
|
||||
|
||||
stack.push(self.start_point);
|
||||
while let Some(p) = stack.pop() {
|
||||
if !self.regioncx.region_contains_point(self.borrow.region, p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !visited.insert(p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let block_data = &self.mir[p.block];
|
||||
let (defined, used) = self.def_use(p, block_data.visitable(p.statement_index));
|
||||
|
||||
if used {
|
||||
return Some(p);
|
||||
} else if !defined {
|
||||
if p.statement_index < block_data.statements.len() {
|
||||
stack.push(Location {
|
||||
statement_index: p.statement_index + 1,
|
||||
..p
|
||||
});
|
||||
} else {
|
||||
stack.extend(block_data.terminator().successors().map(|&basic_block| {
|
||||
Location {
|
||||
statement_index: 0,
|
||||
block: basic_block,
|
||||
}
|
||||
}));
|
||||
None => {
|
||||
if let Some(region) = regioncx.to_error_region(region_sub) {
|
||||
self.tcx.note_and_explain_free_region(
|
||||
err,
|
||||
"borrowed value must be valid for ",
|
||||
region,
|
||||
"...",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> (bool, bool) {
|
||||
let mut visitor = DefUseVisitor {
|
||||
defined: false,
|
||||
used: false,
|
||||
local: self.local,
|
||||
liveness_mode: self.liveness_mode,
|
||||
};
|
||||
|
||||
thing.apply(location, &mut visitor);
|
||||
|
||||
(visitor.defined, visitor.used)
|
||||
}
|
||||
}
|
||||
|
||||
struct DefUseVisitor {
|
||||
defined: bool,
|
||||
used: bool,
|
||||
local: Local,
|
||||
liveness_mode: LivenessMode,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for DefUseVisitor {
|
||||
fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
|
||||
if local == self.local {
|
||||
match liveness::categorize(context, self.liveness_mode) {
|
||||
Some(DefUse::Def) => self.defined = true,
|
||||
Some(DefUse::Use) => self.used = true,
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use std::fmt;
|
||||
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
|
||||
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
|
||||
use borrow_check::nll::region_infer::values::ToElementIndex;
|
||||
use borrow_check::nll::type_check::Locations;
|
||||
use rustc::hir::def_id::DefId;
|
||||
@ -259,15 +259,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
|
||||
// Find some constraint `X: Y` where:
|
||||
// - `fr1: X` transitively
|
||||
// - and `Y` is live at `elem`
|
||||
// Find some constraint `X: Y` where:
|
||||
// - `fr1: X` transitively
|
||||
// - and `Y` is live at `elem`
|
||||
crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
|
||||
let index = self.blame_constraint(fr1, elem);
|
||||
let region_sub = self.constraints[index].sub;
|
||||
|
||||
// then return why `Y` was live at `elem`
|
||||
self.liveness_constraints.cause(region_sub, elem)
|
||||
self.constraints[index].sub
|
||||
}
|
||||
|
||||
/// Tries to finds a good span to blame for the fact that `fr1`
|
||||
|
@ -19,7 +19,7 @@ use rustc::infer::NLLRegionVariableOrigin;
|
||||
use rustc::infer::RegionVariableOrigin;
|
||||
use rustc::mir::{
|
||||
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
|
||||
Mir
|
||||
Mir,
|
||||
};
|
||||
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::util::common;
|
||||
@ -75,8 +75,6 @@ pub struct RegionInferenceContext<'tcx> {
|
||||
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
|
||||
@ -105,13 +103,6 @@ pub(crate) enum Cause {
|
||||
|
||||
/// point inserted because Local was dropped at the given Location
|
||||
DropVar(Local, Location),
|
||||
|
||||
/// point inserted because the type was live at the given Location,
|
||||
/// but not as part of some local variable
|
||||
LiveOther(Location),
|
||||
|
||||
/// part of the initial set of values for a universally quantified region
|
||||
UniversalRegion(RegionVid),
|
||||
}
|
||||
|
||||
/// A "type test" corresponds to an outlives constraint between a type
|
||||
@ -280,19 +271,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
// Add all nodes in the CFG to liveness constraints
|
||||
for point_index in self.elements.all_point_indices() {
|
||||
self.liveness_constraints.add_element(
|
||||
variable,
|
||||
point_index,
|
||||
&Cause::UniversalRegion(variable),
|
||||
);
|
||||
self.liveness_constraints.add_element(variable, point_index);
|
||||
}
|
||||
|
||||
// Add `end(X)` into the set for X.
|
||||
self.liveness_constraints.add_element(
|
||||
variable,
|
||||
variable,
|
||||
&Cause::UniversalRegion(variable),
|
||||
);
|
||||
self.liveness_constraints.add_element(variable, variable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,26 +320,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
///
|
||||
/// Returns `true` if this constraint is new and `false` is the
|
||||
/// constraint was already present.
|
||||
pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location, cause: &Cause) -> bool {
|
||||
pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) -> bool {
|
||||
debug!("add_live_point({:?}, {:?})", v, point);
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
debug!("add_live_point: @{:?} Adding cause {:?}", point, cause);
|
||||
|
||||
let element = self.elements.index(point);
|
||||
if self.liveness_constraints.add_element(v, element, &cause) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.liveness_constraints.add_element(v, element)
|
||||
}
|
||||
|
||||
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
|
||||
pub(super) fn add_outlives(
|
||||
&mut self,
|
||||
locations: Locations,
|
||||
sup: RegionVid,
|
||||
sub: RegionVid,
|
||||
) {
|
||||
pub(super) fn add_outlives(&mut self, locations: Locations, sup: RegionVid, sub: RegionVid) {
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
self.constraints.push(OutlivesConstraint {
|
||||
locations,
|
||||
@ -440,7 +413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
// The initial values for each region are derived from the liveness
|
||||
// constraints we have accumulated.
|
||||
let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false));
|
||||
let mut inferred_values = self.liveness_constraints.clone();
|
||||
|
||||
let dependency_map = self.dependency_map.as_ref().unwrap();
|
||||
|
||||
@ -461,11 +434,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
debug!("propagate_constraints: sub={:?}", constraint.sub);
|
||||
debug!("propagate_constraints: sup={:?}", constraint.sup);
|
||||
|
||||
self.constraints.each_affected_by_dirty(dependency_map[constraint.sup], |dep_idx| {
|
||||
if clean_bit_vec.remove(dep_idx.index()) {
|
||||
dirty_list.push(dep_idx);
|
||||
}
|
||||
});
|
||||
self.constraints.each_affected_by_dirty(
|
||||
dependency_map[constraint.sup],
|
||||
|dep_idx| {
|
||||
if clean_bit_vec.remove(dep_idx.index()) {
|
||||
dirty_list.push(dep_idx);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
debug!("\n");
|
||||
@ -503,8 +479,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
|
||||
if self.try_promote_type_test(infcx, mir, type_test,
|
||||
propagated_outlives_requirements) {
|
||||
if self.try_promote_type_test(
|
||||
infcx,
|
||||
mir,
|
||||
type_test,
|
||||
propagated_outlives_requirements,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -760,12 +740,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
/// Test if `test` is true when applied to `lower_bound` at
|
||||
/// `point`, and returns true or false.
|
||||
fn eval_region_test(
|
||||
&self,
|
||||
mir: &Mir<'tcx>,
|
||||
lower_bound: RegionVid,
|
||||
test: &RegionTest,
|
||||
) -> bool {
|
||||
fn eval_region_test(&self, mir: &Mir<'tcx>, lower_bound: RegionVid, test: &RegionTest) -> bool {
|
||||
debug!(
|
||||
"eval_region_test(lower_bound={:?}, test={:?})",
|
||||
lower_bound, test
|
||||
@ -797,10 +772,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
sup_region: RegionVid,
|
||||
sub_region: RegionVid,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_outlives({:?}: {:?})",
|
||||
sup_region, sub_region
|
||||
);
|
||||
debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
|
||||
|
||||
let inferred_values = self
|
||||
.inferred_values
|
||||
|
@ -8,18 +8,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::nll::region_infer::TrackCauses;
|
||||
use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc_data_structures::bitvec::SparseBitMatrix;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::Cause;
|
||||
|
||||
/// Maps between the various kinds of elements of a region value to
|
||||
/// the internal indices that w use.
|
||||
pub(super) struct RegionValueElements {
|
||||
@ -32,7 +28,8 @@ pub(super) struct RegionValueElements {
|
||||
impl RegionValueElements {
|
||||
pub(super) fn new(mir: &Mir<'_>, num_universal_regions: usize) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block = mir.basic_blocks()
|
||||
let statements_before_block = mir
|
||||
.basic_blocks()
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
@ -100,7 +97,8 @@ impl RegionValueElements {
|
||||
// be (BB2, 20).
|
||||
//
|
||||
// Nit: we could do a binary search here but I'm too lazy.
|
||||
let (block, &first_index) = self.statements_before_block
|
||||
let (block, &first_index) = self
|
||||
.statements_before_block
|
||||
.iter_enumerated()
|
||||
.filter(|(_, first_index)| **first_index <= point_index)
|
||||
.last()
|
||||
@ -180,19 +178,12 @@ impl ToElementIndex for RegionElementIndex {
|
||||
/// 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>,
|
||||
|
||||
/// If cause tracking is enabled, maps from a pair (r, e)
|
||||
/// consisting of a region `r` that contains some element `e` to
|
||||
/// the reason that the element is contained. There should be an
|
||||
/// entry for every bit set to 1 in `SparseBitMatrix`.
|
||||
causes: Option<CauseMap>,
|
||||
}
|
||||
|
||||
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), 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
|
||||
@ -209,38 +200,15 @@ impl RegionValues {
|
||||
RegionVid::new(num_region_variables),
|
||||
RegionElementIndex::new(elements.num_elements()),
|
||||
),
|
||||
causes: Some(CauseMap::default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_element<E: ToElementIndex>(
|
||||
&mut self,
|
||||
r: RegionVid,
|
||||
elem: E,
|
||||
cause: &Cause,
|
||||
) -> bool {
|
||||
pub(super) fn add_element<E: ToElementIndex>(&mut self, r: RegionVid, elem: E) -> bool {
|
||||
let i = self.elements.index(elem);
|
||||
self.add_internal(r, i, |_| cause.clone())
|
||||
debug!("add(r={:?}, elem={:?})", r, elem);
|
||||
self.matrix.add(r, i)
|
||||
}
|
||||
|
||||
/// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
|
||||
@ -249,40 +217,6 @@ impl RegionValues {
|
||||
self.matrix.merge(r_from, r_to)
|
||||
}
|
||||
|
||||
/// Internal method to add an element to a region.
|
||||
///
|
||||
/// Takes a "lazy" cause -- this function will return the cause, but it will only
|
||||
/// be invoked if cause tracking is enabled.
|
||||
fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F) -> bool
|
||||
where
|
||||
F: FnOnce(&CauseMap) -> Cause,
|
||||
{
|
||||
if self.matrix.add(r, i) {
|
||||
debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
|
||||
|
||||
if let Some(causes) = &mut self.causes {
|
||||
let cause = make_cause(causes);
|
||||
causes.insert((r, i), cause);
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
if let Some(causes) = &mut self.causes {
|
||||
let cause = make_cause(causes);
|
||||
let old_cause = causes.get_mut(&(r, i)).unwrap();
|
||||
// #49998: compare using root cause alone to avoid
|
||||
// useless traffic from similar outlives chains.
|
||||
|
||||
if cause < *old_cause {
|
||||
*old_cause = cause;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// True if the region `r` contains the given element.
|
||||
pub(super) fn contains<E: ToElementIndex>(&self, r: RegionVid, elem: E) -> bool {
|
||||
let i = self.elements.index(elem);
|
||||
@ -398,18 +332,4 @@ impl RegionValues {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a region `r` that contains the element `elem`, returns the `Cause`
|
||||
/// that tells us *why* `elem` is found in that region.
|
||||
///
|
||||
/// Returns None if cause tracking is disabled or `elem` is not
|
||||
/// actually found in `r`.
|
||||
pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Cause> {
|
||||
let index = self.elements.index(elem);
|
||||
if let Some(causes) = &self.causes {
|
||||
causes.get(&(r, index)).cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::nll::region_infer::Cause;
|
||||
use borrow_check::nll::type_check::AtLocation;
|
||||
use dataflow::move_paths::{HasMoveData, MoveData};
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
@ -88,8 +87,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
for live_local in live_locals.iter() {
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
let cause = Cause::LiveVar(live_local, location);
|
||||
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location, cause);
|
||||
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
|
||||
}
|
||||
});
|
||||
|
||||
@ -161,7 +159,6 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
|
||||
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
|
||||
value: T,
|
||||
location: Location,
|
||||
cause: Cause,
|
||||
) where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
@ -171,9 +168,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
|
||||
);
|
||||
|
||||
cx.tcx().for_each_free_region(&value, |live_region| {
|
||||
cx.constraints
|
||||
.liveness_set
|
||||
.push((live_region, location, cause.clone()));
|
||||
cx.constraints.liveness_set.push((live_region, location));
|
||||
});
|
||||
}
|
||||
|
||||
@ -210,9 +205,8 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
|
||||
|
||||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
let cause = Cause::DropVar(dropped_local, location);
|
||||
for &kind in &drop_data.dropck_result.kinds {
|
||||
Self::push_type_live_constraint(&mut self.cx, kind, location, cause);
|
||||
Self::push_type_live_constraint(&mut self.cx, kind, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::constraint_set::ConstraintSet;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::Cause;
|
||||
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use dataflow::move_paths::MoveData;
|
||||
@ -312,7 +311,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
|
||||
debug!("sanitize_constant: expected_ty={:?}", expected_ty);
|
||||
|
||||
if let Err(terr) = self.cx.eq_types(expected_ty, constant.ty, location.boring()) {
|
||||
if let Err(terr) = self
|
||||
.cx
|
||||
.eq_types(expected_ty, constant.ty, location.boring())
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
@ -615,7 +617,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
|
||||
/// not otherwise appear in the MIR -- in particular, the
|
||||
/// late-bound regions that it instantiates at call-sites -- and
|
||||
/// hence it must report on their liveness constraints.
|
||||
crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
|
||||
crate liveness_set: Vec<(ty::Region<'tcx>, Location)>,
|
||||
|
||||
crate outlives_constraints: ConstraintSet,
|
||||
|
||||
@ -771,12 +773,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_types(
|
||||
&mut self,
|
||||
sub: Ty<'tcx>,
|
||||
sup: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
) -> Fallible<()> {
|
||||
fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>, locations: Locations) -> Fallible<()> {
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
@ -808,7 +805,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
false
|
||||
};
|
||||
|
||||
let locations = if is_temp { location.boring() } else { location.interesting() };
|
||||
let locations = if is_temp {
|
||||
location.boring()
|
||||
} else {
|
||||
location.interesting()
|
||||
};
|
||||
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = rv.ty(mir, tcx);
|
||||
@ -983,11 +984,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
// output) types in the signature must be live, since
|
||||
// all the inputs that fed into it were live.
|
||||
for &late_bound_region in map.values() {
|
||||
self.constraints.liveness_set.push((
|
||||
late_bound_region,
|
||||
term_location,
|
||||
Cause::LiveOther(term_location),
|
||||
));
|
||||
self.constraints
|
||||
.liveness_set
|
||||
.push((late_bound_region, term_location));
|
||||
}
|
||||
|
||||
self.check_call_inputs(mir, term, &sig, args, term_location);
|
||||
@ -1507,10 +1506,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
);
|
||||
|
||||
// Hmm, are these constraints *really* boring?
|
||||
self.push_region_constraints(
|
||||
location.boring(),
|
||||
&closure_constraints,
|
||||
);
|
||||
self.push_region_constraints(location.boring(), &closure_constraints);
|
||||
}
|
||||
|
||||
tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
|
||||
|
@ -2,15 +2,10 @@ error[E0597]: `a` does not live long enough
|
||||
--> $DIR/borrowing.rs:18:18
|
||||
|
|
||||
LL | unsafe { (|| yield &a).resume() }
|
||||
| ^^^^^^^^^^^^^
|
||||
| |
|
||||
| borrowed value does not live long enough
|
||||
| borrow may end up in a temporary, created here
|
||||
| ^^^^^^^^^^^^^ borrowed value does not live long enough
|
||||
LL | //~^ ERROR: `a` does not live long enough
|
||||
LL | };
|
||||
| -- temporary later dropped here, potentially using the reference
|
||||
| |
|
||||
| borrowed value only lives until here
|
||||
| - borrowed value only lives until here
|
||||
|
||||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/borrowing.rs:24:9
|
||||
|
@ -1,19 +1,11 @@
|
||||
error[E0597]: `b` does not live long enough
|
||||
--> $DIR/ref-escapes-but-not-over-yield.rs:24:13
|
||||
|
|
||||
LL | let mut b = move || {
|
||||
| _________________-
|
||||
LL | | yield();
|
||||
LL | | let b = 5;
|
||||
LL | | a = &b;
|
||||
| | ^^ borrowed value does not live long enough
|
||||
LL | | //~^ ERROR `b` does not live long enough
|
||||
LL | | };
|
||||
| | -
|
||||
| | |
|
||||
| | borrowed value only lives until here
|
||||
| |_____temporary later dropped here, potentially using the reference
|
||||
| borrow may end up in a temporary, created here
|
||||
LL | a = &b;
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | //~^ ERROR `b` does not live long enough
|
||||
LL | };
|
||||
| - borrowed value only lives until here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -3,15 +3,9 @@ error[E0502]: cannot borrow `heap` as immutable because it is also borrowed as m
|
||||
|
|
||||
LL | let borrow = heap.peek_mut();
|
||||
| ---- mutable borrow occurs here
|
||||
LL |
|
||||
LL | match (borrow, ()) {
|
||||
| ------------ borrow may end up in a temporary, created here
|
||||
LL | (Some(_), ()) => {
|
||||
...
|
||||
LL | println!("{:?}", heap); //~ ERROR cannot borrow `heap` as immutable
|
||||
| ^^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | };
|
||||
| - temporary later dropped here, potentially using the reference
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,14 +2,9 @@ error[E0597]: `*a` does not live long enough
|
||||
--> $DIR/destructor-restrictions.rs:18:10
|
||||
|
|
||||
LL | *a.borrow() + 1
|
||||
| ^---------
|
||||
| |
|
||||
| borrowed value does not live long enough
|
||||
| borrow may end up in a temporary, created here
|
||||
| ^ borrowed value does not live long enough
|
||||
LL | }; //~^ ERROR `*a` does not live long enough
|
||||
| -- temporary later dropped here, potentially using the reference
|
||||
| |
|
||||
| borrowed value only lives until here
|
||||
| - borrowed value only lives until here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,28 +2,17 @@ error[E0597]: `y` does not live long enough
|
||||
--> $DIR/issue-23338-locals-die-before-temps-of-body.rs:20:5
|
||||
|
|
||||
LL | y.borrow().clone()
|
||||
| ^---------
|
||||
| |
|
||||
| borrowed value does not live long enough
|
||||
| borrow may end up in a temporary, created here
|
||||
| ^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| -
|
||||
| |
|
||||
| borrowed value only lives until here
|
||||
| temporary later dropped here, potentially using the reference
|
||||
| - borrowed value only lives until here
|
||||
|
||||
error[E0597]: `y` does not live long enough
|
||||
--> $DIR/issue-23338-locals-die-before-temps-of-body.rs:27:9
|
||||
|
|
||||
LL | y.borrow().clone()
|
||||
| ^---------
|
||||
| |
|
||||
| borrowed value does not live long enough
|
||||
| borrow may end up in a temporary, created here
|
||||
| ^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| -- temporary later dropped here, potentially using the reference
|
||||
| |
|
||||
| borrowed value only lives until here
|
||||
| - borrowed value only lives until here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user