interp: fix CFG in case of for loop with empty init and cond

Refactor `for` variants for clarity. Ensure all possible 8 combinations
are covered.

Fixes #942.
This commit is contained in:
Marc Vertes
2020-11-05 11:00:04 +01:00
committed by GitHub
parent b1ccfbf47f
commit 61f4704925
3 changed files with 58 additions and 41 deletions

16
_test/for16.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func main() {
max := 1
for ; ; max-- {
if max == 0 {
break
}
println("in for")
}
println("bye")
}
// Output:
// in for
// bye

View File

@@ -51,13 +51,14 @@ const (
fieldList
fileStmt
forStmt0 // for {}
forStmt0a // for init; ; {}
forStmt1 // for cond {}
forStmt2 // for init; cond; {}
forStmt3 // for ; cond; post {}
forStmt3a // for init; ; post {}
forStmt4 // for init; cond; post {}
forRangeStmt // for range
forStmt1 // for init; ; {}
forStmt2 // for cond {}
forStmt3 // for init; cond; {}
forStmt4 // for ; ; post {}
forStmt5 // for ; cond; post {}
forStmt6 // for init; ; post {}
forStmt7 // for init; cond; post {}
forRangeStmt // for range {}
funcDecl
funcLit
funcType
@@ -132,12 +133,13 @@ var kinds = [...]string{
fieldList: "fieldList",
fileStmt: "fileStmt",
forStmt0: "forStmt0",
forStmt0a: "forStmt0a",
forStmt1: "forStmt1",
forStmt2: "forStmt2",
forStmt3: "forStmt3",
forStmt3a: "forStmt3a",
forStmt4: "forStmt4",
forStmt5: "forStmt5",
forStmt6: "forStmt6",
forStmt7: "forStmt7",
forRangeStmt: "forRangeStmt",
funcDecl: "funcDecl",
funcType: "funcType",
@@ -656,27 +658,23 @@ func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error
case *ast.ForStmt:
// Disambiguate variants of FOR statements with a node kind per variant
var kind nkind
if a.Cond == nil {
if a.Init != nil {
if a.Post != nil {
kind = forStmt3a
} else {
kind = forStmt0a
}
} else {
kind = forStmt0
}
} else {
switch {
case a.Init == nil && a.Post == nil:
kind = forStmt1
case a.Init != nil && a.Post == nil:
kind = forStmt2
case a.Init == nil && a.Post != nil:
kind = forStmt3
default:
kind = forStmt4
}
switch {
case a.Cond == nil && a.Init == nil && a.Post == nil:
kind = forStmt0
case a.Cond == nil && a.Init != nil && a.Post == nil:
kind = forStmt1
case a.Cond != nil && a.Init == nil && a.Post == nil:
kind = forStmt2
case a.Cond != nil && a.Init != nil && a.Post == nil:
kind = forStmt3
case a.Cond == nil && a.Init == nil && a.Post != nil:
kind = forStmt4
case a.Cond != nil && a.Init == nil && a.Post != nil:
kind = forStmt5
case a.Cond == nil && a.Init != nil && a.Post != nil:
kind = forStmt6
case a.Cond != nil && a.Init != nil && a.Post != nil:
kind = forStmt7
}
st.push(addChild(&root, anc, pos, kind, aNop), nod)

View File

@@ -320,11 +320,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
}
case forStmt0, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.child[0]
case forStmt0a, forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.lastChild()
@@ -1050,14 +1046,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = n.start
sc = sc.pop()
case forStmt0a: // for init; ; {}
case forStmt1: // for init; ; {}
init, body := n.child[0], n.child[1]
n.start = init.start
init.tnext = body.start
body.tnext = n.start
sc = sc.pop()
case forStmt1: // for cond {}
case forStmt2: // for cond {}
cond, body := n.child[0], n.child[1]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1076,7 +1072,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt2: // for init; cond; {}
case forStmt3: // for init; cond; {}
init, cond, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1098,7 +1094,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt3: // for ; cond; post {}
case forStmt4: // for ; ; post {}
post, body := n.child[0], n.child[1]
n.start = body.start
post.tnext = body.start
body.tnext = post.start
sc = sc.pop()
case forStmt5: // for ; cond; post {}
cond, post, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1118,7 +1121,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = post.start
sc = sc.pop()
case forStmt3a: // for init; ; post {}
case forStmt6: // for init; ; post {}
init, post, body := n.child[0], n.child[1], n.child[2]
n.start = init.start
init.tnext = body.start
@@ -1126,7 +1129,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
post.tnext = body.start
sc = sc.pop()
case forStmt4: // for init; cond; post {}
case forStmt7: // for init; cond; post {}
init, cond, post, body := n.child[0], n.child[1], n.child[2], n.child[3]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")