|  | // run | 
|  |  | 
|  | // Copyright 2010 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Test of recover during recursive panics. | 
|  | // Here be dragons. | 
|  |  | 
|  | package main | 
|  |  | 
|  | import "runtime" | 
|  |  | 
|  | func main() { | 
|  | test1() | 
|  | test2() | 
|  | test3() | 
|  | test4() | 
|  | test5() | 
|  | test6() | 
|  | test7() | 
|  | } | 
|  |  | 
|  | func die() { | 
|  | runtime.Breakpoint()	// can't depend on panic | 
|  | } | 
|  |  | 
|  | func mustRecover(x interface{}) { | 
|  | mustNotRecover()	// because it's not a defer call | 
|  | v := recover() | 
|  | if v == nil { | 
|  | println("missing recover") | 
|  | die()	// panic is useless here | 
|  | } | 
|  | if v != x { | 
|  | println("wrong value", v, x) | 
|  | die() | 
|  | } | 
|  |  | 
|  | // the value should be gone now regardless | 
|  | v = recover() | 
|  | if v != nil { | 
|  | println("recover didn't recover") | 
|  | die() | 
|  | } | 
|  | } | 
|  |  | 
|  | func mustNotRecover() { | 
|  | v := recover() | 
|  | if v != nil { | 
|  | println("spurious recover") | 
|  | die() | 
|  | } | 
|  | } | 
|  |  | 
|  | func withoutRecover() { | 
|  | mustNotRecover()	// because it's a sub-call | 
|  | } | 
|  |  | 
|  | func test1() { | 
|  | // Easy nested recursive panic. | 
|  | defer mustRecover(1) | 
|  | defer func() { | 
|  | defer mustRecover(2) | 
|  | panic(2) | 
|  | }() | 
|  | panic(1) | 
|  | } | 
|  |  | 
|  | func test2() { | 
|  | // Sequential panic. | 
|  | defer mustNotRecover() | 
|  | defer func() { | 
|  | v := recover() | 
|  | if v == nil || v.(int) != 2 { | 
|  | println("wrong value", v, 2) | 
|  | die() | 
|  | } | 
|  | defer mustRecover(3) | 
|  | panic(3) | 
|  | }() | 
|  | panic(2) | 
|  | } | 
|  |  | 
|  | func test3() { | 
|  | // Sequential panic - like test2 but less picky. | 
|  | defer mustNotRecover() | 
|  | defer func() { | 
|  | recover() | 
|  | defer mustRecover(3) | 
|  | panic(3) | 
|  | }() | 
|  | panic(2) | 
|  | } | 
|  |  | 
|  | func test4() { | 
|  | // Single panic. | 
|  | defer mustNotRecover() | 
|  | defer func() { | 
|  | recover() | 
|  | }() | 
|  | panic(4) | 
|  | } | 
|  |  | 
|  | func test5() { | 
|  | // Single panic but recover called via defer | 
|  | defer mustNotRecover() | 
|  | defer func() { | 
|  | defer recover() | 
|  | }() | 
|  | panic(5) | 
|  | } | 
|  |  | 
|  | func test6() { | 
|  | // Sequential panic. | 
|  | // Like test3, but changed recover to defer (same change as test4 → test5). | 
|  | defer mustNotRecover() | 
|  | defer func() { | 
|  | defer recover()	// like a normal call from this func; runs because mustRecover stops the panic | 
|  | defer mustRecover(3) | 
|  | panic(3) | 
|  | }() | 
|  | panic(2) | 
|  | } | 
|  |  | 
|  | func test7() { | 
|  | // Like test6, but swapped defer order. | 
|  | // The recover in "defer recover()" is now a no-op, | 
|  | // because it runs called from panic, not from the func, | 
|  | // and therefore cannot see the panic of 2. | 
|  | // (Alternately, it cannot see the panic of 2 because | 
|  | // there is an active panic of 3.  And it cannot see the | 
|  | // panic of 3 because it is at the wrong level (too high on the stack).) | 
|  | defer mustRecover(2) | 
|  | defer func() { | 
|  | defer mustRecover(3) | 
|  | defer recover()	// now a no-op, unlike in test6. | 
|  | panic(3) | 
|  | }() | 
|  | panic(2) | 
|  | } |