@@ -8,6 +8,10 @@ use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
8
8
/// The activation states of a pointer.
9
9
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
10
10
enum PermissionPriv {
11
+ /// represents: a shared reference to interior mutable data.
12
+ /// allows: all foreign and child accesses;
13
+ /// rejects: nothing
14
+ Cell ,
11
15
/// represents: a local mutable reference that has not yet been written to;
12
16
/// allows: child reads, foreign reads;
13
17
/// affected by: child writes (becomes Active),
@@ -60,6 +64,14 @@ impl PartialOrd for PermissionPriv {
60
64
use Ordering :: * ;
61
65
Some ( match ( self , other) {
62
66
( 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 ,
63
75
( Disabled , _) => Greater ,
64
76
( _, Disabled ) => Less ,
65
77
( Frozen , _) => Greater ,
@@ -71,27 +83,29 @@ impl PartialOrd for PermissionPriv {
71
83
// `bool` is ordered such that `false <= true`, so this works as intended.
72
84
c1. cmp ( c2)
73
85
}
74
- // Versions of `Reserved` with different interior mutability are incomparable with each
75
- // other.
76
- ( ReservedIM , ReservedFrz { .. } ) | ( ReservedFrz { .. } , ReservedIM ) => return None ,
77
86
} )
78
87
}
79
88
}
80
89
81
90
impl PermissionPriv {
82
91
/// Check if `self` can be the initial state of a pointer.
83
92
fn is_initial ( & self ) -> bool {
84
- matches ! ( self , ReservedFrz { conflicted: false } | Frozen | ReservedIM )
93
+ matches ! ( self , ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell )
85
94
}
86
95
87
96
/// Reject `ReservedIM` that cannot exist in the presence of a protector.
88
97
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 )
90
102
}
91
103
92
104
/// See `foreign_access_skipping.rs`. Computes the SIFA of a permission.
93
105
fn strongest_idempotent_foreign_access ( & self , prot : bool ) -> IdempotentForeignAccess {
94
106
match self {
107
+ // Cell survives any foreign access
108
+ Cell => IdempotentForeignAccess :: Write ,
95
109
// A protected non-conflicted Reserved will become conflicted under a foreign read,
96
110
// and is hence not idempotent under it.
97
111
ReservedFrz { conflicted } if prot && !conflicted => IdempotentForeignAccess :: None ,
@@ -124,14 +138,16 @@ mod transition {
124
138
Disabled => return None ,
125
139
// The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
126
140
// 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,
128
142
} )
129
143
}
130
144
131
145
/// A non-child node was read-accessed: keep `Reserved` but mark it as `conflicted` if it
132
146
/// is protected; invalidate `Active`.
133
147
fn foreign_read ( state : PermissionPriv , protected : bool ) -> Option < PermissionPriv > {
134
148
Some ( match state {
149
+ // Cell ignores foreign reads.
150
+ Cell => Cell ,
135
151
// Non-writeable states just ignore foreign reads.
136
152
non_writeable @ ( Frozen | Disabled ) => non_writeable,
137
153
// Writeable states are more tricky, and depend on whether things are protected.
@@ -167,6 +183,8 @@ mod transition {
167
183
/// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
168
184
fn child_write ( state : PermissionPriv , protected : bool ) -> Option < PermissionPriv > {
169
185
Some ( match state {
186
+ // Cell ignores child writes.
187
+ Cell => Cell ,
170
188
// If the `conflicted` flag is set, then there was a foreign read during
171
189
// the function call that is still ongoing (still `protected`),
172
190
// this is UB (`noalias` violation).
@@ -185,6 +203,8 @@ mod transition {
185
203
// types receive a `ReservedFrz` instead of `ReservedIM` when retagged under a protector,
186
204
// so the result of this function does indirectly depend on (past) protector status.
187
205
Some ( match state {
206
+ // Cell ignores foreign writes.
207
+ Cell => Cell ,
188
208
res @ ReservedIM => {
189
209
// We can never create a `ReservedIM` under a protector, only `ReservedFrz`.
190
210
assert ! ( !protected) ;
@@ -242,6 +262,11 @@ impl Permission {
242
262
self . inner == Frozen
243
263
}
244
264
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
+
245
270
/// Default initial permission of the root of a new tree at inbounds positions.
246
271
/// Must *only* be used for the root, this is not in general an "initial" permission!
247
272
pub fn new_active ( ) -> Self {
@@ -278,11 +303,27 @@ impl Permission {
278
303
Self { inner : Disabled }
279
304
}
280
305
306
+ /// Default initial permission of a shared reference to interior mutable data.
307
+ pub fn new_cell ( ) -> Self {
308
+ Self { inner : Cell }
309
+ }
310
+
281
311
/// Reject `ReservedIM` that cannot exist in the presence of a protector.
282
312
pub fn compatible_with_protector ( & self ) -> bool {
283
313
self . inner . compatible_with_protector ( )
284
314
}
285
315
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
+
286
327
/// Apply the transition to the inner PermissionPriv.
287
328
pub fn perform_access (
288
329
kind : AccessKind ,
@@ -306,30 +347,32 @@ impl Permission {
306
347
/// remove protected parents.
307
348
pub fn can_be_replaced_by_child ( self , child : Self ) -> bool {
308
349
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.
311
358
( ReservedIM , _) => true ,
359
+ ( _, ReservedIM ) => false ,
312
360
// 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
316
363
( ReservedFrz { .. } , _) => true ,
364
+ ( _, ReservedFrz { .. } ) => false ,
317
365
// 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*).
321
367
// Replacing a state by itself is always okay, even if the child state is protected.
322
- ( Active , Active ) => true ,
323
368
// 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 ,
326
371
// 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 ,
330
374
// Disabled can not be replaced by anything else.
331
375
( Disabled , Disabled ) => true ,
332
- ( Disabled , _) => false ,
333
376
}
334
377
}
335
378
@@ -383,6 +426,7 @@ pub mod diagnostics {
383
426
f,
384
427
"{}" ,
385
428
match self {
429
+ Cell => "Cell" ,
386
430
ReservedFrz { conflicted: false } => "Reserved" ,
387
431
ReservedFrz { conflicted: true } => "Reserved (conflicted)" ,
388
432
ReservedIM => "Reserved (interior mutable)" ,
@@ -413,6 +457,7 @@ pub mod diagnostics {
413
457
// and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
414
458
// alignment will be incorrect.
415
459
match self . inner {
460
+ Cell => "Cel " ,
416
461
ReservedFrz { conflicted : false } => "Res " ,
417
462
ReservedFrz { conflicted : true } => "ResC" ,
418
463
ReservedIM => "ReIM" ,
@@ -459,7 +504,7 @@ pub mod diagnostics {
459
504
/// (Reserved < Active < Frozen < Disabled);
460
505
/// - between `self` and `err` the permission should also be increasing,
461
506
/// 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
463
508
/// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)`
464
509
/// of either of them;
465
510
/// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
@@ -492,13 +537,14 @@ pub mod diagnostics {
492
537
( ReservedFrz { conflicted : true } | Active | Frozen , Disabled ) => false ,
493
538
( ReservedFrz { conflicted : true } , Frozen ) => false ,
494
539
495
- // `Active` and `Reserved ` have all permissions, so a
540
+ // `Active`, `Reserved`, and `Cell ` have all permissions, so a
496
541
// `ChildAccessForbidden(Reserved | Active)` can never exist.
497
- ( _, Active ) | ( _, ReservedFrz { conflicted : false } ) =>
542
+ ( _, Active ) | ( _, ReservedFrz { conflicted : false } ) | ( _ , Cell ) =>
498
543
unreachable ! ( "this permission cannot cause an error" ) ,
499
544
// 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 , _) =>
502
548
unreachable ! ( "self is a noop transition" ) ,
503
549
// All transitions produced in normal executions (using `apply_access`)
504
550
// change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
@@ -544,16 +590,17 @@ pub mod diagnostics {
544
590
"permission that results in Disabled should not itself be Disabled in the first place"
545
591
) ,
546
592
// 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 , _) =>
549
596
unreachable ! ( "self is a noop transition" ) ,
550
597
551
598
// Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
552
599
// so permissions found must be increasing in the order
553
600
// `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 ) =>
557
604
unreachable ! ( "permissions between self and err must be increasing" ) ,
558
605
}
559
606
}
@@ -590,7 +637,7 @@ mod propagation_optimization_checks {
590
637
impl Exhaustive for PermissionPriv {
591
638
fn exhaustive ( ) -> Box < dyn Iterator < Item = Self > > {
592
639
Box :: new (
593
- vec ! [ Active , Frozen , Disabled , ReservedIM ]
640
+ vec ! [ Active , Frozen , Disabled , ReservedIM , Cell ]
594
641
. into_iter ( )
595
642
. chain ( <bool >:: exhaustive ( ) . map ( |conflicted| ReservedFrz { conflicted } ) ) ,
596
643
)
0 commit comments