@@ -42,6 +42,7 @@ pub(super) struct LocationState {
4242 /// protected, that is *not* the case for uninitialized locations. Instead we just have a latent
4343 /// "future initial permission" of `Disabled`, causing UB only if an access is ever actually
4444 /// performed.
45+ /// Note that the tree root is also always initialized, as if the allocation was a write access.
4546 initialized : bool ,
4647 /// This pointer's current permission / future initial permission.
4748 permission : Permission ,
@@ -55,17 +56,18 @@ pub(super) struct LocationState {
5556}
5657
5758impl 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( ) ) ;
6164 Self { permission, initialized : false , latest_foreign_access : None }
6265 }
6366
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 }
6971 }
7072
7173 /// Check if the location has been initialized, i.e. if it has
@@ -238,8 +240,10 @@ pub(super) struct Node {
238240 /// If the pointer was reborrowed, it has children.
239241 // FIXME: bench to compare this to FxHashSet and to other SmallVec sizes
240242 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.
243247 default_initial_perm : Permission ,
244248 /// Some extra information useful only for debugging purposes
245249 pub debug_info : NodeDebugInfo ,
@@ -444,12 +448,14 @@ impl<'tree> TreeVisitor<'tree> {
444448impl Tree {
445449 /// Create a new tree, with only a root pointer.
446450 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 ( ) ;
448454 let mut tag_mapping = UniKeyMap :: default ( ) ;
449455 let root_idx = tag_mapping. insert ( root_tag) ;
450456 let nodes = {
451457 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) ;
453459 // name the root so that all allocations contain one named pointer
454460 debug_info. add_name ( "root of the allocation" ) ;
455461 nodes. insert (
@@ -458,15 +464,19 @@ impl Tree {
458464 tag : root_tag,
459465 parent : None ,
460466 children : SmallVec :: default ( ) ,
461- default_initial_perm : root_perm ,
467+ default_initial_perm : root_default_perm ,
462468 debug_info,
463469 } ,
464470 ) ;
465471 nodes
466472 } ;
467473 let rperms = {
468474 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 ( ) ) ) ;
470480 RangeMap :: new ( size, perms)
471481 } ;
472482 Self { root : root_idx, nodes, rperms, tag_mapping }
@@ -500,7 +510,7 @@ impl<'tcx> Tree {
500510 // Register new_tag as a child of parent_tag
501511 self . nodes . get_mut ( parent_idx) . unwrap ( ) . children . push ( idx) ;
502512 // Initialize perms
503- let perm = LocationState :: new ( default_initial_perm) . with_access ( ) ;
513+ let perm = LocationState :: new_init ( default_initial_perm) ;
504514 for ( _perms_range, perms) in self . rperms . iter_mut ( reborrow_range. start , reborrow_range. size )
505515 {
506516 perms. insert ( idx, perm) ;
@@ -599,7 +609,7 @@ impl<'tcx> Tree {
599609 -> Result < ContinueTraversal , TransitionError > {
600610 let NodeAppArgs { node, mut perm, rel_pos } = args;
601611
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 ) ) ;
603613
604614 match old_state. skip_if_known_noop ( access_kind, rel_pos) {
605615 ContinueTraversal :: SkipChildren => return Ok ( ContinueTraversal :: SkipChildren ) ,
0 commit comments