From e59a19ccebe87b84e69625d0b83df6d0fe2499db Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 22 Jun 2021 20:33:00 -0700 Subject: [PATCH] [dev.typeparams] cmd/compile: simplify walkGoDefer order already takes care of wrapping all go/defer function calls, so there's no need for walk to duplicate that logic: it's never going to be used. Change-Id: I54e545404e52ab8f9d60151d1bd2aff4b9bd8b72 Reviewed-on: https://go-review.googlesource.com/c/go/+/330270 Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le Trust: Cuong Manh Le Trust: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/walk/stmt.go | 130 ++++---------------------- 1 file changed, 17 insertions(+), 113 deletions(-) diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go index 0bf76680c4..e1ac652364 100644 --- a/src/cmd/compile/internal/walk/stmt.go +++ b/src/cmd/compile/internal/walk/stmt.go @@ -7,7 +7,6 @@ package walk import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" - "cmd/compile/internal/typecheck" ) // The result of walkStmt MUST be assigned back to n, e.g. @@ -187,33 +186,26 @@ func walkFor(n *ir.ForStmt) ir.Node { return n } +// validGoDeferCall reports whether call is a valid call to appear in +// a go or defer statement; that is, whether it's a regular function +// call without arguments or results. +func validGoDeferCall(call ir.Node) bool { + if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 { + sig := call.X.Type() + return sig.NumParams()+sig.NumResults() == 0 + } + return false +} + // walkGoDefer walks an OGO or ODEFER node. func walkGoDefer(n *ir.GoDeferStmt) ir.Node { - var init ir.Nodes - switch call := n.Call; call.Op() { - case ir.OPRINT, ir.OPRINTN: - call := call.(*ir.CallExpr) - n.Call = wrapCall(call, &init) - - case ir.ODELETE: - call := call.(*ir.CallExpr) - n.Call = wrapCall(call, &init) - - case ir.OCOPY: - call := call.(*ir.BinaryExpr) - n.Call = walkCopy(call, &init, true) - - case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: - call := call.(*ir.CallExpr) - if len(call.KeepAlive) > 0 { - n.Call = wrapCall(call, &init) - } else { - n.Call = walkExpr(call, &init) - } - - default: - n.Call = walkExpr(call, &init) + if !validGoDeferCall(n.Call) { + base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call) } + + var init ir.Nodes + n.Call = walkExpr(n.Call, &init) + if len(init) > 0 { init.Append(n) return ir.NewBlockStmt(n.Pos(), init) @@ -229,94 +221,6 @@ func walkIf(n *ir.IfStmt) ir.Node { return n } -// Rewrite -// go builtin(x, y, z) -// into -// go func(a1, a2, a3) { -// builtin(a1, a2, a3) -// }(x, y, z) -// for print, println, and delete. -// -// Rewrite -// go f(x, y, uintptr(unsafe.Pointer(z))) -// into -// go func(a1, a2, a3) { -// f(a1, a2, uintptr(a3)) -// }(x, y, unsafe.Pointer(z)) -// for function contains unsafe-uintptr arguments. - -var wrapCall_prgen int - -// The result of wrapCall MUST be assigned back to n, e.g. -// n.Left = wrapCall(n.Left, init) -func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { - if len(n.Init()) != 0 { - walkStmtList(n.Init()) - init.Append(ir.TakeInit(n)...) - } - - isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER - - // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e). - if !isBuiltinCall && n.IsDDD { - undoVariadic(n) - } - - wrapArgs := n.Args - // If there's a receiver argument, it needs to be passed through the wrapper too. - if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER { - recv := n.X.(*ir.SelectorExpr).X - wrapArgs = append([]ir.Node{recv}, wrapArgs...) - } - - // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion. - origArgs := make([]ir.Node, len(wrapArgs)) - var funcArgs []*ir.Field - for i, arg := range wrapArgs { - s := typecheck.LookupNum("a", i) - if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() { - origArgs[i] = arg - arg = arg.(*ir.ConvExpr).X - wrapArgs[i] = arg - } - funcArgs = append(funcArgs, ir.NewField(base.Pos, s, nil, arg.Type())) - } - t := ir.NewFuncType(base.Pos, nil, funcArgs, nil) - - wrapCall_prgen++ - sym := typecheck.LookupNum("wrap·", wrapCall_prgen) - fn := typecheck.DeclFunc(sym, t) - - args := ir.ParamNames(t.Type()) - for i, origArg := range origArgs { - if origArg == nil { - continue - } - args[i] = ir.NewConvExpr(base.Pos, origArg.Op(), origArg.Type(), args[i]) - } - if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER { - // Move wrapped receiver argument back to its appropriate place. - recv := typecheck.Expr(args[0]) - n.X.(*ir.SelectorExpr).X = recv - args = args[1:] - } - call := ir.NewCallExpr(base.Pos, n.Op(), n.X, args) - if !isBuiltinCall { - call.SetOp(ir.OCALL) - call.IsDDD = n.IsDDD - } - fn.Body = []ir.Node{call} - - typecheck.FinishFuncBody() - - typecheck.Func(fn) - typecheck.Stmts(fn.Body) - typecheck.Target.Decls = append(typecheck.Target.Decls, fn) - - call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, wrapArgs) - return walkExpr(typecheck.Stmt(call), init) -} - // undoVariadic turns a call to a variadic function of the form // // f(a, b, []T{c, d, e}...)