This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

C++ PATCH: rethrow from cdtor function try block


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]