1 | // Copyright 2022 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | package main |
6 | |
7 | func a() (r string) { |
8 | s := "initial" |
9 | var p *struct{ i int } |
10 | defer func() { |
11 | recover() |
12 | r = s |
13 | }() |
14 | |
15 | s, p.i = "set", 2 // s must be set before p.i panics |
16 | return "unreachable" |
17 | } |
18 | |
19 | func b() (r string) { |
20 | s := "initial" |
21 | fn := func() []int { panic("") } |
22 | defer func() { |
23 | recover() |
24 | r = s |
25 | }() |
26 | |
27 | s, fn()[0] = "set", 2 // fn() panics before any assignment occurs |
28 | return "unreachable" |
29 | } |
30 | |
31 | func c() (r string) { |
32 | s := "initial" |
33 | var p map[int]int |
34 | defer func() { |
35 | recover() |
36 | r = s |
37 | }() |
38 | |
39 | s, p[0] = "set", 2 //s must be set before p[0] index panics" |
40 | return "unreachable" |
41 | } |
42 | |
43 | func d() (r string) { |
44 | s := "initial" |
45 | var p map[int]int |
46 | defer func() { |
47 | recover() |
48 | r = s |
49 | }() |
50 | fn := func() int { panic("") } |
51 | |
52 | s, p[0] = "set", fn() // fn() panics before s is set |
53 | return "unreachable" |
54 | } |
55 | |
56 | func e() (r string) { |
57 | s := "initial" |
58 | p := map[int]int{} |
59 | defer func() { |
60 | recover() |
61 | r = s |
62 | }() |
63 | fn := func() int { panic("") } |
64 | |
65 | s, p[fn()] = "set", 0 // fn() panics before any assignment occurs |
66 | return "unreachable" |
67 | } |
68 | |
69 | func f() (r string) { |
70 | s := "initial" |
71 | p := []int{} |
72 | defer func() { |
73 | recover() |
74 | r = s |
75 | }() |
76 | |
77 | s, p[1] = "set", 0 // p[1] panics after s is set |
78 | return "unreachable" |
79 | } |
80 | |
81 | func g() (r string) { |
82 | s := "initial" |
83 | p := map[any]any{} |
84 | defer func() { |
85 | recover() |
86 | r = s |
87 | }() |
88 | var i any = func() {} |
89 | s, p[i] = "set", 0 // p[i] panics after s is set |
90 | return "unreachable" |
91 | } |
92 | |
93 | func h() (r string) { |
94 | fail := false |
95 | defer func() { |
96 | recover() |
97 | if fail { |
98 | r = "fail" |
99 | } else { |
100 | r = "success" |
101 | } |
102 | }() |
103 | |
104 | type T struct{ f int } |
105 | var p *struct{ *T } |
106 | |
107 | // The implicit "p.T" operand should be evaluated in phase 1 (and panic), |
108 | // before the "fail = true" assignment in phase 2. |
109 | fail, p.f = true, 0 |
110 | return "unreachable" |
111 | } |
112 | |
113 | func main() { |
114 | for _, test := range []struct { |
115 | fn func() string |
116 | want string |
117 | desc string |
118 | }{ |
119 | {a, "set", "s must be set before p.i panics"}, |
120 | {b, "initial", "p() panics before s is set"}, |
121 | {c, "set", "s must be set before p[0] index panics"}, |
122 | {d, "initial", "fn() panics before s is set"}, |
123 | {e, "initial", "fn() panics before s is set"}, |
124 | {f, "set", "p[1] panics after s is set"}, |
125 | {g, "set", "p[i] panics after s is set"}, |
126 | {h, "success", "p.T panics before fail is set"}, |
127 | } { |
128 | if test.fn() != test.want { |
129 | panic(test.desc) |
130 | } |
131 | } |
132 | } |
133 |
Members