@@ -8,6 +8,10 @@ use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
88/// The activation states of a pointer.
99#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
1010enum PermissionPriv {
11+ /// represents: a shared reference to interior mutable data.
12+ /// allows: all foreign and child accesses;
13+ /// rejects: nothing
14+ Cell ,
1115 /// represents: a local mutable reference that has not yet been written to;
1216 /// allows: child reads, foreign reads;
1317 /// affected by: child writes (becomes Active),
@@ -60,6 +64,14 @@ impl PartialOrd for PermissionPriv {
6064 use Ordering :: * ;
6165 Some ( match ( self , other) {
6266 ( a, b) if a == b => Equal ,
67+ // Versions of `Reserved` with different interior mutability are incomparable with each
68+ // other.
69+ ( ReservedIM , ReservedFrz { .. } )
70+ | ( ReservedFrz { .. } , ReservedIM )
71+ // `Cell` is not comparable with any other permission
72+ // since it never transitions to any other state and we
73+ // can never get to `Cell` from another state.
74+ | ( Cell , _) | ( _, Cell ) => return None ,
6375 ( Disabled , _) => Greater ,
6476 ( _, Disabled ) => Less ,
6577 ( Frozen , _) => Greater ,
@@ -71,27 +83,29 @@ impl PartialOrd for PermissionPriv {
7183 // `bool` is ordered such that `false <= true`, so this works as intended.
7284 c1. cmp ( c2)
7385 }
74- // Versions of `Reserved` with different interior mutability are incomparable with each
75- // other.
76- ( ReservedIM , ReservedFrz { .. } ) | ( ReservedFrz { .. } , ReservedIM ) => return None ,
7786 } )
7887 }
7988}
8089
8190impl PermissionPriv {
8291 /// Check if `self` can be the initial state of a pointer.
8392 fn is_initial ( & self ) -> bool {
84- matches ! ( self , ReservedFrz { conflicted: false } | Frozen | ReservedIM )
93+ matches ! ( self , ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell )
8594 }
8695
8796 /// Reject `ReservedIM` that cannot exist in the presence of a protector.
8897 fn compatible_with_protector ( & self ) -> bool {
89- !matches ! ( self , ReservedIM )
98+ // FIXME(TB-Cell): It is unclear what to do here.
99+ // `Cell` will occur with a protector but won't provide the guarantees
100+ // of noalias (it will fail the `protected_enforces_noalias` test).
101+ !matches ! ( self , ReservedIM | Cell )
90102 }
91103
92104 /// See `foreign_access_skipping.rs`. Computes the SIFA of a permission.
93105 fn strongest_idempotent_foreign_access ( & self , prot : bool ) -> IdempotentForeignAccess {
94106 match self {
107+ // Cell survives any foreign access
108+ Cell => IdempotentForeignAccess :: Write ,
95109 // A protected non-conflicted Reserved will become conflicted under a foreign read,
96110 // and is hence not idempotent under it.
97111 ReservedFrz { conflicted } if prot && !conflicted => IdempotentForeignAccess :: None ,
@@ -124,14 +138,16 @@ mod transition {
124138 Disabled => return None ,
125139 // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
126140 // accesses, since the data is not being mutated. Hence the `{ .. }`.
127- readable @ ( ReservedFrz { .. } | ReservedIM | Active | Frozen ) => readable,
141+ readable @ ( Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen ) => readable,
128142 } )
129143 }
130144
131145 /// A non-child node was read-accessed: keep `Reserved` but mark it as `conflicted` if it
132146 /// is protected; invalidate `Active`.
133147 fn foreign_read ( state : PermissionPriv , protected : bool ) -> Option < PermissionPriv > {
134148 Some ( match state {
149+ // Cell ignores foreign reads.
150+ Cell => Cell ,
135151 // Non-writeable states just ignore foreign reads.
136152 non_writeable @ ( Frozen | Disabled ) => non_writeable,
137153 // Writeable states are more tricky, and depend on whether things are protected.
@@ -167,6 +183,8 @@ mod transition {
167183 /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
168184 fn child_write ( state : PermissionPriv , protected : bool ) -> Option < PermissionPriv > {
169185 Some ( match state {
186+ // Cell ignores child writes.
187+ Cell => Cell ,
170188 // If the `conflicted` flag is set, then there was a foreign read during
171189 // the function call that is still ongoing (still `protected`),
172190 // this is UB (`noalias` violation).
@@ -185,6 +203,8 @@ mod transition {
185203 // types receive a `ReservedFrz` instead of `ReservedIM` when retagged under a protector,
186204 // so the result of this function does indirectly depend on (past) protector status.
187205 Some ( match state {
206+ // Cell ignores foreign writes.
207+ Cell => Cell ,
188208 res @ ReservedIM => {
189209 // We can never create a `ReservedIM` under a protector, only `ReservedFrz`.
190210 assert ! ( !protected) ;
@@ -242,6 +262,11 @@ impl Permission {
242262 self . inner == Frozen
243263 }
244264
265+ /// Check if `self` is the shared-reference-to-interior-mutable-data state of a pointer.
266+ pub fn is_cell ( & self ) -> bool {
267+ self . inner == Cell
268+ }
269+
245270 /// Default initial permission of the root of a new tree at inbounds positions.
246271 /// Must *only* be used for the root, this is not in general an "initial" permission!
247272 pub fn new_active ( ) -> Self {
@@ -278,11 +303,27 @@ impl Permission {
278303 Self { inner : Disabled }
279304 }
280305
306+ /// Default initial permission of a shared reference to interior mutable data.
307+ pub fn new_cell ( ) -> Self {
308+ Self { inner : Cell }
309+ }
310+
281311 /// Reject `ReservedIM` that cannot exist in the presence of a protector.
282312 pub fn compatible_with_protector ( & self ) -> bool {
283313 self . inner . compatible_with_protector ( )
284314 }
285315
316+ /// What kind of access to perform before releasing the protector.
317+ pub fn protector_end_access ( & self ) -> Option < AccessKind > {
318+ match self . inner {
319+ // Do not do perform access if it is a `Cell`, as this
320+ // can cause data races when using thread-safe data types.
321+ Cell => None ,
322+ Active => Some ( AccessKind :: Write ) ,
323+ _ => Some ( AccessKind :: Read ) ,
324+ }
325+ }
326+
286327 /// Apply the transition to the inner PermissionPriv.
287328 pub fn perform_access (
288329 kind : AccessKind ,
@@ -306,30 +347,32 @@ impl Permission {
306347 /// remove protected parents.
307348 pub fn can_be_replaced_by_child ( self , child : Self ) -> bool {
308349 match ( self . inner , child. inner ) {
309- // ReservedIM can be replaced by anything, as it allows all
310- // transitions.
350+ // Cell allows all transitions.
351+ ( Cell , _) => true ,
352+ // Cell is the most permissive, nothing can be replaced by Cell.
353+ // (ReservedIM, Cell) => true,
354+ ( _, Cell ) => false ,
355+ // ReservedIM can be replaced by anything besides Cell.
356+ // ReservedIM allows all transitions, but unlike Cell, a local write
357+ // to ReservedIM transitions to Active, while it is a no-op for Cell.
311358 ( ReservedIM , _) => true ,
359+ ( _, ReservedIM ) => false ,
312360 // Reserved (as parent, where conflictedness does not matter)
313- // can be replaced by all but ReservedIM,
314- // since ReservedIM alone would survive foreign writes
315- ( ReservedFrz { .. } , ReservedIM ) => false ,
361+ // can be replaced by all but ReservedIM and Cell,
362+ // since ReservedIM and Cell alone would survive foreign writes
316363 ( ReservedFrz { .. } , _) => true ,
364+ ( _, ReservedFrz { .. } ) => false ,
317365 // Active can not be replaced by something surviving
318- // foreign reads and then remaining writable.
319- ( Active , ReservedIM ) => false ,
320- ( Active , ReservedFrz { .. } ) => false ,
366+ // foreign reads and then remaining writable (i.e., Reserved*).
321367 // Replacing a state by itself is always okay, even if the child state is protected.
322- ( Active , Active ) => true ,
323368 // Active can be replaced by Frozen, since it is not protected.
324- ( Active , Frozen ) => true ,
325- ( Active , Disabled ) => true ,
369+ ( Active , Active | Frozen | Disabled ) => true ,
370+ ( _ , Active ) => false ,
326371 // Frozen can only be replaced by Disabled (and itself).
327- ( Frozen , Frozen ) => true ,
328- ( Frozen , Disabled ) => true ,
329- ( Frozen , _) => false ,
372+ ( Frozen , Frozen | Disabled ) => true ,
373+ ( _, Frozen ) => false ,
330374 // Disabled can not be replaced by anything else.
331375 ( Disabled , Disabled ) => true ,
332- ( Disabled , _) => false ,
333376 }
334377 }
335378
@@ -383,6 +426,7 @@ pub mod diagnostics {
383426 f,
384427 "{}" ,
385428 match self {
429+ Cell => "Cell" ,
386430 ReservedFrz { conflicted: false } => "Reserved" ,
387431 ReservedFrz { conflicted: true } => "Reserved (conflicted)" ,
388432 ReservedIM => "Reserved (interior mutable)" ,
@@ -413,6 +457,7 @@ pub mod diagnostics {
413457 // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
414458 // alignment will be incorrect.
415459 match self . inner {
460+ Cell => "Cel " ,
416461 ReservedFrz { conflicted : false } => "Res " ,
417462 ReservedFrz { conflicted : true } => "ResC" ,
418463 ReservedIM => "ReIM" ,
@@ -459,7 +504,7 @@ pub mod diagnostics {
459504 /// (Reserved < Active < Frozen < Disabled);
460505 /// - between `self` and `err` the permission should also be increasing,
461506 /// so all permissions inside `err` should be greater than `self.1`;
462- /// - `Active` and `Reserved(conflicted=false)` cannot cause an error
507+ /// - `Active`, `Reserved(conflicted=false)`, and `Cell ` cannot cause an error
463508 /// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)`
464509 /// of either of them;
465510 /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
@@ -492,13 +537,14 @@ pub mod diagnostics {
492537 ( ReservedFrz { conflicted : true } | Active | Frozen , Disabled ) => false ,
493538 ( ReservedFrz { conflicted : true } , Frozen ) => false ,
494539
495- // `Active` and `Reserved ` have all permissions, so a
540+ // `Active`, `Reserved`, and `Cell ` have all permissions, so a
496541 // `ChildAccessForbidden(Reserved | Active)` can never exist.
497- ( _, Active ) | ( _, ReservedFrz { conflicted : false } ) =>
542+ ( _, Active ) | ( _, ReservedFrz { conflicted : false } ) | ( _ , Cell ) =>
498543 unreachable ! ( "this permission cannot cause an error" ) ,
499544 // No transition has `Reserved { conflicted: false }` or `ReservedIM`
500- // as its `.to` unless it's a noop.
501- ( ReservedFrz { conflicted : false } | ReservedIM , _) =>
545+ // as its `.to` unless it's a noop. `Cell` cannot be in its `.to`
546+ // because all child accesses are a noop.
547+ ( ReservedFrz { conflicted : false } | ReservedIM | Cell , _) =>
502548 unreachable ! ( "self is a noop transition" ) ,
503549 // All transitions produced in normal executions (using `apply_access`)
504550 // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
@@ -544,16 +590,17 @@ pub mod diagnostics {
544590 "permission that results in Disabled should not itself be Disabled in the first place"
545591 ) ,
546592 // No transition has `Reserved { conflicted: false }` or `ReservedIM` as its `.to`
547- // unless it's a noop.
548- ( ReservedFrz { conflicted : false } | ReservedIM , _) =>
593+ // unless it's a noop. `Cell` cannot be in its `.to` because all child
594+ // accesses are a noop.
595+ ( ReservedFrz { conflicted : false } | ReservedIM | Cell , _) =>
549596 unreachable ! ( "self is a noop transition" ) ,
550597
551598 // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
552599 // so permissions found must be increasing in the order
553600 // `self.from < self.to <= forbidden.from < forbidden.to`.
554- ( Disabled , ReservedFrz { .. } | ReservedIM | Active | Frozen )
555- | ( Frozen , ReservedFrz { .. } | ReservedIM | Active )
556- | ( Active , ReservedFrz { .. } | ReservedIM ) =>
601+ ( Disabled , Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen )
602+ | ( Frozen , Cell | ReservedFrz { .. } | ReservedIM | Active )
603+ | ( Active , Cell | ReservedFrz { .. } | ReservedIM ) =>
557604 unreachable ! ( "permissions between self and err must be increasing" ) ,
558605 }
559606 }
@@ -590,7 +637,7 @@ mod propagation_optimization_checks {
590637 impl Exhaustive for PermissionPriv {
591638 fn exhaustive ( ) -> Box < dyn Iterator < Item = Self > > {
592639 Box :: new (
593- vec ! [ Active , Frozen , Disabled , ReservedIM ]
640+ vec ! [ Active , Frozen , Disabled , ReservedIM , Cell ]
594641 . into_iter ( )
595642 . chain ( <bool >:: exhaustive ( ) . map ( |conflicted| ReservedFrz { conflicted } ) ) ,
596643 )
0 commit comments