| // 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) | 
 | } |