aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCuong Manh Le <cuong.manhle.vn@gmail.com>2023-02-07 19:28:15 +0700
committerMichael Pratt <mpratt@google.com>2023-02-15 21:46:55 +0000
commit2d01f3695becd725959a723b512cf46e88ae60fe (patch)
treed2eb2b799a3ca7b7a40c9d633b76624d54e48f02
parent965e9ba0fb6ed8b511860beaefa7a3ac97a81c36 (diff)
downloadgo-2d01f3695becd725959a723b512cf46e88ae60fe.tar.gz
go-2d01f3695becd725959a723b512cf46e88ae60fe.zip
[release-branch.go1.20] cmd/compile: fix wrong escape analysis for go/defer generic calls
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>
-rw-r--r--src/cmd/compile/internal/escape/call.go18
-rw-r--r--test/fixedbugs/issue58341.go30
2 files changed, 47 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index e2235520e5..448702e3f0 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -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
index 0000000000..c7b09bee9f
--- /dev/null
+++ b/test/fixedbugs/issue58341.go
@@ -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]{}