From eb691fdd62c9f1dc36c9c9a974ac2ddad677fd99 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 23 Jun 2021 00:31:16 -0700 Subject: [PATCH] [dev.typeparams] cmd/compile: escape analysis of method expression calls This CL extends escape analysis to analyze function calls using method expressions the same as it would a normal method call. That is, it now analyzes "T.M(recv, args...)" the same as "recv.M(args...)". This is useful because it means the frontend can eventually stop supporting both function calls and method calls. We can simply desugar method calls into function calls, like we already do in the backend to simplify SSA construction. Change-Id: I9cd5ec0d534cbcd9860f0014c86e4ae416920c26 Reviewed-on: https://go-review.googlesource.com/c/go/+/330331 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/escape/call.go | 37 +++++++++++++++++-------- test/escape5.go | 3 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 7b9dbe0dbc6..850b9cbde28 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -56,11 +56,15 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir var fn *ir.Name switch call.Op() { case ir.OCALLFUNC: - switch v := ir.StaticValue(call.X); { - case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC: - fn = v.(*ir.Name) - case v.Op() == ir.OCLOSURE: + switch v := ir.StaticValue(call.X); v.Op() { + case ir.ONAME: + if v := v.(*ir.Name); v.Class == ir.PFUNC { + fn = v + } + case ir.OCLOSURE: fn = v.(*ir.ClosureExpr).Func.Nname + case ir.OMETHEXPR: + fn = ir.MethodExprName(v) } case ir.OCALLMETH: fn = ir.MethodExprName(call.X) @@ -77,19 +81,30 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir } } - if r := fntype.Recv(); r != nil { - dot := call.X.(*ir.SelectorExpr) - argumentFunc(fn, e.tagHole(ks, fn, r), &dot.X) - } else { + var recvp *ir.Node + if call.Op() == ir.OCALLFUNC { // Evaluate callee function expression. // - // Note: We use argument and not argumentFunc, because call.X - // here may be an argument to runtime.{new,defer}proc, but it's - // not an argument to fn itself. + // Note: We use argument and not argumentFunc, because while + // call.X here may be an argument to runtime.{new,defer}proc, + // it's not an argument to fn itself. argument(e.discardHole(), &call.X) + } else { + recvp = &call.X.(*ir.SelectorExpr).X } args := call.Args + if recv := fntype.Recv(); recv != nil { + if recvp == nil { + // Function call using method expression. Recevier argument is + // at the front of the regular arguments list. + recvp = &args[0] + args = args[1:] + } + + argumentFunc(fn, e.tagHole(ks, fn, recv), recvp) + } + for i, param := range fntype.Params().FieldSlice() { argumentFunc(fn, e.tagHole(ks, fn, param), &args[i]) } diff --git a/test/escape5.go b/test/escape5.go index 73acfb46a94..97aaf23b2d1 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -180,8 +180,7 @@ func _() { } func fbad24305() { - // BAD u should not be heap allocated - var u U // ERROR "moved to heap: u" + var u U (*U).M(&u) (*U).N(&u) }