Skip to content

Commit 6d02243

Browse files
authored
Factor: collapse triplicated alloc recovery into one arm (#135)
This is a follow-up to #131. That PR fixed a real panic (non-builtin-deref Static/VTable allocations), but the fix landed as three nearly identical match arms: Static, VTable, and Function, each repeating the same "try `get_prov_ty`, fall back to opaque placeholder" logic. The only meaningful difference between them was a single predicate ("is this type usable directly?") and the debug log string. This PR collapses them back into one arm, makes the predicate explicit, and documents a previously unexplained jq filter. ## What changed **`src/printer/mir_visitor.rs`** The three arms now share a single code path. The predicate that actually differs between them is captured in a `needs_recovery` variable: - Static/VTable: `builtin_deref(true).is_none()` (not a reference, raw pointer, or Box) - Function: `!kind.is_fn_ptr()` (outer type isn't already a function pointer) Worth noting: these two predicates are *not* equivalent (a function pointer passes `builtin_deref` but fails `is_fn_ptr`), which is why a naive "just combine the arms" without the inner match would have changed behavior for Function allocs. The inner match on `global_alloc` makes this asymmetry visible rather than hiding it across separate arms. The rest of the logic (try `get_prov_ty`, fall back to opaque placeholder) is written once. Also dropped an unnecessary `.clone()` on the `builtin_deref` call; it takes `&self`. **`tests/integration/normalise-filter.jq`** The `def_id` filter had a terse comment ("unrelated to this regression") that didn't explain *why* it exists or why it's safe to strip globally. Replaced it with a proper explanation: `def_id` values are interned compiler indices (same class as `alloc_id` and `adt_def`) that are consistent within a single rustc invocation but non-deterministic across runs. Downstream consumers need them as cross-reference keys to join `AggregateKind::Adt` in MIR bodies with type metadata entries, so they can't be dropped from the output itself; we only strip them here for golden-file comparison. (See #125 for the full picture on interned-index non-determinism.) ## Test plan - [ ] `cargo build` compiles cleanly - [ ] `make integration-test` passes (no behavioral change; this is a pure refactor)
1 parent 047ca6a commit 6d02243

2 files changed

Lines changed: 22 additions & 61 deletions

File tree

src/printer/mir_visitor.rs

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,21 @@ fn collect_alloc(
265265
.insert(val, (opaque_placeholder_ty(), global_alloc.clone()));
266266
}
267267
}
268-
GlobalAlloc::Static(_) => {
269-
// Keep builtin-deref behavior; recover only non-builtin-deref cases.
270-
if kind.clone().builtin_deref(true).is_none() {
268+
GlobalAlloc::Static(_) | GlobalAlloc::VTable(_, _) | GlobalAlloc::Function(_) => {
269+
// Does the outer type need provenance recovery to find the real
270+
// pointee? Static/VTable pointers are usable directly when
271+
// builtin_deref succeeds; Function allocs are usable directly
272+
// when the outer type is already a fn pointer.
273+
let needs_recovery = match &global_alloc {
274+
GlobalAlloc::Function(_) => !kind.is_fn_ptr(),
275+
_ => kind.builtin_deref(true).is_none(),
276+
};
277+
278+
if needs_recovery {
271279
let prov_ty = get_prov_ty(ty, &offset);
272280
debug_log_println!(
273-
"DEBUG: GlobalAlloc::Static with non-builtin-deref type; alloc_id={:?}, ty={:?}, offset={}, kind={:?}, recovered_prov_ty={:?}",
281+
"DEBUG: {:?} with non-direct type; alloc_id={:?}, ty={:?}, offset={}, kind={:?}, recovered_prov_ty={:?}",
282+
global_alloc,
274283
val,
275284
ty,
276285
offset,
@@ -288,62 +297,7 @@ fn collect_alloc(
288297
.insert(val, (opaque_placeholder_ty(), global_alloc.clone()));
289298
}
290299
} else {
291-
val_collector
292-
.visited_allocs
293-
.insert(val, (ty, global_alloc.clone()));
294-
}
295-
}
296-
GlobalAlloc::VTable(_, _) => {
297-
// Same policy as Static: keep builtin-deref, recover non-builtin-deref.
298-
if kind.clone().builtin_deref(true).is_none() {
299-
let prov_ty = get_prov_ty(ty, &offset);
300-
debug_log_println!(
301-
"DEBUG: GlobalAlloc::VTable with non-builtin-deref type; alloc_id={:?}, ty={:?}, offset={}, kind={:?}, recovered_prov_ty={:?}",
302-
val,
303-
ty,
304-
offset,
305-
kind,
306-
prov_ty
307-
);
308-
if let Some(p_ty) = prov_ty {
309-
val_collector
310-
.visited_allocs
311-
.insert(val, (p_ty, global_alloc.clone()));
312-
} else {
313-
// Unknown is safer than wrong pointee type.
314-
val_collector
315-
.visited_allocs
316-
.insert(val, (opaque_placeholder_ty(), global_alloc.clone()));
317-
}
318-
} else {
319-
val_collector
320-
.visited_allocs
321-
.insert(val, (ty, global_alloc.clone()));
322-
}
323-
}
324-
GlobalAlloc::Function(_) => {
325-
if !kind.is_fn_ptr() {
326-
let prov_ty = get_prov_ty(ty, &offset);
327-
debug_log_println!(
328-
"DEBUG: GlobalAlloc::Function with non-fn-ptr type; alloc_id={:?}, ty={:?}, offset={}, kind={:?}, recovered_prov_ty={:?}",
329-
val,
330-
ty,
331-
offset,
332-
kind,
333-
prov_ty
334-
);
335-
if let Some(p_ty) = prov_ty {
336-
val_collector
337-
.visited_allocs
338-
.insert(val, (p_ty, global_alloc.clone()));
339-
} else {
340-
// Could not recover a precise pointee type; use an opaque 0-valued Ty
341-
// as a conservative placeholder.
342-
val_collector
343-
.visited_allocs
344-
.insert(val, (opaque_placeholder_ty(), global_alloc.clone()));
345-
}
346-
} else {
300+
// Type is already the correct pointee; use it directly.
347301
val_collector
348302
.visited_allocs
349303
.insert(val, (ty, global_alloc.clone()));

tests/integration/normalise-filter.jq

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,12 @@
2929
( .types | map(select(.[0].FunType) | sort) )
3030
] | flatten(1) )
3131
}
32-
# drop unstable compiler-internal ids that are unrelated to this regression
32+
# Strip def_id fields globally. These are interned compiler indices (the
33+
# underlying ID inside AdtDef) that are consistent within a single rustc
34+
# invocation but not stable across runs; the same non-determinism that
35+
# affects alloc_id, Ty indices, and adt_def (see lines 5-6, 18-21 above).
36+
# Downstream consumers use adt_def/def_id as cross-reference keys to join
37+
# AggregateKind::Adt in MIR bodies with type metadata entries, so the
38+
# values can't be dropped from the output itself; we only strip them here
39+
# for golden-file comparison.
3340
| walk(if type == "object" then del(.def_id) else . end)

0 commit comments

Comments
 (0)