This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: rethrow from cdtor function try block
- To: egcs-patches at egcs dot cygnus dot com
- Subject: C++ PATCH: rethrow from cdtor function try block
- From: Nathan Sidwell <nathan at acm dot org>
- Date: Tue, 04 May 1999 17:14:40 +0100
- Organization: University of Bristol
- Reply-To: nathan at compsci dot bristol dot ac dot uk
Hi,
here's a patch to fix the defect reported as
http://egcs.cygnus.com/ml/egcs-bugs/1999-04/msg00512.html. The patch implements
15.3/16.
I keep a static local variable in parse.y, which is 1 inside a cdtor's
function-try-block catcher. Outside it is zero, and inside a nested try block
it is greater than 1. At the end of a handler, I emit a rethrow, if this flag
is 1. This logic will fail, if there is a local class inside a cdtor's
function-try-block catcher which contains member functions with try blocks. I
find it hard to imagine why such a situation would be useful.
I've removed some cruft from cp-tree.h (a now obsolete global variable
declaration).
Attached is a test case which checks this patch works.
Enjoy, ok to install?
nathan
--
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
You can up the bandwidth, but you can't up the speed of light
nathan@acm.org http://www.cs.bris.ac.uk/~nathan/ nathan@cs.bris.ac.uk
1999-05-04 Nathan Sidwell <nathan@acm.org>
* cp-tree.h (exception_throw_decl): Remove obsolete global.
* parse.y (cdtor_function_try_block): New static variable.
(function_try_block): Set it for cdtor's. Clear it afterwards.
(try_block): Nest it, if needed.
(handler): Emit trailing rethrow, if needed.
Index: egcs/gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.229
diff -c -3 -p -r1.229 cp-tree.h
*** cp-tree.h 1999/05/02 17:45:13 1.229
--- cp-tree.h 1999/05/04 15:55:05
*************** extern int pedantic;
*** 325,334 ****
#define C_SET_EXP_ORIGINAL_CODE(exp, code) \
(TREE_COMPLEXITY (exp) = (int)(code))
- /* If non-zero, a VAR_DECL whose cleanup will cause a throw to the
- next exception handler. */
- extern tree exception_throw_decl;
-
extern tree double_type_node, long_double_type_node, float_type_node;
extern tree char_type_node, unsigned_char_type_node, signed_char_type_node;
extern tree ptrdiff_type_node;
--- 325,330 ----
Index: egcs/gcc/cp/parse.y
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/parse.y,v
retrieving revision 1.119
diff -c -3 -p -r1.119 parse.y
*** parse.y 1999/04/22 17:36:48 1.119
--- parse.y 1999/05/04 15:55:07
*************** static int parse_decl PROTO((tree, tree,
*** 69,74 ****
--- 69,77 ----
int have_extern_spec;
int used_extern_spec;
+ /* 1 iff we're in a catcher of a cdtor function try block. */
+ static int cdtor_function_try_block;
+
/* Cons up an empty parameter list. */
#ifdef __GNUC__
__inline
*************** base_init:
*** 801,807 ****
}
else if (current_class_type == NULL_TREE)
error ("base initializers not allowed for non-member functions");
! else if (! DECL_CONSTRUCTOR_P (current_function_decl))
error ("only constructors take base initializers");
}
;
--- 804,810 ----
}
else if (current_class_type == NULL_TREE)
error ("base initializers not allowed for non-member functions");
! else
error ("only constructors take base initializers");
}
;
*************** function_try_block:
*** 3390,3398 ****
--- 3393,3405 ----
ctor_initializer_opt compstmt
{
expand_start_all_catch ();
+ if (DECL_CONSTRUCTOR_P (current_function_decl)
+ || DECL_DESTRUCTOR_P (current_function_decl))
+ cdtor_function_try_block = 1;
}
handler_seq
{
+ cdtor_function_try_block = 0;
expand_end_all_catch ();
$$ = $3;
}
*************** try_block:
*** 3402,3410 ****
TRY
{ $<ttype>$ = begin_try_block (); }
compstmt
! { finish_try_block ($<ttype>2); }
handler_seq
! { finish_handler_sequence ($<ttype>2); }
;
handler_seq:
--- 3409,3425 ----
TRY
{ $<ttype>$ = begin_try_block (); }
compstmt
! {
! finish_try_block ($<ttype>2);
! if (cdtor_function_try_block)
! cdtor_function_try_block++;
! }
handler_seq
! {
! if (cdtor_function_try_block)
! cdtor_function_try_block--;
! finish_handler_sequence ($<ttype>2);
! }
;
handler_seq:
*************** handler:
*** 3418,3424 ****
handler_args
{ finish_handler_parms ($<ttype>2); }
compstmt
! { finish_handler ($<ttype>2); }
;
type_specifier_seq:
--- 3433,3445 ----
handler_args
{ finish_handler_parms ($<ttype>2); }
compstmt
! {
! if (cdtor_function_try_block == 1)
! /* A cdtor function try block rethrows [except.handle/16]. */
! expand_throw (NULL_TREE);
!
! finish_handler ($<ttype>2);
! }
;
type_specifier_seq:
// Copyright (C) 1999 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell4 May 1999 <nathan@acm.org>
// Derived from a bug report by Egenij Gawrilow <gawrilow@math.tu-berlin.de>
// http://egcs.cygnus.com/ml/egcs-bugs/1999-04/msg00512.html
// normally falling off the end of the catcher in a function try block is
// equivalent to `return;'. Except for a ctor or dtor, in which case it is
// equivalent to `throw;', what a pain!. [except.handle/16]
// this check makes sure we get it right.
#include <stdio.h>
int f () throw (int)
{
throw 1;
}
static int caught = 0;
struct B
{
static int m;
B () {m++;}
~B () {m--;}
};
int B::m = 0;
struct A
{
B m;
int i;
A ();
A (int);
};
A::A ()
try
{
f();
}
catch (...)
{
printf ("caught in %s function try block\n", __PRETTY_FUNCTION__);
caught = 1;
try
{
f ();
}
catch (...)
{
printf ("recaught in %s function try block\n", __PRETTY_FUNCTION__);
caught = 2;
}
if (caught == 2)
caught = 3;
// this should throw
}
A::A (int)
try
{
try
{
f ();
}
catch (...)
{
printf ("caught in %s body\n", __PRETTY_FUNCTION__);
caught = 2;
}
}
catch (...)
{
printf ("caught in %s function try block\n", __PRETTY_FUNCTION__);
caught = 1;
// this should throw
}
void fn ()
try
{
if (f ())
return;
}
catch (...)
{
printf ("caught in %s function try block\n", __PRETTY_FUNCTION__);
caught = 1;
// this should implicitly return
}
int main ()
{
int ok = 1;
caught = 0;
try
{
A a;
a.i = 0;
printf ("returned in %s (FAIL)\n", __PRETTY_FUNCTION__);
ok = 0;
}
catch (...)
{
if (caught != 3)
{
printf ("not caught properly in ctor (FAIL)\n");
ok = 0;
}
printf ("caught in %s\n", __PRETTY_FUNCTION__);
}
if (B::m)
{
printf ("not cleaned up members (FAIL)\n");
B::m = 0;
ok = 0;
}
caught = 0;
try
{
A a (1);
a.i = 0;
printf ("returned in %s\n", __PRETTY_FUNCTION__);
if (caught != 2)
{
printf ("not caught once in ctor (FAIL)\n");
ok = 0;
}
}
catch (...)
{
ok = 0;
printf ("caught in %s (FAIL)\n", __PRETTY_FUNCTION__);
}
if (B::m)
{
printf ("not cleaned up members (FAIL)\n");
B::m = 0;
ok = 0;
}
caught = 0;
try
{
fn ();
printf ("returned in %s\n", __PRETTY_FUNCTION__);
if (!caught)
{
printf ("not caught once in function (FAIL)\n");
ok = 0;
}
}
catch (...)
{
ok = 0;
printf ("caught in %s (FAIL)\n", __PRETTY_FUNCTION__);
}
printf (ok ? "PASS\n" : "FAIL\n");
return !ok;
}