mirror of
https://github.com/golang/go
synced 2024-11-22 15:24:42 -07:00
cmd/compile: Ensure left-to-right assignment
Add temporaries to reorder the assignment for OAS2XXX nodes. This makes orderstmt(), rewrite a, b, c = ... as tmp1, tmp2, tmp3 = ... a, b, c = tmp1, tmp2, tmp3 and a, ok = ... as t1, t2 = ... a = t1 ok = t2 Fixes #13433. Change-Id: Id0f5956e3a254d0a6f4b89b5f7b0e055b1f0e21f Reviewed-on: https://go-review.googlesource.com/34713 Run-TryBot: Dhananjay Nakrani <dhananjayn@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
e0d50a5830
commit
1cde87b312
@ -508,7 +508,7 @@ func orderstmt(n *Node, order *Order) {
|
||||
orderexprlist(n.List, order)
|
||||
orderexprlist(n.Rlist, order)
|
||||
switch n.Op {
|
||||
case OAS2, OAS2DOTTYPE:
|
||||
case OAS2:
|
||||
ordermapassign(n, order)
|
||||
default:
|
||||
order.out = append(order.out, n)
|
||||
@ -554,7 +554,7 @@ func orderstmt(n *Node, order *Order) {
|
||||
r.Right.Op = OARRAYBYTESTRTMP
|
||||
}
|
||||
ordermapkeytemp(r, order)
|
||||
ordermapassign(n, order)
|
||||
orderokas2(n, order)
|
||||
cleantemp(t, order)
|
||||
|
||||
// Special: avoid copy of func call n->rlist->n.
|
||||
@ -563,7 +563,7 @@ func orderstmt(n *Node, order *Order) {
|
||||
|
||||
orderexprlist(n.List, order)
|
||||
ordercall(n.Rlist.First(), order)
|
||||
ordermapassign(n, order)
|
||||
orderas2(n, order)
|
||||
cleantemp(t, order)
|
||||
|
||||
// Special: use temporary variables to hold result,
|
||||
@ -574,31 +574,7 @@ func orderstmt(n *Node, order *Order) {
|
||||
|
||||
orderexprlist(n.List, order)
|
||||
n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
|
||||
|
||||
var tmp1, tmp2 *Node
|
||||
if !isblank(n.List.First()) {
|
||||
typ := n.Rlist.First().Type
|
||||
tmp1 = ordertemp(typ, order, haspointers(typ))
|
||||
}
|
||||
if !isblank(n.List.Second()) && !n.List.Second().Type.IsBoolean() {
|
||||
tmp2 = ordertemp(Types[TBOOL], order, false)
|
||||
}
|
||||
|
||||
order.out = append(order.out, n)
|
||||
|
||||
if tmp1 != nil {
|
||||
r := nod(OAS, n.List.First(), tmp1)
|
||||
r = typecheck(r, Etop)
|
||||
ordermapassign(r, order)
|
||||
n.List.SetIndex(0, tmp1)
|
||||
}
|
||||
if tmp2 != nil {
|
||||
r := okas(n.List.Second(), tmp2)
|
||||
r = typecheck(r, Etop)
|
||||
ordermapassign(r, order)
|
||||
n.List.SetIndex(1, tmp2)
|
||||
}
|
||||
|
||||
orderokas2(n, order)
|
||||
cleantemp(t, order)
|
||||
|
||||
// Special: use temporary variables to hold result,
|
||||
@ -1229,3 +1205,68 @@ func okas(ok, val *Node) *Node {
|
||||
}
|
||||
return nod(OAS, ok, val)
|
||||
}
|
||||
|
||||
// orderas2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
|
||||
// The caller should order the right-hand side of the assignment before calling orderas2.
|
||||
// It rewrites,
|
||||
// a, b, a = ...
|
||||
// as
|
||||
// tmp1, tmp2, tmp3 = ...
|
||||
// a, b, a = tmp1, tmp2, tmp3
|
||||
// This is necessary to ensure left to right assignment order.
|
||||
func orderas2(n *Node, order *Order) {
|
||||
tmplist := []*Node{}
|
||||
left := []*Node{}
|
||||
for _, l := range n.List.Slice() {
|
||||
if !isblank(l) {
|
||||
tmp := ordertemp(l.Type, order, haspointers(l.Type))
|
||||
tmplist = append(tmplist, tmp)
|
||||
left = append(left, l)
|
||||
}
|
||||
}
|
||||
|
||||
order.out = append(order.out, n)
|
||||
|
||||
as := nod(OAS2, nil, nil)
|
||||
as.List.Set(left)
|
||||
as.Rlist.Set(tmplist)
|
||||
as = typecheck(as, Etop)
|
||||
orderstmt(as, order)
|
||||
|
||||
ti := 0
|
||||
for ni, l := range n.List.Slice() {
|
||||
if !isblank(l) {
|
||||
n.List.SetIndex(ni, tmplist[ti])
|
||||
ti++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// orderokas2 orders OAS2 with ok.
|
||||
// Just like orderas2(), this also adds temporaries to ensure left-to-right assignment.
|
||||
func orderokas2(n *Node, order *Order) {
|
||||
var tmp1, tmp2 *Node
|
||||
if !isblank(n.List.First()) {
|
||||
typ := n.Rlist.First().Type
|
||||
tmp1 = ordertemp(typ, order, haspointers(typ))
|
||||
}
|
||||
|
||||
if !isblank(n.List.Second()) {
|
||||
tmp2 = ordertemp(Types[TBOOL], order, false)
|
||||
}
|
||||
|
||||
order.out = append(order.out, n)
|
||||
|
||||
if tmp1 != nil {
|
||||
r := nod(OAS, n.List.First(), tmp1)
|
||||
r = typecheck(r, Etop)
|
||||
ordermapassign(r, order)
|
||||
n.List.SetIndex(0, tmp1)
|
||||
}
|
||||
if tmp2 != nil {
|
||||
r := okas(n.List.Second(), tmp2)
|
||||
r = typecheck(r, Etop)
|
||||
ordermapassign(r, order)
|
||||
n.List.SetIndex(1, tmp2)
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ func main() {
|
||||
p6()
|
||||
p7()
|
||||
p8()
|
||||
p9()
|
||||
}
|
||||
|
||||
var gx []int
|
||||
@ -112,3 +113,39 @@ func p8() {
|
||||
panic(m[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #13433: Left-to-right assignment of OAS2XXX nodes.
|
||||
func p9() {
|
||||
var x bool
|
||||
|
||||
// OAS2FUNC
|
||||
x, x = fn()
|
||||
checkOAS2XXX(x, "x, x = fn()")
|
||||
|
||||
// OAS2RECV
|
||||
var c = make(chan bool, 10)
|
||||
c <- false
|
||||
x, x = <-c
|
||||
checkOAS2XXX(x, "x, x <-c")
|
||||
|
||||
// OAS2MAPR
|
||||
var m = map[int]bool{0: false}
|
||||
x, x = m[0]
|
||||
checkOAS2XXX(x, "x, x = m[0]")
|
||||
|
||||
// OAS2DOTTYPE
|
||||
var i interface{} = false
|
||||
x, x = i.(bool)
|
||||
checkOAS2XXX(x, "x, x = i.(bool)")
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func fn() (bool, bool) { return false, true }
|
||||
|
||||
// checks the order of OAS2XXX.
|
||||
func checkOAS2XXX(x bool, s string) {
|
||||
if !x {
|
||||
fmt.Printf("%s; got=(false); want=(true)\n", s)
|
||||
panic("failed")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user