7a9389330e
gcc/: * gcc.c (default_compilers): Add entry for ".go". * common.opt: Add -static-libgo as a driver option. * doc/install.texi (Configuration): Mention libgo as an option for --enable-shared. Mention go as an option for --enable-languages. * doc/invoke.texi (Overall Options): Mention .go as a file name suffix. Mention go as a -x option. * doc/frontends.texi (G++ and GCC): Mention Go as a supported language. * doc/sourcebuild.texi (Top Level): Mention libgo. * doc/standards.texi (Standards): Add section on Go language. Move references for other languages into their own section. * doc/contrib.texi (Contributors): Mention that I contributed the Go frontend. gcc/testsuite/: * lib/go.exp: New file. * lib/go-dg.exp: New file. * lib/go-torture.exp: New file. * lib/target-supports.exp (check_compile): Match // Go. From-SVN: r167407
93 lines
2.7 KiB
C
93 lines
2.7 KiB
C
/* go-deferred-recover.c -- support for a deferred recover function.
|
|
|
|
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. */
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "go-panic.h"
|
|
#include "go-defer.h"
|
|
|
|
/* This is called when a call to recover is deferred. That is,
|
|
something like
|
|
defer recover()
|
|
|
|
We need to handle this specially. In 6g/8g, the recover function
|
|
looks up the stack frame. In particular, that means that a
|
|
deferred recover will not recover a panic thrown in the same
|
|
function that defers the recover. It will only recover a panic
|
|
thrown in a function that defers the deferred call to recover.
|
|
|
|
In other words:
|
|
|
|
func f1() {
|
|
defer recover() // does not stop panic
|
|
panic(0)
|
|
}
|
|
|
|
func f2() {
|
|
defer func() {
|
|
defer recover() // stops panic(0)
|
|
}()
|
|
panic(0)
|
|
}
|
|
|
|
func f3() {
|
|
defer func() {
|
|
defer recover() // does not stop panic
|
|
panic(0)
|
|
}()
|
|
panic(1)
|
|
}
|
|
|
|
func f4() {
|
|
defer func() {
|
|
defer func() {
|
|
defer recover() // stops panic(0)
|
|
}()
|
|
panic(0)
|
|
}()
|
|
panic(1)
|
|
}
|
|
|
|
The interesting case here is f3. As can be seen from f2, the
|
|
deferred recover could pick up panic(1). However, this does not
|
|
happen because it is blocked by the panic(0).
|
|
|
|
When a function calls recover, then when we invoke it we pass a
|
|
hidden parameter indicating whether it should recover something.
|
|
This parameter is set based on whether the function is being
|
|
invoked directly from defer. The parameter winds up determining
|
|
whether __go_recover or __go_deferred_recover is called at all.
|
|
|
|
In the case of a deferred recover, the hidden parameter which
|
|
controls the call is actually the one set up for the function which
|
|
runs the defer recover() statement. That is the right thing in all
|
|
the cases above except for f3. In f3 the function is permitted to
|
|
call recover, but the deferred recover call is not. We address
|
|
that here by checking for that specific case before calling
|
|
recover. If this function was deferred when there is already a
|
|
panic on the panic stack, then we can only recover that panic, not
|
|
any other.
|
|
|
|
Note that we can get away with using a special function here
|
|
because you are not permitted to take the address of a predeclared
|
|
function like recover. */
|
|
|
|
struct __go_empty_interface
|
|
__go_deferred_recover ()
|
|
{
|
|
if (__go_panic_defer == NULL
|
|
|| __go_panic_defer->__defer == NULL
|
|
|| __go_panic_defer->__defer->__panic != __go_panic_defer->__panic)
|
|
{
|
|
struct __go_empty_interface ret;
|
|
|
|
ret.__type_descriptor = NULL;
|
|
ret.__object = NULL;
|
|
return ret;
|
|
}
|
|
return __go_recover();
|
|
}
|