@@ -392,7 +392,7 @@ impl<'tcx> Stack {
392
392
393
393
// Step 1: Find granting item.
394
394
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 ) ) ?;
396
396
397
397
// Step 2: Remove incompatible items above them. Make sure we do not remove protected
398
398
// items. Behavior differs for reads and writes.
@@ -476,8 +476,7 @@ impl<'tcx> Stack {
476
476
) -> InterpResult < ' tcx > {
477
477
// Step 1: Make a write access.
478
478
// 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) ?;
481
480
482
481
// Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
483
482
for idx in ( 0 ..self . len ( ) ) . rev ( ) {
@@ -489,39 +488,42 @@ impl<'tcx> Stack {
489
488
}
490
489
491
490
/// 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.
497
493
fn grant (
498
494
& mut self ,
499
495
derived_from : ProvenanceExtra ,
500
496
new : Item ,
497
+ access : Option < AccessKind > ,
501
498
global : & GlobalStateInner ,
502
499
dcx : & mut DiagnosticCx < ' _ , ' _ , ' _ , ' tcx > ,
503
500
exposed_tags : & FxHashSet < SbTag > ,
504
501
) -> InterpResult < ' tcx > {
505
502
dcx. start_grant ( new. perm ( ) ) ;
506
503
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
-
517
504
// Compute where to put the new item.
518
505
// Either way, we ensure that we insert the new item in a way such that between
519
506
// `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 ) ) ?;
525
527
526
528
let ( Some ( granting_idx) , ProvenanceExtra :: Concrete ( _) ) = ( granting_idx, derived_from) else {
527
529
// The parent is a wildcard pointer or matched the unknown bottom.
@@ -538,17 +540,6 @@ impl<'tcx> Stack {
538
540
// be popped to (i.e., we insert it above all the write-compatible items).
539
541
// This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`.
540
542
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 ( )
552
543
} ;
553
544
554
545
// Put the new item there.
@@ -864,18 +855,22 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
864
855
// Update the stacks.
865
856
// Make sure that raw pointers and mutable shared references are reborrowed "weak":
866
857
// 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)
873
869
}
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 )
877
873
}
878
- RefKind :: Raw { mutable : true } => Permission :: SharedReadWrite ,
879
874
RefKind :: Shared | RefKind :: Raw { mutable : false } => {
880
875
// Shared references and *const are a whole different kind of game, the
881
876
// permission is not uniform across the entire range!
@@ -892,10 +887,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
892
887
// Adjust range.
893
888
range. start += base_offset;
894
889
// 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 ) )
897
892
} 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 )
899
897
} ;
900
898
let protected = if frozen {
901
899
protect. is_some ( )
@@ -914,7 +912,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
914
912
alloc_range ( base_offset, size) ,
915
913
) ;
916
914
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)
918
916
} )
919
917
} ) ?;
920
918
return Ok ( Some ( alloc_id) ) ;
@@ -941,7 +939,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
941
939
alloc_range ( base_offset, size) ,
942
940
) ;
943
941
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)
945
943
} ) ?;
946
944
947
945
Ok ( Some ( alloc_id) )
0 commit comments