fix: correct control flow graph for constant conditional statements
This commit is contained in:
13
_test/for10.go
Normal file
13
_test/for10.go
Normal 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
14
_test/for11.go
Normal 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
12
_test/for12.go
Normal 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
13
_test/for13.go
Normal 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
16
_test/for14.go
Normal 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
12
_test/for9.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for false {
|
||||
println("nok")
|
||||
break
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
17
_test/if3.go
Normal file
17
_test/if3.go
Normal 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
19
_test/if4.go
Normal 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
12
_test/if5.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if true {
|
||||
println("ok")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
// bye
|
||||
11
_test/if6.go
Normal file
11
_test/if6.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if false {
|
||||
println("nok")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
110
interp/cfg.go
110
interp/cfg.go
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user