Skip to content

Commit e2c7e74

Browse files
authored
Merge pull request #4707 from royAmmerschuber/feature/wildcard-root
Support retagging of wildcard references in tree borrows
2 parents 092a83d + e1c480e commit e2c7e74

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1669
-303
lines changed

src/borrow_tracker/tree_borrows/diagnostics.rs

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ struct DisplayFmtPadding {
488488
indent_middle: S,
489489
/// Indentation for the last child.
490490
indent_last: S,
491+
/// Replaces `join_last` for a wildcard root.
492+
wildcard_root: S,
491493
}
492494
/// How to show whether a location has been accessed
493495
///
@@ -561,6 +563,11 @@ impl DisplayFmt {
561563
})
562564
.unwrap_or("")
563565
}
566+
567+
/// Print extra text if the tag is exposed.
568+
fn print_exposed(&self, exposed: bool) -> S {
569+
if exposed { " (exposed)" } else { "" }
570+
}
564571
}
565572

566573
/// Track the indentation of the tree.
@@ -607,23 +614,21 @@ fn char_repeat(c: char, n: usize) -> String {
607614
struct DisplayRepr {
608615
tag: BorTag,
609616
name: Option<String>,
617+
exposed: bool,
610618
rperm: Vec<Option<LocationState>>,
611619
children: Vec<DisplayRepr>,
612620
}
613621

614622
impl DisplayRepr {
615-
fn from(tree: &Tree, show_unnamed: bool) -> Option<Self> {
623+
fn from(tree: &Tree, root: UniIndex, show_unnamed: bool) -> Option<Self> {
616624
let mut v = Vec::new();
617-
extraction_aux(tree, tree.root, show_unnamed, &mut v);
625+
extraction_aux(tree, root, show_unnamed, &mut v);
618626
let Some(root) = v.pop() else {
619627
if show_unnamed {
620628
unreachable!(
621629
"This allocation contains no tags, not even a root. This should not happen."
622630
);
623631
}
624-
eprintln!(
625-
"This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
626-
);
627632
return None;
628633
};
629634
assert!(v.is_empty());
@@ -637,6 +642,7 @@ impl DisplayRepr {
637642
) {
638643
let node = tree.nodes.get(idx).unwrap();
639644
let name = node.debug_info.name.clone();
645+
let exposed = node.is_exposed;
640646
let children_sorted = {
641647
let mut children = node.children.iter().cloned().collect::<Vec<_>>();
642648
children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag);
@@ -661,12 +667,13 @@ impl DisplayRepr {
661667
for child_idx in children_sorted {
662668
extraction_aux(tree, child_idx, show_unnamed, &mut children);
663669
}
664-
acc.push(DisplayRepr { tag: node.tag, name, rperm, children });
670+
acc.push(DisplayRepr { tag: node.tag, name, rperm, children, exposed });
665671
}
666672
}
667673
}
668674
fn print(
669-
&self,
675+
main_root: &Option<DisplayRepr>,
676+
wildcard_subtrees: &[DisplayRepr],
670677
fmt: &DisplayFmt,
671678
indenter: &mut DisplayIndent,
672679
protected_tags: &FxHashMap<BorTag, ProtectorKind>,
@@ -703,15 +710,41 @@ impl DisplayRepr {
703710
block.push(s);
704711
}
705712
// This is the actual work
706-
print_aux(
707-
self,
708-
&range_padding,
709-
fmt,
710-
indenter,
711-
protected_tags,
712-
true, /* root _is_ the last child */
713-
&mut block,
714-
);
713+
if let Some(root) = main_root {
714+
print_aux(
715+
root,
716+
&range_padding,
717+
fmt,
718+
indenter,
719+
protected_tags,
720+
true, /* root _is_ the last child */
721+
false, /* not a wildcard_root*/
722+
&mut block,
723+
);
724+
}
725+
for tree in wildcard_subtrees.iter() {
726+
let mut gap_line = String::new();
727+
gap_line.push_str(fmt.perm.open);
728+
for (i, &pad) in range_padding.iter().enumerate() {
729+
if i > 0 {
730+
gap_line.push_str(fmt.perm.sep);
731+
}
732+
gap_line.push_str(&format!("{}{}", char_repeat(' ', pad), " "));
733+
}
734+
gap_line.push_str(fmt.perm.close);
735+
block.push(gap_line);
736+
737+
print_aux(
738+
tree,
739+
&range_padding,
740+
fmt,
741+
indenter,
742+
protected_tags,
743+
true, /* root _is_ the last child */
744+
true, /* wildcard_root*/
745+
&mut block,
746+
);
747+
}
715748
// Then it's just prettifying it with a border of dashes.
716749
{
717750
let wr = &fmt.wrapper;
@@ -741,6 +774,7 @@ impl DisplayRepr {
741774
indent: &mut DisplayIndent,
742775
protected_tags: &FxHashMap<BorTag, ProtectorKind>,
743776
is_last_child: bool,
777+
is_wildcard_root: bool,
744778
acc: &mut Vec<String>,
745779
) {
746780
let mut line = String::new();
@@ -760,7 +794,9 @@ impl DisplayRepr {
760794
indent.write(&mut line);
761795
{
762796
// padding
763-
line.push_str(if is_last_child {
797+
line.push_str(if is_wildcard_root {
798+
fmt.padding.wildcard_root
799+
} else if is_last_child {
764800
fmt.padding.join_last
765801
} else {
766802
fmt.padding.join_middle
@@ -777,12 +813,22 @@ impl DisplayRepr {
777813
line.push_str(&fmt.print_tag(tree.tag, &tree.name));
778814
let protector = protected_tags.get(&tree.tag);
779815
line.push_str(fmt.print_protector(protector));
816+
line.push_str(fmt.print_exposed(tree.exposed));
780817
// Push the line to the accumulator then recurse.
781818
acc.push(line);
782819
let nb_children = tree.children.len();
783820
for (i, child) in tree.children.iter().enumerate() {
784821
indent.increment(fmt, is_last_child);
785-
print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc);
822+
print_aux(
823+
child,
824+
padding,
825+
fmt,
826+
indent,
827+
protected_tags,
828+
/* is_last_child */ i + 1 == nb_children,
829+
/* is_wildcard_root */ false,
830+
acc,
831+
);
786832
indent.decrement(fmt);
787833
}
788834
}
@@ -803,6 +849,7 @@ const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt {
803849
indent_last: " ",
804850
join_haschild: "┬",
805851
join_default: "─",
852+
wildcard_root: "*",
806853
},
807854
accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" },
808855
};
@@ -816,15 +863,27 @@ impl<'tcx> Tree {
816863
) -> InterpResult<'tcx> {
817864
let mut indenter = DisplayIndent::new();
818865
let ranges = self.locations.iter_all().map(|(range, _loc)| range).collect::<Vec<_>>();
819-
if let Some(repr) = DisplayRepr::from(self, show_unnamed) {
820-
repr.print(
821-
&DEFAULT_FORMATTER,
822-
&mut indenter,
823-
protected_tags,
824-
ranges,
825-
/* print warning message about tags not shown */ !show_unnamed,
866+
let main_tree = DisplayRepr::from(self, self.roots[0], show_unnamed);
867+
let wildcard_subtrees = self.roots[1..]
868+
.iter()
869+
.filter_map(|root| DisplayRepr::from(self, *root, show_unnamed))
870+
.collect::<Vec<_>>();
871+
872+
if main_tree.is_none() && wildcard_subtrees.is_empty() {
873+
eprintln!(
874+
"This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
826875
);
827876
}
877+
878+
DisplayRepr::print(
879+
&main_tree,
880+
wildcard_subtrees.as_slice(),
881+
&DEFAULT_FORMATTER,
882+
&mut indenter,
883+
protected_tags,
884+
ranges,
885+
/* print warning message about tags not shown */ !show_unnamed,
886+
);
828887
interp_ok(())
829888
}
830889
}

src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -239,18 +239,14 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
239239
return interp_ok(new_prov);
240240
}
241241
};
242+
let new_prov = Provenance::Concrete { alloc_id, tag: new_tag };
242243

243244
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
244245

245-
let orig_tag = match parent_prov {
246-
ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle retagging wildcard pointers
247-
ProvenanceExtra::Concrete(tag) => tag,
248-
};
249-
250246
trace!(
251247
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
252248
new_tag,
253-
orig_tag,
249+
parent_prov,
254250
place.layout.ty,
255251
interpret::Pointer::new(alloc_id, base_offset),
256252
ptr_size.bytes()
@@ -281,7 +277,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
281277
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
282278
// There's not actually any bytes here where accesses could even be tracked.
283279
// Just produce the new provenance, nothing else to do.
284-
return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
280+
return interp_ok(Some(new_prov));
285281
}
286282

287283
let protected = new_perm.protector.is_some();
@@ -367,11 +363,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
367363
}
368364
}
369365
}
370-
371366
// Record the parent-child pair in the tree.
372367
tree_borrows.new_child(
373368
base_offset,
374-
orig_tag,
369+
parent_prov,
375370
new_tag,
376371
inside_perms,
377372
new_perm.outside_perm,
@@ -380,7 +375,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
380375
)?;
381376
drop(tree_borrows);
382377

383-
interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
378+
interp_ok(Some(new_prov))
384379
}
385380

386381
fn tb_retag_place(

0 commit comments

Comments
 (0)