Skip to content

Commit cae5c5e

Browse files
committed
WIP: implement borrowck
1 parent 6cd7eec commit cae5c5e

15 files changed

Lines changed: 324 additions & 341 deletions

compiler/rustc_borrowck/src/borrow_set.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,6 @@ impl<'tcx> BorrowData<'tcx> {
121121
pub fn assigned_place(&self) -> mir::Place<'tcx> {
122122
self.assigned_place
123123
}
124-
125-
pub(crate) fn is_pinned(&self) -> bool {
126-
matches!(self.pinnedness, Pinnedness::Pinned { .. })
127-
}
128-
129-
/// Returns the Pin result place if this borrow is pinned.
130-
#[allow(dead_code)]
131-
pub(crate) fn pin_target_local(&self) -> Option<mir::Local> {
132-
match self.pinnedness {
133-
Pinnedness::Pinned { to, .. } => Some(to.local),
134-
Pinnedness::Not => None,
135-
}
136-
}
137124
}
138125

139126
impl<'tcx> fmt::Display for BorrowData<'tcx> {

compiler/rustc_borrowck/src/borrowck_errors.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,38 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
479479
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> {
480480
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed")
481481
}
482+
483+
pub(crate) fn cannot_move_out_while_pinned(
484+
&self,
485+
span: Span,
486+
pin_span: Span,
487+
place: &str,
488+
pin_place: &str,
489+
value_place: &str,
490+
) -> Diag<'infcx> {
491+
self.dcx().create_err(crate::session_diagnostics::MovePin {
492+
place,
493+
pin_place,
494+
value_place,
495+
span,
496+
pin_span,
497+
})
498+
}
499+
500+
pub(crate) fn cannot_mutably_borrow_pinned(
501+
&self,
502+
span: Span,
503+
pin_span: Span,
504+
place: &str,
505+
pin_place: &str,
506+
) -> Diag<'infcx> {
507+
self.dcx().create_err(crate::session_diagnostics::MutablyBorrowPin {
508+
place,
509+
span,
510+
pin_place,
511+
pin_span,
512+
})
513+
}
482514
}
483515

484516
pub(crate) fn borrowed_data_escapes_closure<'tcx>(

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
3636
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
3737
BorrowckDomain {
3838
borrows: self.borrows.bottom_value(body),
39-
pins: self.pins.bottom_value(body),
39+
pinned_borrows: self.pins.bottom_value(body),
4040
uninits: self.uninits.bottom_value(body),
4141
ever_inits: self.ever_inits.bottom_value(body),
4242
}
@@ -54,7 +54,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
5454
loc: Location,
5555
) {
5656
self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
57-
self.pins.apply_early_statement_effect(&mut state.pins, stmt, loc);
57+
self.pins.apply_early_statement_effect(&mut state.pinned_borrows, stmt, loc);
5858
self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
5959
self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc);
6060
}
@@ -66,7 +66,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
6666
loc: Location,
6767
) {
6868
self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
69-
self.pins.apply_primary_statement_effect(&mut state.pins, stmt, loc);
69+
self.pins.apply_primary_statement_effect(&mut state.pinned_borrows, stmt, loc);
7070
self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
7171
self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc);
7272
}
@@ -78,7 +78,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
7878
loc: Location,
7979
) {
8080
self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
81-
self.pins.apply_early_terminator_effect(&mut state.pins, term, loc);
81+
self.pins.apply_early_terminator_effect(&mut state.pinned_borrows, term, loc);
8282
self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
8383
self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc);
8484
}
@@ -90,7 +90,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
9090
loc: Location,
9191
) -> TerminatorEdges<'mir, 'tcx> {
9292
self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
93-
self.pins.apply_primary_terminator_effect(&mut state.pins, term, loc);
93+
self.pins.apply_primary_terminator_effect(&mut state.pinned_borrows, term, loc);
9494
self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
9595
self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);
9696

@@ -124,8 +124,8 @@ where
124124
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125125
f.write_str("borrows: ")?;
126126
self.borrows.fmt_with(ctxt, f)?;
127-
f.write_str(" pins: ")?;
128-
self.pins.fmt_with(ctxt, f)?;
127+
f.write_str(" pinned_borrows: ")?;
128+
self.pinned_borrows.fmt_with(ctxt, f)?;
129129
f.write_str(" uninits: ")?;
130130
self.uninits.fmt_with(ctxt, f)?;
131131
f.write_str(" ever_inits: ")?;
@@ -144,9 +144,9 @@ where
144144
f.write_str("\n")?;
145145
}
146146

