diff --git a/compiler/channel.go b/compiler/channel.go index 0ff2ab7f3..82139de8b 100644 --- a/compiler/channel.go +++ b/compiler/channel.go @@ -48,7 +48,7 @@ func (b *builder) createChanSend(instr *ssa.Send) { channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op") // Do the send. - b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "") + b.createRuntimeInvoke("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "") // End the lifetime of the allocas. // This also works around a bug in CoroSplit, at least in LLVM 8: @@ -101,7 +101,7 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value { // createChanClose closes the given channel. func (b *builder) createChanClose(ch llvm.Value) { - b.createRuntimeCall("chanClose", []llvm.Value{ch}, "") + b.createRuntimeInvoke("chanClose", []llvm.Value{ch}, "") } // createSelect emits all IR necessary for a select statements. That's a diff --git a/compiler/map.go b/compiler/map.go index 59d4bbf81..fda2cec2c 100644 --- a/compiler/map.go +++ b/compiler/map.go @@ -133,7 +133,7 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { // key is a string params := []llvm.Value{m, key, valueAlloca} - b.createRuntimeCall("hashmapStringSet", params, "") + b.createRuntimeInvoke("hashmapStringSet", params, "") } else { // Key stored at actual type. keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") @@ -143,7 +143,7 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, fnName = "hashmapGenericSet" } params := []llvm.Value{m, keyAlloca, valueAlloca} - b.createRuntimeCall(fnName, params, "") + b.createRuntimeInvoke(fnName, params, "") b.emitLifetimeEnd(keyAlloca, keySize) } b.emitLifetimeEnd(valueAlloca, valueSize) diff --git a/testdata/recover.go b/testdata/recover.go index 37b59607f..1b7791d8b 100644 --- a/testdata/recover.go +++ b/testdata/recover.go @@ -41,6 +41,9 @@ func main() { println("\n# recover runtime errors") recoverRuntimeError() + + println("\n# recover from nil map and closed channel") + recoverNilMapAndChan() } func recoverSimple() { @@ -241,3 +244,20 @@ func recoverMustPanic(name string, f func()) { }() f() } + +// Test recovering from nil map assignment and closed channel send. +func recoverNilMapAndChan() { + recoverMustPanic("nil map", func() { + var m map[string]int + m["x"] = 1 + }) + recoverMustPanic("closed chan", func() { + ch := make(chan int) + close(ch) + ch <- 1 + }) + recoverMustPanic("close nil chan", func() { + var ch chan int + close(ch) + }) +} diff --git a/testdata/recover.txt b/testdata/recover.txt index 2b6b47af9..18ae7bad9 100644 --- a/testdata/recover.txt +++ b/testdata/recover.txt @@ -44,3 +44,8 @@ outer recovered: repanic value recovered: slice recovered: type assert recovered: empty interface type assert + +# recover from nil map and closed channel + recovered: nil map + recovered: closed chan + recovered: close nil chan