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]
Other format: [Raw text]

C++ PATCH to destructor cleanups


We weren't properly destroying the bases and members of an object before
transferring control to a catch clause of a destructor function-try-block.
It seemed to me that the best way to deal with this would be to change the
member destruction to use cleanups; that way we get the exception semantics
for free.

In order to use the cleanups, I needed to add an additional binding level
around the main compound-statement of the function for destructors, as we
already did for constructors with explicit member-initializers.  It seemed
simplest just to add it unconditionally.  I also moved the destructor
deletion and constructor end-of-partial-cleanups stuff to the end of this
"body" block rather than end of function, since they are not relevant to
the function-catch clauses, and this allowed me to remove a redundant
end_protect_partials from the function-try-block handling.

I'm not entirely comfortable with the name "body block"; alternate
suggestions are welcome.

Tested i686-pc-linux-gnu.  Test in g++.dg/eh/dtor1.C.

2001-12-13  Jason Merrill  <jason@redhat.com>

	* c-common.h (COMPOUND_STMT_BODY_BLOCK): New macro.

2001-12-13  Jason Merrill  <jason@redhat.com>

	* Make-lang.in (parse.h): Separate rule, just depend on parse.c.

	Use cleanups to run base and member destructors.
	* init.c (push_base_cleanups): New function, split out from...
	(build_delete): ...here.  Lose !TYPE_HAS_DESTRUCTOR code.
	* decl.c (finish_destructor_body): Move vbase destruction code to
	push_base_cleanups.
	(begin_function_body, finish_function_body): New fns.
	(finish_function): Move [cd]tor handling and call_poplevel to
	finish_function_body.
	(pushdecl): Skip the new level.
	* semantics.c (genrtl_try_block): Don't call end_protect_partials.
	(setup_vtbl_ptr): Call push_base_cleanups.
	* method.c (synthesize_method): Call {begin,end}_function_body.
	* pt.c (tsubst_expr): Handle COMPOUND_STMT_BODY_BLOCK.
	* cp-tree.h: Declare new fns.
	* parse.y (function_body, .begin_function_body): New nonterminals.
	(fndef, pending_inline, function_try_block): Use function_body.
	(ctor_initializer_opt, function_try_block): No longer has a value.
	(base_init): Remove .set_base_init token.
	(.set_base_init, compstmt_or_error): Remove.
	* Make-lang.in (parse.c): Expect two fewer s/r conflicts.

Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.106
diff -c -p -r1.106 c-common.h
*** c-common.h	2001/12/11 19:42:32	1.106
--- c-common.h	2001/12/14 02:47:33
*************** Software Foundation, 59 Temple Place - S
*** 37,42 ****
--- 37,43 ----
        STMT_IS_FULL_EXPR_P (in _STMT)
     2: STMT_LINENO_FOR_FN_P (in _STMT)
     3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
+       COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT)
     4: SCOPE_PARTIAL_P (in SCOPE_STMT)
  */
  
*************** extern tree build_break_stmt            
*** 761,766 ****
--- 762,771 ----
  extern tree build_return_stmt                   PARAMS ((tree));
  
  #define COMPOUND_STMT_NO_SCOPE(NODE)	TREE_LANG_FLAG_0 (NODE)
+ 
+ /* Used by the C++ frontend to mark the block around the member
+    initializers and cleanups.  */
+ #define COMPOUND_STMT_BODY_BLOCK(NODE)	TREE_LANG_FLAG_3 (NODE)
  
  extern void c_expand_asm_operands		PARAMS ((tree, tree, tree, tree, int, const char *, int));
  
