// 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") } }