diff --git a/ssa/interp/interp.go b/ssa/interp/interp.go index b9adf6b1..61d05030 100644 --- a/ssa/interp/interp.go +++ b/ssa/interp/interp.go @@ -532,9 +532,13 @@ func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, // After a normal return, fr.result contains the result of the call // and fr.block is nil. // -// After a recovered panic, fr.result is undefined and fr.block -// contains the block at which to resume control, which may be -// nil for a normal return. +// A recovered panic in a function without named return parameters +// (NRPs) becomes a normal return of the zero value of the function's +// result type. +// +// After a recovered panic in a function with NRPs, fr.result is +// undefined and fr.block contains the block at which to resume +// control. // func runFrame(fr *frame) { defer func() { @@ -550,7 +554,10 @@ func runFrame(fr *frame) { fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic) } fr.runDefers() - fr.block = fr.fn.Recover // recovered panic + fr.block = fr.fn.Recover + if fr.block == nil { + fr.result = zero(fr.fn.Signature.Results()) + } }() for { diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index 524ca173..e32bdf9c 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -235,6 +235,15 @@ func zero(t types.Type) value { s[i] = zero(t.Field(i).Type()) } return s + case *types.Tuple: + if t.Len() == 1 { + return zero(t.At(0).Type()) + } + s := make(tuple, t.Len()) + for i := range s { + s[i] = zero(t.At(i).Type()) + } + return s case *types.Chan: return chan value(nil) case *types.Map: diff --git a/ssa/interp/testdata/recover.go b/ssa/interp/testdata/recover.go index 39aad6c2..b5600522 100644 --- a/ssa/interp/testdata/recover.go +++ b/ssa/interp/testdata/recover.go @@ -2,6 +2,8 @@ package main // Tests of panic/recover. +import "fmt" + func fortyTwo() (r int) { r = 42 // The next two statements simulate a 'return' statement. @@ -9,8 +11,24 @@ func fortyTwo() (r int) { panic(nil) } +func zero() int { + defer func() { recover() }() + panic(1) +} + +func zeroEmpty() (int, string) { + defer func() { recover() }() + panic(1) +} + func main() { if r := fortyTwo(); r != 42 { panic(r) } + if r := zero(); r != 0 { + panic(r) + } + if r, s := zeroEmpty(); r != 0 || s != "" { + panic(fmt.Sprint(r, s)) + } }