diff options
-rw-r--r-- | src/cmd/compile/internal/gc/walk.go | 21 | ||||
-rw-r--r-- | test/fixedbugs/issue24491a.go | 31 |
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 } |