| // Copyright 2022 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. |
| |
| package main |
| |
| func a() (r string) { |
| s := "initial" |
| var p *struct{ i int } |
| defer func() { |
| recover() |
| r = s |
| }() |
| |
| s, p.i = "set", 2 // s must be set before p.i panics |
| return "unreachable" |
| } |
| |
| func b() (r string) { |
| s := "initial" |
| fn := func() []int { panic("") } |
| defer func() { |
| recover() |
| r = s |
| }() |
| |
| s, fn()[0] = "set", 2 // fn() panics before any assignment occurs |
| return "unreachable" |
| } |
| |
| func c() (r string) { |
| s := "initial" |
| var p map[int]int |
| defer func() { |
| recover() |
| r = s |
| }() |
| |
| s, p[0] = "set", 2 //s must be set before p[0] index panics" |
| return "unreachable" |
| } |
| |
| func d() (r string) { |
| s := "initial" |
| var p map[int]int |
| defer func() { |
| recover() |
| r = s |
| }() |
| fn := func() int { panic("") } |
| |
| s, p[0] = "set", fn() // fn() panics before s is set |
| return "unreachable" |
| } |
| |
| func e() (r string) { |
| s := "initial" |
| p := map[int]int{} |
| defer func() { |
| recover() |
| r = s |
| }() |
| fn := func() int { panic("") } |
| |
| s, p[fn()] = "set", 0 // fn() panics before any assignment occurs |
| return "unreachable" |
| } |
| |
| func f() (r string) { |
| s := "initial" |
| p := []int{} |
| defer func() { |
| recover() |
| r = s |
| }() |
| |
| s, p[1] = "set", 0 // p[1] panics after s is set |
| return "unreachable" |
| } |
| |
| func g() (r string) { |
| s := "initial" |
| p := map[any]any{} |
| defer func() { |
| recover() |
| r = s |
| }() |
| var i any = func() {} |
| s, p[i] = "set", 0 // p[i] panics after s is set |
| return "unreachable" |
| } |
| |
| func h() (r string) { |
| fail := false |
| defer func() { |
| recover() |
| if fail { |
| r = "fail" |
| } else { |
| r = "success" |
| } |
| }() |
| |
| type T struct{ f int } |
| var p *struct{ *T } |
| |
| // The implicit "p.T" operand should be evaluated in phase 1 (and panic), |
| // before the "fail = true" assignment in phase 2. |
| fail, p.f = true, 0 |
| return "unreachable" |
| } |
| |
| func main() { |
| for _, test := range []struct { |
| fn func() string |
| want string |
| desc string |
| }{ |
| {a, "set", "s must be set before p.i panics"}, |
| {b, "initial", "p() panics before s is set"}, |
| {c, "set", "s must be set before p[0] index panics"}, |
| {d, "initial", "fn() panics before s is set"}, |
| {e, "initial", "fn() panics before s is set"}, |
| {f, "set", "p[1] panics after s is set"}, |
| {g, "set", "p[i] panics after s is set"}, |
| {h, "success", "p.T panics before fail is set"}, |
| } { |
| if test.fn() != test.want { |
| panic(test.desc) |
| } |
| } |
| } |