]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.20] cmd/compile: fix wrong escape analysis for go/defer generic...
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Tue, 7 Feb 2023 12:28:15 +0000 (19:28 +0700)
committerMichael Pratt <mpratt@google.com>
Wed, 15 Feb 2023 21:46:55 +0000 (21:46 +0000)
For go/defer calls like "defer f(x, y)", the compiler rewrites it to:

x1, y1 := x, y
defer func() { f(x1, y1) }()

However, if "f" needs runtime type information, the "RType" field will
refer to the outer ".dict" param, causing wrong liveness analysis.

To fix this, if "f" refers to outer ".dict", the dict param will be
copied to an autotmp, and "f" will refer to this autotmp instead.

Fixes #58467

Change-Id: I238b6e75441442b5540d39bc818205398e80c94d
Reviewed-on: https://go-review.googlesource.com/c/go/+/466035
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/467935
Reviewed-by: Michael Pratt <mpratt@google.com>
src/cmd/compile/internal/escape/call.go
test/fixedbugs/issue58341.go [new file with mode: 0644]

index e2235520e5cd730e13bdb8945b7c01dcec65cbee..448702e3f07c62ff0222ac0962f05e4dafc7ad50 100644 (file)
@@ -19,7 +19,7 @@ func (e *escape) call(ks []hole, call ir.Node) {
        var init ir.Nodes
        e.callCommon(ks, call, &init, nil)
        if len(init) != 0 {
-               call.(*ir.CallExpr).PtrInit().Append(init...)
+               call.(ir.InitNode).PtrInit().Append(init...)
        }
 }
 
@@ -38,6 +38,18 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                argumentFunc(nil, k, argp)
        }
 
+       argumentRType := func(rtypep *ir.Node) {
+               rtype := *rtypep
+               if rtype == nil {
+                       return
+               }
+               // common case: static rtype/itab argument, which can be evaluated within the wrapper instead.
+               if addr, ok := rtype.(*ir.AddrExpr); ok && addr.Op() == ir.OADDR && addr.X.Op() == ir.OLINKSYMOFFSET {
+                       return
+               }
+               e.wrapExpr(rtype.Pos(), rtypep, init, call, wrapper)
+       }
+
        switch call.Op() {
        default:
                ir.Dump("esc", call)
@@ -153,6 +165,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                                argument(e.heapHole(), &args[i])
                        }
                }
+               argumentRType(&call.RType)
 
        case ir.OCOPY:
                call := call.(*ir.BinaryExpr)
@@ -163,6 +176,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                        copiedK = e.heapHole().deref(call, "copied slice")
                }
                argument(copiedK, &call.Y)
+               argumentRType(&call.RType)
 
        case ir.OPANIC:
                call := call.(*ir.UnaryExpr)
@@ -179,6 +193,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                for i := range call.Args {
                        argument(e.discardHole(), &call.Args[i])
                }
+               argumentRType(&call.RType)
 
        case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
                call := call.(*ir.UnaryExpr)
@@ -192,6 +207,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                call := call.(*ir.BinaryExpr)
                argument(ks[0], &call.X)
                argument(e.discardHole(), &call.Y)
+               argumentRType(&call.RType)
        }
 }
 
diff --git a/test/fixedbugs/issue58341.go b/test/fixedbugs/issue58341.go
new file mode 100644 (file)
index 0000000..c7b09be
--- /dev/null
@@ -0,0 +1,30 @@
+// compile
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type S[T comparable] struct {
+       m map[T]T
+}
+
+func (s S[T]) M1(node T) {
+       defer delete(s.m, node)
+}
+
+func (s S[T]) M2(node T) {
+       defer func() {
+               delete(s.m, node)
+       }()
+}
+
+func (s S[T]) M3(node T) {
+       defer f(s.m, node)
+}
+
+//go:noinline
+func f[T comparable](map[T]T, T) {}
+
+var _ = S[int]{}