var args []*ssa.Value
var argNodes []*ir.Name
+ if objabi.Experiment.RegabiDefer && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER) {
+ s.Fatalf("defer call with arguments: %v", n)
+ }
+
opendefer := &openDeferInfo{
n: n,
}
}
}
+ if objabi.Experiment.RegabiDefer && k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER) {
+ s.Fatalf("go/defer call with arguments: %v", n)
+ }
+
switch n.Op() {
case ir.OCALLFUNC:
if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
return walkStmt(typecheck.Stmt(r))
}
+// walkRecover walks an ORECOVER node.
+func walkRecover(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
+ // Call gorecover with the FP of this frame.
+ // FP is equal to caller's SP plus FixedFrameSize().
+ var fp ir.Node = mkcall("getcallersp", types.Types[types.TUINTPTR], init)
+ if off := base.Ctxt.FixedFrameSize(); off != 0 {
+ fp = ir.NewBinaryExpr(fp.Pos(), ir.OADD, fp, ir.NewInt(off))
+ }
+ fp = ir.NewConvExpr(fp.Pos(), ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp)
+ return mkcall("gorecover", nn.Type(), init, fp)
+}
+
func badtype(op ir.Op, tl, tr *types.Type) {
var s string
if tl != nil {
return mkcall("gopanic", nil, init, n.X)
case ir.ORECOVER:
- n := n.(*ir.CallExpr)
- // Call gorecover with the FP of this frame.
- // FP is equal to caller's SP plus FixedFrameSize().
- var fp ir.Node = mkcall("getcallersp", types.Types[types.TUINTPTR], init)
- if off := base.Ctxt.FixedFrameSize(); off != 0 {
- fp = ir.NewBinaryExpr(fp.Pos(), ir.OADD, fp, ir.NewInt(off))
- }
- fp = ir.NewConvExpr(fp.Pos(), ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp)
- return mkcall("gorecover", n.Type(), init, fp)
+ return walkRecover(n.(*ir.CallExpr), init)
case ir.OCFUNC:
return n
t := o.markTemp()
o.init(n.Call)
o.call(n.Call)
+ if n.Call.Op() == ir.ORECOVER {
+ // Special handling of "defer recover()". We need to evaluate the FP
+ // argument before wrapping.
+ var init ir.Nodes
+ n.Call = walkRecover(n.Call.(*ir.CallExpr), &init)
+ o.stmtList(init)
+ }
if objabi.Experiment.RegabiDefer {
o.wrapGoDefer(n)
}
callArgs = []ir.Node{x.X}
mkNewCall = func(pos src.XPos, op ir.Op, fun ir.Node, args []ir.Node) ir.Node {
if len(args) != 1 {
- panic("internal error, expecting single arg to close")
+ panic("internal error, expecting single arg")
}
return ir.Node(ir.NewUnaryExpr(pos, op, args[0]))
}
panic("unhandled op")
}
- // No need to wrap if called func has no args. However in the case
- // of "defer func() { ... }()" we need to protect against the
- // possibility of directClosureCall rewriting things so that the
- // call does have arguments.
- if len(callArgs) == 0 {
+ // No need to wrap if called func has no args and no receiver.
+ // However in the case of "defer func() { ... }()" we need to
+ // protect against the possibility of directClosureCall rewriting
+ // things so that the call does have arguments.
+ //
+ // Do wrap method calls (OCALLMETH, OCALLINTER), because it has
+ // a receiver.
+ //
+ // Also do wrap builtin functions, because they may be expanded to
+ // calls with arguments (e.g. ORECOVER).
+ if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC {
if c, ok := call.(*ir.CallExpr); ok && callX != nil && callX.Op() == ir.OCLOSURE {
cloFunc := callX.(*ir.ClosureExpr).Func
cloFunc.SetClosureCalled(false)