mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 23:25:22 +00:00
compiler: correctly handle defer in functions without return values
Fix #2253.
This commit is contained in:
parent
b31a8d750e
commit
a91581fa16
2 changed files with 37 additions and 4 deletions
|
@ -499,6 +499,7 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
|
||||||
// we should clean alt.stack manually.
|
// we should clean alt.stack manually.
|
||||||
// This can be the case with void and named-return functions.
|
// This can be the case with void and named-return functions.
|
||||||
if !isInit && !isDeploy && !lastStmtIsReturn(decl.Body) {
|
if !isInit && !isDeploy && !lastStmtIsReturn(decl.Body) {
|
||||||
|
c.processDefers()
|
||||||
c.saveSequencePoint(decl.Body)
|
c.saveSequencePoint(decl.Body)
|
||||||
emit.Opcodes(c.prog.BinWriter, opcode.RET)
|
emit.Opcodes(c.prog.BinWriter, opcode.RET)
|
||||||
}
|
}
|
||||||
|
@ -1329,10 +1330,13 @@ func (c *codegen) processDefers() {
|
||||||
c.emitStoreByIndex(varLocal, finalIndex)
|
c.emitStoreByIndex(varLocal, finalIndex)
|
||||||
ast.Walk(c, stmt.expr)
|
ast.Walk(c, stmt.expr)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
// After panic, default values must be returns, except for named returns,
|
results := c.scope.decl.Type.Results
|
||||||
// which we don't support here for now.
|
if results.NumFields() != 0 {
|
||||||
for i := len(c.scope.decl.Type.Results.List) - 1; i >= 0; i-- {
|
// After panic, default values must be returns, except for named returns,
|
||||||
c.emitDefault(c.typeOf(c.scope.decl.Type.Results.List[i].Type))
|
// which we don't support here for now.
|
||||||
|
for i := len(results.List) - 1; i >= 0; i-- {
|
||||||
|
c.emitDefault(c.typeOf(results.List[i].Type))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit.Jmp(c.prog.BinWriter, opcode.ENDTRYL, after)
|
emit.Jmp(c.prog.BinWriter, opcode.ENDTRYL, after)
|
||||||
|
|
|
@ -3,6 +3,8 @@ package compiler_test
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDefer(t *testing.T) {
|
func TestDefer(t *testing.T) {
|
||||||
|
@ -79,6 +81,33 @@ func TestDefer(t *testing.T) {
|
||||||
}`
|
}`
|
||||||
eval(t, src, big.NewInt(13))
|
eval(t, src, big.NewInt(13))
|
||||||
})
|
})
|
||||||
|
t.Run("NoReturnReturn", func(t *testing.T) {
|
||||||
|
src := `package main
|
||||||
|
var i int
|
||||||
|
func Main() {
|
||||||
|
defer func() {
|
||||||
|
i++
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}`
|
||||||
|
vm := vmAndCompile(t, src)
|
||||||
|
err := vm.Run()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 0, vm.Estack().Len(), "stack contains unexpected items")
|
||||||
|
})
|
||||||
|
t.Run("NoReturnNoReturn", func(t *testing.T) {
|
||||||
|
src := `package main
|
||||||
|
var i int
|
||||||
|
func Main() {
|
||||||
|
defer func() {
|
||||||
|
i++
|
||||||
|
}()
|
||||||
|
}`
|
||||||
|
vm := vmAndCompile(t, src)
|
||||||
|
err := vm.Run()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 0, vm.Estack().Len(), "stack contains unexpected items")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecover(t *testing.T) {
|
func TestRecover(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue