@@ -312,8 +312,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
312312 }
313313
314314 let span = this. machine . current_span ( ) ;
315- let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
316- let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
317315
318316 // Store initial permissions and their corresponding range.
319317 let mut perms_map: RangeMap < LocationState > = RangeMap :: new (
@@ -342,36 +340,83 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
342340 assert ! ( new_perm. freeze_access) ;
343341
344342 let protected = new_perm. protector . is_some ( ) ;
345- this. visit_freeze_sensitive ( place, ptr_size, |range, frozen| {
346- has_unsafe_cell = has_unsafe_cell || !frozen;
347-
348- // We are only ever `Frozen` inside the frozen bits.
349- let ( perm, access) = if frozen {
343+ let precise_interior_mut = this
344+ . machine
345+ . borrow_tracker
346+ . as_mut ( )
347+ . unwrap ( )
348+ . get_mut ( )
349+ . borrow_tracker_method
350+ . get_tree_borrows_params ( )
351+ . precise_interior_mut ;
352+
353+ let default_perm = if !precise_interior_mut {
354+ // NOTE: Using `ty_is_freeze` doesn't give the same result as going through the range
355+ // and computing `has_unsafe_cell`. This is because of zero-sized `UnsafeCell`, for which
356+ // `has_unsafe_cell` is false, but `!ty_is_freeze` is true.
357+ let ty_is_freeze = place. layout . ty . is_freeze ( * this. tcx , this. typing_env ( ) ) ;
358+ let ( perm, access) = if ty_is_freeze {
350359 ( new_perm. freeze_perm , new_perm. freeze_access )
351360 } else {
352361 ( new_perm. nonfreeze_perm , new_perm. nonfreeze_access )
353362 } ;
363+ let sifa = perm. strongest_idempotent_foreign_access ( protected) ;
364+ let new_loc = if access {
365+ LocationState :: new_accessed ( perm, sifa)
366+ } else {
367+ LocationState :: new_non_accessed ( perm, sifa)
368+ } ;
369+
370+ for ( _loc_range, loc) in perms_map. iter_mut_all ( ) {
371+ * loc = new_loc;
372+ }
373+
374+ perm
375+ } else {
376+ this. visit_freeze_sensitive ( place, ptr_size, |range, frozen| {
377+ has_unsafe_cell = has_unsafe_cell || !frozen;
354378
355- // Store initial permissions.
356- for ( _loc_range, loc) in perms_map. iter_mut ( range. start , range. size ) {
379+ // We are only ever `Frozen` inside the frozen bits.
380+ let ( perm, access) = if frozen {
381+ ( new_perm. freeze_perm , new_perm. freeze_access )
382+ } else {
383+ ( new_perm. nonfreeze_perm , new_perm. nonfreeze_access )
384+ } ;
357385 let sifa = perm. strongest_idempotent_foreign_access ( protected) ;
358386 // NOTE: Currently, `access` is false if and only if `perm` is Cell, so this `if`
359387 // doesn't not change whether any code is UB or not. We could just always use
360388 // `new_accessed` and everything would stay the same. But that seems conceptually
361389 // odd, so we keep the initial "accessed" bit of the `LocationState` in sync with whether
362390 // a read access is performed below.
363- if access {
364- * loc = LocationState :: new_accessed ( perm, sifa) ;
391+ let new_loc = if access {
392+ LocationState :: new_accessed ( perm, sifa)
365393 } else {
366- * loc = LocationState :: new_non_accessed ( perm, sifa) ;
394+ LocationState :: new_non_accessed ( perm, sifa)
395+ } ;
396+
397+ // Store initial permissions.
398+ for ( _loc_range, loc) in perms_map. iter_mut ( range. start , range. size ) {
399+ * loc = new_loc;
367400 }
368- }
369401
370- // Some reborrows incur a read access to the parent.
371- if access {
402+ interp_ok ( ( ) )
403+ } ) ?;
404+
405+ // Allow lazily writing to surrounding data if we found an `UnsafeCell`.
406+ if has_unsafe_cell { new_perm. nonfreeze_perm } else { new_perm. freeze_perm }
407+ } ;
408+
409+ let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
410+ let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
411+
412+ for ( perm_range, perm) in perms_map. iter_mut_all ( ) {
413+ if perm. is_accessed ( ) {
414+ // Some reborrows incur a read access to the parent.
372415 // Adjust range to be relative to allocation start (rather than to `place`).
373- let mut range_in_alloc = range;
374- range_in_alloc. start += base_offset;
416+ let range_in_alloc = AllocRange {
417+ start : Size :: from_bytes ( perm_range. start ) + base_offset,
418+ size : Size :: from_bytes ( perm_range. end - perm_range. start ) ,
419+ } ;
375420
376421 tree_borrows. perform_access (
377422 orig_tag,
@@ -382,7 +427,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
382427 ) ?;
383428
384429 // Also inform the data race model (but only if any bytes are actually affected).
385- if range . size . bytes ( ) > 0 {
430+ if range_in_alloc . size . bytes ( ) > 0 {
386431 if let Some ( data_race) = alloc_extra. data_race . as_vclocks_ref ( ) {
387432 data_race. read (
388433 alloc_id,
@@ -394,17 +439,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
394439 }
395440 }
396441 }
397- interp_ok ( ( ) )
398- } ) ?;
442+ }
399443
400444 // Record the parent-child pair in the tree.
401445 tree_borrows. new_child (
402446 base_offset,
403447 orig_tag,
404448 new_tag,
405449 perms_map,
406- // Allow lazily writing to surrounding data if we found an `UnsafeCell`.
407- if has_unsafe_cell { new_perm. nonfreeze_perm } else { new_perm. freeze_perm } ,
450+ default_perm,
408451 protected,
409452 span,
410453 ) ?;
0 commit comments