147-
if self.pins != old.pins {
148-
f.write_str("pins: ")?;
149-
self.pins.fmt_diff_with(&old.pins, ctxt, f)?;
147+
if self.pinned_borrows != old.pinned_borrows {
148+
f.write_str("pinned_borrows: ")?;
149+
self.pinned_borrows.fmt_diff_with(&old.pinned_borrows, ctxt, f)?;
150150
f.write_str("\n")?;
151151
}
152152

@@ -170,7 +170,7 @@ where
170170
#[derive(Clone, Debug, PartialEq, Eq)]
171171
pub(crate) struct BorrowckDomain {
172172
pub(crate) borrows: BorrowsDomain,
173-
pub(crate) pins: PinsDomain,
173+
pub(crate) pinned_borrows: BorrowsDomain,
174174
pub(crate) uninits: MaybeUninitializedPlacesDomain,
175175
pub(crate) ever_inits: EverInitializedPlacesDomain,
176176
}
@@ -183,14 +183,6 @@ rustc_index::newtype_index! {
183183

184184
impl<C> DebugWithContext<C> for BorrowIndex {}
185185

186-
rustc_index::newtype_index! {
187-
#[orderable]
188-
#[debug_format = "pi{}"]
189-
pub struct PinIndex {}
190-
}
191-
192-
impl<C> DebugWithContext<C> for PinIndex {}
193-
194186
/// `Borrows` stores the data used in the analyses that track the flow
195187
/// of borrows.
196188
///
@@ -215,7 +207,8 @@ pub struct Borrows<'a, 'tcx> {
215207
pub(crate) struct Pins<'a, 'tcx> {
216208
tcx: TyCtxt<'tcx>,
217209
body: &'a Body<'tcx>,
218-
pin_set: &'a PinSet<'tcx>,
210+
borrow_set: &'a BorrowSet<'tcx>,
211+
pin_set: &'a PinSet,
219212
}
220213

221214
struct OutOfScopePrecomputer<'a, 'tcx> {
@@ -658,16 +651,26 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
658651
}
659652

660653
impl<'a, 'tcx> Pins<'a, 'tcx> {
661-
pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, pin_set: &'a PinSet<'tcx>) -> Self {
662-
Pins { tcx, body, pin_set }
654+
pub(crate) fn new(
655+
tcx: TyCtxt<'tcx>,
656+
body: &'a Body<'tcx>,
657+
borrow_set: &'a BorrowSet<'tcx>,
658+
pin_set: &'a PinSet,
659+
) -> Self {
660+
Pins { tcx, body, borrow_set, pin_set }
663661
}
664662

665663
/// Kill any pins whose original pinned place conflicts with `place`.
666664
fn kill_pins_on_place(&self, state: &mut <Self as Analysis<'tcx>>::Domain, place: Place<'tcx>) {
667665
debug!("kill_pins_on_place: place={:?}", place);
668666

669-
let other_pins_of_local =
670-
self.pin_set.local_map.get(&place.local).into_iter().flat_map(|ps| ps.iter()).copied();
667+
let other_pins_of_local = self
668+
.borrow_set
669+
.local_map
670+
.get(&place.local)
671+
.into_iter()
672+
.flat_map(|bs| bs.iter())
673+
.copied();
671674

672675
// If the place is a local with no projections, all pins of this
673676
// local must be killed. This is purely an optimization so we don't have to call
@@ -685,7 +688,7 @@ impl<'a, 'tcx> Pins<'a, 'tcx> {
685688
places_conflict(
686689
self.tcx,
687690
self.body,
688-
self.pin_set[i].pinned_place,
691+
self.borrow_set[i].borrowed_place,
689692
place,
690693
PlaceConflictBias::NoOverlap,
691694
)
@@ -704,26 +707,24 @@ impl<'a, 'tcx> Pins<'a, 'tcx> {
704707
debug!("kill_pins_by_pin_local: local={:?}", local);
705708

706709
let pins_of_local =
707-
self.pin_set.pin_local_map.get(&local).into_iter().flat_map(|ps| ps.iter()).copied();
710+
self.pin_set.pin_local_map.get(&local).into_iter().flat_map(|bs| bs.iter()).copied();
708711

709712
state.kill_all(pins_of_local);
710713
}
711714
}
712715

713-
type PinsDomain = MixedBitSet<PinIndex>;
714-
715716
/// Forward dataflow computation of the set of pins that are in scope at a particular location.
716717
/// - we gen the introduced pins
717718
/// - we kill pins on locals going out of scope
718719
/// - we kill pins when the pinned place is moved or overwritten
719720
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> {
720-
type Domain = PinsDomain;
721+
type Domain = BorrowsDomain;
721722

722723
const NAME: &'static str = "pins";
723724

724725
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
725726
// bottom = nothing is pinned yet
726-
MixedBitSet::new_empty(self.pin_set.len())
727+
MixedBitSet::new_empty(self.borrow_set.len())
727728
}
728729

729730
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
@@ -758,20 +759,26 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> {
758759
) {
759760
match &stmt.kind {
760761
mir::StatementKind::Assign(box (lhs, rhs)) => {
762+
self.kill_pins_on_place(state, *lhs);
763+
761764
// Check if this is a Pin aggregate creation
762765
if let mir::Rvalue::Aggregate(box agg_kind, _) = rhs
763766
&& let mir::AggregateKind::Adt(adt_did, _, args, _, _) = agg_kind
764767
&& self.tcx.adt_def(*adt_did).is_pin()
765768
&& args.type_at(0).is_ref()
766769
{
767770
// Generate the pin
768-
if let Some(index) = self.pin_set.get_index_of(&location) {
771+
for index in self
772+
.pin_set
773+
.pin_location_map
774+
.get(&location)
775+
.into_iter()
776+
.flat_map(|bs| bs.iter())
777+
.copied()
778+
{
769779
state.gen_(index);
770780
}
771781
}
772-
773-
// Kill any pins on the place being assigned to
774-
self.kill_pins_on_place(state, *lhs);
775782
}
776783

777784
mir::StatementKind::StorageDead(local) => {

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,60 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
19791979
err
19801980
}
19811981

1982+
pub(crate) fn report_move_after_pinned(
1983+
&mut self,
1984+
location: Location,
1985+
(place, span): (Place<'tcx>, Span),
1986+
borrow: &BorrowData<'tcx>,
1987+
) {
1988+
debug!(
1989+
"report_move_after_pinned: location={:?} place={:?} span={:?} borrow={:?}",
1990+
location, place, span, borrow
1991+
);
1992+
1993+
let value_msg = self.describe_any_place(place.as_ref());
1994+
let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
1995+
1996+
let borrow_spans = self.retrieve_borrow_spans(borrow);
1997+
let borrow_span = borrow_spans.args_or_use();
1998+
1999+
let move_spans = self.move_spans(place.as_ref(), location);
2000+
let span = move_spans.args_or_use();
2001+
2002+
let err = self.cannot_move_out_while_pinned(
2003+
span,
2004+
borrow_span,
2005+
&self.describe_any_place(place.as_ref()),
2006+
&borrow_msg,
2007+
&value_msg,
2008+
);
2009+
self.buffer_error(err);
2010+
}
2011+
2012+
pub(crate) fn report_mutably_borrow_after_pinned(
2013+
&mut self,
2014+
location: Location,
2015+
(place, span): (Place<'tcx>, Span),
2016+
borrow: &BorrowData<'tcx>,
2017+
) {
2018+
debug!(
2019+
"report_mutably_borrow_after_pinned: location={:?} place={:?} span={:?} borrow={:?}",
2020+
location, place, span, borrow
2021+
);
2022+
2023+
let borrow_spans = self.borrow_spans(span, location);
2024+
let span = borrow_spans.args_or_use();
2025+
2026+
let pin_spans = self.retrieve_borrow_spans(borrow);
2027+
let pin_span = pin_spans.args_or_use();
2028+
2029+
let value_msg = self.describe_any_place(place.as_ref());
2030+
let pin_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
2031+
2032+
let err = self.cannot_mutably_borrow_pinned(span, pin_span, &value_msg, &pin_msg);
2033+
self.buffer_error(err);
2034+
}
2035+
19822036
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'infcx>, place: Place<'tcx>) {
19832037
let tcx = self.infcx.tcx;
19842038
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,6 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
612612
borrow: &BorrowData<'tcx>,
613613
kind_place: Option<(WriteKind, Place<'tcx>)>,
614614
) -> BorrowExplanation<'tcx> {
615-
// For pinned borrows, the borrow lifetime is extended beyond the NLL region.
616-
// The region inference can't explain why the borrow is still active,
617-
// so return Unexplained and let the caller provide context.
618-
if borrow.is_pinned() {
619-
return BorrowExplanation::Unexplained;
620-
}
621-
622615
let regioncx = &self.regioncx;
623616
let body: &Body<'_> = self.body;
624617
let tcx = self.infcx.tcx;

0 commit comments

Comments
 (0)