cmd/compile: check deferred nil interface call before wrapping it

Currently, for "defer i.M()" if i is nil it panics at the point of
defer statement, not when deferred function is called. We need to
do the nil check before wrapping it.

Updates #40724.

Change-Id: I62c669264668991f71999e2cf4610a9066247f9d
Reviewed-on: https://go-review.googlesource.com/c/go/+/305549
Trust: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Zhang 2021-03-29 13:44:08 -04:00
parent 4e1bf8ed38
commit bd6628e62d

View file

@ -1602,6 +1602,17 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
n := callX.(*ir.SelectorExpr)
n.X = mkArgCopy(n.X)
methSelectorExpr = n
if callX.Op() == ir.ODOTINTER {
// Currently for "defer i.M()" if i is nil it panics at the
// point of defer statement, not when deferred function is called.
// (I think there is an issue discussing what is the intended
// behavior but I cannot find it.)
// We need to do the nil check outside of the wrapper.
tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X))
c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, tab)
c.SetTypecheck(1)
o.append(c)
}
case !(callX.Op() == ir.ONAME && callX.(*ir.Name).Class == ir.PFUNC):
// Deal with "defer returnsafunc()(x, y)" (for
// example) by copying the callee expression.