@@ -21,6 +21,7 @@ use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, plac
2121// computed individually with `iterate_to_fixpoint`.
2222pub ( crate ) struct Borrowck < ' a , ' tcx > {
2323 pub ( crate ) borrows : Borrows < ' a , ' tcx > ,
24+ pub ( crate ) pins : Pins < ' a , ' tcx > ,
2425 pub ( crate ) uninits : MaybeUninitializedPlaces < ' a , ' tcx > ,
2526 pub ( crate ) ever_inits : EverInitializedPlaces < ' a , ' tcx > ,
2627}
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
3334 fn bottom_value ( & self , body : & mir:: Body < ' tcx > ) -> Self :: Domain {
3435 BorrowckDomain {
3536 borrows : self . borrows . bottom_value ( body) ,
37+ pinned_borrows : self . pins . bottom_value ( body) ,
3638 uninits : self . uninits . bottom_value ( body) ,
3739 ever_inits : self . ever_inits . bottom_value ( body) ,
3840 }
@@ -50,6 +52,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
5052 loc : Location ,
5153 ) {
5254 self . borrows . apply_early_statement_effect ( & mut state. borrows , stmt, loc) ;
55+ self . pins . apply_early_statement_effect ( & mut state. pinned_borrows , stmt, loc) ;
5356 self . uninits . apply_early_statement_effect ( & mut state. uninits , stmt, loc) ;
5457 self . ever_inits . apply_early_statement_effect ( & mut state. ever_inits , stmt, loc) ;
5558 }
@@ -61,6 +64,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
6164 loc : Location ,
6265 ) {
6366 self . borrows . apply_primary_statement_effect ( & mut state. borrows , stmt, loc) ;
67+ self . pins . apply_primary_statement_effect ( & mut state. pinned_borrows , stmt, loc) ;
6468 self . uninits . apply_primary_statement_effect ( & mut state. uninits , stmt, loc) ;
6569 self . ever_inits . apply_primary_statement_effect ( & mut state. ever_inits , stmt, loc) ;
6670 }
@@ -72,6 +76,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
7276 loc : Location ,
7377 ) {
7478 self . borrows . apply_early_terminator_effect ( & mut state. borrows , term, loc) ;
79+ self . pins . apply_early_terminator_effect ( & mut state. pinned_borrows , term, loc) ;
7580 self . uninits . apply_early_terminator_effect ( & mut state. uninits , term, loc) ;
7681 self . ever_inits . apply_early_terminator_effect ( & mut state. ever_inits , term, loc) ;
7782 }
@@ -83,6 +88,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
8388 loc : Location ,
8489 ) -> TerminatorEdges < ' mir , ' tcx > {
8590 self . borrows . apply_primary_terminator_effect ( & mut state. borrows , term, loc) ;
91+ self . pins . apply_primary_terminator_effect ( & mut state. pinned_borrows , term, loc) ;
8692 self . uninits . apply_primary_terminator_effect ( & mut state. uninits , term, loc) ;
8793 self . ever_inits . apply_primary_terminator_effect ( & mut state. ever_inits , term, loc) ;
8894
@@ -116,6 +122,8 @@ where
116122 fn fmt_with ( & self , ctxt : & C , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
117123 f. write_str ( "borrows: " ) ?;
118124 self . borrows . fmt_with ( ctxt, f) ?;
125+ f. write_str ( " pinned_borrows: " ) ?;
126+ self . pinned_borrows . fmt_with ( ctxt, f) ?;
119127 f. write_str ( " uninits: " ) ?;
120128 self . uninits . fmt_with ( ctxt, f) ?;
121129 f. write_str ( " ever_inits: " ) ?;
@@ -134,6 +142,12 @@ where
134142 f. write_str ( "\n " ) ?;
135143 }
136144
145+ if self . pinned_borrows != old. pinned_borrows {
146+ f. write_str ( "pinned_borrows: " ) ?;
147+ self . pinned_borrows . fmt_diff_with ( & old. pinned_borrows , ctxt, f) ?;
148+ f. write_str ( "\n " ) ?;
149+ }
150+
137151 if self . uninits != old. uninits {
138152 f. write_str ( "uninits: " ) ?;
139153 self . uninits . fmt_diff_with ( & old. uninits , ctxt, f) ?;
@@ -154,6 +168,7 @@ where
154168#[ derive( Clone , Debug , PartialEq , Eq ) ]
155169pub ( crate ) struct BorrowckDomain {
156170 pub ( crate ) borrows : BorrowsDomain ,
171+ pub ( crate ) pinned_borrows : BorrowsDomain ,
157172 pub ( crate ) uninits : MaybeUninitializedPlacesDomain ,
158173 pub ( crate ) ever_inits : EverInitializedPlacesDomain ,
159174}
@@ -164,6 +179,8 @@ rustc_index::newtype_index! {
164179 pub struct BorrowIndex { }
165180}
166181
182+ impl < C > DebugWithContext < C > for BorrowIndex { }
183+
167184/// `Borrows` stores the data used in the analyses that track the flow
168185/// of borrows.
169186///
@@ -178,6 +195,19 @@ pub struct Borrows<'a, 'tcx> {
178195 borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
179196}
180197
198+ /// `Pins` stores the data used in the analyses that track the flow
199+ /// of pins.
200+ ///
201+ /// It uniquely identifies every pinned borrow by a
202+ /// `PinIndex`, and maps each such index to a `PinData`
203+ /// describing the pin. These indexes are used for representing the
204+ /// pins in compact bitvectors.
205+ pub ( crate ) struct Pins < ' a , ' tcx > {
206+ tcx : TyCtxt < ' tcx > ,
207+ body : & ' a Body < ' tcx > ,
208+ borrow_set : & ' a BorrowSet < ' tcx > ,
209+ }
210+
181211struct OutOfScopePrecomputer < ' a , ' tcx > {
182212 visited : DenseBitSet < mir:: BasicBlock > ,
183213 visit_stack : Vec < mir:: BasicBlock > ,
@@ -617,4 +647,166 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
617647 }
618648}
619649
620- impl < C > DebugWithContext < C > for BorrowIndex { }
650+ impl < ' a , ' tcx > Pins < ' a , ' tcx > {
651+ pub ( crate ) fn new (
652+ tcx : TyCtxt < ' tcx > ,
653+ body : & ' a Body < ' tcx > ,
654+ borrow_set : & ' a BorrowSet < ' tcx > ,
655+ ) -> Self {
656+ Pins { tcx, body, borrow_set }
657+ }
658+
659+ fn gen_pins_on_place ( & self , state : & mut <Self as Analysis < ' tcx > >:: Domain , place : Place < ' tcx > ) {
660+ self . borrow_set
661+ . local_map
662+ . get ( & place. local )
663+ . into_iter ( )
664+ . flat_map ( |bs| bs. iter ( ) )
665+ . copied ( )
666+ . filter ( |& index| self . borrow_set [ index] . borrowed_place == place)
667+ . for_each ( |index| {
668+ state. gen_ ( index) ;
669+ } ) ;
670+ }
671+
672+ /// Kill any pins whose original pinned place conflicts with `place`.
673+ fn kill_pins_on_place ( & self , state : & mut <Self as Analysis < ' tcx > >:: Domain , place : Place < ' tcx > ) {
674+ debug ! ( "kill_pins_on_place: place={:?}" , place) ;
675+
676+ let other_pins_of_local = self
677+ . borrow_set
678+ . local_map
679+ . get ( & place. local )
680+ . into_iter ( )
681+ . flat_map ( |bs| bs. iter ( ) )
682+ . copied ( ) ;
683+
684+ // If the place is a local with no projections, all pins of this
685+ // local must be killed. This is purely an optimization so we don't have to call
686+ // `places_conflict` for every pin.
687+ if place. projection . is_empty ( ) {
688+ state. kill_all ( other_pins_of_local) ;
689+ return ;
690+ }
691+
692+ // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
693+ // pair of array indices are not equal, so that when `places_conflict` returns true, we
694+ // will be assured that two places being compared definitely denotes the same sets of
695+ // locations.
696+ let definitely_conflicting_pins = other_pins_of_local. filter ( |& i| {
697+ places_conflict (
698+ self . tcx ,
699+ self . body ,
700+ self . borrow_set [ i] . borrowed_place ,
701+ place,
702+ PlaceConflictBias :: NoOverlap ,
703+ )
704+ } ) ;
705+
706+ state. kill_all ( definitely_conflicting_pins) ;
707+ }
708+ }
709+
710+ /// Forward dataflow computation of the set of pins that are in scope at a particular location.
711+ /// - we gen the introduced pins
712+ /// - we kill pins on locals going out of scope
713+ /// - we kill pins when the pinned place is moved or overwritten
714+ impl < ' tcx > rustc_mir_dataflow:: Analysis < ' tcx > for Pins < ' _ , ' tcx > {
715+ type Domain = BorrowsDomain ;
716+
717+ const NAME : & ' static str = "pins" ;
718+
719+ fn bottom_value ( & self , _: & mir:: Body < ' tcx > ) -> Self :: Domain {
720+ // bottom = nothing is pinned yet
721+ MixedBitSet :: new_empty ( self . borrow_set . len ( ) )
722+ }
723+
724+ fn initialize_start_block ( & self , _: & mir:: Body < ' tcx > , _: & mut Self :: Domain ) {
725+ // no pins have been created prior to function execution
726+ }
727+
728+ fn apply_early_statement_effect (
729+ & self ,
730+ state : & mut Self :: Domain ,
731+ statement : & mir:: Statement < ' tcx > ,
732+ _location : Location ,
733+ ) {
734+ // Kill pins early on reassignment/StorageDead so that the visitor
735+ // (which runs after the early phase) sees the updated pin state.
736+ // Note: we do NOT kill pins when the Pin result local goes out of scope
737+ // (kill_pins_by_pin_local), because a pinned place stays pinned until
738+ // the place itself is reassigned.
739+ match & statement. kind {
740+ mir:: StatementKind :: Assign ( box ( lhs, _) ) => {
741+ self . kill_pins_on_place ( state, * lhs) ;
742+ }
743+ mir:: StatementKind :: StorageDead ( local) => {
744+ self . kill_pins_on_place ( state, Place :: from ( * local) ) ;
745+ }
746+ _ => { }
747+ }
748+ }
749+
750+ fn apply_primary_statement_effect (
751+ & self ,
752+ state : & mut Self :: Domain ,
753+ stmt : & mir:: Statement < ' tcx > ,
754+ _location : Location ,
755+ ) {
756+ match & stmt. kind {
757+ mir:: StatementKind :: Assign ( box ( lhs, rhs) ) => {
758+ self . kill_pins_on_place ( state, * lhs) ;
759+
760+ // Check if this is a pinned borrow
761+ if let mir:: Rvalue :: Ref ( _, mir:: BorrowKind :: Pinned ( _) , place) = rhs {
762+ // Generate the pin
763+ self . gen_pins_on_place ( state, * place) ;
764+ }
765+ }
766+
767+ mir:: StatementKind :: StorageDead ( local) => {
768+ // Kill all pins on locals that are going out of scope
769+ self . kill_pins_on_place ( state, Place :: from ( * local) ) ;
770+ }
771+
772+ mir:: StatementKind :: FakeRead ( ..)
773+ | mir:: StatementKind :: SetDiscriminant { .. }
774+ | mir:: StatementKind :: StorageLive ( ..)
775+ | mir:: StatementKind :: Retag { .. }
776+ | mir:: StatementKind :: PlaceMention ( ..)
777+ | mir:: StatementKind :: AscribeUserType ( ..)
778+ | mir:: StatementKind :: Coverage ( ..)
779+ | mir:: StatementKind :: Intrinsic ( ..)
780+ | mir:: StatementKind :: ConstEvalCounter
781+ | mir:: StatementKind :: BackwardIncompatibleDropHint { .. }
782+ | mir:: StatementKind :: Nop => { }
783+ }
784+ }
785+
786+ fn apply_early_terminator_effect (
787+ & self ,
788+ _state : & mut Self :: Domain ,
789+ _terminator : & mir:: Terminator < ' tcx > ,
790+ _location : Location ,
791+ ) {
792+ // No early terminator effects for pins
793+ }
794+
795+ fn apply_primary_terminator_effect < ' mir > (
796+ & self ,
797+ state : & mut Self :: Domain ,
798+ terminator : & ' mir mir:: Terminator < ' tcx > ,
799+ _location : Location ,
800+ ) -> TerminatorEdges < ' mir , ' tcx > {
801+ if let mir:: TerminatorKind :: InlineAsm { operands, .. } = & terminator. kind {
802+ for op in operands {
803+ if let mir:: InlineAsmOperand :: Out { place : Some ( place) , .. }
804+ | mir:: InlineAsmOperand :: InOut { out_place : Some ( place) , .. } = * op
805+ {
806+ self . kill_pins_on_place ( state, place) ;
807+ }
808+ }
809+ }
810+ terminator. edges ( )
811+ }
812+ }
0 commit comments