fix: correct control flow graph for constant conditional statements

This commit is contained in:
Marc Vertes
2020-03-25 12:18:05 +01:00
committed by GitHub
parent 0a99eb48c3
commit 4995654e04
11 changed files with 229 additions and 20 deletions

13
_test/for10.go Normal file
View File

@@ -0,0 +1,13 @@
package main
func main() {
for a := 0; false; {
println("nok", a)
a++
break
}
println("bye")
}
// Output:
// bye

14
_test/for11.go Normal file
View File

@@ -0,0 +1,14 @@
package main
func main() {
a := 0
for ; true; a++ {
println("nok", a)
break
}
println("bye", a)
}
// Output:
// nok 0
// bye 0

12
_test/for12.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
for a := 0; false; a++ {
println("nok", a)
break
}
println("bye")
}
// Output:
// bye

13
_test/for13.go Normal file
View File

@@ -0,0 +1,13 @@
package main
func main() {
a := 0
for ; false; a++ {
println("nok", a)
break
}
println("bye", a)
}
// Output:
// bye 0

16
_test/for14.go Normal file
View File

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

12
_test/for9.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
for false {
println("nok")
break
}
println("bye")
}
// Output:
// bye

17
_test/if3.go Normal file
View File

@@ -0,0 +1,17 @@
package main
func main() {
a := 0
if false {
println("false")
a = 1
} else {
println("true")
a = -1
}
println(a)
}
// Output:
// true
// -1

19
_test/if4.go Normal file
View File

@@ -0,0 +1,19 @@
package main
const bad = false
func main() {
a := 0
if bad {
println("false")
a = 1
} else {
println("true")
a = -1
}
println(a)
}
// Output:
// true
// -1

12
_test/if5.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
if true {
println("ok")
}
println("bye")
}
// Output:
// ok
// bye

11
_test/if6.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func main() {
if false {
println("nok")
}
println("bye")
}
// Output:
// bye

View File

@@ -863,10 +863,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = cond.start
cond.tnext = body.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
n.start = body.start
body.tnext = body.start
}
} else {
n.start = cond.start
cond.tnext = body.start
body.tnext = cond.start
}
cond.fnext = n
body.tnext = cond.start
sc = sc.pop()
case forStmt2: // for init; cond; {}
@@ -875,10 +883,20 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = init.start
init.tnext = cond.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
init.tnext = body.start
body.tnext = body.start
} else {
init.tnext = n
}
} else {
init.tnext = cond.start
body.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
body.tnext = cond.start
sc = sc.pop()
case forStmt3: // for ; cond; post {}
@@ -886,14 +904,22 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = cond.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
n.start = body.start
post.tnext = body.start
}
} else {
n.start = cond.start
post.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
body.tnext = post.start
post.tnext = cond.start
sc = sc.pop()
case forStmt3a: // for int; ; post {}
case forStmt3a: // for init; ; post {}
init, post, body := n.child[0], n.child[1], n.child[2]
n.start = init.start
init.tnext = body.start
@@ -907,11 +933,21 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = init.start
init.tnext = cond.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
init.tnext = body.start
post.tnext = body.start
} else {
init.tnext = n
}
} else {
init.tnext = cond.start
post.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
body.tnext = post.start
post.tnext = cond.start
sc = sc.pop()
case forRangeStmt:
@@ -986,8 +1022,15 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = cond.start
cond.tnext = tbody.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
n.start = tbody.start
}
} else {
n.start = cond.start
cond.tnext = tbody.start
}
cond.fnext = n
tbody.tnext = n
sc = sc.pop()
@@ -997,9 +1040,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test and the useless branch.
if cond.rval.Bool() {
n.start = tbody.start
} else {
n.start = fbody.start
}
} else {
n.start = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
}
tbody.tnext = n
fbody.tnext = n
sc = sc.pop()
@@ -1010,9 +1062,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = init.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
init.tnext = tbody.start
} else {
init.tnext = n
}
} else {
init.tnext = cond.start
cond.tnext = tbody.start
}
tbody.tnext = n
init.tnext = cond.start
cond.tnext = tbody.start
cond.fnext = n
sc = sc.pop()
@@ -1022,9 +1083,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = init.start
init.tnext = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
if cond.rval.IsValid() {
// Condition is known at compile time, bypass test.
if cond.rval.Bool() {
init.tnext = tbody.start
} else {
init.tnext = fbody.start
}
} else {
init.tnext = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
}
tbody.tnext = n
fbody.tnext = n
sc = sc.pop()