Go version

tip, and Go 1.18 - 1.24

Output of go env in your module/workspace:

darwin/arm64 (or any)

What did you do?

Run https://go.dev/play/p/z4BHWcNalVg

package main

func callRecover() {
    if recover() != nil {
        println("recovered")
    }
}

type T int

func (*T) M() { callRecover() }

type S struct{ *T } // has a wrapper S.M wrapping (*T.M)

var p = S{new(T)}

var fn = S.M // using a function pointer to force using the wrapper

func main() {
    defer fn(p)
    panic("XXX")
}

What did you see happen?

The panic is recovered. The program prints "recovered" and exits normally.

What did you expect to see?

Similar to #73916, it is expected to not recover.

Also similarly, it panics as expected if inlining is disabled.

$ go run -gcflags=-l x.go
panic: XXX

goroutine 1 [running]:
main.main()
    /tmp/x.go:21 +0x68
exit status 2

Go 1.17 got it right. Go 1.18 and later fail. Bisection points to CL https://go.dev/cl/327871 . Also similarly, it is a phase ordering change. Before that CL, the wrapper S.M is generated late and cannot inline the wrapped function (*T).M. After the CL, it does, while keeping the WRAPPER attribute. The rest of the reasoning is the same as #73916.

Found while investigating #73747.

Comment From: gabyhelp

Related Issues

Related Code Changes

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: gopherbot

Change https://go.dev/cl/677675 mentions this issue: cmd/compile: Modify inline tree to avoid parent node for tail call site.

Comment From: gopherbot

Change https://go.dev/cl/685375 mentions this issue: runtime: iterate through inlinings when processing recover()