@@ -14,13 +14,16 @@ use rustc_mir_dataflow::impls::{
1414use rustc_mir_dataflow:: { Analysis , GenKill , JoinSemiLattice } ;
1515use tracing:: debug;
1616
17- use crate :: { BorrowSet , PlaceConflictBias , PlaceExt , RegionInferenceContext , places_conflict} ;
17+ use crate :: {
18+ BorrowSet , PinSet , PlaceConflictBias , PlaceExt , RegionInferenceContext , places_conflict,
19+ } ;
1820
1921// This analysis is different to most others. Its results aren't computed with
2022// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
2123// computed individually with `iterate_to_fixpoint`.
2224pub ( crate ) struct Borrowck < ' a , ' tcx > {
2325 pub ( crate ) borrows : Borrows < ' a , ' tcx > ,
26+ pub ( crate ) pins : Pins < ' a , ' tcx > ,
2427 pub ( crate ) uninits : MaybeUninitializedPlaces < ' a , ' tcx > ,
2528 pub ( crate ) ever_inits : EverInitializedPlaces < ' a , ' tcx > ,
2629}
@@ -33,6 +36,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
3336 fn bottom_value ( & self , body : & mir:: Body < ' tcx > ) -> Self :: Domain {
3437 BorrowckDomain {
3538 borrows : self . borrows . bottom_value ( body) ,
39+ pins : self . pins . bottom_value ( body) ,
3640 uninits : self . uninits . bottom_value ( body) ,
3741 ever_inits : self . ever_inits . bottom_value ( body) ,
3842 }
@@ -50,6 +54,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
5054 loc : Location ,
5155 ) {
5256 self . borrows . apply_early_statement_effect ( & mut state. borrows , stmt, loc) ;
57+ self . pins . apply_early_statement_effect ( & mut state. pins , stmt, loc) ;
5358 self . uninits . apply_early_statement_effect ( & mut state. uninits , stmt, loc) ;
5459 self . ever_inits . apply_early_statement_effect ( & mut state. ever_inits , stmt, loc) ;
5560 }
@@ -61,6 +66,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
6166 loc : Location ,
6267 ) {
6368 self . borrows . apply_primary_statement_effect ( & mut state. borrows , stmt, loc) ;
69+ self . pins . apply_primary_statement_effect ( & mut state. pins , stmt, loc) ;
6470 self . uninits . apply_primary_statement_effect ( & mut state. uninits , stmt, loc) ;
6571 self . ever_inits . apply_primary_statement_effect ( & mut state. ever_inits , stmt, loc) ;
6672 }
@@ -72,6 +78,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
7278 loc : Location ,
7379 ) {
7480 self . borrows . apply_early_terminator_effect ( & mut state. borrows , term, loc) ;
81+ self . pins . apply_early_terminator_effect ( & mut state. pins , term, loc) ;
7582 self . uninits . apply_early_terminator_effect ( & mut state. uninits , term, loc) ;
7683 self . ever_inits . apply_early_terminator_effect ( & mut state. ever_inits , term, loc) ;
7784 }
@@ -83,6 +90,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
8390 loc : Location ,
8491 ) -> TerminatorEdges < ' mir , ' tcx > {
8592 self . borrows . apply_primary_terminator_effect ( & mut state. borrows , term, loc) ;
93+ self . pins . apply_primary_terminator_effect ( & mut state. pins , term, loc) ;
8694 self . uninits . apply_primary_terminator_effect ( & mut state. uninits , term, loc) ;
8795 self . ever_inits . apply_primary_terminator_effect ( & mut state. ever_inits , term, loc) ;
8896
@@ -116,6 +124,8 @@ where
116124 fn fmt_with ( & self , ctxt : & C , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
117125 f. write_str ( "borrows: " ) ?;
118126 self . borrows . fmt_with ( ctxt, f) ?;
127+ f. write_str ( " pins: " ) ?;
128+ self . pins . fmt_with ( ctxt, f) ?;
119129 f. write_str ( " uninits: " ) ?;
120130 self . uninits . fmt_with ( ctxt, f) ?;
121131 f. write_str ( " ever_inits: " ) ?;
@@ -134,6 +144,12 @@ where
134144 f. write_str ( "\n " ) ?;
135145 }
136146
147+ if self . pins != old. pins {
148+ f. write_str ( "pins: " ) ?;
149+ self . pins . fmt_diff_with ( & old. pins , ctxt, f) ?;
150+ f. write_str ( "\n " ) ?;
151+ }
152+
137153 if self . uninits != old. uninits {
138154 f. write_str ( "uninits: " ) ?;
139155 self . uninits . fmt_diff_with ( & old. uninits , ctxt, f) ?;
@@ -154,6 +170,7 @@ where
154170#[ derive( Clone , Debug , PartialEq , Eq ) ]
155171pub ( crate ) struct BorrowckDomain {
156172 pub ( crate ) borrows : BorrowsDomain ,
173+ pub ( crate ) pins : PinsDomain ,
157174 pub ( crate ) uninits : MaybeUninitializedPlacesDomain ,
158175 pub ( crate ) ever_inits : EverInitializedPlacesDomain ,
159176}
@@ -164,6 +181,16 @@ rustc_index::newtype_index! {
164181 pub struct BorrowIndex { }
165182}
166183
184+ impl < C > DebugWithContext < C > for BorrowIndex { }
185+
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+
167194/// `Borrows` stores the data used in the analyses that track the flow
168195/// of borrows.
169196///
@@ -178,6 +205,19 @@ pub struct Borrows<'a, 'tcx> {
178205 borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
179206}
180207
208+ /// `Pins` stores the data used in the analyses that track the flow
209+ /// of pins.
210+ ///
211+ /// It uniquely identifies every pinned borrow by a
212+ /// `PinIndex`, and maps each such index to a `PinData`
213+ /// describing the pin. These indexes are used for representing the
214+ /// pins in compact bitvectors.
215+ pub ( crate ) struct Pins < ' a , ' tcx > {
216+ tcx : TyCtxt < ' tcx > ,
217+ body : & ' a Body < ' tcx > ,
218+ pin_set : & ' a PinSet < ' tcx > ,
219+ }
220+
181221struct OutOfScopePrecomputer < ' a , ' tcx > {
182222 visited : DenseBitSet < mir:: BasicBlock > ,
183223 visit_stack : Vec < mir:: BasicBlock > ,
@@ -617,4 +657,153 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
617657 }
618658}
619659
620- impl < C > DebugWithContext < C > for BorrowIndex { }
660+ impl < ' a , ' tcx > Pins < ' a , ' tcx > {
661+ pub ( crate ) fn new (
662+ tcx : TyCtxt < ' tcx > ,
663+ body : & ' a Body < ' tcx > ,
664+ pin_set : & ' a PinSet < ' tcx > ,
665+ ) -> Self {
666+ Pins { tcx, body, pin_set }
667+ }
668+
669+ /// Kill any pins on `place`.
670+ fn kill_pins_on_place (
671+ & self ,
672+ state : & mut <Self as Analysis < ' tcx > >:: Domain ,
673+ place : Place < ' tcx > ,
674+ ) {
675+ debug ! ( "kill_pins_on_place: place={:?}" , place) ;
676+
677+ let other_pins_of_local = self
678+ . pin_set
679+ . local_map
680+ . get ( & place. local )
681+ . into_iter ( )
682+ . flat_map ( |ps| ps. iter ( ) )
683+ . copied ( ) ;
684+
685+ // If the place is a local with no projections, all pins of this
686+ // local must be killed. This is purely an optimization so we don't have to call
687+ // `places_conflict` for every pin.
688+ if place. projection . is_empty ( ) {
689+ state. kill_all ( other_pins_of_local) ;
690+ return ;
691+ }
692+
693+ // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
694+ // pair of array indices are not equal, so that when `places_conflict` returns true, we
695+ // will be assured that two places being compared definitely denotes the same sets of
696+ // locations.
697+ let definitely_conflicting_pins = other_pins_of_local. filter ( |& i| {
698+ places_conflict (
699+ self . tcx ,
700+ self . body ,
701+ self . pin_set [ i] . pinned_place ,
702+ place,
703+ PlaceConflictBias :: NoOverlap ,
704+ )
705+ } ) ;
706+
707+ state. kill_all ( definitely_conflicting_pins) ;
708+ }
709+ }
710+
711+ type PinsDomain = MixedBitSet < PinIndex > ;
712+
713+ /// Forward dataflow computation of the set of pins that are in scope at a particular location.
714+ /// - we gen the introduced pins
715+ /// - we kill pins on locals going out of scope
716+ /// - we kill pins when the pinned place is moved or overwritten
717+ impl < ' tcx > rustc_mir_dataflow:: Analysis < ' tcx > for Pins < ' _ , ' tcx > {
718+ type Domain = PinsDomain ;
719+
720+ const NAME : & ' static str = "pins" ;
721+
722+ fn bottom_value ( & self , _: & mir:: Body < ' tcx > ) -> Self :: Domain {
723+ // bottom = nothing is pinned yet
724+ MixedBitSet :: new_empty ( self . pin_set . len ( ) )
725+ }
726+
727+ fn initialize_start_block ( & self , _: & mir:: Body < ' tcx > , _: & mut Self :: Domain ) {
728+ // no pins have been created prior to function execution
729+ }
730+
731+ fn apply_early_statement_effect (
732+ & self ,
733+ _state : & mut Self :: Domain ,
734+ _statement : & mir:: Statement < ' tcx > ,
735+ _location : Location ,
736+ ) {
737+ // Pins don't go out of scope based on regions like borrows do
738+ }
739+
740+ fn apply_primary_statement_effect (
741+ & self ,
742+ state : & mut Self :: Domain ,
743+ stmt : & mir:: Statement < ' tcx > ,
744+ location : Location ,
745+ ) {
746+ match & stmt. kind {
747+ mir:: StatementKind :: Assign ( box ( lhs, rhs) ) => {
748+ // Check if this is a Pin aggregate creation
749+ if let mir:: Rvalue :: Aggregate ( box agg_kind, _) = rhs
750+ && let mir:: AggregateKind :: Adt ( adt_did, _, args, _, _) = agg_kind
751+ && self . tcx . adt_def ( adt_did) . is_pin ( )
752+ && args. type_at ( 0 ) . is_ref ( )
753+ {
754+ // Generate the pin
755+ if let Some ( index) = self . pin_set . get_index_of ( & location) {
756+ state. gen_ ( index) ;
757+ }
758+ }
759+
760+ // Kill any pins on the place being assigned to
761+ self . kill_pins_on_place ( state, * lhs) ;
762+ }
763+
764+ mir:: StatementKind :: StorageDead ( local) => {
765+ // Kill all pins on locals that are going out of scope
766+ self . kill_pins_on_place ( state, Place :: from ( * local) ) ;
767+ }
768+
769+ mir:: StatementKind :: FakeRead ( ..)
770+ | mir:: StatementKind :: SetDiscriminant { .. }
771+ | mir:: StatementKind :: StorageLive ( ..)
772+ | mir:: StatementKind :: Retag { .. }
773+ | mir:: StatementKind :: PlaceMention ( ..)
774+ | mir:: StatementKind :: AscribeUserType ( ..)
775+ | mir:: StatementKind :: Coverage ( ..)
776+ | mir:: StatementKind :: Intrinsic ( ..)
777+ | mir:: StatementKind :: ConstEvalCounter
778+ | mir:: StatementKind :: BackwardIncompatibleDropHint { .. }
779+ | mir:: StatementKind :: Nop => { }
780+ }
781+ }
782+
783+ fn apply_early_terminator_effect (
784+ & self ,
785+ _state : & mut Self :: Domain ,
786+ _terminator : & mir:: Terminator < ' tcx > ,
787+ _location : Location ,
788+ ) {
789+ // No early terminator effects for pins
790+ }
791+
792+ fn apply_primary_terminator_effect < ' mir > (
793+ & self ,
794+ state : & mut Self :: Domain ,
795+ terminator : & ' mir mir:: Terminator < ' tcx > ,
796+ _location : Location ,
797+ ) -> TerminatorEdges < ' mir , ' tcx > {
798+ if let mir:: TerminatorKind :: InlineAsm { operands, .. } = & terminator. kind {
799+ for op in operands {
800+ if let mir:: InlineAsmOperand :: Out { place : Some ( place) , .. }
801+ | mir:: InlineAsmOperand :: InOut { out_place : Some ( place) , .. } = * op
802+ {
803+ self . kill_pins_on_place ( state, place) ;
804+ }
805+ }
806+ }
807+ terminator. edges ( )
808+ }
809+ }
0 commit comments