From ef2722d0bc8c599cb0c35515a8f9a443ebda1103 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Wed, 29 Jul 2026 19:04:31 +0800 Subject: [PATCH 1/2] ssa: terminate empty defer dispatch blocks --- ssa/eh.go | 3 +++ ssa/eh_defer_test.go | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ssa/eh.go b/ssa/eh.go index b8ead4eb64..2991fdef67 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -591,6 +591,9 @@ func (p Function) endDefer(b Builder) { b.Jump(rethNext) } } + 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..bcfbed33ee 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) { @@ -73,7 +74,10 @@ func TestExplicitDeferStackDrainWithoutLoopCases(t *testing.T) { 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() @@ -88,6 +92,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) { From 8784fb91a79f216c1b083fecb6d4cee3481e40c5 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Wed, 29 Jul 2026 21:56:37 +0800 Subject: [PATCH 2/2] test: cover empty defer dispatch --- ssa/eh.go | 1 + ssa/eh_defer_test.go | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssa/eh.go b/ssa/eh.go index 2991fdef67..7ca1d90c39 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -591,6 +591,7 @@ 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) } diff --git a/ssa/eh_defer_test.go b/ssa/eh_defer_test.go index bcfbed33ee..fa1dcd5df3 100644 --- a/ssa/eh_defer_test.go +++ b/ssa/eh_defer_test.go @@ -68,7 +68,7 @@ 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") @@ -80,7 +80,6 @@ func TestExplicitDeferStackDrainWithoutLoopCases(t *testing.T) { b.SetBlock(fn.Block(0)) _ = b.BuiltinCall("ssa:deferstack") - b.DeferStackDrain() b.RunDefers() b.Return() b.EndBuild()