]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix "append outside assignment" ICE
authorMatthew Dempsky <mdempsky@google.com>
Mon, 25 Mar 2019 23:34:19 +0000 (16:34 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 26 Mar 2019 02:20:09 +0000 (02:20 +0000)
Some special-case code paths in order.go didn't expect OCALLFUNC to
have Ninit; in particular, OAS2FUNC and ODEFER/OGO failed to call
o.init on their child OCALLFUNC node. This resulted in not all of the
AST being properly ordered.

This was noticed because order is responsible for introducing an
invariant around how OAPPEND is used, which is enforced by walk.
However, there were perhaps simpler cases (e.g., simple order of
evaluation) that were being silently miscompiled.

Fixes #31010.

Change-Id: Ib928890ab5ec2aebd8e30a030bc2b404387f9123
Reviewed-on: https://go-review.googlesource.com/c/go/+/169257
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/order.go
test/fixedbugs/issue31010.go [new file with mode: 0644]

index 7b86537a21078215eeda93e23a301e898a3dd40b..aae18ff22727cfa9aa80a1fe9e678974475381c2 100644 (file)
@@ -383,6 +383,10 @@ func (o *Order) init(n *Node) {
 // call orders the call expression n.
 // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
 func (o *Order) call(n *Node) {
+       if n.Ninit.Len() > 0 {
+               // Caller should have already called o.init(n).
+               Fatalf("%v with unexpected ninit", n.Op)
+       }
        n.Left = o.expr(n.Left, nil)
        n.Right = o.expr(n.Right, nil) // ODDDARG temp
        o.exprList(n.List)
@@ -578,6 +582,7 @@ func (o *Order) stmt(n *Node) {
        case OAS2FUNC:
                t := o.markTemp()
                o.exprList(n.List)
+               o.init(n.Rlist.First())
                o.call(n.Rlist.First())
                o.as2(n)
                o.cleanTemp(t)
@@ -637,6 +642,7 @@ func (o *Order) stmt(n *Node) {
        // Special: order arguments to inner call but not call itself.
        case ODEFER, OGO:
                t := o.markTemp()
+               o.init(n.Left)
                o.call(n.Left)
                o.out = append(o.out, n)
                o.cleanTemp(t)
diff --git a/test/fixedbugs/issue31010.go b/test/fixedbugs/issue31010.go
new file mode 100644 (file)
index 0000000..836e85f
--- /dev/null
@@ -0,0 +1,24 @@
+// compile
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var (
+       x  int
+       xs []int
+)
+
+func a([]int) (int, error)
+
+func b() (int, error) {
+       return a(append(xs, x))
+}
+
+func c(int, error) (int, error)
+
+func d() (int, error) {
+       return c(b())
+}