This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [3.3] Followup to C++ forced unwinding
On Wed, Apr 30, 2003 at 11:39:41AM -0700, Mark Mitchell wrote:
> (4) Some other black magic in except.c that I couldn't get my head
> around on the first try. What do these bits do?
I presume you're talking about
(RNL_ALWAYS_CAUGHT): New.
(reachable_next_level): Return RNL_ALWAYS_CAUGHT for empty filter
spec and must_not_throw shadowing other catch handlers.
(reachable_handlers): With forced unwinding, only mark cleanups
live after catch(...), not throw().
(can_throw_external): Similarly wrt exceptions escaping the function.
Well, the existing code had bits to notice that must_not_throw
(the wrapper around destructor during cleanup that calls terminate)
was different from catch(...), but didn't distinguish between
throw() and catch(...). This makes that distinction, because...
> One key question that I'm not sure got resolved on the thread was what
> happens in this case:
>
> try {
> // Something that might:
> // (a) result in cancellation.
> // (b) result in a foreign exception being thrown.
> // (c) result in longjmp_unwind being called.
> } catch (...) {
> // There is no "throw;" here to rethrow.
> }
>
> Presumably (a) is the same as either (b) or (c). Which one?
... I thought (a) was similar to (c) and that the catch
handler here is *not* invoked in either case.
So continuing with the first question, we want to note that with
-fforced-unwind-exceptions that while cleanups after catch(...)
are live, cleanups after throw() are not.
Oops, I've missed a case:
void foo() throw()
{
read(...)
}
will (properly) abort, but
void bar() throw()
{
try {
read(...)
} catch (...) {
}
}
won't. I'll fix that and update the patch.
> And, if which of these cases are we implicitly rethrowing from the
> catch, even though the user didn't write "throw;"?
We don't implicitly rethrow, because we don't allow the catch.
I've thought about this a bit, and have reservations because...
> The reason I ask is that:
>
> f = fopen(...);
> try {
> } catch (...) {
> }
> fclose (f);
>
> looks to a C++ programmer to be a perfectly safe piece of code, modulo
> longjmp.
... of this. It *isn't* safe unless you know that nothing in the
catch handler can throw. If we can get folks to write this as
struct closer {
FILE *f;
closer(FILE *x) : f(x) { }
~closer() { if (f) fclose (f); }
};
f = fopen(...);
{
closer c(f);
try {
} catch (...) {
}
}
I'd be much happier. Or, heaven forfend, use iostreams and
auto_ptr, which are a bit more prepared for this sort of thing
without having to define your own local classes.
> Does the IA-64 ABI specify this?
No. It says things can work either way, which is a bit unsatisfying.
> But, I'd be unhappy if foreign exceptions and/or thread cancellation did
> an implicit rethrow.
Ok, good, we're on the same page.
r~