This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
fix c++/3757
- To: gcc-patches at gcc dot gnu dot org
- Subject: fix c++/3757
- From: Richard Henderson <rth at redhat dot com>
- Date: Fri, 3 Aug 2001 16:25:56 -0700
- Cc: teemu at torma dot org
Hopefully the commentary describes the bug well enough, since
at the moment I can't think of any other words to use.
The test case from the PR has been distilled as filter1.C.
There was a similar problem in which we failed to call std::terminate
in case a destructor-in-cleanup threw. That is the subject of filter2.C.
The following is for mainline; I'll fix the branch in a moment.
r~
* except.c (collect_one_action_chain): Add an explicit cleanup
action if regions surrounding a catch were encoded entirely
within the call-site entry.
* g++.dg/eh/filter1.C, g++.dg/eh/filter2.C: New tests.
Index: except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/except.c,v
retrieving revision 1.179
diff -c -p -d -r1.179 except.c
*** except.c 2001/08/01 22:47:09 1.179
--- except.c 2001/08/03 23:10:12
*************** expand_eh_return ()
*** 3020,3025 ****
--- 3020,3036 ----
emit_label (around_label);
}
+ /* In the following functions, we represent entries in the action table
+ as 1-based indicies. Special cases are:
+
+ 0: null action record, non-null landing pad; implies cleanups
+ -1: null action record, null landing pad; implies no action
+ -2: no call-site entry; implies must_not_throw
+ -3: we have yet to process outer regions
+
+ Further, no special cases apply to the "next" field of the record.
+ For next, 0 means end of list. */
+
struct action_record
{
int offset;
*************** collect_one_action_chain (ar_hash, regio
*** 3123,3130 ****
if (next == -3)
{
next = collect_one_action_chain (ar_hash, region->outer);
! if (next < 0)
next = 0;
}
next = add_action_record (ar_hash, c->u.catch.filter, next);
}
--- 3134,3149 ----
if (next == -3)
{
next = collect_one_action_chain (ar_hash, region->outer);
!
! /* If there is no next action, terminate the chain. */
! if (next == -1)
next = 0;
+ /* If all outer actions are cleanups or must_not_throw,
+ we'll have no action record for it, since we had wanted
+ to encode these states in the call-site record directly.
+ Add a cleanup action to the chain to catch these. */
+ else if (next <= 0)
+ next = add_action_record (ar_hash, 0, 0);
}
next = add_action_record (ar_hash, c->u.catch.filter, next);
}
Index: testsuite/g++.dg/eh/filter1.C
===================================================================
RCS file: filter1.C
diff -N filter1.C
*** /dev/null Tue May 5 13:32:27 1998
--- filter1.C Fri Aug 3 16:10:12 2001
***************
*** 0 ****
--- 1,43 ----
+ // Test that cleanups get run when a catch filter fails to match.
+ // { dg-do run }
+
+ extern "C" void exit(int);
+ extern "C" void abort();
+
+ struct a
+ {
+ a();
+ ~a();
+ };
+
+ struct e1 {};
+ struct e2 {};
+
+ void
+ ex_test ()
+ {
+ a aa;
+ try
+ {
+ throw e1 ();
+ }
+ catch (e2 &)
+ {
+ }
+ }
+
+ int
+ main ()
+ {
+ try
+ {
+ ex_test ();
+ }
+ catch (...)
+ {
+ }
+ abort ();
+ }
+
+ a::a() { }
+ a::~a() { exit (0); }
Index: testsuite/g++.dg/eh/filter2.C
===================================================================
RCS file: filter2.C
diff -N filter2.C
*** /dev/null Tue May 5 13:32:27 1998
--- filter2.C Fri Aug 3 16:10:12 2001
***************
*** 0 ****
--- 1,59 ----
+ // Test that terminate gets run when a catch filter fails to match while
+ // running destructors. Original bug depended on a::~a being inlined.
+ // { dg-do run }
+ // { dg-options -O }
+
+ #include <exception>
+ #include <cstdlib>
+
+ struct e1 {};
+ struct e2 {};
+
+ struct a
+ {
+ a () { }
+
+ ~a ()
+ {
+ try
+ {
+ throw e1();
+ }
+ catch (e2 &)
+ {
+ }
+ }
+ };
+
+ void
+ ex_test ()
+ {
+ a aa;
+ try
+ {
+ throw e1 ();
+ }
+ catch (e2 &)
+ {
+ }
+ }
+
+ void my_terminate ()
+ {
+ std::exit (0);
+ }
+
+ int
+ main ()
+ {
+ std::set_terminate (my_terminate);
+
+ try
+ {
+ ex_test ();
+ }
+ catch (...)
+ {
+ }
+ abort ();
+ }