Skip to content

Commit 817dda7

Browse files
committed
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
2 parents e42247f + 7b628e1 commit 817dda7

21 files changed

+300
-184
lines changed

src/librustc_mir/borrow_check/flows.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ use std::rc::Rc;
3333

3434
// (forced to be `pub` due to its use as an associated type below.)
3535
crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
36-
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
37-
pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
38-
pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
36+
borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
37+
pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
38+
pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
3939

4040
/// Polonius Output
4141
pub polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
4242
}
4343

4444
impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
4545
crate fn new(
46-
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
47-
uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
48-
ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
46+
borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
47+
uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
48+
ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
4949
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
5050
) -> Self {
5151
Flows {

src/librustc_mir/borrow_check/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ mod move_errors;
6363
mod mutability_errors;
6464
mod path_utils;
6565
crate mod place_ext;
66-
mod places_conflict;
66+
crate mod places_conflict;
6767
mod prefixes;
6868
mod used_muts;
6969

@@ -1369,7 +1369,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13691369
place,
13701370
borrow.kind,
13711371
root_place,
1372-
sd
1372+
sd,
1373+
places_conflict::PlaceConflictBias::Overlap,
13731374
) {
13741375
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
13751376
// FIXME: should be talking about the region lifetime instead

src/librustc_mir/borrow_check/nll/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
8585
mir: &Mir<'tcx>,
8686
location_table: &LocationTable,
8787
param_env: ty::ParamEnv<'gcx>,
88-
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
88+
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
8989
move_data: &MoveData<'tcx>,
9090
borrow_set: &BorrowSet<'tcx>,
9191
errors_buffer: &mut Vec<Diagnostic>,

src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub(super) fn generate<'gcx, 'tcx>(
3939
typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
4040
mir: &Mir<'tcx>,
4141
elements: &Rc<RegionValueElements>,
42-
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
42+
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
4343
move_data: &MoveData<'tcx>,
4444
location_table: &LocationTable,
4545
) {

src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub(super) fn trace(
4646
typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
4747
mir: &Mir<'tcx>,
4848
elements: &Rc<RegionValueElements>,
49-
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
49+
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
5050
move_data: &MoveData<'tcx>,
5151
liveness_map: &NllLivenessMap,
5252
location_table: &LocationTable,
@@ -99,7 +99,7 @@ where
9999

100100
/// Results of dataflow tracking which variables (and paths) have been
101101
/// initialized.
102-
flow_inits: &'me mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
102+
flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
103103

104104
/// Index indicating where each variable is assigned, used, or
105105
/// dropped.

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
123123
location_table: &LocationTable,
124124
borrow_set: &BorrowSet<'tcx>,
125125
all_facts: &mut Option<AllFacts>,
126-
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
126+
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
127127
move_data: &MoveData<'tcx>,
128128
elements: &Rc<RegionValueElements>,
129129
) -> MirTypeckResults<'tcx> {

src/librustc_mir/borrow_check/path_utils.rs

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
6868
borrowed.kind,
6969
place,
7070
access,
71+
places_conflict::PlaceConflictBias::Overlap,
7172
) {
7273
debug!(
7374
"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",

src/librustc_mir/borrow_check/places_conflict.rs

+60-9
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,55 @@ use rustc::mir::{Projection, ProjectionElem};
1717
use rustc::ty::{self, TyCtxt};
1818
use std::cmp::max;
1919

20+
/// When checking if a place conflicts with another place, this enum is used to influence decisions
21+
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
22+
/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these
23+
/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate
24+
/// being run in the calling context, the conservative choice is to assume the compared indices
25+
/// are disjoint (and therefore, do not overlap).
26+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
27+
crate enum PlaceConflictBias {
28+
Overlap,
29+
NoOverlap,
30+
}
31+
32+
/// Helper function for checking if places conflict with a mutable borrow and deep access depth.
33+
/// This is used to check for places conflicting outside of the borrow checking code (such as in
34+
/// dataflow).
35+
crate fn places_conflict<'gcx, 'tcx>(
36+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
37+
mir: &Mir<'tcx>,
38+
borrow_place: &Place<'tcx>,
39+
access_place: &Place<'tcx>,
40+
bias: PlaceConflictBias,
41+
) -> bool {
42+
borrow_conflicts_with_place(
43+
tcx,
44+
mir,
45+
borrow_place,
46+
BorrowKind::Mut { allow_two_phase_borrow: true },
47+
access_place,
48+
AccessDepth::Deep,
49+
bias,
50+
)
51+
}
52+
53+
/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and
54+
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
55+
/// array indices, for example) should be interpreted - this depends on what the caller wants in
56+
/// order to make the conservative choice and preserve soundness.
2057
pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
2158
tcx: TyCtxt<'_, 'gcx, 'tcx>,
2259
mir: &Mir<'tcx>,
2360
borrow_place: &Place<'tcx>,
2461
borrow_kind: BorrowKind,
2562
access_place: &Place<'tcx>,
2663
access: AccessDepth,
64+
bias: PlaceConflictBias,
2765
) -> bool {
2866
debug!(
29-
"borrow_conflicts_with_place({:?},{:?},{:?})",
30-
borrow_place, access_place, access
67+
"borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
68+
borrow_place, access_place, access, bias,
3169
);
3270

3371
// 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>(
4684
borrow_components,
4785
borrow_kind,
4886
access_components,
49-
access
87+
access,
88+
bias,
5089
)
5190
})
5291
})
@@ -59,6 +98,7 @@ fn place_components_conflict<'gcx, 'tcx>(
5998
borrow_kind: BorrowKind,
6099
mut access_components: PlaceComponentsIter<'_, 'tcx>,
61100
access: AccessDepth,
101+
bias: PlaceConflictBias,
62102
) -> bool {
63103
// The borrowck rules for proving disjointness are applied from the "root" of the
64104
// borrow forwards, iterating over "similar" projections in lockstep until
@@ -121,7 +161,7 @@ fn place_components_conflict<'gcx, 'tcx>(
121161
// check whether the components being borrowed vs
122162
// accessed are disjoint (as in the second example,
123163
// but not the first).
124-
match place_element_conflict(tcx, mir, borrow_c, access_c) {
164+
match place_element_conflict(tcx, mir, borrow_c, access_c, bias) {
125165
Overlap::Arbitrary => {
126166
// We have encountered different fields of potentially
127167
// the same union - the borrow now partially overlaps.
@@ -190,7 +230,7 @@ fn place_components_conflict<'gcx, 'tcx>(
190230
bug!("Tracking borrow behind shared reference.");
191231
}
192232
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
193-
// Values behind a mutatble reference are not access either by Dropping a
233+
// Values behind a mutable reference are not access either by dropping a
194234
// value, or by StorageDead
195235
debug!("borrow_conflicts_with_place: drop access behind ptr");
196236
return false;
@@ -328,6 +368,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
328368
mir: &Mir<'tcx>,
329369
elem1: &Place<'tcx>,
330370
elem2: &Place<'tcx>,
371+
bias: PlaceConflictBias,
331372
) -> Overlap {
332373
match (elem1, elem2) {
333374
(Place::Local(l1), Place::Local(l2)) => {
@@ -445,10 +486,20 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
445486
| (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..))
446487
| (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => {
447488
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
448-
// (if the indexes differ) or equal (if they are the same), so this
449-
// is the recursive case that gives "equal *or* disjoint" its meaning.
450-
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
451-
Overlap::EqualOrDisjoint
489+
// (if the indexes differ) or equal (if they are the same).
490+
match bias {
491+
PlaceConflictBias::Overlap => {
492+
// If we are biased towards overlapping, then this is the recursive
493+
// case that gives "equal *or* disjoint" its meaning.
494+
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
495+
Overlap::EqualOrDisjoint
496+
}
497+
PlaceConflictBias::NoOverlap => {
498+
// If we are biased towards no overlapping, then this is disjoint.
499+
debug!("place_element_conflict: DISJOINT-ARRAY-INDEX");
500+
Overlap::Disjoint
501+
}
502+
}
452503
}
453504
(ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false },
454505
ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false })

src/librustc_mir/dataflow/at_location.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,19 @@ pub trait FlowsAtLocation {
7070
/// (e.g., via `reconstruct_statement_effect` and
7171
/// `reconstruct_terminator_effect`; don't forget to call
7272
/// `apply_local_effect`).
73-
pub struct FlowAtLocation<BD>
73+
pub struct FlowAtLocation<'tcx, BD>
7474
where
75-
BD: BitDenotation,
75+
BD: BitDenotation<'tcx>,
7676
{
77-
base_results: DataflowResults<BD>,
77+
base_results: DataflowResults<'tcx, BD>,
7878
curr_state: BitSet<BD::Idx>,
7979
stmt_gen: HybridBitSet<BD::Idx>,
8080
stmt_kill: HybridBitSet<BD::Idx>,
8181
}
8282

83-
impl<BD> FlowAtLocation<BD>
83+
impl<'tcx, BD> FlowAtLocation<'tcx, BD>
8484
where
85-
BD: BitDenotation,
85+
BD: BitDenotation<'tcx>,
8686
{
8787
/// Iterate over each bit set in the current state.
8888
pub fn each_state_bit<F>(&self, f: F)
@@ -102,7 +102,7 @@ where
102102
self.stmt_gen.iter().for_each(f)
103103
}
104104

105-
pub fn new(results: DataflowResults<BD>) -> Self {
105+
pub fn new(results: DataflowResults<'tcx, BD>) -> Self {
106106
let bits_per_block = results.sets().bits_per_block();
107107
let curr_state = BitSet::new_empty(bits_per_block);
108108
let stmt_gen = HybridBitSet::new_empty(bits_per_block);
@@ -143,8 +143,8 @@ where
143143
}
144144
}
145145

146-
impl<BD> FlowsAtLocation for FlowAtLocation<BD>
147-
where BD: BitDenotation
146+
impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>
147+
where BD: BitDenotation<'tcx>
148148
{
149149
fn reset_to_entry_of(&mut self, bb: BasicBlock) {
150150
self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
@@ -213,9 +213,9 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
213213
}
214214

215215

216-
impl<'tcx, T> FlowAtLocation<T>
216+
impl<'tcx, T> FlowAtLocation<'tcx, T>
217217
where
218-
T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
218+
T: HasMoveData<'tcx> + BitDenotation<'tcx, Idx = MovePathIndex>,
219219
{
220220
pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
221221
// We process `mpi` before the loop below, for two reasons:

src/librustc_mir/dataflow/graphviz.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ use super::DataflowBuilder;
2525
use super::DebugFormatted;
2626

2727
pub trait MirWithFlowState<'tcx> {
28-
type BD: BitDenotation;
28+
type BD: BitDenotation<'tcx>;
2929
fn node_id(&self) -> NodeId;
3030
fn mir(&self) -> &Mir<'tcx>;
31-
fn flow_state(&self) -> &DataflowState<Self::BD>;
31+
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
3232
}
3333

3434
impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
35-
where BD: BitDenotation
35+
where BD: BitDenotation<'tcx>
3636
{
3737
type BD = BD;
3838
fn node_id(&self) -> NodeId { self.node_id }
3939
fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
40-
fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
40+
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
4141
}
4242

4343
struct Graph<'a, 'tcx, MWF:'a, P> where
@@ -53,8 +53,8 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
5353
path: &Path,
5454
render_idx: P)
5555
-> io::Result<()>
56-
where BD: BitDenotation,
57-
P: Fn(&BD, BD::Idx) -> DebugFormatted
56+
where BD: BitDenotation<'tcx>,
57+
P: Fn(&BD, BD::Idx) -> DebugFormatted,
5858
{
5959
let g = Graph { mbcx, phantom: PhantomData, render_idx };
6060
let mut v = Vec::new();
@@ -76,7 +76,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
7676

7777
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
7878
where MWF: MirWithFlowState<'tcx>,
79-
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
79+
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
8080
{
8181
type Node = Node;
8282
type Edge = Edge;
@@ -128,7 +128,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
128128

129129
impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
130130
where MWF: MirWithFlowState<'tcx>,
131-
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
131+
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
132132
{
133133
/// Generate the node label
134134
fn node_label_internal<W: io::Write>(&self,

src/librustc_mir/dataflow/impls/borrowed_locals.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
3636
}
3737
}
3838

39-
impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
39+
impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
4040
type Idx = Local;
4141
fn name() -> &'static str { "has_been_borrowed_locals" }
4242
fn bits_per_block(&self) -> usize {
@@ -71,11 +71,13 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
7171
}.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
7272
}
7373

74-
fn propagate_call_return(&self,
75-
_in_out: &mut BitSet<Local>,
76-
_call_bb: mir::BasicBlock,
77-
_dest_bb: mir::BasicBlock,
78-
_dest_place: &mir::Place) {
74+
fn propagate_call_return(
75+
&self,
76+
_in_out: &mut BitSet<Local>,
77+
_call_bb: mir::BasicBlock,
78+
_dest_bb: mir::BasicBlock,
79+
_dest_place: &mir::Place<'tcx>,
80+
) {
7981
// Nothing to do when a call returns successfully
8082
}
8183
}

0 commit comments

Comments
 (0)