]> Cypherpunks.ru repositories - gostls13.git/blobdiff - test/recover.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / test / recover.go
index dc8bcfe8015cbdf0db60b5fe4da311cc200cfd94..e4187c018f68a7e0d6b4bc7feb17af21e2ae4c4a 100644 (file)
@@ -1,6 +1,6 @@
 // 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.
 
@@ -15,38 +15,56 @@ import (
 )
 
 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() {
@@ -61,7 +79,7 @@ func mustRecoverBody(v1, v2, v3, x interface{}) {
        }
        v = v2
        if v == nil {
-               println("missing recover")
+               println("missing recover", x.(int))
                die() // panic is useless here
        }
        if v != x {
@@ -97,10 +115,23 @@ func withoutRecover() {
        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)
 }
 
@@ -121,7 +152,7 @@ func test1WithClosures() {
                mustNotRecover()
                v := recover()
                if v == nil {
-                       println("missing recover")
+                       println("missing recover", x.(int))
                        die()
                }
                if v != x {
@@ -311,10 +342,12 @@ func test8() {
        }
 }
 
-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)
@@ -364,7 +397,7 @@ func test10reflect2() {
 }
 
 // tiny receiver, so basic wrapper in i.M()
-type T3 struct {}
+type T3 struct{}
 
 func (T3) M() {
        mustRecoverBody(doubleRecover(), recover(), recover(), 11)
@@ -388,6 +421,49 @@ func test11reflect2() {
        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
 
@@ -485,3 +561,27 @@ func test15() {
        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)
+}