1111//! - idempotency properties asserted in `perms.rs` (for optimizations)
1212
1313use std:: ops:: Range ;
14- use std:: { fmt, mem} ;
14+ use std:: { cmp , fmt, mem} ;
1515
1616use rustc_abi:: Size ;
1717use rustc_data_structures:: fx:: FxHashSet ;
@@ -57,7 +57,7 @@ pub(super) struct LocationState {
5757impl LocationState {
5858 /// Constructs a new initial state. It has neither been accessed, nor been subjected
5959 /// to any foreign access yet.
60- /// The permission is not allowed to be `Active `.
60+ /// The permission is not allowed to be `Unique `.
6161 /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
6262 pub fn new_non_accessed ( permission : Permission , sifa : IdempotentForeignAccess ) -> Self {
6363 assert ! ( permission. is_initial( ) || permission. is_disabled( ) ) ;
@@ -73,23 +73,10 @@ impl LocationState {
7373
7474 /// Check if the location has been accessed, i.e. if it has
7575 /// ever been accessed through a child pointer.
76- pub fn is_accessed ( & self ) -> bool {
76+ pub fn accessed ( & self ) -> bool {
7777 self . accessed
7878 }
7979
80- /// Check if the state can exist as the initial permission of a pointer.
81- ///
82- /// Do not confuse with `is_accessed`, the two are almost orthogonal
83- /// as apart from `Active` which is not initial and must be accessed,
84- /// any other permission can have an arbitrary combination of being
85- /// initial/accessed.
86- /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally
87- /// passes and can be uncommented, remove this `#[allow(dead_code)]`.
88- #[ cfg_attr( not( test) , allow( dead_code) ) ]
89- pub fn is_initial ( & self ) -> bool {
90- self . permission . is_initial ( )
91- }
92-
9380 pub fn permission ( & self ) -> Permission {
9481 self . permission
9582 }
@@ -170,7 +157,7 @@ impl LocationState {
170157 }
171158 if self . permission . is_frozen ( ) && access_kind == AccessKind :: Read {
172159 // A foreign read to a `Frozen` tag will have almost no observable effect.
173- // It's a theorem that `Frozen` nodes have no active children, so all children
160+ // It's a theorem that `Frozen` nodes have no `Unique` children, so all children
174161 // already survive foreign reads. Foreign reads in general have almost no
175162 // effect, the only further thing they could do is make protected `Reserved`
176163 // nodes become conflicted, i.e. make them reject child writes for the further
@@ -265,7 +252,7 @@ pub(super) struct Node {
265252 pub children : SmallVec < [ UniIndex ; 4 ] > ,
266253 /// Either `Reserved`, `Frozen`, or `Disabled`, it is the permission this tag will
267254 /// lazily be initialized to on the first access.
268- /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active ` by
255+ /// It is only ever `Disabled` for a tree root, since the root is initialized to `Unique ` by
269256 /// its own separate mechanism.
270257 default_initial_perm : Permission ,
271258 /// The default initial (strongest) idempotent foreign access.
@@ -598,14 +585,14 @@ impl Tree {
598585 } ;
599586 let rperms = {
600587 let mut perms = UniValMap :: default ( ) ;
601- // We manually set it to `Active ` on all in-bounds positions.
602- // We also ensure that it is accessed, so that no `Active ` but
588+ // We manually set it to `Unique ` on all in-bounds positions.
589+ // We also ensure that it is accessed, so that no `Unique ` but
603590 // not yet accessed nodes exist. Essentially, we pretend there
604- // was a write that initialized these to `Active `.
591+ // was a write that initialized these to `Unique `.
605592 perms. insert (
606593 root_idx,
607594 LocationState :: new_accessed (
608- Permission :: new_active ( ) ,
595+ Permission :: new_unique ( ) ,
609596 IdempotentForeignAccess :: None ,
610597 ) ,
611598 ) ;
@@ -618,67 +605,62 @@ impl Tree {
618605impl < ' tcx > Tree {
619606 /// Insert a new tag in the tree.
620607 ///
621- /// `initial_perms` defines the initial permissions for the part of memory
622- /// that is already considered "initialized" immediately. The ranges in this
623- /// map are relative to `base_offset`.
624- /// `default_perm` defines the initial permission for the rest of the allocation.
625- ///
626- /// For all non-accessed locations in the RangeMap (those that haven't had an
627- /// implicit read), their SIFA must be weaker than or as weak as the SIFA of
628- /// `default_perm`.
608+ /// `inside_perm` defines the initial permissions for a block of memory starting at
609+ /// `base_offset`. These may nor may not be already marked as "accessed".
610+ /// `outside_perm` defines the initial permission for the rest of the allocation.
611+ /// These are definitely not "accessed".
629612 pub ( super ) fn new_child (
630613 & mut self ,
631614 base_offset : Size ,
632615 parent_tag : BorTag ,
633616 new_tag : BorTag ,
634- initial_perms : DedupRangeMap < LocationState > ,
635- default_perm : Permission ,
617+ inside_perms : DedupRangeMap < LocationState > ,
618+ outside_perm : Permission ,
636619 protected : bool ,
637620 span : Span ,
638621 ) -> InterpResult < ' tcx > {
639622 let idx = self . tag_mapping . insert ( new_tag) ;
640623 let parent_idx = self . tag_mapping . get ( & parent_tag) . unwrap ( ) ;
641- assert ! ( default_perm . is_initial( ) ) ;
624+ assert ! ( outside_perm . is_initial( ) ) ;
642625
643626 let default_strongest_idempotent =
644- default_perm . strongest_idempotent_foreign_access ( protected) ;
627+ outside_perm . strongest_idempotent_foreign_access ( protected) ;
645628 // Create the node
646629 self . nodes . insert (
647630 idx,
648631 Node {
649632 tag : new_tag,
650633 parent : Some ( parent_idx) ,
651634 children : SmallVec :: default ( ) ,
652- default_initial_perm : default_perm ,
635+ default_initial_perm : outside_perm ,
653636 default_initial_idempotent_foreign_access : default_strongest_idempotent,
654- debug_info : NodeDebugInfo :: new ( new_tag, default_perm , span) ,
637+ debug_info : NodeDebugInfo :: new ( new_tag, outside_perm , span) ,
655638 } ,
656639 ) ;
657640 // Register new_tag as a child of parent_tag
658641 self . nodes . get_mut ( parent_idx) . unwrap ( ) . children . push ( idx) ;
659642
643+ // We need to know the biggest SIFA for `update_last_accessed_after_retag` below.
644+ let mut max_sifa = default_strongest_idempotent;
660645 for ( Range { start, end } , & perm) in
661- initial_perms . iter ( Size :: from_bytes ( 0 ) , initial_perms . size ( ) )
646+ inside_perms . iter ( Size :: from_bytes ( 0 ) , inside_perms . size ( ) )
662647 {
663- assert ! ( perm. is_initial( ) ) ;
648+ assert ! ( perm. permission. is_initial( ) ) ;
649+ max_sifa = cmp:: max ( max_sifa, perm. idempotent_foreign_access ) ;
664650 for ( _perms_range, perms) in self
665651 . rperms
666652 . iter_mut ( Size :: from_bytes ( start) + base_offset, Size :: from_bytes ( end - start) )
667653 {
668- assert ! (
669- default_strongest_idempotent
670- >= perm. permission. strongest_idempotent_foreign_access( protected)
671- ) ;
672654 perms. insert ( idx, perm) ;
673655 }
674656 }
675657
676- // Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`).
677- // We now weaken the recorded SIFA for our parents, until the invariant is restored.
678- // We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA
679- // for the new permission statically, and use that.
680- // See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm` .
681- self . update_last_accessed_after_retag ( parent_idx, default_strongest_idempotent ) ;
658+ // Inserting the new perms might have broken the SIFA invariant (see
659+ // `foreign_access_skipping.rs`). We now weaken the recorded SIFA for our parents, until the
660+ // invariant is restored. We could weaken them all to `LocalAccess`, but it is more
661+ // efficient to compute the SIFA for the new permission statically, and use that. For this
662+ // we need the *maximum* SIFA (`Write` needs more fixup than `None`) .
663+ self . update_last_accessed_after_retag ( parent_idx, max_sifa ) ;
682664
683665 interp_ok ( ( ) )
684666 }
@@ -755,9 +737,9 @@ impl<'tcx> Tree {
755737 == Some ( & ProtectorKind :: StrongProtector )
756738 // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
757739 // Related to https://github.com/rust-lang/rust/issues/55005.
758- && !perm. permission ( ) . is_cell ( )
740+ && !perm. permission . is_cell ( )
759741 // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
760- && perm. is_accessed ( )
742+ && perm. accessed
761743 {
762744 Err ( TransitionError :: ProtectedDealloc )
763745 } else {
@@ -790,7 +772,7 @@ impl<'tcx> Tree {
790772 /// - the access will be applied only to accessed locations of the allocation,
791773 /// - it will not be visible to children,
792774 /// - it will be recorded as a `FnExit` diagnostic access
793- /// - and it will be a read except if the location is `Active `, i.e. has been written to,
775+ /// - and it will be a read except if the location is `Unique `, i.e. has been written to,
794776 /// in which case it will be a write.
795777 ///
796778 /// `LocationState::perform_access` will take care of raising transition
0 commit comments