// run
-// Copyright 2010 The Go Authors. All rights reserved.
+// 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.
)
func main() {
+ // go.tools/ssa/interp still has:
+ // - some lesser bugs in recover()
+ // - incomplete support for reflection
+ interp := os.Getenv("GOSSAINTERP") != ""
+
test1()
test1WithClosures()
test2()
test3()
- // exp/ssa/interp still has some bugs in recover().
- if os.Getenv("GOSSAINTERP") == "" {
+ if !interp {
test4()
- test5()
}
+ test5()
test6()
test6WithClosures()
test7()
test8()
test9()
- test9reflect1()
- test9reflect2()
+ if !interp {
+ test9reflect1()
+ test9reflect2()
+ }
test10()
- test10reflect1()
- test10reflect2()
+ if !interp {
+ test10reflect1()
+ test10reflect2()
+ }
test11()
- test11reflect1()
- test11reflect2()
+ if !interp {
+ test11reflect1()
+ test11reflect2()
+ }
+ test111()
test12()
- test12reflect1()
- test12reflect2()
+ if !interp {
+ test12reflect1()
+ test12reflect2()
+ }
test13()
- test13reflect1()
- test13reflect2()
+ if !interp {
+ test13reflect1()
+ test13reflect2()
+ }
test14()
- test14reflect1()
- test14reflect2()
- test15()
+ if !interp {
+ test14reflect1()
+ test14reflect2()
+ test15()
+ test16()
+ }
}
func die() {
}
v = v2
if v == nil {
- println("missing recover")
+ println("missing recover", x.(int))
die() // panic is useless here
}
if v != x {
mustNotRecover() // because it's a sub-call
}
+func withoutRecoverRecursive(n int) {
+ if n == 0 {
+ withoutRecoverRecursive(1)
+ } else {
+ v := recover()
+ if v != nil {
+ println("spurious recover (recursive)", v)
+ die()
+ }
+ }
+}
+
func test1() {
- defer mustNotRecover() // because mustRecover will squelch it
- defer mustRecover(1) // because of panic below
- defer withoutRecover() // should be no-op, leaving for mustRecover to find
+ defer mustNotRecover() // because mustRecover will squelch it
+ defer mustRecover(1) // because of panic below
+ defer withoutRecover() // should be no-op, leaving for mustRecover to find
+ defer withoutRecoverRecursive(0) // ditto
panic(1)
}
mustNotRecover()
v := recover()
if v == nil {
- println("missing recover")
+ println("missing recover", x.(int))
die()
}
if v != x {
}
}
-type I interface{ M() }
+type I interface {
+ M()
+}
// pointer receiver, so no wrapper in i.M()
-type T1 struct {}
+type T1 struct{}
func (*T1) M() {
mustRecoverBody(doubleRecover(), recover(), recover(), 9)
}
// tiny receiver, so basic wrapper in i.M()
-type T3 struct {}
+type T3 struct{}
func (T3) M() {
mustRecoverBody(doubleRecover(), recover(), recover(), 11)
panic(11)
}
+// tiny receiver, so basic wrapper in i.M()
+type T3deeper struct{}
+
+func (T3deeper) M() {
+ badstate() // difference from T3
+ mustRecoverBody(doubleRecover(), recover(), recover(), 111)
+}
+
+func test111() {
+ var i I = T3deeper{}
+ defer i.M()
+ panic(111)
+}
+
+type Tiny struct{}
+
+func (Tiny) M() {
+ panic(112)
+}
+
+// i.M is a wrapper, and i.M panics.
+//
+// This is a torture test for an old implementation of recover that
+// tried to deal with wrapper functions by doing some argument
+// positioning math on both entry and exit. Doing anything on exit
+// is a problem because sometimes functions exit via panic instead
+// of an ordinary return, so panic would have to know to do the
+// same math when unwinding the stack. It gets complicated fast.
+// This particular test never worked with the old scheme, because
+// panic never did the right unwinding math.
+//
+// The new scheme adjusts Panic.argp on entry to a wrapper.
+// It has no exit work, so if a wrapper is interrupted by a panic,
+// there's no cleanup that panic itself must do.
+// This test just works now.
+func badstate() {
+ defer func() {
+ recover()
+ }()
+ var i I = Tiny{}
+ i.M()
+}
+
// large receiver, so basic wrapper in i.M()
type T4 [2]string
defer f()
panic(15)
}
+
+func reflectFunc2(args []reflect.Value) (results []reflect.Value) {
+ // This will call reflectFunc3
+ args[0].Interface().(func())()
+ return nil
+}
+
+func reflectFunc3(args []reflect.Value) (results []reflect.Value) {
+ if v := recover(); v != nil {
+ println("spurious recover", v)
+ die()
+ }
+ return nil
+}
+
+func test16() {
+ defer mustRecover(16)
+
+ f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func()))
+ f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func())
+ defer f2(f3)
+
+ panic(16)
+}