aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/gc/walk.go21
-rw-r--r--test/fixedbugs/issue24491a.go31
2 files changed, 48 insertions, 4 deletions
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 98ebb23991..02a7269ff8 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3927,15 +3927,22 @@ func wrapCall(n *Node, init *Nodes) *Node {
}
}
+ wrapArgs := n.List.Slice()
+ // If there's a receiver argument, it needs to be passed through the wrapper too.
+ if n.Op == OCALLMETH || n.Op == OCALLINTER {
+ recv := n.Left.Left
+ wrapArgs = append([]*Node{recv}, wrapArgs...)
+ }
+
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
- origArgs := make([]*Node, n.List.Len())
+ origArgs := make([]*Node, len(wrapArgs))
t := nod(OTFUNC, nil, nil)
- for i, arg := range n.List.Slice() {
+ for i, arg := range wrapArgs {
s := lookupN("a", i)
if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
origArgs[i] = arg
arg = arg.Left
- n.List.SetIndex(i, arg)
+ wrapArgs[i] = arg
}
t.List.Append(symfield(s, arg.Type))
}
@@ -3953,6 +3960,12 @@ func wrapCall(n *Node, init *Nodes) *Node {
arg.Type = origArg.Type
args[i] = arg
}
+ if n.Op == OCALLMETH || n.Op == OCALLINTER {
+ // Move wrapped receiver argument back to its appropriate place.
+ recv := typecheck(args[0], ctxExpr)
+ n.Left.Left = recv
+ args = args[1:]
+ }
call := nod(n.Op, nil, nil)
if !isBuiltinCall {
call.Op = OCALL
@@ -3970,7 +3983,7 @@ func wrapCall(n *Node, init *Nodes) *Node {
call = nod(OCALL, nil, nil)
call.Left = fn.Func.Nname
- call.List.Set(n.List.Slice())
+ call.List.Set(wrapArgs)
call = typecheck(call, ctxStmt)
call = walkexpr(call, init)
return call
diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go
index 8accf8c0a3..d30b65b233 100644
--- a/test/fixedbugs/issue24491a.go
+++ b/test/fixedbugs/issue24491a.go
@@ -48,6 +48,14 @@ func f() int {
return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
}
+type S struct{}
+
+//go:noinline
+//go:uintptrescapes
+func (S) test(s string, p, q uintptr, rest ...uintptr) int {
+ return test(s, p, q, rest...)
+}
+
func main() {
test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
<-done
@@ -60,6 +68,29 @@ func main() {
}()
<-done
+ func() {
+ for {
+ defer test("defer in for loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+ break
+ }
+ }()
+
+ <-done
+ func() {
+ s := &S{}
+ defer s.test("method call", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+ }()
+ <-done
+
+ func() {
+ s := &S{}
+ for {
+ defer s.test("defer method loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+ break
+ }
+ }()
+ <-done
+
f()
<-done
}