Skip to content

Commit ad8bce1

Browse files
committed
WIP: implement borrowck
1 parent 67b7412 commit ad8bce1

8 files changed

Lines changed: 105 additions & 92 deletions

File tree

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,31 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
557557
state.kill_all(definitely_conflicting_borrows);
558558
}
559559

560+
/// Kill pinned borrows whose borrowed place's local matches `local`.
561+
/// This is called in the early phase when the borrowed place's storage dies,
562+
/// to prevent spurious E0716 errors.
563+
fn kill_pinned_borrows_on_borrowed_local(
564+
&self,
565+
state: &mut <Self as Analysis<'tcx>>::Domain,
566+
local: mir::Local,
567+
) {
568+
debug!("kill_pinned_borrows_on_borrowed_local: local={:?}", local);
569+
570+
let to_kill: Vec<_> = self
571+
.borrow_set
572+
.iter_enumerated()
573+
.filter_map(|(idx, data)| {
574+
if data.is_pinned() && data.borrowed_place.local == local {
575+
Some(idx)
576+
} else {
577+
None
578+
}
579+
})
580+
.collect();
581+
582+
state.kill_all(to_kill.into_iter());
583+
}
584+
560585
/// Kill pinned borrows whose Pin result local matches `local`.
561586
/// This is called when the Pin value goes out of scope (StorageDead).
562587
fn kill_pinned_borrows_on_local(
@@ -569,9 +594,11 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
569594
let to_kill: Vec<_> = self
570595
.borrow_set
571596
.iter_enumerated()
572-
.filter_map(|(idx, data)| {
573-
if data.pin_target_local() == Some(local) { Some(idx) } else { None }
574-
})
597+
.filter_map(
598+
|(idx, data)| {
599+
if data.pin_target_local() == Some(local) { Some(idx) } else { None }
600+
},
601+
)
575602
.collect();
576603

577604
state.kill_all(to_kill.into_iter());
@@ -596,8 +623,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
596623

597624
if place.projection.is_empty() {
598625
// Only kill pinned borrows, not regular ones
599-
let pinned_borrows = other_borrows_of_local
600-
.filter(|&i| self.borrow_set[i].is_pinned());
626+
let pinned_borrows = other_borrows_of_local.filter(|&i| self.borrow_set[i].is_pinned());
601627
state.kill_all(pinned_borrows);
602628
return;
603629
}
@@ -649,11 +675,23 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
649675
) {
650676
self.kill_loans_out_of_scope_at_location(state, location);
651677

652-
// For pinned borrows whose lifetime is extended beyond NLL scope,
653-
// kill them early when the pinned place is reassigned. This allows
654-
// the reassignment to proceed without conflicting with the borrow.
655-
if let mir::StatementKind::Assign(box (lhs, _)) = &statement.kind {
656-
self.kill_pinned_borrows_on_reassignment(state, *lhs);
678+
match &statement.kind {
679+
// For pinned borrows whose lifetime is extended beyond NLL scope,
680+
// kill them early when the pinned place is reassigned. This allows
681+
// the reassignment to proceed without conflicting with the borrow.
682+
mir::StatementKind::Assign(box (lhs, _)) => {
683+
self.kill_pinned_borrows_on_reassignment(state, *lhs);
684+
}
685+
// Kill pinned borrows in the early phase when the borrowed place's
686+
// local has StorageDead. This must happen before the visitor's
687+
// StorageDead check (which runs after early effects) to avoid
688+
// spurious E0716 errors for temporaries whose storage dies before
689+
// the Pin result local.
690+
mir::StatementKind::StorageDead(local) => {
691+
self.kill_pinned_borrows_on_local(state, *local);
692+
self.kill_pinned_borrows_on_borrowed_local(state, *local);
693+
}
694+
_ => {}
657695
}
658696
}
659697

@@ -736,29 +774,16 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
736774
}
737775

