@@ -392,7 +392,7 @@ impl<'tcx> Stack {
392392
393393 // Step 1: Find granting item.
394394 let granting_idx =
395- self . find_granting ( access, tag, exposed_tags) . map_err ( |_ | dcx. access_error ( self ) ) ?;
395+ self . find_granting ( access, tag, exposed_tags) . map_err ( |( ) | dcx. access_error ( self ) ) ?;
396396
397397 // Step 2: Remove incompatible items above them. Make sure we do not remove protected
398398 // items. Behavior differs for reads and writes.
@@ -476,8 +476,7 @@ impl<'tcx> Stack {
476476 ) -> InterpResult < ' tcx > {
477477 // Step 1: Make a write access.
478478 // As part of this we do regular protector checking, i.e. even weakly protected items cause UB when popped.
479- self . access ( AccessKind :: Write , tag, global, dcx, exposed_tags)
480- . map_err ( |_| dcx. dealloc_error ( ) ) ?;
479+ self . access ( AccessKind :: Write , tag, global, dcx, exposed_tags) ?;
481480
482481 // Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
483482 for idx in ( 0 ..self . len ( ) ) . rev ( ) {
@@ -489,39 +488,42 @@ impl<'tcx> Stack {
489488 }
490489
491490 /// Derive a new pointer from one with the given tag.
492- /// `weak` controls whether this operation is weak or strong: weak granting does not act as
493- /// an access, and they add the new item directly on top of the one it is derived
494- /// from instead of all the way at the top of the stack.
495- /// `range` refers the entire operation, and `offset` refers to the specific location in
496- /// `range` that we are currently checking.
491+ ///
492+ /// `access` indicates which kind of memory access this retag itself should correspond to.
497493 fn grant (
498494 & mut self ,
499495 derived_from : ProvenanceExtra ,
500496 new : Item ,
497+ access : Option < AccessKind > ,
501498 global : & GlobalStateInner ,
502499 dcx : & mut DiagnosticCx < ' _ , ' _ , ' _ , ' tcx > ,
503500 exposed_tags : & FxHashSet < SbTag > ,
504501 ) -> InterpResult < ' tcx > {
505502 dcx. start_grant ( new. perm ( ) ) ;
506503
507- // Figure out which access `perm` corresponds to.
508- let access =
509- if new. perm ( ) . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
510-
511- // Now we figure out which item grants our parent (`derived_from`) this kind of access.
512- // We use that to determine where to put the new item.
513- let granting_idx = self
514- . find_granting ( access, derived_from, exposed_tags)
515- . map_err ( |_| dcx. grant_error ( new. perm ( ) , self ) ) ?;
516-
517504 // Compute where to put the new item.
518505 // Either way, we ensure that we insert the new item in a way such that between
519506 // `derived_from` and the new one, there are only items *compatible with* `derived_from`.
520- let new_idx = if new. perm ( ) == Permission :: SharedReadWrite {
521- assert ! (
522- access == AccessKind :: Write ,
523- "this case only makes sense for stack-like accesses"
524- ) ;
507+ let new_idx = if let Some ( access) = access {
508+ // Simple case: We are just a regular memory access, and then push our thing on top,
509+ // like a regular stack.
510+ // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
511+ self . access ( access, derived_from, global, dcx, exposed_tags) ?;
512+
513+ // We insert "as far up as possible": We know only compatible items are remaining
514+ // on top of `derived_from`, and we want the new item at the top so that we
515+ // get the strongest possible guarantees.
516+ // This ensures U1 and F1.
517+ self . len ( )
518+ } else {
519+ // The tricky case: creating a new SRW permission without actually being an access.
520+ assert ! ( new. perm( ) == Permission :: SharedReadWrite ) ;
521+
522+ // First we figure out which item grants our parent (`derived_from`) this kind of access.
523+ // We use that to determine where to put the new item.
524+ let granting_idx = self
525+ . find_granting ( AccessKind :: Write , derived_from, exposed_tags)
526+ . map_err ( |( ) | dcx. grant_error ( self ) ) ?;
525527
526528 let ( Some ( granting_idx) , ProvenanceExtra :: Concrete ( _) ) = ( granting_idx, derived_from) else {
527529 // The parent is a wildcard pointer or matched the unknown bottom.
@@ -538,17 +540,6 @@ impl<'tcx> Stack {
538540 // be popped to (i.e., we insert it above all the write-compatible items).
539541 // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`.
540542 self . find_first_write_incompatible ( granting_idx)
541- } else {
542- // A "safe" reborrow for a pointer that actually expects some aliasing guarantees.
543- // Here, creating a reference actually counts as an access.
544- // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
545- self . access ( access, derived_from, global, dcx, exposed_tags) ?;
546-
547- // We insert "as far up as possible": We know only compatible items are remaining
548- // on top of `derived_from`, and we want the new item at the top so that we
549- // get the strongest possible guarantees.
550- // This ensures U1 and F1.
551- self . len ( )
552543 } ;
553544
554545 // Put the new item there.
@@ -864,18 +855,22 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
864855 // Update the stacks.
865856 // Make sure that raw pointers and mutable shared references are reborrowed "weak":
866857 // There could be existing unique pointers reborrowed from them that should remain valid!
867- let perm = match kind {
868- RefKind :: Unique { two_phase : false }
869- if place. layout . ty . is_unpin ( * this. tcx , this. param_env ( ) ) =>
870- {
871- // Only if the type is unpin do we actually enforce uniqueness
872- Permission :: Unique
858+ let ( perm, access) = match kind {
859+ RefKind :: Unique { two_phase } => {
860+ // Permission is Unique only if the type is `Unpin` and this is not twophase
861+ let perm = if !two_phase && place. layout . ty . is_unpin ( * this. tcx , this. param_env ( ) ) {
862+ Permission :: Unique
863+ } else {
864+ Permission :: SharedReadWrite
865+ } ;
866+ // We do an access for all full borrows, even if `!Unpin`.
867+ let access = if !two_phase { Some ( AccessKind :: Write ) } else { None } ;
868+ ( perm, access)
873869 }
874- RefKind :: Unique { .. } => {
875- // Two-phase references and !Unpin references are treated as SharedReadWrite
876- Permission :: SharedReadWrite
870+ RefKind :: Raw { mutable : true } => {
871+ // Creating a raw ptr does not count as an access
872+ ( Permission :: SharedReadWrite , None )
877873 }
878- RefKind :: Raw { mutable : true } => Permission :: SharedReadWrite ,
879874 RefKind :: Shared | RefKind :: Raw { mutable : false } => {
880875 // Shared references and *const are a whole different kind of game, the
881876 // permission is not uniform across the entire range!
@@ -892,10 +887,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
892887 // Adjust range.
893888 range. start += base_offset;
894889 // We are only ever `SharedReadOnly` inside the frozen bits.
895- let perm = if frozen {
896- Permission :: SharedReadOnly
890+ let ( perm, access ) = if frozen {
891+ ( Permission :: SharedReadOnly , Some ( AccessKind :: Read ) )
897892 } else {
898- Permission :: SharedReadWrite
893+ // Inside UnsafeCell, this does *not* count as an access, as there
894+ // might actually be mutable references further up the stack that
895+ // we have to keep alive.
896+ ( Permission :: SharedReadWrite , None )
899897 } ;
900898 let protected = if frozen {
901899 protect. is_some ( )
@@ -914,7 +912,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
914912 alloc_range ( base_offset, size) ,
915913 ) ;
916914 stacked_borrows. for_each ( range, dcx, |stack, dcx, exposed_tags| {
917- stack. grant ( orig_tag, item, & global, dcx, exposed_tags)
915+ stack. grant ( orig_tag, item, access , & global, dcx, exposed_tags)
918916 } )
919917 } ) ?;
920918 return Ok ( Some ( alloc_id) ) ;
@@ -941,7 +939,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
941939 alloc_range ( base_offset, size) ,
942940 ) ;
943941 stacked_borrows. for_each ( range, dcx, |stack, dcx, exposed_tags| {
944- stack. grant ( orig_tag, item, & global, dcx, exposed_tags)
942+ stack. grant ( orig_tag, item, access , & global, dcx, exposed_tags)
945943 } ) ?;
946944
947945 Ok ( Some ( alloc_id) )
0 commit comments