| // run |
| |
| // Copyright 2021 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. |
| |
| // This testcase caused a crash when the register ABI was in effect, |
| // on amd64 (problem with register allocation). |
| |
| package main |
| |
| type Op struct { |
| tag string |
| _x []string |
| _q [20]uint64 |
| plist []P |
| } |
| |
| type P struct { |
| tag string |
| _x [10]uint64 |
| b bool |
| } |
| |
| type M int |
| |
| //go:noinline |
| func (w *M) walkP(p *P) *P { |
| np := &P{} |
| *np = *p |
| np.tag += "new" |
| return np |
| } |
| |
| func (w *M) walkOp(op *Op) *Op { |
| if op == nil { |
| return nil |
| } |
| |
| orig := op |
| cloned := false |
| clone := func() { |
| if !cloned { |
| cloned = true |
| op = &Op{} |
| *op = *orig |
| } |
| } |
| |
| pCloned := false |
| for i := range op.plist { |
| if s := w.walkP(&op.plist[i]); s != &op.plist[i] { |
| if !pCloned { |
| pCloned = true |
| clone() |
| op.plist = make([]P, len(orig.plist)) |
| copy(op.plist, orig.plist) |
| } |
| op.plist[i] = *s |
| } |
| } |
| |
| return op |
| } |
| |
| func main() { |
| var ww M |
| w := &ww |
| p1 := P{tag: "a"} |
| p1._x[1] = 9 |
| o := Op{tag: "old", plist: []P{p1}} |
| no := w.walkOp(&o) |
| if no.plist[0].tag != "anew" { |
| panic("bad") |
| } |
| } |