diff --git a/ssa/eh.go b/ssa/eh.go index b8ead4eb64..7ca1d90c39 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -591,6 +591,10 @@ func (p Function) endDefer(b Builder) { b.Jump(rethNext) } } + // With no defer statements, the loop does not position the builder. + if n == 0 { + b.SetBlockEx(procBlk, AtEnd, true) + } link := b.getField(b.Load(self.data), deferLink) b.Call(b.Pkg.rtFunc("SetThreadDefer"), link) b.IndirectJump(b.Load(rundPtr), nexts) diff --git a/ssa/eh_defer_test.go b/ssa/eh_defer_test.go index 5f99729b1e..fa1dcd5df3 100644 --- a/ssa/eh_defer_test.go +++ b/ssa/eh_defer_test.go @@ -9,6 +9,7 @@ import ( "github.com/goplus/llgo/ssa" "github.com/goplus/llgo/ssa/ssatest" + "github.com/xgo-dev/llvm" ) func TestExplicitDeferStackIR(t *testing.T) { @@ -67,16 +68,18 @@ func TestExplicitDeferStackFallbackAndNilBuiltin(t *testing.T) { } } -func TestExplicitDeferStackDrainWithoutLoopCases(t *testing.T) { +func TestExplicitDeferStackWithoutDeferredActions(t *testing.T) { prog := ssatest.NewProgram(t, nil) pkg := prog.NewPackage("foo", "foo") fn := pkg.NewFunc("main", ssa.NoArgsNoRet, ssa.InGo) b := fn.MakeBody(1) - fn.SetRecover(fn.MakeBlock()) + recoverBlock := fn.MakeBlock() + fn.SetRecover(recoverBlock) + b.SetBlock(recoverBlock).Return() + b.SetBlock(fn.Block(0)) _ = b.BuiltinCall("ssa:deferstack") - b.DeferStackDrain() b.RunDefers() b.Return() b.EndBuild() @@ -88,6 +91,9 @@ func TestExplicitDeferStackDrainWithoutLoopCases(t *testing.T) { if !strings.Contains(ir, "sigsetjmp") && !strings.Contains(ir, "setjmp") { t.Fatalf("expected defer stack setup with recover, got:\n%s", ir) } + if err := llvm.VerifyModule(pkg.Module(), llvm.ReturnStatusAction); err != nil { + t.Fatalf("explicit defer stack without loop cases produced invalid IR: %v\n%s", err, ir) + } } func TestExplicitDeferStackDrainWithoutRecoverNoop(t *testing.T) {