Skip to content

Commit f6b714b

Browse files
committed
WIP: implement borrowck
1 parent cae5c5e commit f6b714b

9 files changed

Lines changed: 212 additions & 134 deletions

File tree

compiler/rustc_borrowck/src/borrow_set.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ pub(crate) enum Pinnedness<'tcx> {
7777
Pinned { to: mir::Place<'tcx>, at: Location },
7878
}
7979

80+
impl<'tcx> Pinnedness<'tcx> {
81+
pub(crate) fn is_pinned(&self) -> bool {
82+
matches!(self, Self::Pinned { .. })
83+
}
84+
}
85+
8086
#[derive(Debug, Clone)]
8187
pub struct BorrowData<'tcx> {
8288
/// Location where the borrow reservation starts.

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -696,21 +696,6 @@ impl<'a, 'tcx> Pins<'a, 'tcx> {
696696

697697
state.kill_all(definitely_conflicting_pins);
698698
}
699-
700-
/// Kill any pins whose Pin result local is `local`.
701-
/// This is used when the Pin value goes out of scope (StorageDead).
702-
fn kill_pins_by_pin_local(
703-
&self,
704-
state: &mut <Self as Analysis<'tcx>>::Domain,
705-
local: mir::Local,
706-
) {
707-
debug!("kill_pins_by_pin_local: local={:?}", local);
708-
709-
let pins_of_local =
710-
self.pin_set.pin_local_map.get(&local).into_iter().flat_map(|bs| bs.iter()).copied();
711-
712-
state.kill_all(pins_of_local);
713-
}
714699
}
715700

716701
/// Forward dataflow computation of the set of pins that are in scope at a particular location.
@@ -739,13 +724,15 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> {
739724
) {
740725
// Kill pins early on reassignment/StorageDead so that the visitor
741726
// (which runs after the early phase) sees the updated pin state.
727+
// Note: we do NOT kill pins when the Pin result local goes out of scope
728+
// (kill_pins_by_pin_local), because a pinned place stays pinned until
729+
// the place itself is reassigned.
742730
match &statement.kind {
743731
mir::StatementKind::Assign(box (lhs, _)) => {
744732
self.kill_pins_on_place(state, *lhs);
745733
}
746734
mir::StatementKind::StorageDead(local) => {
747735
self.kill_pins_on_place(state, Place::from(*local));
748-
self.kill_pins_by_pin_local(state, *local);
749736
}
750737
_ => {}
751738
}
@@ -784,8 +771,6 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> {
784771
mir::StatementKind::StorageDead(local) => {
785772
// Kill all pins on locals that are going out of scope
786773
self.kill_pins_on_place(state, Place::from(*local));
787-
// Also kill pins whose Pin result local is going out of scope
788-
self.kill_pins_by_pin_local(state, *local);
789774
}
790775

791776
mir::StatementKind::FakeRead(..)

compiler/rustc_borrowck/src/lib.rs

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
12741274
}
12751275
}
12761276

