fix: correct control flow graph for defer statements
This commit is contained in:
23
_test/defer4.go
Normal file
23
_test/defer4.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
|
||||
type T struct {
|
||||
mu sync.RWMutex
|
||||
name string
|
||||
}
|
||||
|
||||
func (t *T) get() string {
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
return t.name
|
||||
}
|
||||
|
||||
var d = T{name: "test"}
|
||||
|
||||
func main() {
|
||||
println(d.get())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test
|
||||
@@ -200,7 +200,6 @@ const (
|
||||
aCase
|
||||
aCompositeLit
|
||||
aDec
|
||||
aDefer
|
||||
aEqual
|
||||
aGreater
|
||||
aGreaterEqual
|
||||
@@ -258,7 +257,6 @@ var actions = [...]string{
|
||||
aCase: "case",
|
||||
aCompositeLit: "compositeLit",
|
||||
aDec: "--",
|
||||
aDefer: "defer",
|
||||
aEqual: "==",
|
||||
aGreater: ">",
|
||||
aGetFunc: "getFunc",
|
||||
@@ -569,7 +567,7 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
|
||||
st.push(addChild(&root, anc, pos, declStmt, aNop), nod)
|
||||
|
||||
case *ast.DeferStmt:
|
||||
st.push(addChild(&root, anc, pos, deferStmt, aDefer), nod)
|
||||
st.push(addChild(&root, anc, pos, deferStmt, aNop), nod)
|
||||
|
||||
case *ast.Ellipsis:
|
||||
st.push(addChild(&root, anc, pos, ellipsisExpr, aNop), nod)
|
||||
|
||||
@@ -936,7 +936,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc = sc.pop()
|
||||
err = genRun(n)
|
||||
|
||||
case goStmt:
|
||||
case deferStmt, goStmt:
|
||||
wireChild(n)
|
||||
|
||||
case identExpr:
|
||||
|
||||
@@ -29,7 +29,6 @@ var builtin = [...]bltnGenerator{
|
||||
aCase: _case,
|
||||
aCompositeLit: arrayLit,
|
||||
aDec: dec,
|
||||
aDefer: _defer,
|
||||
aEqual: equal,
|
||||
aGetFunc: getFunc,
|
||||
aGreater: greater,
|
||||
@@ -597,47 +596,6 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func _defer(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
values := make([]func(*frame) reflect.Value, len(n.child[0].child))
|
||||
var method func(*frame) reflect.Value
|
||||
|
||||
for i, c := range n.child[0].child {
|
||||
if c.typ.cat == funcT {
|
||||
values[i] = genFunctionWrapper(c)
|
||||
} else {
|
||||
if c.recv != nil {
|
||||
// defer a method on a binary obj
|
||||
mi := c.val.(int)
|
||||
m := genValue(c.child[0])
|
||||
method = func(f *frame) reflect.Value { return m(f).Method(mi) }
|
||||
}
|
||||
values[i] = genValue(c)
|
||||
}
|
||||
}
|
||||
|
||||
if method != nil {
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := make([]reflect.Value, len(values))
|
||||
val[0] = method(f)
|
||||
for i, v := range values[1:] {
|
||||
val[i+1] = v(f)
|
||||
}
|
||||
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := make([]reflect.Value, len(values))
|
||||
for i, v := range values {
|
||||
val[i] = v(f)
|
||||
}
|
||||
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func call(n *node) {
|
||||
goroutine := n.anc.kind == goStmt
|
||||
var method bool
|
||||
@@ -709,6 +667,21 @@ func call(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
if n.anc.kind == deferStmt {
|
||||
// Store function call in frame for deferred execution.
|
||||
value = genFunctionWrapper(n.child[0])
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := make([]reflect.Value, len(values)+1)
|
||||
val[0] = value(f)
|
||||
for i, v := range values {
|
||||
val[i+1] = v(f)
|
||||
}
|
||||
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
||||
return tnext
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
var def *node
|
||||
var ok bool
|
||||
@@ -893,8 +866,19 @@ func callBin(n *node) {
|
||||
l := len(values)
|
||||
|
||||
switch {
|
||||
case n.anc.kind == deferStmt:
|
||||
// Store function call in frame for deferred execution.
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := make([]reflect.Value, l+1)
|
||||
val[0] = value(f)
|
||||
for i, v := range values {
|
||||
val[i+1] = v(f)
|
||||
}
|
||||
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
||||
return tnext
|
||||
}
|
||||
case n.anc.kind == goStmt:
|
||||
// Execute function in a goroutine, discard results
|
||||
// Execute function in a goroutine, discard results.
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
@@ -904,7 +888,7 @@ func callBin(n *node) {
|
||||
return tnext
|
||||
}
|
||||
case fnext != nil:
|
||||
// Handle branching according to boolean result
|
||||
// Handle branching according to boolean result.
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
|
||||
Reference in New Issue
Block a user