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