diff --git a/GNUmakefile b/GNUmakefile index 2b85d610e..80d6a6e89 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -383,6 +383,7 @@ TEST_PACKAGES_LINUX := \ crypto/hmac \ debug/dwarf \ debug/plan9obj \ + encoding/binary \ go/constant \ image \ io/ioutil \ @@ -406,6 +407,7 @@ TEST_PACKAGES_WINDOWS := \ compress/flate \ crypto/des \ crypto/hmac \ + encoding/binary \ go/constant \ math/bits \ strconv \ diff --git a/compiler/asserts.go b/compiler/asserts.go index a3d060ce5..2de9a8128 100644 --- a/compiler/asserts.go +++ b/compiler/asserts.go @@ -31,7 +31,7 @@ func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value) { // Now do the bounds check: index >= arrayLen outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "") - b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", false) + b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", true) } // createSliceBoundsCheck emits a bounds check before a slicing operation to make @@ -230,7 +230,7 @@ func (b *builder) createDivideByZeroCheck(y llvm.Value) { // createRuntimeAssert is a common function to create a new branch on an assert // bool, calling an assert func if the assert value is true (1). -func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, invoke bool) { +func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, isInvoke bool) { // Check whether we can resolve this check at compile time. if !assert.IsAConstantInt().IsNil() { val := assert.ZExtValue() @@ -245,23 +245,17 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc // current insert position. faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw") nextBlock := b.insertBasicBlock(blockPrefix + ".next") - b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes // Now branch to the out-of-bounds or the regular block. b.CreateCondBr(assert, faultBlock, nextBlock) // Fail: the assert triggered so panic. b.SetInsertPointAtEnd(faultBlock) - if invoke { - // This runtime panic is recoverable. - b.createRuntimeInvoke(assertFunc, nil, "") - } else { - // This runtime panic is not recoverable. - b.createRuntimeCall(assertFunc, nil, "") - } + b.createRuntimeCallCommon(assertFunc, nil, "", isInvoke) b.CreateUnreachable() // Ok: assert didn't trigger so continue normally. + b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes b.SetInsertPointAtEnd(nextBlock) } diff --git a/src/runtime/error.go b/src/runtime/error.go index 0bca20c0b..20c8faa42 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -21,5 +21,6 @@ func (r runtimeError) RuntimeError() {} var ( divideError error = runtimeError{"runtime error: integer divide by zero"} + lookupError error = runtimeError{"runtime error: index out of range"} overflowError error = runtimeError{"runtime error: integer overflow"} ) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 1cabe8a51..fb5cbceab 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -187,7 +187,7 @@ func nilMapPanic() { // Panic when trying to access an array or slice out of bounds. func lookupPanic() { - runtimePanicAt(returnAddress(0), "index out of range") + _panic(lookupError) } // Panic when trying to slice a slice out of bounds. diff --git a/testdata/recover.go b/testdata/recover.go index 0a6a93dd7..7d335fbbf 100644 --- a/testdata/recover.go +++ b/testdata/recover.go @@ -32,6 +32,7 @@ func main() { println("\n# runtime panics") runtimePanicDivByZero(1, 0) + runtimePanicLookup([]int{1, 2, 3}, 10) println("\n# runtime.Goexit") runtimeGoexit() @@ -127,6 +128,16 @@ func runtimePanicDivByZero(a, b int) int { return a / b } +func runtimePanicLookup(slice []int, index int) int { + defer func() { + if err := recover(); err != nil { + println("recovered:", err) + } + }() + + return slice[index] +} + func runtimeGoexit() { wg.Add(1) go func() {