ssa: terminate empty defer dispatch blocks - #2213
Conversation
There was a problem hiding this comment.
Review summary
The fix is correct and minimal. When endDefer runs with no recorded defer statements (n == 0), the for i := n-1; i >= 0 loop never executes, so the builder is never repositioned onto procBlk. The trailing SetThreadDefer / IndirectJump (eh.go:597-599) would then be emitted into a stale/wrong block, producing invalid IR. Setting the builder to procBlk for the n == 0 case mirrors the n == 1 path (where the loop leaves the builder on rethsNext[1] == procBlk), so this is the right target block.
The test change is a meaningful regression guard: TestExplicitDeferStackDrainWithoutLoopCases now materializes a real recover block and adds an llvm.VerifyModule assertion (eh_defer_test.go:95-97) that would fail against the un-fixed code. The added github.com/xgo-dev/llvm import and VerifyModule(..., ReturnStatusAction) pattern match existing test conventions in this package.
Security and performance: no concerns — this is cold-path compile-time codegen bookkeeping.
Note: tests could not be executed in this environment (LLVM C headers unavailable), so verification is by code inspection only.
One minor maintainability suggestion is left inline.
| b.Jump(rethNext) | ||
| } | ||
| } | ||
| if n == 0 { |
There was a problem hiding this comment.
The n == 0 branch encodes a subtle, load-bearing invariant with no comment: the n >= 1 loop above implicitly leaves the builder positioned on rethsNext[1] (which equals procBlk when n == 1, since the final i == 0 iteration skips its Jump), so the trailing SetThreadDefer / IndirectJump land in procBlk. When n == 0 the loop never runs and nothing sets the insert point, so this branch is required for those instructions to be emitted into procBlk.
Consider a one-line comment, e.g.:
// No defer stmts: the loop above never runs, so position the builder
// on procBlk directly before emitting the tail (SetThreadDefer/IndirectJump).
if n == 0 {
b.SetBlockEx(procBlk, AtEnd, true)
}This matches the inline-comment style already used nearby (e.g. eh.go:601) and prevents a future maintainer from mistaking the branch for dead/redundant code.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Closing as an unproven/unreachable frontend case. The regression test constructs the low-level builder state directly (
We were unable to produce a Go source fixture that reaches |
Summary
This is the main-update compatibility fix extracted independently from #2196. It has no dependency on the process-isolation series.
Size
Tests
go test ./ssa -run ^TestExplicitDeferStackDrainWithoutLoopCases$ -count=1git diff --check