The use-scan drops an unsafe block's trailing expression, and panics on any variant it does not list
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 14
- Forks
- 2
- Avg merge
- 12h 42m
- Merged PRs (30d)
- 61
Description
TypeChecker::extract_uses_expr (src/hir/env.rs) walks an expression collecting the names it reads. It serves two purposes: liveness and residency analysis, and — in the flat driver — discovering which imported functions a body calls, so their portable bodies can be linked from a .vxlib.
The user-visible bug. The UnsafeBlock arm walks the block's statements and never visits its trailing expression:
Expr::UnsafeBlock(u) => {
for s in &u.stmts {
Self::extract_uses_stmt(s, uses);
}
// u.ret is not visited
}
So let v = unsafe { imported(21) }; — where the call is the trailing expression — records no use of imported. Its body is never appended from the artifact, the module declares the symbol private, and the program fails at the linker:
ld: symbol(s) not found for architecture arm64
with no diagnostic naming the cause. It predates the unsafe fn work; the older binary reproduces it.
Why the obvious fix does not work, measured. Visiting u.ret is two lines, and it does fix the link failure. It also breaks the build, because the match ends in
_ => panic!("Unsupported expr for extract_uses_expr: {:?}", expr),
Every variant the walk has never reached is a compiler panic, not a silent miss. Widening the walk by one arm made previously unreachable variants reachable and crashed on them: first Number (13 unit tests in codegen::flat::tests), then, after adding the leaf arms, Grad/Jvp/Vjp from the autodiff test plus test_middle_end, test_frontend_pass, test_backend and the object-emission suite. Each fix uncovered the next variant.
So the walk is total only over the subset it happens to be called with today, and that subset is enforced by a panic rather than by the type system.
What the fix actually needs.
- Make the match exhaustive over
Expr— remove_ =>entirely, so the compiler names every variant that must be considered. Unvisited today, ignoring pure leaves:ComptimeBlock,IndirectCall,EnumVariant,VecMacro,MacroCall,Grad,Jvp,Vjp,InlineMlir,TransferPredicate. - Decide for each whether it carries a use, and recurse where it does.
IndirectCallandComptimeBlockare the two most likely to hide one. - Re-run the residency and memory-capacity suites: seeing more uses changes which tiles count as live, and those diagnostics depend on it. That is the reason this is not a drive-by.
Until then the linking failure stands. driver_link_interface_refuses_an_unguarded_unsafe_import deliberately avoids it: it checks the refusal against an unsafe library and the absence of a refusal against a safe one, both with --action print-ast, so it discriminates without needing a body to link.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/hir/env.rs at TypeChecker::extract_uses_expr and inspect the Expr variants and recursive helpers it currently handles. Use the listed codegen, autodiff, middle-end, frontend, backend, object-emission, residency, and memory-capacity tests to identify missing cases; done means the walk handles every Expr variant without compiler panics and the affected suites pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100