Skip to content

Commit ce58a39

Browse files
committed
cmd/compile/internal/gc: fix Node.copy and introduce (raw|sep)copy
Node.copy used to make a shallow copy of a node. Often, this is not correct: If a node n's Orig field pointed to itself, the copy's Orig field has to be adjusted to point to the copy. Otherwise, if n is modified later, the copy's Orig appears modified as well (because it points to n). This was fixed for one specific case with https://go-review.googlesource.com/c/go/+/136395 (issue #26855). This change instead addresses copy in general: In two cases we don't want the Orig adjustment as it causes escape analysis output to fail (not match the existing error messages). rawcopy is used in those cases. In several cases Orig is set to the copy immediately after making a copy; a new function sepcopy is used there. Updates #26855. Fixes #27765. Change-Id: Idaadeb5c4b9a027daabd46a2361348f7a93f2b00 Reviewed-on: https://go-review.googlesource.com/136540 Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 499fbb1 commit ce58a39

File tree

6 files changed

+41
-33
lines changed

6 files changed

+41
-33
lines changed

src/cmd/compile/internal/gc/const.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
234234
if n.Op == OLITERAL && !reuse {
235235
// Can't always set n.Type directly on OLITERAL nodes.
236236
// See discussion on CL 20813.
237-
n = n.copy()
237+
n = n.rawcopy()
238238
reuse = true
239239
}
240240

