Auto merge of #51889 - spastorino:make-causal-tracking-lazy, r=nikomatsakis

Make causal tracking lazy

Closes #51710

r? @nikomatsakis
This commit is contained in:
bors 2018-07-03 09:08:58 +00:00
commit 64f8ae08fd
14 changed files with 335 additions and 436 deletions

View File

@ -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 { .. }

View File

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

View 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;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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