]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: preserve loop depth when evaluating block
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Thu, 5 Sep 2019 04:15:59 +0000 (11:15 +0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 6 Sep 2019 01:35:46 +0000 (01:35 +0000)
Add block method to preserve loop depth when evaluating statements in a
block, so escape analysis can handle looping label more precisely.

Updates #22438

Change-Id: I39b306544a6c0ee3fcbebbe0d0ee735cb71773e6
Reviewed-on: https://go-review.googlesource.com/c/go/+/193517
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/escape.go
test/escape_goto.go [new file with mode: 0644]

index c03e50628d2eb150fbfc627e7a5ab20d076101ec..d2e096d0f0fffaeb3e5faa63e0a61c1391560852 100644 (file)
@@ -201,7 +201,7 @@ func (e *Escape) walkFunc(fn *Node) {
 
        e.curfn = fn
        e.loopDepth = 1
-       e.stmts(fn.Nbody)
+       e.block(fn.Nbody)
 }
 
 // Below we implement the methods for walking the AST and recording
@@ -284,14 +284,14 @@ func (e *Escape) stmt(n *Node) {
 
        case OIF:
                e.discard(n.Left)
-               e.stmts(n.Nbody)
-               e.stmts(n.Rlist)
+               e.block(n.Nbody)
+               e.block(n.Rlist)
 
        case OFOR, OFORUNTIL:
                e.loopDepth++
                e.discard(n.Left)
                e.stmt(n.Right)
-               e.stmts(n.Nbody)
+               e.block(n.Nbody)
                e.loopDepth--
 
        case ORANGE:
@@ -311,7 +311,7 @@ func (e *Escape) stmt(n *Node) {
                        }
                }
 
-               e.stmts(n.Nbody)
+               e.block(n.Nbody)
                e.loopDepth--
 
        case OSWITCH:
@@ -340,13 +340,13 @@ func (e *Escape) stmt(n *Node) {
                        }
 
                        e.discards(cas.List)
-                       e.stmts(cas.Nbody)
+                       e.block(cas.Nbody)
                }
 
        case OSELECT:
                for _, cas := range n.List.Slice() {
                        e.stmt(cas.Left)
-                       e.stmts(cas.Nbody)
+                       e.block(cas.Nbody)
                }
        case OSELRECV:
                e.assign(n.Left, n.Right, "selrecv", n)
@@ -398,12 +398,18 @@ func (e *Escape) stmt(n *Node) {
 }
 
 func (e *Escape) stmts(l Nodes) {
-       // TODO(mdempsky): Preserve and restore e.loopDepth? See also #22438.
        for _, n := range l.Slice() {
                e.stmt(n)
        }
 }
 
+// block is like stmts, but preserves loopDepth.
+func (e *Escape) block(l Nodes) {
+       old := e.loopDepth
+       e.stmts(l)
+       e.loopDepth = old
+}
+
 // expr models evaluating an expression n and flowing the result into
 // hole k.
 func (e *Escape) expr(k EscHole, n *Node) {
diff --git a/test/escape_goto.go b/test/escape_goto.go
new file mode 100644 (file)
index 0000000..f024a9a
--- /dev/null
@@ -0,0 +1,44 @@
+// errorcheck -0 -m -l
+
+// 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.
+
+// Test escape analysis for goto statements.
+
+package escape
+
+var x bool
+
+func _() {
+       var p *int
+loop:
+       if x {
+               goto loop
+       }
+       // BAD: We should be able to recognize that there
+       // aren't any more "goto loop" after here.
+       p = new(int) // ERROR "escapes to heap"
+       _ = p
+}
+
+func _() {
+       var p *int
+       if x {
+       loop:
+               goto loop
+       } else {
+               p = new(int) // ERROR "does not escape"
+       }
+       _ = p
+}
+
+func _() {
+       var p *int
+       if x {
+       loop:
+               goto loop
+       }
+       p = new(int) // ERROR "does not escape"
+       _ = p
+}