1// run
2
3// Copyright 2021 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// This testcase caused a crash when the register ABI was in effect,
8// on amd64 (problem with register allocation).
9
10package main
11
12type Op struct {
13	tag   string
14	_x    []string
15	_q    [20]uint64
16	plist []P
17}
18
19type P struct {
20	tag string
21	_x  [10]uint64
22	b   bool
23}
24
25type M int
26
27//go:noinline
28func (w *M) walkP(p *P) *P {
29	np := &P{}
30	*np = *p
31	np.tag += "new"
32	return np
33}
34
35func (w *M) walkOp(op *Op) *Op {
36	if op == nil {
37		return nil
38	}
39
40	orig := op
41	cloned := false
42	clone := func() {
43		if !cloned {
44			cloned = true
45			op = &Op{}
46			*op = *orig
47		}
48	}
49
50	pCloned := false
51	for i := range op.plist {
52		if s := w.walkP(&op.plist[i]); s != &op.plist[i] {
53			if !pCloned {
54				pCloned = true
55				clone()
56				op.plist = make([]P, len(orig.plist))
57				copy(op.plist, orig.plist)
58			}
59			op.plist[i] = *s
60		}
61	}
62
63	return op
64}
65
66func main() {
67	var ww M
68	w := &ww
69	p1 := P{tag: "a"}
70	p1._x[1] = 9
71	o := Op{tag: "old", plist: []P{p1}}
72	no := w.walkOp(&o)
73	if no.plist[0].tag != "anew" {
74		panic("bad")
75	}
76}
77