@@ -1200,8 +1200,7 @@ func setconst(n *Node, v Val) {
12001200
// Ensure n.Orig still points to a semantically-equivalent
12011201
// expression after we rewrite n into a constant.
12021202
if n.Orig == n {
1203-
n.Orig = n.copy()
1204-
n.Orig.Orig = n.Orig
1203+
n.Orig = n.sepcopy()
12051204
}
12061205

12071206
*n = Node{
@@ -1331,7 +1330,7 @@ func defaultlitreuse(n *Node, t *types.Type, reuse canReuseNode) *Node {
13311330
}
13321331

13331332
if n.Op == OLITERAL && !reuse {
1334-
n = n.copy()
1333+
n = n.rawcopy()
13351334
reuse = true
13361335
}
13371336

src/cmd/compile/internal/gc/order.go

+4-8
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ func (o *Order) cheapExpr(n *Node) *Node {
109109
if l == n.Left {
110110
return n
111111
}
112-
a := n.copy()
113-
a.Orig = a
112+
a := n.sepcopy()
114113
a.Left = l
115114
return typecheck(a, Erv)
116115
}
@@ -135,8 +134,7 @@ func (o *Order) safeExpr(n *Node) *Node {
135134
if l == n.Left {
136135
return n
137136
}
138-
a := n.copy()
139-
a.Orig = a
137+
a := n.sepcopy()
140138
a.Left = l
141139
return typecheck(a, Erv)
142140

@@ -145,8 +143,7 @@ func (o *Order) safeExpr(n *Node) *Node {
145143
if l == n.Left {
146144
return n
147145
}
148-
a := n.copy()
149-
a.Orig = a
146+
a := n.sepcopy()
150147
a.Left = l
151148
return typecheck(a, Erv)
152149

@@ -161,8 +158,7 @@ func (o *Order) safeExpr(n *Node) *Node {
161158
if l == n.Left && r == n.Right {
162159
return n
163160
}
164-
a := n.copy()
165-
a.Orig = a
161+
a := n.sepcopy()
166162
a.Left = l
167163
a.Right = r
168164
return typecheck(a, Erv)

src/cmd/compile/internal/gc/sinit.go

+4-8
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,13 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
349349
gdata(n, e.Expr, int(n.Type.Width))
350350
continue
351351
}
352-
ll := n.copy()
353-
ll.Orig = ll // completely separate copy
352+
ll := n.sepcopy()
354353
if staticassign(ll, e.Expr, out) {
355354
continue
356355
}
357356
// Requires computation, but we're
358357
// copying someone else's computation.
359-
rr := orig.copy()
360-
rr.Orig = rr // completely separate copy
358+
rr := orig.sepcopy()
361359
rr.Type = ll.Type
362360
rr.Xoffset += e.Xoffset
363361
setlineno(rr)
@@ -453,8 +451,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
453451
continue
454452
}
455453
setlineno(e.Expr)
456-
a := n.copy()
457-
a.Orig = a // completely separate copy
454+
a := n.sepcopy()
458455
if !staticassign(a, e.Expr, out) {
459456
*out = append(*out, nod(OAS, a, e.Expr))
460457
}
@@ -518,8 +515,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
518515
// Copy val directly into n.
519516
n.Type = val.Type
520517
setlineno(val)
521-
a := n.copy()
522-
a.Orig = a
518+
a := n.sepcopy()
523519
if !staticassign(a, val, out) {
524520
*out = append(*out, nod(OAS, a, val))
525521
}

src/cmd/compile/internal/gc/subr.go

+29-4
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,35 @@ func nodSym(op Op, left *Node, sym *types.Sym) *Node {
364364
return n
365365
}
366366

367+
// rawcopy returns a shallow copy of n.
368+
// Note: copy or sepcopy (rather than rawcopy) is usually the
369+
// correct choice (see comment with Node.copy, below).
370+
func (n *Node) rawcopy() *Node {
371+
copy := *n
372+
return &copy
373+
}
374+
375+
// sepcopy returns a separate shallow copy of n, with the copy's
376+
// Orig pointing to itself.
377+
func (n *Node) sepcopy() *Node {
378+
copy := *n
379+
copy.Orig = &copy
380+
return &copy
381+
}
382+
383+
// copy returns shallow copy of n and adjusts the copy's Orig if
384+
// necessary: In general, if n.Orig points to itself, the copy's
385+
// Orig should point to itself as well. Otherwise, if n is modified,
386+
// the copy's Orig node appears modified, too, and then doesn't
387+
// represent the original node anymore.
388+
// (This caused the wrong complit Op to be used when printing error
389+
// messages; see issues #26855, #27765).
367390
func (n *Node) copy() *Node {
368-
n2 := *n
369-
return &n2
391+
copy := *n
392+
if n.Orig == n {
393+
copy.Orig = &copy
394+
}
395+
return &copy
370396
}
371397

372398
// methcmp sorts methods by symbol.
@@ -412,8 +438,7 @@ func treecopy(n *Node, pos src.XPos) *Node {
412438

413439
switch n.Op {
414440
default:
415-
m := n.copy()
416-
m.Orig = m
441+
m := n.sepcopy()
417442
m.Left = treecopy(n.Left, pos)
418443
m.Right = treecopy(n.Right, pos)
419444
m.List.Set(listtreecopy(n.List.Slice(), pos))

src/cmd/compile/internal/gc/typecheck.go

-8
Original file line numberDiff line numberDiff line change
@@ -2923,14 +2923,6 @@ func typecheckcomplit(n *Node) *Node {
29232923

29242924
// Save original node (including n.Right)
29252925
norig := n.copy()
2926-
// If n.Orig points to itself, norig.Orig must point to itself, too.
2927-
// Otherwise, because n.Op is changed below, n.Orig's Op is changed
2928-
// as well because it (and the copy norig) still point to the original
2929-
// node n. This caused the wrong complit Op to be used when printing
2930-
// error messages (issue #26855).
2931-
if n.Orig == n {
2932-
norig.Orig = norig
2933-
}
29342926

29352927
setlineno(n.Right)
29362928
n.Right = typecheck(n.Right, Etype|Ecomplit)

src/cmd/compile/internal/gc/walk.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -4052,7 +4052,7 @@ func wrapCall(n *Node, init *Nodes) *Node {
40524052
// The result of substArgTypes MUST be assigned back to old, e.g.
40534053
// n.Left = substArgTypes(n.Left, t1, t2)
40544054
func substArgTypes(old *Node, types_ ...*types.Type) *Node {
4055-
n := old.copy() // make shallow copy
4055+
n := old.copy()
40564056

40574057
for _, t := range types_ {
40584058
dowidth(t)

0 commit comments

Comments
 (0)