Index: cp/Make-lang.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/Make-lang.in,v
retrieving revision 1.102
diff -c -p -r1.102 Make-lang.in
*** cp/Make-lang.in	2001/12/03 12:39:46	1.102
--- cp/Make-lang.in	2001/12/14 02:47:58
*************** $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.g
*** 118,125 ****
  	gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
  		$(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
  
! $(srcdir)/cp/parse.h $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
! 	@echo "Expect 36 shift/reduce conflicts and 58 reduce/reduce conflicts."
  	cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
  	grep '^#define[ 	]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
  	mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
--- 118,126 ----
  	gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
  		$(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
  
! $(srcdir)/cp/parse.h: $(srcdir)/cp/parse.c
! $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
! 	@echo "Expect 34 shift/reduce conflicts and 58 reduce/reduce conflicts."
  	cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
  	grep '^#define[ 	]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
  	mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
Index: cp/cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.60
diff -c -p -r1.60 cp-tree.def
*** cp/cp-tree.def	2001/10/23 09:14:11	1.60
--- cp/cp-tree.def	2001/12/14 02:47:59
*************** DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e'
*** 234,239 ****
--- 234,241 ----
     constructed.  If, after this point, the CLEANUP_DECL goes out of
     scope, the CLEANUP_EXPR must be run.  */
  DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", 'e', 2)
+ /* CTOR_INITIALIZER is a placeholder in template code for a call to
+    setup_vtbl_pointer (and appears in all functions, not just ctors).  */
  DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
  DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
  DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.664
diff -c -p -r1.664 cp-tree.h
*** cp/cp-tree.h	2001/12/13 01:37:48	1.664
--- cp/cp-tree.h	2001/12/14 02:48:13
*************** extern tree start_enum				PARAMS ((tree)
*** 3677,3682 ****
--- 3677,3684 ----
  extern void finish_enum				PARAMS ((tree));
  extern void build_enumerator			PARAMS ((tree, tree, tree));
  extern int start_function			PARAMS ((tree, tree, tree, int));
+ extern tree begin_function_body			PARAMS ((void));
+ extern void finish_function_body		PARAMS ((tree));
  extern tree finish_function			PARAMS ((int));
  extern tree start_method			PARAMS ((tree, tree, tree));
  extern tree finish_method			PARAMS ((tree));
*************** extern tree build_new				PARAMS ((tree, 
*** 3849,3854 ****
--- 3851,3857 ----
  extern tree build_vec_init			PARAMS ((tree, tree, int));
  extern tree build_x_delete			PARAMS ((tree, int, tree));
  extern tree build_delete			PARAMS ((tree, tree, special_function_kind, int, int));
+ extern void push_base_cleanups			PARAMS ((void));
  extern tree build_vbase_delete			PARAMS ((tree, tree));
  extern tree build_vec_delete			PARAMS ((tree, tree, special_function_kind, int));
  extern tree create_temporary_var                PARAMS ((tree));
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.840
diff -c -p -r1.840 decl.c
*** cp/decl.c	2001/12/13 01:37:49	1.840
--- cp/decl.c	2001/12/14 02:48:36
*************** pushdecl (x)
*** 4188,4195 ****
  		     them there.  */
  		  struct binding_level *b = current_binding_level->level_chain;
  
! 		  if (cleanup_label)
! 		    b = b->level_chain;
  
  		  /* ARM $8.3 */
  		  if (b->parm_flag == 1)
--- 4188,4195 ----
  		     them there.  */
  		  struct binding_level *b = current_binding_level->level_chain;
  
! 		  /* Skip the ctor/dtor cleanup level.  */
! 		  b = b->level_chain;
  
  		  /* ARM $8.3 */
  		  if (b->parm_flag == 1)
*************** save_function_data (decl)
*** 13920,14025 ****
      }
  }
  
! /* At the end of every constructor we generate to code to return
!    `this'.  Do that now.  */
  
  static void
  finish_constructor_body ()
  {
!   /* Mark the end of the constructor.  */
    add_stmt (build_stmt (CTOR_STMT));
  }
  
! /* At the end of every destructor we generate code to restore virtual
!    function tables to the values desired by base classes and to call
!    to base class destructors.  Do that now.  */
  
  static void
  finish_destructor_body ()
  {
-   tree compound_stmt;
    tree exprstmt;
  
-   /* Create a block to contain all the extra code.  */
-   compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
- 
-   /* Any return from a destructor will end up here.  */
-   add_stmt (build_stmt (LABEL_STMT, dtor_label));
- 
-   /* Generate the code to call destructor on base class.  If this
-      destructor belongs to a class with virtual functions, then set
-      the virtual function table pointer to represent the type of our
-      base class.  */
- 
-   /* This side-effect makes call to `build_delete' generate the code
-      we have to have at the end of this destructor.  `build_delete'
-      will set the flag again.  */
-   TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
- 
-   exprstmt = build_delete (current_class_type,
- 			   current_class_ref,
- 			   sfk_base_destructor,
- 			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
- 			   0);
- 
-   if (exprstmt != error_mark_node
-       && (TREE_CODE (exprstmt) != NOP_EXPR
- 	  || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- 	  || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
-     {
-       if (exprstmt != void_zero_node)
- 	/* Don't call `expand_expr_stmt' if we're not going to do
- 	   anything, since -Wall will give a diagnostic.  */
- 	finish_expr_stmt (exprstmt);
- 
-       /* Run destructors for all virtual baseclasses.  */
-       if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- 	{
- 	  tree vbases;
- 	  tree if_stmt;
- 
- 	  if_stmt = begin_if_stmt ();
- 	  finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
- 				      current_in_charge_parm,
- 				      integer_two_node),
- 			       if_stmt);
- 
- 	  vbases = CLASSTYPE_VBASECLASSES (current_class_type);
- 	  /* The CLASSTYPE_VBASECLASSES list is in initialization
- 	     order, so we have to march through it in reverse order.  */
- 	  for (vbases = nreverse (copy_list (vbases));
- 	       vbases;
- 	       vbases = TREE_CHAIN (vbases))
- 	    {
- 	      tree vbase = TREE_VALUE (vbases);
- 	      tree base_type = BINFO_TYPE (vbase);
- 
- 	      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
- 		{
-                   tree base_ptr_type = build_pointer_type (base_type);
- 	          tree expr = current_class_ptr;
- 	          
- 	          /* Convert to the basetype here, as we know the layout is
-                      fixed. What is more, if we let build_method_call do it,
-                      it will use the vtable, which may have been clobbered
-                      by the deletion of our primary base.  */
-                   
-                   expr = build1 (NOP_EXPR, base_ptr_type, expr);
- 	          expr = build (PLUS_EXPR, base_ptr_type, expr,
- 	                        BINFO_OFFSET (vbase));
- 	          expr = build_indirect_ref (expr, NULL);
- 	          expr = build_method_call (expr, base_dtor_identifier,
- 	                                    NULL_TREE, vbase,
- 	                                    LOOKUP_NORMAL);
- 		  finish_expr_stmt (expr);
- 		}
- 	    }
- 
- 	  finish_then_clause (if_stmt);
- 	  finish_if_stmt ();
- 	}
-     }
- 
    /* In a virtual destructor, we must call delete.  */
    if (DECL_VIRTUAL_P (current_function_decl))
      {
--- 13920,13948 ----
      }
  }
  
! /* Add a note to mark the end of the main body of the constructor.  This is
!    used to end the cleanup regions for fully-constructed bases and
!    members.  */
  
  static void
  finish_constructor_body ()
  {
!   /* Mark the end of the cleanups for a partially constructed object.
! 
!      ??? These should really be handled automatically by closing the block,
!      as with the destructor cleanups; the only difference is that these are
!      only run if an exception is thrown.  */
    add_stmt (build_stmt (CTOR_STMT));
  }
  
! /* At the end of every destructor we generate code to delete the object if
!    necessary.  Do that now.  */
  
  static void
  finish_destructor_body ()
  {
    tree exprstmt;
  
    /* In a virtual destructor, we must call delete.  */
    if (DECL_VIRTUAL_P (current_function_decl))
      {
*************** finish_destructor_body ()
*** 14045,14064 ****
        finish_then_clause (if_stmt);
        finish_if_stmt ();
      }
- 
-   /* Close the block we started above.  */
-   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
  }
  
  /* Finish up a function declaration and compile that function
     all the way to assembler language output.  The free the storage
     for the function definition.
  
     FLAGS is a bitwise or of the following values:
-      1 - CALL_POPLEVEL
-        An extra call to poplevel (and expand_end_bindings) must be
-        made to take care of the binding contour for the base
-        initializers.  This is only relevant for constructors.
       2 - INCLASS_INLINE
         We just finished processing the body of an in-class inline
         function definition.  (This processing will have taken place
--- 13968,14025 ----
        finish_then_clause (if_stmt);
        finish_if_stmt ();
      }
  }
  
+ /* Do the necessary processing for the beginning of a function body, which
+    in this case includes member-initializers, but not the catch clauses of
+    a function-try-block.  Currently, this means opening a binding level
+    for the member-initializers (in a ctor) and member cleanups (in a dtor).
+    In other functions, this isn't necessary, but it doesn't hurt.  */
+ 
+ tree
+ begin_function_body ()
+ {
+   tree stmt = begin_compound_stmt (0);
+   COMPOUND_STMT_BODY_BLOCK (stmt) = 1;
+   return stmt;
+ }
+ 
+ /* Do the processing for the end of a function body.  Currently, this means
+    closing out the cleanups for fully-constructed bases and members, and in
+    the case of the destructor, deleting the object if desired.  Again, this
+    is only meaningful for [cd]tors, since they are the only functions where
+    there is a significant distinction between the main body and any
+    function catch clauses.  Handling, say, main() return semantics here
+    would be wrong, as flowing off the end of a function catch clause for
+    main() would also need to return 0.  */
+ 
+ void
+ finish_function_body (compstmt)
+      tree compstmt;
+ {
+   if (processing_template_decl)
+     /* Do nothing now.  */;
+   else if (DECL_DESTRUCTOR_P (current_function_decl))
+     /* Any return from a destructor will end up here.  Put it before the
+        cleanups so that an explicit return doesn't duplicate them.  */
+     add_stmt (build_stmt (LABEL_STMT, dtor_label));
+ 
+   /* Close the block; in a destructor, run the member cleanups.  */
+   finish_compound_stmt (0, compstmt);
+ 
+   if (processing_template_decl)
+     /* Do nothing now.  */;
+   else if (DECL_CONSTRUCTOR_P (current_function_decl))
+     finish_constructor_body ();
+   else if (DECL_DESTRUCTOR_P (current_function_decl))
+     finish_destructor_body ();
+ }  
+ 
  /* Finish up a function declaration and compile that function
     all the way to assembler language output.  The free the storage
     for the function definition.
  
     FLAGS is a bitwise or of the following values:
       2 - INCLASS_INLINE
         We just finished processing the body of an in-class inline
         function definition.  (This processing will have taken place
*************** finish_function (flags)
*** 14070,14076 ****
  {
    register tree fndecl = current_function_decl;
    tree fntype, ctype = NULL_TREE;
-   int call_poplevel = (flags & 1) != 0;
    int inclass_inline = (flags & 2) != 0;
    int nested;
  
--- 14031,14036 ----
*************** finish_function (flags)
*** 14094,14108 ****
       there's no need to add any extra bits.  */
    if (!DECL_CLONED_FUNCTION_P (fndecl))
      {
!       if (DECL_CONSTRUCTOR_P (fndecl))
! 	{
! 	  finish_constructor_body ();
! 	  if (call_poplevel)
! 	    do_poplevel ();
! 	}
!       else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
! 	finish_destructor_body ();
!       else if (DECL_MAIN_P (fndecl))
  	{
  	  /* Make it so that `main' always returns 0 by default.  */
  #ifdef VMS_TARGET
--- 14054,14060 ----
       there's no need to add any extra bits.  */
    if (!DECL_CLONED_FUNCTION_P (fndecl))
      {
!       if (DECL_MAIN_P (current_function_decl))
  	{
  	  /* Make it so that `main' always returns 0 by default.  */
  #ifdef VMS_TARGET
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.256
diff -c -p -r1.256 init.c
*** cp/init.c	2001/12/05 23:48:17	1.256
--- cp/init.c	2001/12/14 02:48:42
*************** build_dtor_call (exp, dtor_kind, flags)
*** 3078,3087 ****
     sfk_deleting_destructor.
  
     FLAGS is the logical disjunction of zero or more LOOKUP_
!    flags.  See cp-tree.h for more info.
  
-    This function does not delete an object's virtual base classes.  */
- 
  tree
  build_delete (type, addr, auto_delete, flags, use_global_delete)
       tree type, addr;
--- 3078,3085 ----
     sfk_deleting_destructor.
  
     FLAGS is the logical disjunction of zero or more LOOKUP_
!    flags.  See cp-tree.h for more info.  */
  
  tree
  build_delete (type, addr, auto_delete, flags, use_global_delete)
       tree type, addr;
*************** build_delete (type, addr, auto_delete, f
*** 3089,3095 ****
       int flags;
       int use_global_delete;
  {
-   tree member;
    tree expr;
  
    if (addr == error_mark_node)
--- 3087,3092 ----
*************** build_delete (type, addr, auto_delete, f
*** 3157,3171 ****
  	 LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
  	 NULL_TREE);
      }
! 
!   /* Below, we will reverse the order in which these calls are made.
!      If we have a destructor, then that destructor will take care
!      of the base classes; otherwise, we must do that here.  */
!   if (TYPE_HAS_DESTRUCTOR (type))
      {
        tree do_delete = NULL_TREE;
        tree ifexp;
  
        /* For `::delete x', we must not use the deleting destructor
  	 since then we would not be sure to get the global `operator
  	 delete'.  */
--- 3154,3166 ----
  	 LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
  	 NULL_TREE);
      }
!   else
      {
        tree do_delete = NULL_TREE;
        tree ifexp;
  
+       my_friendly_assert (TYPE_HAS_DESTRUCTOR (type), 20011213);
+ 
        /* For `::delete x', we must not use the deleting destructor
  	 since then we would not be sure to get the global `operator
  	 delete'.  */
*************** build_delete (type, addr, auto_delete, f
*** 3215,3270 ****
  
        return expr;
      }
!   else
!     {
!       /* We only get here from finish_function for a destructor.  */
!       tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
!       int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
!       tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
!       tree exprstmt = NULL_TREE;
!       tree ref = build_indirect_ref (addr, NULL);
! 
!       /* Set this again before we call anything, as we might get called
! 	 recursively.  */
!       TYPE_HAS_DESTRUCTOR (type) = 1;
! 
!       /* If we have member delete or vbases, we call delete in
! 	 finish_function.  */
!       my_friendly_assert (auto_delete == sfk_base_destructor, 20000411);
  
!       /* Take care of the remaining baseclasses.  */
!       for (i = 0; i < n_baseclasses; i++)
! 	{
! 	  base_binfo = TREE_VEC_ELT (binfos, i);
! 	  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
! 	      || TREE_VIA_VIRTUAL (base_binfo))
! 	    continue;
  
! 	  expr = build_scoped_method_call (ref, base_binfo,
! 					   base_dtor_identifier,
! 					   NULL_TREE);
  
! 	  exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
! 	}
  
!       for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
  	{
! 	  if (TREE_CODE (member) != FIELD_DECL)
! 	    continue;
! 	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
  	    {
! 	      tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
! 	      tree this_type = TREE_TYPE (member);
! 	      expr = build_delete (this_type, this_member,
! 				   sfk_complete_destructor, flags, 0);
! 	      exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
  	    }
  	}
  
!       if (exprstmt)
! 	return build_compound_expr (exprstmt);
!       /* Virtual base classes make this function do nothing.  */
!       return void_zero_node;
      }
  }
  
--- 3210,3307 ----
  
        return expr;
      }
! }
  
! /* At the beginning of a destructor, push cleanups that will call the
!    destructors for our base classes and members.
  
!    Called from setup_vtbl_ptr.  */
  
! void
! push_base_cleanups ()
! {
!   tree binfos;
!   int i, n_baseclasses;
!   tree member;
!   tree expr;
  
!   /* Run destructors for all virtual baseclasses.  */
!   if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
!     {
!       tree vbases;
!       tree cond = (condition_conversion
! 		   (build (BIT_AND_EXPR, integer_type_node,
! 			   current_in_charge_parm,
! 			   integer_two_node)));
! 
!       vbases = CLASSTYPE_VBASECLASSES (current_class_type);
!       /* The CLASSTYPE_VBASECLASSES list is in initialization
! 	 order, which is also the right order for pushing cleanups.  */
!       for (; vbases;
! 	   vbases = TREE_CHAIN (vbases))
  	{
! 	  tree vbase = TREE_VALUE (vbases);
! 	  tree base_type = BINFO_TYPE (vbase);
! 
! 	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
  	    {
! 	      tree base_ptr_type = build_pointer_type (base_type);
! 	      expr = current_class_ptr;
! 	          
! 	      /* Convert to the basetype here, as we know the layout is
! 		 fixed. What is more, if we let build_method_call do it,
! 		 it will use the vtable, which may have been clobbered
! 		 by the deletion of our primary base.  */
!                   
! 	      expr = build1 (NOP_EXPR, base_ptr_type, expr);
! 	      expr = build (PLUS_EXPR, base_ptr_type, expr,
! 			    BINFO_OFFSET (vbase));
! 	      expr = build_indirect_ref (expr, NULL);
! 	      expr = build_method_call (expr, base_dtor_identifier,
! 					NULL_TREE, vbase,
! 					LOOKUP_NORMAL);
! 	      expr = build (COND_EXPR, void_type_node, cond,
! 			    expr, void_zero_node);
! 	      finish_decl_cleanup (NULL_TREE, expr);
  	    }
  	}
+     }
+ 
+   binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
+   n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
  
!   /* Take care of the remaining baseclasses.  */
!   for (i = 0; i < n_baseclasses; i++)
!     {
!       tree base_binfo = TREE_VEC_ELT (binfos, i);
!       if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
! 	  || TREE_VIA_VIRTUAL (base_binfo))
! 	continue;
! 
!       expr = build_scoped_method_call (current_class_ref, base_binfo,
! 				       base_dtor_identifier,
! 				       NULL_TREE);
! 
!       finish_decl_cleanup (NULL_TREE, expr);
!     }
! 
!   for (member = TYPE_FIELDS (current_class_type); member;
!        member = TREE_CHAIN (member))
!     {
!       if (TREE_CODE (member) != FIELD_DECL)
! 	continue;
!       if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
! 	{
! 	  tree this_member = (build_component_ref
! 			      (current_class_ref, DECL_NAME (member),
! 			       NULL_TREE, 0));
! 	  tree this_type = TREE_TYPE (member);
! 	  expr = build_delete (this_type, this_member,
! 			       sfk_complete_destructor,
! 			       LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
! 			       0);
! 	  finish_decl_cleanup (NULL_TREE, expr);
! 	}
      }
  }
  
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.212
diff -c -p -r1.212 method.c
*** cp/method.c	2001/12/13 01:37:51	1.212
--- cp/method.c	2001/12/14 02:48:44
*************** synthesize_method (fndecl)
*** 727,732 ****
--- 727,733 ----
    int nested = (current_function_decl != NULL_TREE);
    tree context = decl_function_context (fndecl);
    int need_body = 1;
+   tree stmt;
  
    if (at_eof)
      import_export_decl (fndecl);
*************** synthesize_method (fndecl)
*** 757,762 ****
--- 758,764 ----
    interface_unknown = 1;
    start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
    clear_last_expr ();
+   stmt = begin_function_body ();
  
    if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
      {
*************** synthesize_method (fndecl)
*** 783,788 ****
--- 785,791 ----
        finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
      }
  
+   finish_function_body (stmt);
    expand_body (finish_function (0));
  
    extract_interface_info ();
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.236
diff -c -p -r1.236 parse.y
*** cp/parse.y	2001/12/11 20:11:34	1.236
--- cp/parse.y	2001/12/14 02:48:50
*************** cp_parse_init ()
*** 385,391 ****
  %token <pi> PRE_PARSED_FUNCTION_DECL 
  %type <ttype> component_constructor_declarator
  %type <ttype> fn.def2 return_id constructor_declarator
! %type <itype> ctor_initializer_opt function_try_block
  %type <ttype> named_class_head_sans_basetype
  %type <ftype> class_head named_class_head 
  %type <ftype> named_complex_class_head_sans_basetype 
--- 385,391 ----
  %token <pi> PRE_PARSED_FUNCTION_DECL 
  %type <ttype> component_constructor_declarator
  %type <ttype> fn.def2 return_id constructor_declarator
! %type <ttype> .begin_function_body
  %type <ttype> named_class_head_sans_basetype
  %type <ftype> class_head named_class_head 
  %type <ftype> named_complex_class_head_sans_basetype 
*************** datadef:
*** 747,755 ****
  
  ctor_initializer_opt:
  	  nodecls
- 		{ $$ = 0; }
  	| base_init
- 		{ $$ = 1; }
  	;
  
  maybe_return_init:
--- 747,753 ----
*************** eat_saved_input:
*** 763,773 ****
  	| END_OF_SAVED_INPUT
  	;
  
  fndef:
! 	  fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
! 		{ expand_body (finish_function ((int)$3)); }
  	| fn.def1 maybe_return_init function_try_block
! 		{ expand_body (finish_function ((int)$3)); }
  	| fn.def1 maybe_return_init error
  		{ }
  	;
--- 761,778 ----
  	| END_OF_SAVED_INPUT
  	;
  
+ function_body:
+ 	  .begin_function_body ctor_initializer_opt compstmt
+ 		{
+ 		  finish_function_body ($1);
+ 		}
+ 	;
+ 
  fndef:
! 	  fn.def1 maybe_return_init function_body
! 		{ expand_body (finish_function (0)); }
  	| fn.def1 maybe_return_init function_try_block
! 		{ expand_body (finish_function (0)); }
  	| fn.def1 maybe_return_init error
  		{ }
  	;
*************** return_init:
*** 890,914 ****
  	;
  
  base_init:
! 	  ':' .set_base_init member_init_list
  		{
! 		  if ($3.new_type_flag == 0)
  		    error ("no base or member initializers given following ':'");
  
! 		  finish_mem_initializers ($3.t);
  		}
  	;
  
! .set_base_init:
  	  /* empty */
  		{
! 		  if (DECL_CONSTRUCTOR_P (current_function_decl))
! 		    /* Make a contour for the initializer list.  */
! 		    do_pushlevel ();
! 		  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");
  		}
  	;
  
--- 895,915 ----
  	;
  
  base_init:
! 	  ':' member_init_list
  		{
! 		  if (! DECL_CONSTRUCTOR_P (current_function_decl))
! 		    error ("only constructors take base initializers");
! 		  else if ($2.new_type_flag == 0)
  		    error ("no base or member initializers given following ':'");
  
! 		  finish_mem_initializers ($2.t);
  		}
  	;
  
! .begin_function_body:
  	  /* empty */
  		{
! 		  $$ = begin_function_body ();
  		}
  	;
  
*************** initlist:
*** 2208,2221 ****
  	;
  
  pending_inline:
! 	  PRE_PARSED_FUNCTION_DECL maybe_return_init ctor_initializer_opt compstmt_or_error
  		{
! 		  expand_body (finish_function ((int)$3 | 2));
  		  process_next_inline ($1);
  		}
  	| PRE_PARSED_FUNCTION_DECL maybe_return_init function_try_block
  		{ 
! 		  expand_body (finish_function ((int)$3 | 2)); 
                    process_next_inline ($1);
  		}
  	| PRE_PARSED_FUNCTION_DECL maybe_return_init error
--- 2209,2222 ----
  	;
  
  pending_inline:
! 	  PRE_PARSED_FUNCTION_DECL maybe_return_init function_body
  		{
! 		  expand_body (finish_function (2));
  		  process_next_inline ($1);
  		}
  	| PRE_PARSED_FUNCTION_DECL maybe_return_init function_try_block
  		{ 
! 		  expand_body (finish_function (2)); 
                    process_next_inline ($1);
  		}
  	| PRE_PARSED_FUNCTION_DECL maybe_return_init error
*************** label_decl:
*** 3328,3340 ****
  		}
  	;
  
- /* This is the body of a function definition.
-    It causes syntax errors to ignore to the next openbrace.  */
- compstmt_or_error:
- 	  compstmt
- 	| error compstmt
- 	;
- 
  compstmt:
  	  save_lineno '{'
                  { $<ttype>$ = begin_compound_stmt (0); }
--- 3329,3334 ----
*************** simple_stmt:
*** 3499,3511 ****
  function_try_block:
  	  TRY
  		{ $<ttype>$ = begin_function_try_block (); }
! 	  ctor_initializer_opt compstmt
  		{ finish_function_try_block ($<ttype>2); }
  	  handler_seq
! 		{
! 		  finish_function_handler_sequence ($<ttype>2);
! 		  $$ = $3;
! 		}
  	;
  
  try_block:
--- 3493,3502 ----
  function_try_block:
  	  TRY
  		{ $<ttype>$ = begin_function_try_block (); }
! 	  function_body
  		{ finish_function_try_block ($<ttype>2); }
  	  handler_seq
! 		{ finish_function_handler_sequence ($<ttype>2); }
  	;
  
  try_block:
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.562
diff -c -p -r1.562 pt.c
*** cp/pt.c	2001/12/09 16:33:42	1.562
--- cp/pt.c	2001/12/14 02:49:27
*************** tsubst_expr (t, args, complain, in_decl)
*** 7389,7397 ****
      case COMPOUND_STMT:
        {
  	prep_stmt (t);
! 	stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
  	tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
! 	finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
        }
        break;
  
--- 7389,7405 ----
      case COMPOUND_STMT:
        {
  	prep_stmt (t);
! 	if (COMPOUND_STMT_BODY_BLOCK (t))
! 	  stmt = begin_function_body ();
! 	else
! 	  stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
! 
  	tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
! 
! 	if (COMPOUND_STMT_BODY_BLOCK (t))
! 	  finish_function_body (stmt);
! 	else
! 	  finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
        }
        break;
  
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.236
diff -c -p -r1.236 semantics.c
*** cp/semantics.c	2001/12/13 01:37:52	1.236
--- cp/semantics.c	2001/12/14 02:49:32
*************** genrtl_try_block (t)
*** 580,586 ****
  
        if (FN_TRY_BLOCK_P (t))
  	{
- 	  end_protect_partials ();
  	  expand_start_all_catch ();
  	  in_function_try_handler = 1;
  	  expand_stmt (TRY_HANDLERS (t));
--- 580,585 ----
*************** setup_vtbl_ptr (member_init_list, base_i
*** 1216,1221 ****
--- 1215,1224 ----
        finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
        finish_then_clause (if_stmt);
        finish_if_stmt ();
+ 
+       /* And insert cleanups for our bases and members so that they
+          will be properly destroyed if we throw.  */
+       push_base_cleanups ();
      }
  
    /* Always keep the BLOCK node associated with the outermost pair of
*************** static void
*** 2559,2566 ****
  genrtl_start_function (fn)
       tree fn;
  {
-   tree parm;
- 
    /* Tell everybody what function we're processing.  */
    current_function_decl = fn;
    /* Get the RTL machinery going for this function.  */
--- 2562,2567 ----

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