@@ -42,6 +42,7 @@ pub(super) struct LocationState {
42
42
/// protected, that is *not* the case for uninitialized locations. Instead we just have a latent
43
43
/// "future initial permission" of `Disabled`, causing UB only if an access is ever actually
44
44
/// performed.
45
+ /// Note that the tree root is also always initialized, as if the allocation was a write access.
45
46
initialized : bool ,
46
47
/// This pointer's current permission / future initial permission.
47
48
permission : Permission ,
@@ -55,17 +56,18 @@ pub(super) struct LocationState {
55
56
}
56
57
57
58
impl LocationState {
58
- /// Default initial state has never been accessed and has been subjected to no
59
- /// foreign access.
60
- fn new ( permission : Permission ) -> Self {
59
+ /// Constructs a new initial state. It has neither been accessed, nor been subjected
60
+ /// to any foreign access yet.
61
+ /// The permission is not allowed to be `Active`.
62
+ fn new_uninit ( permission : Permission ) -> Self {
63
+ assert ! ( permission. is_initial( ) || permission. is_disabled( ) ) ;
61
64
Self { permission, initialized : false , latest_foreign_access : None }
62
65
}
63
66
64
- /// Record that this location was accessed through a child pointer by
65
- /// marking it as initialized
66
- fn with_access ( mut self ) -> Self {
67
- self . initialized = true ;
68
- self
67
+ /// Constructs a new initial state. It has not yet been subjected
68
+ /// to any foreign access. However, it is already marked as having been accessed.
69
+ fn new_init ( permission : Permission ) -> Self {
70
+ Self { permission, initialized : true , latest_foreign_access : None }
69
71
}
70
72
71
73
/// Check if the location has been initialized, i.e. if it has
@@ -238,8 +240,10 @@ pub(super) struct Node {
238
240
/// If the pointer was reborrowed, it has children.
239
241
// FIXME: bench to compare this to FxHashSet and to other SmallVec sizes
240
242
pub children : SmallVec < [ UniIndex ; 4 ] > ,
241
- /// Either `Reserved` or `Frozen`, the permission this tag will be lazily initialized
242
- /// to on the first access.
243
+ /// Either `Reserved`, `Frozen`, or `Disabled`, it is the permission this tag will
244
+ /// lazily be initialized to on the first access.
245
+ /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active` by
246
+ /// its own separate mechanism.
243
247
default_initial_perm : Permission ,
244
248
/// Some extra information useful only for debugging purposes
245
249
pub debug_info : NodeDebugInfo ,
@@ -444,12 +448,14 @@ impl<'tree> TreeVisitor<'tree> {
444
448
impl Tree {
445
449
/// Create a new tree, with only a root pointer.
446
450
pub fn new ( root_tag : BorTag , size : Size , span : Span ) -> Self {
447
- let root_perm = Permission :: new_active ( ) ;
451
+ // The root has `Disabled` as the default permission,
452
+ // so that any access out of bounds is invalid.
453
+ let root_default_perm = Permission :: new_disabled ( ) ;
448
454
let mut tag_mapping = UniKeyMap :: default ( ) ;
449
455
let root_idx = tag_mapping. insert ( root_tag) ;
450
456
let nodes = {
451
457
let mut nodes = UniValMap :: < Node > :: default ( ) ;
452
- let mut debug_info = NodeDebugInfo :: new ( root_tag, root_perm , span) ;
458
+ let mut debug_info = NodeDebugInfo :: new ( root_tag, root_default_perm , span) ;
453
459
// name the root so that all allocations contain one named pointer
454
460
debug_info. add_name ( "root of the allocation" ) ;
455
461
nodes. insert (
@@ -458,15 +464,19 @@ impl Tree {
458
464
tag : root_tag,
459
465
parent : None ,
460
466
children : SmallVec :: default ( ) ,
461
- default_initial_perm : root_perm ,
467
+ default_initial_perm : root_default_perm ,
462
468
debug_info,
463
469
} ,
464
470
) ;
465
471
nodes
466
472
} ;
467
473
let rperms = {
468
474
let mut perms = UniValMap :: default ( ) ;
469
- perms. insert ( root_idx, LocationState :: new ( root_perm) . with_access ( ) ) ;
475
+ // We manually set it to `Active` on all in-bounds positions.
476
+ // We also ensure that it is initalized, so that no `Active` but
477
+ // not yet initialized nodes exist. Essentially, we pretend there
478
+ // was a write that initialized these to `Active`.
479
+ perms. insert ( root_idx, LocationState :: new_init ( Permission :: new_active ( ) ) ) ;
470
480
RangeMap :: new ( size, perms)
471
481
} ;
472
482
Self { root : root_idx, nodes, rperms, tag_mapping }
@@ -500,7 +510,7 @@ impl<'tcx> Tree {
500
510
// Register new_tag as a child of parent_tag
501
511
self . nodes . get_mut ( parent_idx) . unwrap ( ) . children . push ( idx) ;
502
512
// Initialize perms
503
- let perm = LocationState :: new ( default_initial_perm) . with_access ( ) ;
513
+ let perm = LocationState :: new_init ( default_initial_perm) ;
504
514
for ( _perms_range, perms) in self . rperms . iter_mut ( reborrow_range. start , reborrow_range. size )
505
515
{
506
516
perms. insert ( idx, perm) ;
@@ -599,7 +609,7 @@ impl<'tcx> Tree {
599
609
-> Result < ContinueTraversal , TransitionError > {
600
610
let NodeAppArgs { node, mut perm, rel_pos } = args;
601
611
602
- let old_state = perm. or_insert ( LocationState :: new ( node. default_initial_perm ) ) ;
612
+ let old_state = perm. or_insert ( LocationState :: new_uninit ( node. default_initial_perm ) ) ;
603
613
604
614
match old_state. skip_if_known_noop ( access_kind, rel_pos) {
605
615
ContinueTraversal :: SkipChildren => return Ok ( ContinueTraversal :: SkipChildren ) ,
0 commit comments