1277+
fn pinned_borrows<'s>(
1278+
&self,
1279+
state: &'s BorrowckDomain,
1280+
) -> Option<&'s MixedBitSet<BorrowIndex>> {
1281+
// FIXME(pin_ergonomics): borrowck behaviors depend on a safe trait
1282+
// which should not contain any safety invariants.
1283+
// if place
1284+
// .ty(self.body, self.infcx.tcx)
1285+
// .ty
1286+
// .is_unpin(self.infcx.tcx, self.body.typing_env(self.infcx.tcx))
1287+
// {
1288+
// None
1289+
// } else {
1290+
Some(&state.pinned_borrows)
1291+
// }
1292+
}
1293+
12771294
#[instrument(level = "debug", skip(self, state))]
12781295
fn check_access_for_conflict(
12791296
&mut self,
@@ -1286,7 +1303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
12861303
let mut error_reported = false;
12871304

12881305
let borrows_in_scope = self.borrows_in_scope(location, state);
1289-
let pinned_borrows = &state.pinned_borrows;
1306+
let pinned_borrows = self.pinned_borrows(state);
12901307

12911308
each_borrow_involving_path(
12921309
self,
@@ -1295,7 +1312,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
12951312
(sd, place_span.0),
12961313
self.borrow_set,
12971314
|borrow_index| {
1298-
borrows_in_scope.contains(borrow_index) || pinned_borrows.contains(borrow_index)
1315+
borrows_in_scope.contains(borrow_index)
1316+
|| pinned_borrows.is_some_and(|p| p.contains(borrow_index))
12991317
},
13001318
|this, borrow_index, borrow| match (rw, borrow.kind) {
13011319
// Obviously an activation is compatible with its own
@@ -1333,6 +1351,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13331351
ControlFlow::Continue(())
13341352
}
13351353

1354+
// Ignore the expired borrow (pinnedness never conflicts with a read)
1355+
(Read(_), BorrowKind::Mut { .. }) if !borrows_in_scope.contains(borrow_index) => {
1356+
ControlFlow::Continue(())
1357+
}
1358+
13361359
(Read(kind), BorrowKind::Mut { .. }) => {
13371360
// Reading from mere reservations of mutable-borrows is OK.
13381361
if !is_active(this.dominators(), borrow, location) {
@@ -1356,19 +1379,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13561379
ControlFlow::Break(())
13571380
}
13581381

1359-
(Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1360-
if pinned_borrows.contains(borrow_index)
1361-
&& !borrows_in_scope.contains(borrow_index)
1362-
{
1363-
// drop or write to the place is allowed after pinning
1364-
if matches!(
1365-
kind,
1366-
WriteKind::StorageDeadOrDrop | WriteKind::Mutate | WriteKind::Replace
1367-
) {
1368-
return ControlFlow::Continue(());
1382+
// Handle the expired borrows (only pinned borrows)
1383+
(Reservation(kind) | Activation(kind, _) | Write(kind), _)
1384+
if !borrows_in_scope.contains(borrow_index) =>
1385+
{
1386+
debug_assert!(
1387+
pinned_borrows.is_none_or(|p| p.contains(borrow_index)),
1388+
"unexpected expired but non-pinned borrow {borrow_index:?}: {borrow:?}",
1389+
);
1390+
match kind {
1391+
// Pinnedness doesn't conflict with a drop or write
1392+
WriteKind::StorageDeadOrDrop | WriteKind::Mutate | WriteKind::Replace => {
1393+
ControlFlow::Continue(())
1394+
}
1395+
// Mutable (pinned) borrow doesn't conflict with an expired borrow
1396+
WriteKind::MutableBorrow(_)
1397+
if self
1398+
.borrow_set
1399+
.location_map
1400+
.get(&location)
1401+
.is_none_or(|b| b.pinnedness.is_pinned()) =>
1402+
{
1403+
ControlFlow::Continue(())
1404+
}
1405+
// Mutable (but non-pinned) borrow conflicts with an earlier pinned borrow
1406+
WriteKind::MutableBorrow(_) => {
1407+
this.report_mutably_borrow_after_pinned(location, place_span, borrow);
1408+
error_reported = true;
1409+
ControlFlow::Break(())
1410+
}
1411+
WriteKind::Move => {
1412+
this.report_move_after_pinned(location, place_span, borrow);
1413+
error_reported = true;
1414+
ControlFlow::Break(())
13691415
}
13701416
}
1417+
}
13711418

1419+
(Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
13721420
match rw {
13731421
Reservation(..) => {
13741422
debug!(
@@ -1391,15 +1439,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13911439
error_reported = true;
13921440
match kind {
13931441
WriteKind::MutableBorrow(bk) => {
1394-
if pinned_borrows.contains(borrow_index) {
1395-
this.report_mutably_borrow_after_pinned(
1396-
location, place_span, borrow,
1397-
);
1398-
} else {
1399-
let err = this
1400-
.report_conflicting_borrow(location, place_span, bk, borrow);
1401-
this.buffer_error(err);
1402-
}
1442+
let err =
1443+
this.report_conflicting_borrow(location, place_span, bk, borrow);
1444+
this.buffer_error(err);
14031445
}
14041446
WriteKind::StorageDeadOrDrop => this
14051447
.report_borrowed_value_does_not_live_long_enough(
@@ -1412,11 +1454,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
14121454
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
14131455
}
14141456
WriteKind::Move => {
1415-
if pinned_borrows.contains(borrow_index) {
1416-
this.report_move_after_pinned(location, place_span, borrow);
1417-
} else {
1418-
this.report_move_out_while_borrowed(location, place_span, borrow)
1419-
}
1457+
this.report_move_out_while_borrowed(location, place_span, borrow)
14201458
}
14211459
WriteKind::Replace => {
14221460
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)

compiler/rustc_borrowck/src/pin_set.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ use crate::consumers::BorrowSet;
88
use crate::dataflow::BorrowIndex;
99

1010
pub(crate) struct PinSet {
11-
/// Map from Pin result location to the borrows it pinned.
11+
/// Map from Pin aggregate location to the borrows it pinned.
1212
pub(crate) pin_location_map: FxIndexMap<Location, FxIndexSet<BorrowIndex>>,
13-
/// Map from Pin result local to all the borrows it pined.
14-
pub(crate) pin_local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
1513
}
1614

1715
impl PinSet {
@@ -20,19 +18,14 @@ impl PinSet {
2018
body: &Body<'tcx>,
2119
borrow_set: &BorrowSet<'tcx>,
2220
) -> Self {
23-
let mut visitor = GatherPins {
24-
tcx,
25-
body,
26-
borrow_set,
27-
pin_location_map: Default::default(),
28-
pin_local_map: Default::default(),
29-
};
21+
let mut visitor =
22+
GatherPins { tcx, body, borrow_set, pin_location_map: Default::default() };
3023

3124
for (block, block_data) in traversal::preorder(body) {
3225
visitor.visit_basic_block_data(block, block_data);
3326
}
3427

35-
PinSet { pin_location_map: visitor.pin_location_map, pin_local_map: visitor.pin_local_map }
28+
PinSet { pin_location_map: visitor.pin_location_map }
3629
}
3730
}
3831

@@ -41,7 +34,6 @@ struct GatherPins<'a, 'tcx> {
4134
body: &'a Body<'tcx>,
4235
borrow_set: &'a BorrowSet<'tcx>,
4336
pin_location_map: FxIndexMap<Location, FxIndexSet<BorrowIndex>>,
44-
pin_local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
4537
}
4638

4739
impl<'tcx> Visitor<'tcx> for GatherPins<'_, 'tcx> {
@@ -66,8 +58,7 @@ impl<'tcx> Visitor<'tcx> for GatherPins<'_, 'tcx> {
6658
&& let Some((borrow_location, _borrowed_place)) = self.find_original_borrowed_place(location, ref_place)
6759
&& let Some(idx) = self.borrow_set.get_index_of(&borrow_location)
6860
{
69-
self.pin_location_map.entry(borrow_location).or_default().insert(idx);
70-
self.pin_local_map.entry(pin_result_place.local).or_default().insert(idx);
61+
self.pin_location_map.entry(location).or_default().insert(idx);
7162
}
7263

7364
self.super_assign(pin_result_place, rvalue, location)

0 commit comments

Comments
 (0)