From: Dhananjay Nakrani Date: Sat, 24 Dec 2016 06:28:45 +0000 (-0800) Subject: cmd/compile: Ensure left-to-right assignment X-Git-Tag: go1.9beta1~1608 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1cde87b312c5687cd0d70457c48586055e8c53ca;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 9530d4d928..2a707a32ac 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -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) + } +} diff --git a/test/reorder.go b/test/reorder.go index fc44be90de..3a87d025c2 100644 --- a/test/reorder.go +++ b/test/reorder.go @@ -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") + } +}