738776
impl<'a, 'tcx> Pins<'a, 'tcx> {
739-
pub(crate) fn new(
740-
tcx: TyCtxt<'tcx>,
741-
body: &'a Body<'tcx>,
742-
pin_set: &'a PinSet<'tcx>,
743-
) -> Self {
777+
pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, pin_set: &'a PinSet<'tcx>) -> Self {
744778
Pins { tcx, body, pin_set }
745779
}
746780

747781
/// Kill any pins whose original pinned place conflicts with `place`.
748-
fn kill_pins_on_place(
749-
&self,
750-
state: &mut <Self as Analysis<'tcx>>::Domain,
751-
place: Place<'tcx>,
752-
) {
782+
fn kill_pins_on_place(&self, state: &mut <Self as Analysis<'tcx>>::Domain, place: Place<'tcx>) {
753783
debug!("kill_pins_on_place: place={:?}", place);
754784

755-
let other_pins_of_local = self
756-
.pin_set
757-
.local_map
758-
.get(&place.local)
759-
.into_iter()
760-
.flat_map(|ps| ps.iter())
761-
.copied();
785+
let other_pins_of_local =
786+
self.pin_set.local_map.get(&place.local).into_iter().flat_map(|ps| ps.iter()).copied();
762787

763788
// If the place is a local with no projections, all pins of this
764789
// local must be killed. This is purely an optimization so we don't have to call
@@ -794,13 +819,8 @@ impl<'a, 'tcx> Pins<'a, 'tcx> {
794819
) {
795820
debug!("kill_pins_by_pin_local: local={:?}", local);
796821

797-
let pins_of_local = self
798-
.pin_set
799-
.pin_local_map
800-
.get(&local)
801-
.into_iter()
802-
.flat_map(|ps| ps.iter())
803-
.copied();
822+
let pins_of_local =
823+
self.pin_set.pin_local_map.get(&local).into_iter().flat_map(|ps| ps.iter()).copied();
804824

805825
state.kill_all(pins_of_local);
806826
}

compiler/rustc_borrowck/src/lib.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -618,11 +618,7 @@ fn get_flow_results<'a, 'tcx>(
618618
body,
619619
Some("borrowck"),
620620
);
621-
let pins = Pins::new(tcx, body, pin_set).iterate_to_fixpoint(
622-
tcx,
623-
body,
624-
Some("borrowck"),
625-
);
621+
let pins = Pins::new(tcx, body, pin_set).iterate_to_fixpoint(tcx, body, Some("borrowck"));
626622
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
627623
tcx,
628624
body,
@@ -644,10 +640,19 @@ fn get_flow_results<'a, 'tcx>(
644640
assert_eq!(borrows.entry_states.len(), pins.entry_states.len());
645641
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
646642
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
647-
let entry_states: EntryStates<_> =
648-
itertools::izip!(borrows.entry_states, pins.entry_states, uninits.entry_states, ever_inits.entry_states)
649-
.map(|(borrows, pins, uninits, ever_inits)| BorrowckDomain { borrows, pins, uninits, ever_inits })
650-
.collect();
643+
let entry_states: EntryStates<_> = itertools::izip!(
644+
borrows.entry_states,
645+
pins.entry_states,
646+
uninits.entry_states,
647+
ever_inits.entry_states
648+
)
649+
.map(|(borrows, pins, uninits, ever_inits)| BorrowckDomain {
650+
borrows,
651+
pins,
652+
uninits,
653+
ever_inits,
654+
})
655+
.collect();
651656

652657
Results { analysis, entry_states }
653658
}

compiler/rustc_borrowck/src/pin_set.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,7 @@ impl<'tcx> Visitor<'tcx> for GatherPins<'_, 'tcx> {
112112
{
113113
// Look at the preceding statement to find the original borrow:
114114
// _ref = &[mut] _original
115-
if let Some(original_place) =
116-
self.find_original_borrowed_place(location, ref_place)
117-
{
115+
if let Some(original_place) = self.find_original_borrowed_place(location, ref_place) {
118116
let pin_data = PinData {
119117
location,
120118
pinned_place: original_place,
@@ -146,10 +144,8 @@ impl<'tcx> GatherPins<'_, 'tcx> {
146144
if location.statement_index == 0 {
147145
return None;
148146
}
149-
let predecessor = Location {
150-
block: location.block,
151-
statement_index: location.statement_index - 1,
152-
};
147+
let predecessor =
148+
Location { block: location.block, statement_index: location.statement_index - 1 };
153149
let stmt =
154150
&self.body.basic_blocks[predecessor.block].statements[predecessor.statement_index];
155151

compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ where
7878
// We ignore fake borrows as these get removed after analysis and shouldn't effect
7979
// the layout of generators.
8080
Rvalue::RawPtr(_, borrowed_place)
81-
| Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place)
82-
=> {
81+
| Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => {
8382
if !borrowed_place.is_indirect() {
8483
self.trans.gen_(borrowed_place.local);
8584
}

pin_temp

-3.41 MB
Binary file not shown.

0 commit comments

Comments
 (0)