1// run
2
3// Copyright 2010 The Go Authors.  All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// Test of recover during recursive panics.
8// Here be dragons.
9
10package main
11
12import "runtime"
13
14func main() {
15	test1()
16	test2()
17	test3()
18	test4()
19	test5()
20	test6()
21	test7()
22}
23
24func die() {
25	runtime.Breakpoint()	// can't depend on panic
26}
27
28func mustRecover(x interface{}) {
29	mustNotRecover()	// because it's not a defer call
30	v := recover()
31	if v == nil {
32		println("missing recover")
33		die()	// panic is useless here
34	}
35	if v != x {
36		println("wrong value", v, x)
37		die()
38	}
39
40	// the value should be gone now regardless
41	v = recover()
42	if v != nil {
43		println("recover didn't recover")
44		die()
45	}
46}
47
48func mustNotRecover() {
49	v := recover()
50	if v != nil {
51		println("spurious recover")
52		die()
53	}
54}
55
56func withoutRecover() {
57	mustNotRecover()	// because it's a sub-call
58}
59
60func test1() {
61	// Easy nested recursive panic.
62	defer mustRecover(1)
63	defer func() {
64		defer mustRecover(2)
65		panic(2)
66	}()
67	panic(1)
68}
69
70func test2() {
71	// Sequential panic.
72	defer mustNotRecover()
73	defer func() {
74		v := recover()
75		if v == nil || v.(int) != 2 {
76			println("wrong value", v, 2)
77			die()
78		}
79		defer mustRecover(3)
80		panic(3)
81	}()
82	panic(2)
83}
84
85func test3() {
86	// Sequential panic - like test2 but less picky.
87	defer mustNotRecover()
88	defer func() {
89		recover()
90		defer mustRecover(3)
91		panic(3)
92	}()
93	panic(2)
94}
95
96func test4() {
97	// Single panic.
98	defer mustNotRecover()
99	defer func() {
100		recover()
101	}()
102	panic(4)
103}
104
105func test5() {
106	// Single panic but recover called via defer
107	defer mustNotRecover()
108	defer func() {
109		defer recover()
110	}()
111	panic(5)
112}
113
114func test6() {
115	// Sequential panic.
116	// Like test3, but changed recover to defer (same change as test4 → test5).
117	defer mustNotRecover()
118	defer func() {
119		defer recover()	// like a normal call from this func; runs because mustRecover stops the panic
120		defer mustRecover(3)
121		panic(3)
122	}()
123	panic(2)
124}
125
126func test7() {
127	// Like test6, but swapped defer order.
128	// The recover in "defer recover()" is now a no-op,
129	// because it runs called from panic, not from the func,
130	// and therefore cannot see the panic of 2.
131	// (Alternately, it cannot see the panic of 2 because
132	// there is an active panic of 3.  And it cannot see the
133	// panic of 3 because it is at the wrong level (too high on the stack).)
134	defer mustRecover(2)
135	defer func() {
136		defer mustRecover(3)
137		defer recover()	// now a no-op, unlike in test6.
138		panic(3)
139	}()
140	panic(2)
141}
142