@@ -130,7 +130,7 @@ mod transition {
130
130
Active =>
131
131
if protected {
132
132
// We wrote, someone else reads -- that's bad.
133
- // (If this is initialized, this move-to-protected will mean insta-UB.)
133
+ // (Since Active is always initialized, this move-to-protected will mean insta-UB.)
134
134
Disabled
135
135
} else {
136
136
// We don't want to disable here to allow read-read reordering: it is crucial
@@ -267,6 +267,44 @@ impl Permission {
267
267
transition:: perform_access ( kind, rel_pos, old_state, protected)
268
268
. map ( |new_state| PermTransition { from : old_state, to : new_state } )
269
269
}
270
+
271
+ /// During a provenance GC, we want to compact the tree.
272
+ /// For this, we want to merge nodes upwards if they have a singleton parent.
273
+ /// But we need to be careful: If the parent is Frozen, and the child is Reserved,
274
+ /// we can not do such a merge. In general, such a merge is possible if the parent
275
+ /// allows similar accesses, and in particular if the parent never causes UB on its
276
+ /// own. This is enforced by a test, namely `tree_compacting_is_sound`. See that
277
+ /// test for more information.
278
+ /// This method is only sound if the parent is not protected. We never attempt to
279
+ /// remove protected parents.
280
+ pub fn can_be_replaced_by_child ( self , child : Self ) -> bool {
281
+ match ( self . inner , child. inner ) {
282
+ // ReservedIM can be replaced by anything, as it allows all
283
+ // transitions.
284
+ ( ReservedIM , _) => true ,
285
+ // Reserved (as parent, where conflictedness does not matter)
286
+ // can be replaced by all but ReservedIM,
287
+ // since ReservedIM alone would survive foreign writes
288
+ ( ReservedFrz { .. } , ReservedIM ) => false ,
289
+ ( ReservedFrz { .. } , _) => true ,
290
+ // Active can not be replaced by something surviving
291
+ // foreign reads and then remaining writable.
292
+ ( Active , ReservedIM ) => false ,
293
+ ( Active , ReservedFrz { .. } ) => false ,
294
+ // Replacing a state by itself is always okay, even if the child state is protected.
295
+ ( Active , Active ) => true ,
296
+ // Active can be replaced by Frozen, since it is not protected.
297
+ ( Active , Frozen ) => true ,
298
+ ( Active , Disabled ) => true ,
299
+ // Frozen can only be replaced by Disabled (and itself).
300
+ ( Frozen , Frozen ) => true ,
301
+ ( Frozen , Disabled ) => true ,
302
+ ( Frozen , _) => false ,
303
+ // Disabled can not be replaced by anything else.
304
+ ( Disabled , Disabled ) => true ,
305
+ ( Disabled , _) => false ,
306
+ }
307
+ }
270
308
}
271
309
272
310
impl PermTransition {
0 commit comments