Skip to content

Commit 907a4bf

Browse files
committed
[dev.regabi] cmd/compile: fix map assignment order
After the previous cleanup/optimization CLs, ascompatee now correctly handles map assignments too. So remove the code from order.mapAssign, which causes us to assign to the map at the wrong point during execution. It's not every day you get to fix an issue by only removing code. Thanks to Cuong Manh Le for test cases and continually following up on this issue. Passes toolstash -cmp. (Apparently the standard library never uses tricky map assignments. Go figure.) Fixes #23017. Change-Id: Ie0728103d59d884d00c1c050251290a2a46150f9 Reviewed-on: https://go-review.googlesource.com/c/go/+/281172 Trust: Matthew Dempsky <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]>
1 parent f2e6dab commit 907a4bf

File tree

2 files changed

+114
-36
lines changed

2 files changed

+114
-36
lines changed

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

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -537,21 +537,7 @@ func (o *orderState) call(nn ir.Node) {
537537
}
538538
}
539539

540-
// mapAssign appends n to o.out, introducing temporaries
541-
// to make sure that all map assignments have the form m[k] = x.
542-
// (Note: expr has already been called on n, so we know k is addressable.)
543-
//
544-
// If n is the multiple assignment form ..., m[k], ... = ..., x, ..., the rewrite is
545-
// t1 = m
546-
// t2 = k
547-
// ...., t3, ... = ..., x, ...
548-
// t1[t2] = t3
549-
//
550-
// The temporaries t1, t2 are needed in case the ... being assigned
551-
// contain m or k. They are usually unnecessary, but in the unnecessary
552-
// cases they are also typically registerizable, so not much harm done.
553-
// And this only applies to the multiple-assignment form.
554-
// We could do a more precise analysis if needed, like in walk.go.
540+
// mapAssign appends n to o.out.
555541
func (o *orderState) mapAssign(n ir.Node) {
556542
switch n.Op() {
557543
default:
@@ -572,28 +558,7 @@ func (o *orderState) mapAssign(n ir.Node) {
572558

573559
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
574560
n := n.(*ir.AssignListStmt)
575-
var post []ir.Node
576-
for i, m := range n.Lhs {
577-
switch {
578-
case m.Op() == ir.OINDEXMAP:
579-
m := m.(*ir.IndexExpr)
580-
if !ir.IsAutoTmp(m.X) {
581-
m.X = o.copyExpr(m.X)
582-
}
583-
if !ir.IsAutoTmp(m.Index) {
584-
m.Index = o.copyExpr(m.Index)
585-
}
586-
fallthrough
587-
case base.Flag.Cfg.Instrumenting && n.Op() == ir.OAS2FUNC && !ir.IsBlank(m):
588-
t := o.newTemp(m.Type(), false)
589-
n.Lhs[i] = t
590-
a := ir.NewAssignStmt(base.Pos, m, t)
591-
post = append(post, typecheck.Stmt(a))
592-
}
593-
}
594-
595561
o.out = append(o.out, n)
596-
o.out = append(o.out, post...)
597562
}
598563
}
599564

test/fixedbugs/issue23017.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// run
2+
3+
// Copyright 2020 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+
// assignment order in multiple assignments.
8+
// See issue #23017
9+
10+
package main
11+
12+
import "fmt"
13+
14+
func main() {}
15+
16+
func init() {
17+
var m = map[int]int{}
18+
var p *int
19+
20+
defer func() {
21+
recover()
22+
check(1, len(m))
23+
check(42, m[2])
24+
}()
25+
m[2], *p = 42, 2
26+
}
27+
28+
func init() {
29+
var m = map[int]int{}
30+
p := []int{}
31+
32+
defer func() {
33+
recover()
34+
check(1, len(m))
35+
check(2, m[2])
36+
}()
37+
m[2], p[1] = 2, 2
38+
}
39+
40+
func init() {
41+
type P struct{ i int }
42+
var m = map[int]int{}
43+
var p *P
44+
45+
defer func() {
46+
recover()
47+
check(1, len(m))
48+
check(3, m[2])
49+
}()
50+
m[2], p.i = 3, 2
51+
}
52+
53+
func init() {
54+
type T struct{ i int }
55+
var x T
56+
p := &x
57+
p, p.i = new(T), 4
58+
check(4, x.i)
59+
}
60+
61+
func init() {
62+
var m map[int]int
63+
var a int
64+
var p = &a
65+
66+
defer func() {
67+
recover()
68+
check(5, *p)
69+
}()
70+
*p, m[2] = 5, 2
71+
}
72+
73+
var g int
74+
75+
func init() {
76+
var m map[int]int
77+
defer func() {
78+
recover()
79+
check(0, g)
80+
}()
81+
m[0], g = 1, 2
82+
}
83+
84+
func init() {
85+
type T struct{ x struct{ y int } }
86+
var x T
87+
p := &x
88+
p, p.x.y = new(T), 7
89+
check(7, x.x.y)
90+
check(0, p.x.y)
91+
}
92+
93+
func init() {
94+
type T *struct{ x struct{ y int } }
95+
x := struct{ y int }{0}
96+
var q T = &struct{ x struct{ y int } }{x}
97+
p := q
98+
p, p.x.y = nil, 7
99+
check(7, q.x.y)
100+
}
101+
102+
func init() {
103+
x, y := 1, 2
104+
x, y = y, x
105+
check(2, x)
106+
check(1, y)
107+
}
108+
109+
func check(want, got int) {
110+
if want != got {
111+
panic(fmt.Sprintf("wanted %d, but got %d", want, got))
112+
}
113+
}

0 commit comments

Comments
 (0)