Skip to content

Commit ed768d3

Browse files
authored
Merge pull request #4741 from royAmmerschuber/feature/refactor-protector-release
TreeBorrows: split `Tree::perform_protector_release_access` from `Tree::perform_access`
2 parents 001d2f7 + c033444 commit ed768d3

File tree

2 files changed

+71
-58
lines changed

2 files changed

+71
-58
lines changed

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ impl<'tcx> Tree {
6060
let span = machine.current_user_relevant_span();
6161
self.perform_access(
6262
prov,
63-
Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))),
63+
range,
64+
access_kind,
65+
diagnostics::AccessCause::Explicit(access_kind),
6466
global,
6567
alloc_id,
6668
span,
@@ -94,8 +96,7 @@ impl<'tcx> Tree {
9496
alloc_id: AllocId, // diagnostics
9597
) -> InterpResult<'tcx> {
9698
let span = machine.current_user_relevant_span();
97-
// `None` makes it the magic on-protector-end operation
98-
self.perform_access(ProvenanceExtra::Concrete(tag), None, global, alloc_id, span)?;
99+
self.perform_protector_end_access(tag, global, alloc_id, span)?;
99100

100101
self.update_exposure_for_protector_release(tag);
101102

@@ -344,7 +345,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
344345

345346
tree_borrows.perform_access(
346347
parent_prov,
347-
Some((range_in_alloc, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
348+
range_in_alloc,
349+
AccessKind::Read,
350+
diagnostics::AccessCause::Reborrow,
348351
this.machine.borrow_tracker.as_ref().unwrap(),
349352
alloc_id,
350353
this.machine.current_user_relevant_span(),

src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,9 @@ impl<'tcx> Tree {
544544
) -> InterpResult<'tcx> {
545545
self.perform_access(
546546
prov,
547-
Some((access_range, AccessKind::Write, diagnostics::AccessCause::Dealloc)),
547+
access_range,
548+
AccessKind::Write,
549+
diagnostics::AccessCause::Dealloc,
548550
global,
549551
alloc_id,
550552
span,
@@ -620,14 +622,6 @@ impl<'tcx> Tree {
620622
/// to each location of the first component of `access_range_and_kind`,
621623
/// on every tag of the allocation.
622624
///
623-
/// If `access_range_and_kind` is `None`, this is interpreted as the special
624-
/// access that is applied on protector release:
625-
/// - the access will be applied only to accessed locations of the allocation,
626-
/// - it will not be visible to children,
627-
/// - it will be recorded as a `FnExit` diagnostic access
628-
/// - and it will be a read except if the location is `Unique`, i.e. has been written to,
629-
/// in which case it will be a write.
630-
///
631625
/// `LocationState::perform_access` will take care of raising transition
632626
/// errors and updating the `accessed` status of each location,
633627
/// this traversal adds to that:
@@ -637,7 +631,9 @@ impl<'tcx> Tree {
637631
pub fn perform_access(
638632
&mut self,
639633
prov: ProvenanceExtra,
640-
access_range_and_kind: Option<(AllocRange, AccessKind, diagnostics::AccessCause)>,
634+
access_range: AllocRange,
635+
access_kind: AccessKind,
636+
access_cause: AccessCause, // diagnostics
641637
global: &GlobalState,
642638
alloc_id: AllocId, // diagnostics
643639
span: Span, // diagnostics
@@ -651,61 +647,75 @@ impl<'tcx> Tree {
651647
ProvenanceExtra::Concrete(tag) => Some(self.tag_mapping.get(&tag).unwrap()),
652648
ProvenanceExtra::Wildcard => None,
653649
};
654-
if let Some((access_range, access_kind, access_cause)) = access_range_and_kind {
655-
// Default branch: this is a "normal" access through a known range.
656-
// We iterate over affected locations and traverse the tree for each of them.
657-
for (loc_range, loc) in self.locations.iter_mut(access_range.start, access_range.size) {
650+
// We iterate over affected locations and traverse the tree for each of them.
651+
for (loc_range, loc) in self.locations.iter_mut(access_range.start, access_range.size) {
652+
loc.perform_access(
653+
self.roots.iter().copied(),
654+
&mut self.nodes,
655+
source_idx,
656+
loc_range,
657+
Some(access_range),
658+
access_kind,
659+
access_cause,
660+
global,
661+
alloc_id,
662+
span,
663+
ChildrenVisitMode::VisitChildrenOfAccessed,
664+
)?;
665+
}
666+
interp_ok(())
667+
}
668+
/// This is the special access that is applied on protector release:
669+
/// - the access will be applied only to accessed locations of the allocation,
670+
/// - it will not be visible to children,
671+
/// - it will be recorded as a `FnExit` diagnostic access
672+
/// - and it will be a read except if the location is `Unique`, i.e. has been written to,
673+
/// in which case it will be a write.
674+
/// - otherwise identical to `Tree::perform_access`
675+
pub fn perform_protector_end_access(
676+
&mut self,
677+
tag: BorTag,
678+
global: &GlobalState,
679+
alloc_id: AllocId, // diagnostics
680+
span: Span, // diagnostics
681+
) -> InterpResult<'tcx> {
682+
#[cfg(feature = "expensive-consistency-checks")]
683+
if self.roots.len() > 1 {
684+
self.verify_wildcard_consistency(global);
685+
}
686+
687+
let source_idx = self.tag_mapping.get(&tag).unwrap();
688+
689+
// This is a special access through the entire allocation.
690+
// It actually only affects `accessed` locations, so we need
691+
// to filter on those before initiating the traversal.
692+
//
693+
// In addition this implicit access should not be visible to children,
694+
// thus the use of `traverse_nonchildren`.
695+
// See the test case `returned_mut_is_usable` from
696+
// `tests/pass/tree_borrows/tree-borrows.rs` for an example of
697+
// why this is important.
698+
for (loc_range, loc) in self.locations.iter_mut_all() {
699+
// Only visit accessed permissions
700+
if let Some(p) = loc.perms.get(source_idx)
701+
&& let Some(access_kind) = p.permission.protector_end_access()
702+
&& p.accessed
703+
{
704+
let access_cause = diagnostics::AccessCause::FnExit(access_kind);
658705
loc.perform_access(
659706
self.roots.iter().copied(),
660707
&mut self.nodes,
661-
source_idx,
708+
Some(source_idx),
662709
loc_range,
663-
Some(access_range),
710+
None,
664711
access_kind,
665712
access_cause,
666713
global,
667714
alloc_id,
668715
span,
669-
ChildrenVisitMode::VisitChildrenOfAccessed,
716+
ChildrenVisitMode::SkipChildrenOfAccessed,
670717
)?;
671718
}
672-
} else {
673-
// This is a special access through the entire allocation.
674-
// It actually only affects `accessed` locations, so we need
675-
// to filter on those before initiating the traversal.
676-
//
677-
// In addition this implicit access should not be visible to children,
678-
// thus the use of `traverse_nonchildren`.
679-
// See the test case `returned_mut_is_usable` from
680-
// `tests/pass/tree_borrows/tree-borrows.rs` for an example of
681-
// why this is important.
682-
683-
// Wildcard references are never protected. So this can never be
684-
// called with a wildcard reference.
685-
let source_idx = source_idx.unwrap();
686-
687-
for (loc_range, loc) in self.locations.iter_mut_all() {
688-
// Only visit accessed permissions
689-
if let Some(p) = loc.perms.get(source_idx)
690-
&& let Some(access_kind) = p.permission.protector_end_access()
691-
&& p.accessed
692-
{
693-
let access_cause = diagnostics::AccessCause::FnExit(access_kind);
694-
loc.perform_access(
695-
self.roots.iter().copied(),
696-
&mut self.nodes,
697-
Some(source_idx),
698-
loc_range,
699-
None,
700-
access_kind,
701-
access_cause,
702-
global,
703-
alloc_id,
704-
span,
705-
ChildrenVisitMode::SkipChildrenOfAccessed,
706-
)?;
707-
}
708-
}
709719
}
710720
interp_ok(())
711721
}

0 commit comments

Comments
 (0)