mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-06 12:04:36 +00:00
Auto merge of #56649 - davidtwco:issue-46589, r=pnkfelix
MIR borrowck doesn't accept the example of iterating and updating a mutable reference Fixes #46589. r? @pnkfelix or @nikomatsakis
This commit is contained in:
commit
817dda7df0
@ -33,9 +33,9 @@ use std::rc::Rc;
|
||||
|
||||
// (forced to be `pub` due to its use as an associated type below.)
|
||||
crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
|
||||
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
|
||||
pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
|
||||
pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
|
||||
/// Polonius Output
|
||||
pub polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
@ -43,9 +43,9 @@ crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
|
||||
|
||||
impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
|
||||
crate fn new(
|
||||
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
|
||||
uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
|
||||
uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
|
||||
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
) -> Self {
|
||||
Flows {
|
||||
|
@ -63,7 +63,7 @@ mod move_errors;
|
||||
mod mutability_errors;
|
||||
mod path_utils;
|
||||
crate mod place_ext;
|
||||
mod places_conflict;
|
||||
crate mod places_conflict;
|
||||
mod prefixes;
|
||||
mod used_muts;
|
||||
|
||||
@ -1369,7 +1369,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
place,
|
||||
borrow.kind,
|
||||
root_place,
|
||||
sd
|
||||
sd,
|
||||
places_conflict::PlaceConflictBias::Overlap,
|
||||
) {
|
||||
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
|
||||
// FIXME: should be talking about the region lifetime instead
|
||||
|
@ -85,7 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
mir: &Mir<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
|
||||
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
|
@ -39,7 +39,7 @@ pub(super) fn generate<'gcx, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
|
@ -46,7 +46,7 @@ pub(super) fn trace(
|
||||
typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
liveness_map: &NllLivenessMap,
|
||||
location_table: &LocationTable,
|
||||
@ -99,7 +99,7 @@ where
|
||||
|
||||
/// Results of dataflow tracking which variables (and paths) have been
|
||||
/// initialized.
|
||||
flow_inits: &'me mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
|
||||
flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
|
||||
|
||||
/// Index indicating where each variable is assigned, used, or
|
||||
/// dropped.
|
||||
|
@ -123,7 +123,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
location_table: &LocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
|
@ -68,6 +68,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
|
||||
borrowed.kind,
|
||||
place,
|
||||
access,
|
||||
places_conflict::PlaceConflictBias::Overlap,
|
||||
) {
|
||||
debug!(
|
||||
"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
|
||||
|
@ -17,6 +17,43 @@ use rustc::mir::{Projection, ProjectionElem};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use std::cmp::max;
|
||||
|
||||
/// When checking if a place conflicts with another place, this enum is used to influence decisions
|
||||
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
|
||||
/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these
|
||||
/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate
|
||||
/// being run in the calling context, the conservative choice is to assume the compared indices
|
||||
/// are disjoint (and therefore, do not overlap).
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
crate enum PlaceConflictBias {
|
||||
Overlap,
|
||||
NoOverlap,
|
||||
}
|
||||
|
||||
/// Helper function for checking if places conflict with a mutable borrow and deep access depth.
|
||||
/// This is used to check for places conflicting outside of the borrow checking code (such as in
|
||||
/// dataflow).
|
||||
crate fn places_conflict<'gcx, 'tcx>(
|
||||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
borrow_place: &Place<'tcx>,
|
||||
access_place: &Place<'tcx>,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
borrow_conflicts_with_place(
|
||||
tcx,
|
||||
mir,
|
||||
borrow_place,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: true },
|
||||
access_place,
|
||||
AccessDepth::Deep,
|
||||
bias,
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and
|
||||
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
|
||||
/// array indices, for example) should be interpreted - this depends on what the caller wants in
|
||||
/// order to make the conservative choice and preserve soundness.
|
||||
pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
|
||||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
@ -24,10 +61,11 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
|
||||
borrow_kind: BorrowKind,
|
||||
access_place: &Place<'tcx>,
|
||||
access: AccessDepth,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"borrow_conflicts_with_place({:?},{:?},{:?})",
|
||||
borrow_place, access_place, access
|
||||
"borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
|
||||
borrow_place, access_place, access, bias,
|
||||
);
|
||||
|
||||
// This Local/Local case is handled by the more general code below, but
|
||||
@ -46,7 +84,8 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
|
||||
borrow_components,
|
||||
borrow_kind,
|
||||
access_components,
|
||||
access
|
||||
access,
|
||||
bias,
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -59,6 +98,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
||||
borrow_kind: BorrowKind,
|
||||
mut access_components: PlaceComponentsIter<'_, 'tcx>,
|
||||
access: AccessDepth,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
// The borrowck rules for proving disjointness are applied from the "root" of the
|
||||
// borrow forwards, iterating over "similar" projections in lockstep until
|
||||
@ -121,7 +161,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
||||
// check whether the components being borrowed vs
|
||||
// accessed are disjoint (as in the second example,
|
||||
// but not the first).
|
||||
match place_element_conflict(tcx, mir, borrow_c, access_c) {
|
||||
match place_element_conflict(tcx, mir, borrow_c, access_c, bias) {
|
||||
Overlap::Arbitrary => {
|
||||
// We have encountered different fields of potentially
|
||||
// the same union - the borrow now partially overlaps.
|
||||
@ -190,7 +230,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
||||
bug!("Tracking borrow behind shared reference.");
|
||||
}
|
||||
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
|
||||
// Values behind a mutatble reference are not access either by Dropping a
|
||||
// Values behind a mutable reference are not access either by dropping a
|
||||
// value, or by StorageDead
|
||||
debug!("borrow_conflicts_with_place: drop access behind ptr");
|
||||
return false;
|
||||
@ -328,6 +368,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
|
||||
mir: &Mir<'tcx>,
|
||||
elem1: &Place<'tcx>,
|
||||
elem2: &Place<'tcx>,
|
||||
bias: PlaceConflictBias,
|
||||
) -> Overlap {
|
||||
match (elem1, elem2) {
|
||||
(Place::Local(l1), Place::Local(l2)) => {
|
||||
@ -445,10 +486,20 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
|
||||
| (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..))
|
||||
| (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => {
|
||||
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
|
||||
// (if the indexes differ) or equal (if they are the same), so this
|
||||
// is the recursive case that gives "equal *or* disjoint" its meaning.
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
|
||||
Overlap::EqualOrDisjoint
|
||||
// (if the indexes differ) or equal (if they are the same).
|
||||
match bias {
|
||||
PlaceConflictBias::Overlap => {
|
||||
// If we are biased towards overlapping, then this is the recursive
|
||||
// case that gives "equal *or* disjoint" its meaning.
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
PlaceConflictBias::NoOverlap => {
|
||||
// If we are biased towards no overlapping, then this is disjoint.
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-INDEX");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false },
|
||||
ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false })
|
||||
|
@ -70,19 +70,19 @@ pub trait FlowsAtLocation {
|
||||
/// (e.g., via `reconstruct_statement_effect` and
|
||||
/// `reconstruct_terminator_effect`; don't forget to call
|
||||
/// `apply_local_effect`).
|
||||
pub struct FlowAtLocation<BD>
|
||||
pub struct FlowAtLocation<'tcx, BD>
|
||||
where
|
||||
BD: BitDenotation,
|
||||
BD: BitDenotation<'tcx>,
|
||||
{
|
||||
base_results: DataflowResults<BD>,
|
||||
base_results: DataflowResults<'tcx, BD>,
|
||||
curr_state: BitSet<BD::Idx>,
|
||||
stmt_gen: HybridBitSet<BD::Idx>,
|
||||
stmt_kill: HybridBitSet<BD::Idx>,
|
||||
}
|
||||
|
||||
impl<BD> FlowAtLocation<BD>
|
||||
impl<'tcx, BD> FlowAtLocation<'tcx, BD>
|
||||
where
|
||||
BD: BitDenotation,
|
||||
BD: BitDenotation<'tcx>,
|
||||
{
|
||||
/// Iterate over each bit set in the current state.
|
||||
pub fn each_state_bit<F>(&self, f: F)
|
||||
@ -102,7 +102,7 @@ where
|
||||
self.stmt_gen.iter().for_each(f)
|
||||
}
|
||||
|
||||
pub fn new(results: DataflowResults<BD>) -> Self {
|
||||
pub fn new(results: DataflowResults<'tcx, BD>) -> Self {
|
||||
let bits_per_block = results.sets().bits_per_block();
|
||||
let curr_state = BitSet::new_empty(bits_per_block);
|
||||
let stmt_gen = HybridBitSet::new_empty(bits_per_block);
|
||||
@ -143,8 +143,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<BD> FlowsAtLocation for FlowAtLocation<BD>
|
||||
where BD: BitDenotation
|
||||
impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>
|
||||
where BD: BitDenotation<'tcx>
|
||||
{
|
||||
fn reset_to_entry_of(&mut self, bb: BasicBlock) {
|
||||
self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
|
||||
@ -213,9 +213,9 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
|
||||
}
|
||||
|
||||
|
||||
impl<'tcx, T> FlowAtLocation<T>
|
||||
impl<'tcx, T> FlowAtLocation<'tcx, T>
|
||||
where
|
||||
T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
|
||||
T: HasMoveData<'tcx> + BitDenotation<'tcx, Idx = MovePathIndex>,
|
||||
{
|
||||
pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
|
||||
// We process `mpi` before the loop below, for two reasons:
|
||||
|
@ -25,19 +25,19 @@ use super::DataflowBuilder;
|
||||
use super::DebugFormatted;
|
||||
|
||||
pub trait MirWithFlowState<'tcx> {
|
||||
type BD: BitDenotation;
|
||||
type BD: BitDenotation<'tcx>;
|
||||
fn node_id(&self) -> NodeId;
|
||||
fn mir(&self) -> &Mir<'tcx>;
|
||||
fn flow_state(&self) -> &DataflowState<Self::BD>;
|
||||
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
|
||||
where BD: BitDenotation
|
||||
where BD: BitDenotation<'tcx>
|
||||
{
|
||||
type BD = BD;
|
||||
fn node_id(&self) -> NodeId { self.node_id }
|
||||
fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
|
||||
fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
|
||||
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
|
||||
}
|
||||
|
||||
struct Graph<'a, 'tcx, MWF:'a, P> where
|
||||
@ -53,8 +53,8 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
|
||||
path: &Path,
|
||||
render_idx: P)
|
||||
-> io::Result<()>
|
||||
where BD: BitDenotation,
|
||||
P: Fn(&BD, BD::Idx) -> DebugFormatted
|
||||
where BD: BitDenotation<'tcx>,
|
||||
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
||||
{
|
||||
let g = Graph { mbcx, phantom: PhantomData, render_idx };
|
||||
let mut v = Vec::new();
|
||||
@ -76,7 +76,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
|
||||
|
||||
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
|
||||
where MWF: MirWithFlowState<'tcx>,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
|
||||
{
|
||||
type Node = Node;
|
||||
type Edge = Edge;
|
||||
@ -128,7 +128,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
|
||||
|
||||
impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
|
||||
where MWF: MirWithFlowState<'tcx>,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
|
||||
{
|
||||
/// Generate the node label
|
||||
fn node_label_internal<W: io::Write>(&self,
|
||||
|
@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
type Idx = Local;
|
||||
fn name() -> &'static str { "has_been_borrowed_locals" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -71,11 +71,13 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
}.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
_in_out: &mut BitSet<Local>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
_in_out: &mut BitSet<Local>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
// Nothing to do when a call returns successfully
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
use borrow_check::borrow_set::{BorrowSet, BorrowData};
|
||||
use borrow_check::place_ext::PlaceExt;
|
||||
|
||||
use rustc;
|
||||
use rustc::mir::{self, Location, Place, Mir};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::RegionVid;
|
||||
@ -24,6 +23,7 @@ use dataflow::{BitDenotation, BlockSets, InitialFlow};
|
||||
pub use dataflow::indexes::BorrowIndex;
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::places_conflict;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -191,17 +191,55 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn kill_borrows_on_local(&self,
|
||||
sets: &mut BlockSets<BorrowIndex>,
|
||||
local: &rustc::mir::Local)
|
||||
{
|
||||
if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) {
|
||||
sets.kill_all(borrow_indexes);
|
||||
/// Kill any borrows that conflict with `place`.
|
||||
fn kill_borrows_on_place(
|
||||
&self,
|
||||
sets: &mut BlockSets<BorrowIndex>,
|
||||
place: &Place<'tcx>
|
||||
) {
|
||||
debug!("kill_borrows_on_place: place={:?}", place);
|
||||
// Handle the `Place::Local(..)` case first and exit early.
|
||||
if let Place::Local(local) = place {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
|
||||
debug!("kill_borrows_on_place: borrow_indices={:?}", borrow_indices);
|
||||
sets.kill_all(borrow_indices);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, look at all borrows that are live and if they conflict with the assignment
|
||||
// into our place then we can kill them.
|
||||
let mut borrows = sets.on_entry.clone();
|
||||
let _ = borrows.union(sets.gen_set);
|
||||
for borrow_index in borrows.iter() {
|
||||
let borrow_data = &self.borrows()[borrow_index];
|
||||
debug!(
|
||||
"kill_borrows_on_place: borrow_index={:?} borrow_data={:?}",
|
||||
borrow_index, borrow_data,
|
||||
);
|
||||
|
||||
// By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
|
||||
// pair of array indices are unequal, so that when `places_conflict` returns true, we
|
||||
// will be assured that two places being compared definitely denotes the same sets of
|
||||
// locations.
|
||||
if places_conflict::places_conflict(
|
||||
self.tcx,
|
||||
self.mir,
|
||||
place,
|
||||
&borrow_data.borrowed_place,
|
||||
places_conflict::PlaceConflictBias::NoOverlap,
|
||||
) {
|
||||
debug!(
|
||||
"kill_borrows_on_place: (kill) borrow_index={:?} borrow_data={:?}",
|
||||
borrow_index, borrow_data,
|
||||
);
|
||||
sets.kill(borrow_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> {
|
||||
type Idx = BorrowIndex;
|
||||
fn name() -> &'static str { "borrows" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -222,7 +260,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
|
||||
debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);
|
||||
debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location);
|
||||
|
||||
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
|
||||
panic!("could not find block at location {:?}", location);
|
||||
@ -231,20 +269,12 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
panic!("could not find statement at location {:?}");
|
||||
});
|
||||
|
||||
debug!("Borrows::statement_effect: stmt={:?}", stmt);
|
||||
match stmt.kind {
|
||||
mir::StatementKind::Assign(ref lhs, ref rhs) => {
|
||||
// Make sure there are no remaining borrows for variables
|
||||
// that are assigned over.
|
||||
if let Place::Local(ref local) = *lhs {
|
||||
// FIXME: Handle the case in which we're assigning over
|
||||
// a projection (`foo.bar`).
|
||||
self.kill_borrows_on_local(sets, local);
|
||||
}
|
||||
|
||||
// NOTE: if/when the Assign case is revised to inspect
|
||||
// the assigned_place here, make sure to also
|
||||
// re-consider the current implementations of the
|
||||
// propagate_call_return method.
|
||||
self.kill_borrows_on_place(sets, lhs);
|
||||
|
||||
if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
|
||||
if place.ignore_borrow(
|
||||
@ -279,19 +309,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
mir::StatementKind::StorageDead(local) => {
|
||||
// Make sure there are no remaining borrows for locals that
|
||||
// are gone out of scope.
|
||||
self.kill_borrows_on_local(sets, &local)
|
||||
self.kill_borrows_on_place(sets, &Place::Local(local));
|
||||
}
|
||||
|
||||
mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
|
||||
for (output, kind) in outputs.iter().zip(&asm.outputs) {
|
||||
if !kind.is_indirect && !kind.is_rw {
|
||||
// Make sure there are no remaining borrows for direct
|
||||
// output variables.
|
||||
if let Place::Local(ref local) = *output {
|
||||
// FIXME: Handle the case in which we're assigning over
|
||||
// a projection (`foo.bar`).
|
||||
self.kill_borrows_on_local(sets, local);
|
||||
}
|
||||
self.kill_borrows_on_place(sets, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -316,16 +340,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn terminator_effect(&self, _: &mut BlockSets<BorrowIndex>, _: Location) {}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
_in_out: &mut BitSet<BorrowIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place) {
|
||||
// there are no effects on borrows from method call return...
|
||||
//
|
||||
// ... but if overwriting a place can affect flow state, then
|
||||
// latter is not true; see NOTE on Assign case in
|
||||
// statement_effect_on_borrows.
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
_in_out: &mut BitSet<BorrowIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,4 +363,3 @@ impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> {
|
||||
false // bottom = nothing is reserved or activated yet
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ impl<'a, 'gcx, 'tcx> DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
type Idx = MovePathIndex;
|
||||
fn name() -> &'static str { "maybe_init" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -331,11 +331,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 1 (initialized).
|
||||
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
|
||||
@ -344,7 +346,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
type Idx = MovePathIndex;
|
||||
fn name() -> &'static str { "maybe_uninit" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -387,11 +389,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx>
|
||||
)
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 0 (initialized).
|
||||
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
|
||||
@ -400,7 +404,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
type Idx = MovePathIndex;
|
||||
fn name() -> &'static str { "definite_init" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -441,11 +445,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc
|
||||
)
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
in_out: &mut BitSet<MovePathIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 1 (initialized).
|
||||
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
|
||||
@ -454,7 +460,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
type Idx = InitIndex;
|
||||
fn name() -> &'static str { "ever_init" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -530,11 +536,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut BitSet<InitIndex>,
|
||||
call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
in_out: &mut BitSet<InitIndex>,
|
||||
call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
let move_data = self.move_data();
|
||||
let bits_per_block = self.bits_per_block();
|
||||
let init_loc_map = &move_data.init_loc_map;
|
||||
|
@ -29,7 +29,7 @@ impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
|
||||
impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
|
||||
type Idx = Local;
|
||||
fn name() -> &'static str { "maybe_storage_live" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
@ -58,11 +58,13 @@ impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
|
||||
// Terminators have no effect
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
_in_out: &mut BitSet<Local>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place) {
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
_in_out: &mut BitSet<Local>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
// Nothing to do when a call returns successfully
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,9 @@ pub mod move_paths;
|
||||
|
||||
pub(crate) use self::move_paths::indexes;
|
||||
|
||||
pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
|
||||
pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD>
|
||||
where
|
||||
BD: BitDenotation<'tcx>
|
||||
{
|
||||
node_id: ast::NodeId,
|
||||
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
|
||||
@ -71,7 +73,7 @@ impl fmt::Debug for DebugFormatted {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Dataflow<BD: BitDenotation> {
|
||||
pub(crate) trait Dataflow<'tcx, BD: BitDenotation<'tcx>> {
|
||||
/// Sets up and runs the dataflow problem, using `p` to render results if
|
||||
/// implementation so chooses.
|
||||
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
|
||||
@ -87,7 +89,9 @@ pub(crate) trait Dataflow<BD: BitDenotation> {
|
||||
fn propagate(&mut self);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
|
||||
impl<'a, 'tcx: 'a, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD>
|
||||
where
|
||||
BD: BitDenotation<'tcx>
|
||||
{
|
||||
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
|
||||
self.flow_state.build_sets();
|
||||
@ -127,21 +131,21 @@ pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
dead_unwinds: &BitSet<BasicBlock>,
|
||||
bd: BD,
|
||||
p: P)
|
||||
-> DataflowResults<BD>
|
||||
where BD: BitDenotation + InitialFlow,
|
||||
-> DataflowResults<'tcx, BD>
|
||||
where BD: BitDenotation<'tcx> + InitialFlow,
|
||||
P: Fn(&BD, BD::Idx) -> DebugFormatted
|
||||
{
|
||||
let flow_state = DataflowAnalysis::new(mir, dead_unwinds, bd);
|
||||
flow_state.run(tcx, node_id, attributes, p)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
|
||||
{
|
||||
pub(crate) fn run<P>(self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
node_id: ast::NodeId,
|
||||
attributes: &[ast::Attribute],
|
||||
p: P) -> DataflowResults<BD>
|
||||
p: P) -> DataflowResults<'tcx, BD>
|
||||
where P: Fn(&BD, BD::Idx) -> DebugFormatted
|
||||
{
|
||||
let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
|
||||
@ -173,12 +177,12 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD
|
||||
}
|
||||
}
|
||||
|
||||
struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation
|
||||
struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation<'tcx>
|
||||
{
|
||||
builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
|
||||
impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
|
||||
{
|
||||
fn propagate(&mut self) {
|
||||
let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block);
|
||||
@ -228,7 +232,7 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation
|
||||
impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation<'tcx>
|
||||
{
|
||||
fn walk_cfg(&mut self, in_out: &mut BitSet<BD::Idx>) {
|
||||
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
|
||||
@ -259,7 +263,7 @@ fn dataflow_path(context: &str, path: &str) -> PathBuf {
|
||||
path
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
|
||||
impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
|
||||
{
|
||||
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
|
||||
where P: Fn(&BD, BD::Idx) -> DebugFormatted
|
||||
@ -347,10 +351,10 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> {
|
||||
fn mir(&self) -> &'a Mir<'tcx>;
|
||||
}
|
||||
|
||||
pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location,
|
||||
analysis: &T,
|
||||
result: &DataflowResults<T>,
|
||||
mir: &Mir<'tcx>)
|
||||
pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location,
|
||||
analysis: &T,
|
||||
result: &DataflowResults<'tcx, T>,
|
||||
mir: &Mir<'tcx>)
|
||||
-> BitSet<T::Idx> {
|
||||
let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
|
||||
let mut kill_set = on_entry.to_hybrid();
|
||||
@ -381,25 +385,25 @@ pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location,
|
||||
gen_set.to_dense()
|
||||
}
|
||||
|
||||
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
|
||||
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation<'tcx>
|
||||
{
|
||||
flow_state: DataflowState<O>,
|
||||
flow_state: DataflowState<'tcx, O>,
|
||||
dead_unwinds: &'a BitSet<mir::BasicBlock>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation
|
||||
impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation<'tcx>
|
||||
{
|
||||
pub fn results(self) -> DataflowResults<O> {
|
||||
pub fn results(self) -> DataflowResults<'tcx, O> {
|
||||
DataflowResults(self.flow_state)
|
||||
}
|
||||
|
||||
pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
|
||||
}
|
||||
|
||||
pub struct DataflowResults<O>(pub(crate) DataflowState<O>) where O: BitDenotation;
|
||||
pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>) where O: BitDenotation<'tcx>;
|
||||
|
||||
impl<O: BitDenotation> DataflowResults<O> {
|
||||
impl<'tcx, O: BitDenotation<'tcx>> DataflowResults<'tcx, O> {
|
||||
pub fn sets(&self) -> &AllSets<O::Idx> {
|
||||
&self.0.sets
|
||||
}
|
||||
@ -411,7 +415,7 @@ impl<O: BitDenotation> DataflowResults<O> {
|
||||
|
||||
/// State of a dataflow analysis; couples a collection of bit sets
|
||||
/// with operator used to initialize and merge bits during analysis.
|
||||
pub struct DataflowState<O: BitDenotation>
|
||||
pub struct DataflowState<'tcx, O: BitDenotation<'tcx>>
|
||||
{
|
||||
/// All the sets for the analysis. (Factored into its
|
||||
/// own structure so that we can borrow it mutably
|
||||
@ -422,7 +426,7 @@ pub struct DataflowState<O: BitDenotation>
|
||||
pub(crate) operator: O,
|
||||
}
|
||||
|
||||
impl<O: BitDenotation> DataflowState<O> {
|
||||
impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> {
|
||||
pub(crate) fn interpret_set<'c, P>(&self,
|
||||
o: &'c O,
|
||||
set: &BitSet<O::Idx>,
|
||||
@ -561,7 +565,7 @@ pub trait InitialFlow {
|
||||
fn bottom_value() -> bool;
|
||||
}
|
||||
|
||||
pub trait BitDenotation: BitSetOperator {
|
||||
pub trait BitDenotation<'tcx>: BitSetOperator {
|
||||
/// Specifies what index type is used to access the bitvector.
|
||||
type Idx: Idx;
|
||||
|
||||
@ -687,14 +691,16 @@ pub trait BitDenotation: BitSetOperator {
|
||||
/// be better to represent this as an additional gen- and
|
||||
/// kill-sets associated with each edge coming out of the basic
|
||||
/// block.
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut BitSet<Self::Idx>,
|
||||
call_bb: mir::BasicBlock,
|
||||
dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place);
|
||||
fn propagate_call_return(
|
||||
&self,
|
||||
in_out: &mut BitSet<Self::Idx>,
|
||||
call_bb: mir::BasicBlock,
|
||||
dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
|
||||
impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx>
|
||||
{
|
||||
pub fn new(mir: &'a Mir<'tcx>,
|
||||
dead_unwinds: &'a BitSet<mir::BasicBlock>,
|
||||
@ -726,8 +732,7 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
|
||||
{
|
||||
impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> {
|
||||
/// Propagates the bits of `in_out` into all the successors of `bb`,
|
||||
/// using bitwise operator denoted by `self.operator`.
|
||||
///
|
||||
@ -744,7 +749,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
|
||||
fn propagate_bits_into_graph_successors_of(
|
||||
&mut self,
|
||||
in_out: &mut BitSet<D::Idx>,
|
||||
(bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData),
|
||||
(bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData<'tcx>),
|
||||
dirty_list: &mut WorkQueue<mir::BasicBlock>)
|
||||
{
|
||||
match bb_data.terminator().kind {
|
||||
|
@ -303,8 +303,8 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
env: &'a MoveDataParamEnv<'tcx, 'tcx>,
|
||||
flow_inits: DataflowResults<MaybeInitializedPlaces<'a, 'tcx, 'tcx>>,
|
||||
flow_uninits: DataflowResults<MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>,
|
||||
flow_inits: DataflowResults<'tcx, MaybeInitializedPlaces<'a, 'tcx, 'tcx>>,
|
||||
flow_uninits: DataflowResults<'tcx, MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>,
|
||||
drop_flags: FxHashMap<MovePathIndex, Local>,
|
||||
patch: MirPatch<'tcx>,
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
id: ast::NodeId,
|
||||
_attributes: &[ast::Attribute],
|
||||
results: &DataflowResults<O>)
|
||||
where O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
|
||||
results: &DataflowResults<'tcx, O>)
|
||||
where O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx>
|
||||
{
|
||||
debug!("sanity_check_via_rustc_peek id: {:?}", id);
|
||||
// FIXME: this is not DRY. Figure out way to abstract this and
|
||||
@ -110,9 +110,9 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
results: &DataflowResults<O>,
|
||||
results: &DataflowResults<'tcx, O>,
|
||||
bb: mir::BasicBlock) where
|
||||
O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
|
||||
O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx>
|
||||
{
|
||||
let move_data = results.0.operator.move_data();
|
||||
let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb];
|
||||
|
37
src/test/ui/nll/issue-46589.rs
Normal file
37
src/test/ui/nll/issue-46589.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn get_self(&mut self) -> Option<&mut Self> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn new_self(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
fn trigger_bug(&mut self) {
|
||||
let other = &mut (&mut *self);
|
||||
|
||||
*other = match (*other).get_self() {
|
||||
Some(s) => s,
|
||||
None => (*other).new_self()
|
||||
//~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499]
|
||||
};
|
||||
|
||||
let c = other;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
15
src/test/ui/nll/issue-46589.stderr
Normal file
15
src/test/ui/nll/issue-46589.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0499]: cannot borrow `**other` as mutable more than once at a time
|
||||
--> $DIR/issue-46589.rs:29:21
|
||||
|
|
||||
LL | *other = match (*other).get_self() {
|
||||
| -------- first mutable borrow occurs here
|
||||
LL | Some(s) => s,
|
||||
LL | None => (*other).new_self()
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| second mutable borrow occurs here
|
||||
| first borrow later used here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
@ -27,10 +27,8 @@ fn nll_fail() {
|
||||
//~| ERROR (Mir) [E0506]
|
||||
data.0 = 'f';
|
||||
//~^ ERROR (Ast) [E0506]
|
||||
//~| ERROR (Mir) [E0506]
|
||||
data.0 = 'g';
|
||||
//~^ ERROR (Ast) [E0506]
|
||||
//~| ERROR (Mir) [E0506]
|
||||
capitalize(c);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ LL | data.0 = 'f';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:31:5
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:30:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ------ borrow of `data.0` occurs here
|
||||
@ -26,7 +26,7 @@ LL | data.0 = 'g';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:41:5
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:39:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ------ borrow of `data.0` occurs here
|
||||
@ -34,21 +34,21 @@ LL | capitalize(c);
|
||||
LL | data.0 = 'e';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:41:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ------ borrow of `data.0` occurs here
|
||||
...
|
||||
LL | data.0 = 'f';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:43:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ------ borrow of `data.0` occurs here
|
||||
...
|
||||
LL | data.0 = 'f';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:45:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ------ borrow of `data.0` occurs here
|
||||
...
|
||||
LL | data.0 = 'g';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
|
||||
@ -64,30 +64,6 @@ LL | data.0 = 'e';
|
||||
LL | capitalize(c);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:28:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ----------- borrow of `data.0` occurs here
|
||||
...
|
||||
LL | data.0 = 'f';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
...
|
||||
LL | capitalize(c);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
|
||||
--> $DIR/loan_ends_mid_block_pair.rs:31:5
|
||||
|
|
||||
LL | let c = &mut data.0;
|
||||
| ----------- borrow of `data.0` occurs here
|
||||
...
|
||||
LL | data.0 = 'g';
|
||||
| ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
|
||||
...
|
||||
LL | capitalize(c);
|
||||
| - borrow later used here
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
||||
|
Loading…
Reference in New Issue
Block a user