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: Clone destructors



This patch clones destructors, just like constructors.  I temporarily
removed one minor space optimization: delegation of deletion to base
classes.  The way it had been done was incorrect for the new ABI, and
I wanted to think about it a bit.  I'll add the optimization back in
tomorrow, if possible.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-04-12  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (IDENTIFIER_CTOR_OR_DTOR_P): New macro.
	(cp_tree_index): Add CPTI_PUSH_EXCEPTION_IDENTIFIER.
	(cp_push_exception_identifier): New macro.
	(DECL_COMPLETE_DESTRUCTOR_P): New macro.
	(DECL_BASE_DESTRUCTOR_P): Likewise.
	(DECL_DELETING_DESTRUCTOR_P): Likewise.
	(get_vtbl_decl_for_binfo): Fix formatting.
	(in_charge_arg_for_name): New macro.
	(maybe_build_cleanup_and_delete): Remove declaration.
	* call.c (build_field_call): Use IDENTIFIER_CTOR_OR_DTOR_P.
	(in_charge_arg_for_name): New function.
	(build_new_method_call): Use it.  Handle cloned destructors.
	(build_clone): Don't make the base constructor virtual.
	Automatically defer generated functions.
	(clone_function_decl): Handle destructors, too.
	(clone_constructors_and_destructors): Likewise.
	(create_vtable_ptr): Don't create a vtable entry for a cloned
	function.
	* decl.c (predefined_identifier): Add ctor_or_dtor_p.
	(initialize_predefined_identifiers): Update appropriately.
	(finish_destructor_body): Simplify.
	(maybe_build_cleanup_and_delete): Remove.
	* except.c (expand_throw): Handle new-ABI destructors.
	* init.c (expand_cleanup_for_base): Use base_dtor_identifier.
	(build_dtor_call): New function.
	(build_delete): Use it.  Simplify.
	* optimize.c (maybe_clone_body): Handle destructors.
	* search.c (lookup_field_queue_p): Use IDENTIFIER_CTOR_OR_DTOR_P.

Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.441
diff -c -p -r1.441 cp-tree.h
*** cp-tree.h	2000/04/11 20:16:35	1.441
--- cp-tree.h	2000/04/12 07:37:52
*************** Boston, MA 02111-1307, USA.  */
*** 66,71 ****
--- 66,72 ----
        ICS_BAD_FLAG (in _CONV)
        FN_TRY_BLOCK_P (in TRY_BLOCK)
        SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
+       IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
     4: BINFO_NEW_VTABLE_MARKED.
        TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
            or FIELD_DECL).
*************** struct tree_srcloc
*** 482,487 ****
--- 483,493 ----
                OPERATOR_TYPENAME_FORMAT,			\
  	      strlen (OPERATOR_TYPENAME_FORMAT)))
  
+ /* Nonzero if this identifier is the name of a constructor or
+    destructor.  */
+ #define IDENTIFIER_CTOR_OR_DTOR_P(NODE) \
+   TREE_LANG_FLAG_3 (NODE)
+ 
  /* Nonzero means reject anything that ISO standard C++ forbids.  */
  extern int pedantic;
  
*************** enum cp_tree_index
*** 571,576 ****
--- 577,583 ----
      CPTI_PFN_IDENTIFIER,
      CPTI_PFN_OR_DELTA2_IDENTIFIER,
      CPTI_VPTR_IDENTIFIER,
+     CPTI_PUSH_EXCEPTION_IDENTIFIER,
  
      CPTI_LANG_NAME_C,
      CPTI_LANG_NAME_CPLUSPLUS,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 682,687 ****
--- 689,697 ----
  #define pfn_identifier                  cp_global_trees[CPTI_PFN_IDENTIFIER]
  #define pfn_or_delta2_identifier        cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
  #define vptr_identifier                 cp_global_trees[CPTI_VPTR_IDENTIFIER]
+ /* The name of the function to call to push an exception onto the
+    exception stack.  */
+ #define cp_push_exception_identifier    cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
  
  #define lang_name_c                     cp_global_trees[CPTI_LANG_NAME_C]
  #define lang_name_cplusplus             cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
*************** struct lang_decl
*** 1963,1968 ****
--- 1973,1996 ----
  #define DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P(NODE)			\
    (DECL_DESTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE))
  
+ /* Nonzero if NODE (a FUNCTION_DECL) is a destructor for a complete
+    object.  */
+ #define DECL_COMPLETE_DESTRUCTOR_P(NODE)		\
+   (DECL_DESTRUCTOR_P (NODE) 				\
+    && DECL_NAME (NODE) == complete_dtor_identifier)
+ 
+ /* Nonzero if NODE (a FUNCTION_DECL) is a destructor for a base
+    object.  */
+ #define DECL_BASE_DESTRUCTOR_P(NODE)		\
+   (DECL_DESTRUCTOR_P (NODE)			\
+    && DECL_NAME (NODE) == base_dtor_identifier)
+ 
+ /* Nonzero if NODE (a FUNCTION_DECL) is a destructor for a complete
+    object.  */
+ #define DECL_DELETING_DESTRUCTOR_P(NODE)		\
+   (DECL_DESTRUCTOR_P (NODE) 				\
+    && DECL_NAME (NODE) == deleting_dtor_identifier)
+ 
  /* Nonzero if NODE (a FUNCTION_DECL) is a cloned constructor or
     destructor.  */
  #define DECL_CLONED_FUNCTION_P(NODE) \
*************** extern void unreverse_member_declaration
*** 3761,3767 ****
  extern void invalidate_class_lookup_cache       PARAMS ((void));
  extern void maybe_note_name_used_in_class       PARAMS ((tree, tree));
  extern void note_name_declared_in_class         PARAMS ((tree, tree));
! extern tree get_vtbl_decl_for_binfo           PARAMS ((tree));
  
  /* in cvt.c */
  extern tree convert_to_reference		PARAMS ((tree, tree, int, int, tree));
--- 3789,3796 ----
  extern void invalidate_class_lookup_cache       PARAMS ((void));
  extern void maybe_note_name_used_in_class       PARAMS ((tree, tree));
  extern void note_name_declared_in_class         PARAMS ((tree, tree));
! extern tree get_vtbl_decl_for_binfo             PARAMS ((tree));
! extern tree in_charge_arg_for_name              PARAMS ((tree));
  
  /* in cvt.c */
  extern tree convert_to_reference		PARAMS ((tree, tree, int, int, tree));
*************** extern tree finish_function			PARAMS ((i
*** 3898,3904 ****
  extern tree start_method			PARAMS ((tree, tree, tree));
  extern tree finish_method			PARAMS ((tree));
  extern void hack_incomplete_structures		PARAMS ((tree));
- extern tree maybe_build_cleanup_and_delete	PARAMS ((tree));
  extern tree maybe_build_cleanup			PARAMS ((tree));
  extern void cplus_expand_expr_stmt		PARAMS ((tree));
  extern void finish_stmt				PARAMS ((void));
--- 3927,3932 ----
Index: call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.209
diff -c -p -r1.209 call.c
*** call.c	2000/04/11 20:16:34	1.209
--- call.c	2000/04/12 07:37:45
*************** build_field_call (basetype_path, instanc
*** 130,136 ****
  {
    tree field, instance;
  
!   if (name == ctor_identifier || name == dtor_identifier)
      return NULL_TREE;
  
    /* Speed up the common case.  */
--- 130,136 ----
  {
    tree field, instance;
  
!   if (IDENTIFIER_CTOR_OR_DTOR_P (name))
      return NULL_TREE;
  
    /* Speed up the common case.  */
*************** build_over_call (cand, args, flags)
*** 4172,4177 ****
--- 4172,4200 ----
    return convert_from_reference (fn);
  }
  
+ /* Returns the value to use for the in-charge parameter when making a
+    call to a function with the indicated NAME.  */
+ 
+ tree
+ in_charge_arg_for_name (name)
+      tree name;
+ {
+   if (name == base_ctor_identifier
+       || name == base_dtor_identifier)
+     return integer_zero_node;
+   else if (name == complete_ctor_identifier)
+     return integer_one_node;
+   else if (name == complete_dtor_identifier)
+     return integer_two_node;
+   else if (name == deleting_dtor_identifier)
+     return integer_three_node;
+ 
+   /* This function should only be called with one of the names listed
+      above.  */
+   my_friendly_abort (20000411);
+   return NULL_TREE;
+ }
+ 
  static tree
  build_new_method_call (instance, name, args, basetype_path, flags)
       tree instance, name, args, basetype_path;
*************** build_new_method_call (instance, name, a
*** 4253,4282 ****
    /* Callers should explicitly indicate whether they want to construct
       the complete object or just the part without virtual bases.  */
    my_friendly_assert (name != ctor_identifier, 20000408);
  
!   if (name == complete_ctor_identifier 
!       || name == base_ctor_identifier)
      {
!       pretty_name = constructor_name (basetype);
  
        if (!flag_new_abi)
  	{
  	  /* Add the in-charge parameter as an implicit first argument.  */
! 	  if (TYPE_USES_VIRTUAL_BASECLASSES (basetype))
! 	    {
! 	      tree in_charge;
! 
! 	      if (name == complete_ctor_identifier)
! 		in_charge = integer_one_node;
! 	      else
! 		in_charge = integer_zero_node;
! 
! 	      args = tree_cons (NULL_TREE, in_charge, args);
! 	    }
  
  	  /* We want to call the normal constructor function under the
  	     old ABI.  */
! 	  name = ctor_identifier;
  	}
      }
    else
--- 4276,4305 ----
    /* Callers should explicitly indicate whether they want to construct
       the complete object or just the part without virtual bases.  */
    my_friendly_assert (name != ctor_identifier, 20000408);
+   /* Similarly for destructors.  */
+   my_friendly_assert (name != dtor_identifier, 20000408);
  
!   if (IDENTIFIER_CTOR_OR_DTOR_P (name))
      {
!       int constructor_p;
  
+       constructor_p = (name == complete_ctor_identifier
+ 		       || name == base_ctor_identifier);
+       pretty_name = (constructor_p 
+ 		     ? constructor_name (basetype) : dtor_identifier);
+ 
        if (!flag_new_abi)
  	{
  	  /* Add the in-charge parameter as an implicit first argument.  */
! 	  if (!constructor_p
! 	      || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
! 	    args = tree_cons (NULL_TREE,
! 			      in_charge_arg_for_name (name),
! 			      args);
  
  	  /* We want to call the normal constructor function under the
  	     old ABI.  */
! 	  name = constructor_p ? ctor_identifier : dtor_identifier;
  	}
      }
    else
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.290
diff -c -p -r1.290 class.c
*** class.c	2000/04/11 20:16:35	1.290
--- class.c	2000/04/12 07:37:49
*************** build_clone (fn, name)
*** 3883,3888 ****
--- 3883,3896 ----
    /* And it hasn't yet been deferred.  */
    DECL_DEFERRED_FN (clone) = 0;
  
+   /* The base-class destructor is not virtual.  */
+   if (name == base_dtor_identifier)
+     {
+       DECL_VIRTUAL_P (clone) = 0;
+       if (TREE_CODE (clone) != TEMPLATE_DECL)
+ 	DECL_VINDEX (clone) = NULL_TREE;
+     }
+ 
    /* If there was an in-charge paramter, drop it from the function
       type.  */
    if (DECL_HAS_IN_CHARGE_PARM_P (clone))
*************** build_clone (fn, name)
*** 3948,3953 ****
--- 3956,3963 ----
        DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
        DECL_TI_TEMPLATE (result) = clone;
      }
+   else if (DECL_DEFERRED_FN (fn))
+     defer_fn (clone);
  
    return clone;
  }
*************** clone_function_decl (fn, update_method_v
*** 3963,3970 ****
  {
    tree clone;
  
!   if (DECL_CONSTRUCTOR_P (fn))
      {
        clone = build_clone (fn, complete_ctor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
--- 3973,3982 ----
  {
    tree clone;
  
!   if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
      {
+       /* For each constructor, we need two variants: an in-charge version
+ 	 and a not-in-charge version.  */
        clone = build_clone (fn, complete_ctor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
*************** clone_function_decl (fn, update_method_v
*** 3973,3980 ****
  	add_method (DECL_CONTEXT (clone), NULL, clone);
      }
    else
!     /* We don't do destructors yet.  */
!     my_friendly_abort (20000411);
  }
  
  /* For each of the constructors and destructors in T, create an
--- 3985,4006 ----
  	add_method (DECL_CONTEXT (clone), NULL, clone);
      }
    else
!     {
!       my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
! 
!       /* For each destructor, we need two variants: an in-charge
! 	 version, a not-in-charge version, and an in-charge deleting
! 	 version.  */
!       clone = build_clone (fn, complete_dtor_identifier);
!       if (update_method_vec_p)
! 	add_method (DECL_CONTEXT (clone), NULL, clone);
!       clone = build_clone (fn, deleting_dtor_identifier);
!       if (update_method_vec_p)
! 	add_method (DECL_CONTEXT (clone), NULL, clone);
!       clone = build_clone (fn, base_dtor_identifier);
!       if (update_method_vec_p)
! 	add_method (DECL_CONTEXT (clone), NULL, clone);
!     }
  }
  
  /* For each of the constructors and destructors in T, create an
*************** clone_constructors_and_destructors (t)
*** 3995,4006 ****
    if (!CLASSTYPE_METHOD_VEC (t))
      return;
  
-   /* For each constructor, we need two variants: an in-charge version
-      and a not-in-charge version.  */
    for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
      clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
! 
!   /* For now, we don't do the destructors.  */
  }
  
  /* Remove all zero-width bit-fields from T.  */
--- 4021,4030 ----
    if (!CLASSTYPE_METHOD_VEC (t))
      return;
  
    for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
      clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
!   for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
!     clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
  }
  
  /* Remove all zero-width bit-fields from T.  */
*************** create_vtable_ptr (t, empty_p, vfuns_p,
*** 4130,4136 ****
    /* Loop over the virtual functions, adding them to our various
       vtables.  */
    for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
!     if (DECL_VINDEX (fn))
        add_virtual_function (new_virtuals_p, overridden_virtuals_p,
  			    vfuns_p, fn, t);
  
--- 4154,4161 ----
    /* Loop over the virtual functions, adding them to our various
       vtables.  */
    for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
!     if (DECL_VINDEX (fn) 
! 	&& !(flag_new_abi && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)))
        add_virtual_function (new_virtuals_p, overridden_virtuals_p,
  			    vfuns_p, fn, t);
  
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.589
diff -c -p -r1.589 decl.c
*** decl.c	2000/04/11 20:16:35	1.589
--- decl.c	2000/04/12 07:38:01
*************** typedef struct predefined_identifier
*** 6045,6050 ****
--- 6045,6052 ----
    const char *name;
    /* The place where the IDENTIFIER_NODE should be stored.  */
    tree *node;
+   /* Non-zero if this is the name of a constructor or destructor.  */
+   int ctor_or_dtor_p;
  } predefined_identifier;
  
  /* Create all the predefined identifiers.  */
*************** initialize_predefined_identifiers () 
*** 6056,6085 ****
  
    /* A table of identifiers to create at startup.  */
    static predefined_identifier predefined_identifiers[] = {
!     { "C++", &lang_name_cplusplus },
!     { "C", &lang_name_c },
!     { "Java", &lang_name_java },
!     { CTOR_NAME, &ctor_identifier },
!     { "__base_ctor", &base_ctor_identifier },
!     { "__comp_ctor", &complete_ctor_identifier },
!     { DTOR_NAME, &dtor_identifier },
!     { "__comp_dtor", &complete_dtor_identifier },
!     { "__base_dtor", &base_dtor_identifier },
!     { "__deleting_dtor", &deleting_dtor_identifier },
!     { VTABLE_DELTA2_NAME, &delta2_identifier },
!     { VTABLE_DELTA_NAME, &delta_identifier },
!     { IN_CHARGE_NAME, &in_charge_identifier },
!     { VTABLE_INDEX_NAME, &index_identifier },
!     { "nelts", &nelts_identifier },
!     { THIS_NAME, &this_identifier },
!     { VTABLE_PFN_NAME, &pfn_identifier },
!     { "__pfn_or_delta2", &pfn_or_delta2_identifier },
!     { "_vptr", &vptr_identifier },
!     { NULL, NULL }
    };
  
    for (pid = predefined_identifiers; pid->name; ++pid)
!     *pid->node = get_identifier (pid->name);
  }
  
  /* Create the predefined scalar types of C,
--- 6058,6092 ----
  
    /* A table of identifiers to create at startup.  */
    static predefined_identifier predefined_identifiers[] = {
!     { "C++", &lang_name_cplusplus, 0 },
!     { "C", &lang_name_c, 0 },
!     { "Java", &lang_name_java, 0 },
!     { CTOR_NAME, &ctor_identifier, 1 },
!     { "__base_ctor", &base_ctor_identifier, 1 },
!     { "__comp_ctor", &complete_ctor_identifier, 1 },
!     { DTOR_NAME, &dtor_identifier, 1 },
!     { "__comp_dtor", &complete_dtor_identifier, 1 },
!     { "__base_dtor", &base_dtor_identifier, 1 },
!     { "__deleting_dtor", &deleting_dtor_identifier, 1 },
!     { VTABLE_DELTA2_NAME, &delta2_identifier, 0 },
!     { VTABLE_DELTA_NAME, &delta_identifier, 0 },
!     { IN_CHARGE_NAME, &in_charge_identifier, 0 },
!     { VTABLE_INDEX_NAME, &index_identifier, 0 },
!     { "nelts", &nelts_identifier, 0 },
!     { THIS_NAME, &this_identifier, 0 },
!     { VTABLE_PFN_NAME, &pfn_identifier, 0 },
!     { "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
!     { "_vptr", &vptr_identifier, 0 },
!     { "__cp_push_exception", &cp_push_exception_identifier, 0 },
!     { NULL, NULL, 0 }
    };
  
    for (pid = predefined_identifiers; pid->name; ++pid)
!     {
!       *pid->node = get_identifier (pid->name);
!       if (pid->ctor_or_dtor_p)
! 	IDENTIFIER_CTOR_OR_DTOR_P (*pid->node) = 1;
!     }
  }
  
  /* Create the predefined scalar types of C,
*************** static void
*** 13811,13819 ****
  finish_destructor_body ()
  {
    tree compound_stmt;
-   tree in_charge;
    tree virtual_size;
    tree exprstmt;
  
    /* Create a block to contain all the extra code.  */
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
--- 13818,13826 ----
  finish_destructor_body ()
  {
    tree compound_stmt;
    tree virtual_size;
    tree exprstmt;
+   tree if_stmt;
  
    /* Create a block to contain all the extra code.  */
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
*************** finish_destructor_body ()
*** 13831,13846 ****
       will set the flag again.  */
    TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
  
-   /* These are two cases where we cannot delegate deletion.  */
-   if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
-       || TYPE_GETS_REG_DELETE (current_class_type))
-     in_charge = integer_zero_node;
-   else
-     in_charge = current_in_charge_parm;
- 
    exprstmt = build_delete (current_class_type,
  			   current_class_ref,
! 			   in_charge,
  			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
  			   0);
  
--- 13838,13846 ----
       will set the flag again.  */
    TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
  
    exprstmt = build_delete (current_class_type,
  			   current_class_ref,
! 			   integer_zero_node,
  			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
  			   0);
  
*************** finish_destructor_body ()
*** 13873,13880 ****
  		     TYPE_BINFO (current_class_type));
  		  finish_expr_stmt
  		    (build_scoped_method_call
! 		     (current_class_ref, vb, dtor_identifier,
! 		      build_tree_list (NULL_TREE, integer_zero_node)));
  		}
  	      vbases = TREE_CHAIN (vbases);
  	    }
--- 13873,13880 ----
  		     TYPE_BINFO (current_class_type));
  		  finish_expr_stmt
  		    (build_scoped_method_call
! 		     (current_class_ref, vb, complete_dtor_identifier,
! 		      NULL_TREE));
  		}
  	      vbases = TREE_CHAIN (vbases);
  	    }
*************** finish_destructor_body ()
*** 13897,13921 ****
       only defines placement deletes we don't do anything here.  So we
       pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
       they ever try to delete one of these.  */
!   if (TYPE_GETS_REG_DELETE (current_class_type)
!       || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
!     {
!       tree if_stmt;
! 
!       exprstmt = build_op_delete_call
! 	(DELETE_EXPR, current_class_ptr, virtual_size,
! 	 LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
  
-       if_stmt = begin_if_stmt ();
-       finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
- 				  current_in_charge_parm,
- 				  integer_one_node),
- 			   if_stmt);
-       finish_expr_stmt (exprstmt);
-       finish_then_clause (if_stmt);
-       finish_if_stmt ();
-     }
- 
    /* Close the block we started above.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
  }
--- 13897,13915 ----
       only defines placement deletes we don't do anything here.  So we
       pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
       they ever try to delete one of these.  */
!   exprstmt = build_op_delete_call
!     (DELETE_EXPR, current_class_ptr, virtual_size,
!      LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
! 
!   if_stmt = begin_if_stmt ();
!   finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
! 			      current_in_charge_parm,
! 			      integer_one_node),
! 		       if_stmt);
!   finish_expr_stmt (exprstmt);
!   finish_then_clause (if_stmt);
!   finish_if_stmt ();
  
    /* Close the block we started above.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
  }
*************** maybe_build_cleanup_1 (decl, auto_delete
*** 14557,14572 ****
        return rval;
      }
    return 0;
- }
- 
- /* If DECL is of a type which needs a cleanup, build that cleanup
-    here.  The cleanup does free the storage with a call to delete.  */
- 
- tree
- maybe_build_cleanup_and_delete (decl)
-      tree decl;
- {
-   return maybe_build_cleanup_1 (decl, integer_three_node);
  }
  
  /* If DECL is of a type which needs a cleanup, build that cleanup
--- 14551,14556 ----
Index: except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.106
diff -c -p -r1.106 except.c
*** except.c	2000/03/19 18:25:26	1.106
--- except.c	2000/04/12 07:38:02
*************** expand_throw (exp)
*** 888,901 ****
        /* First, decay it.  */
        exp = decay_conversion (exp);
  
!       /* cleanup_type is void (*)(void *, int),
! 	 the internal type of a destructor. */
        if (cleanup_type == NULL_TREE)
! 	cleanup_type = build_pointer_type
! 	  (build_function_type
! 	   (void_type_node, tree_cons
! 	    (NULL_TREE, ptr_type_node, tree_cons
! 	     (NULL_TREE, integer_type_node, void_list_node))));
  
        if (TYPE_PTR_P (TREE_TYPE (exp)))
  	throw_type = build_eh_type_type (TREE_TYPE (exp));
--- 888,907 ----
        /* First, decay it.  */
        exp = decay_conversion (exp);
  
!       /* The CLEANUP_TYPE is the internal type of a destructor.  Under
! 	 the old ABI, destructors are two-argument functions; under
! 	 the new ABI they take only one argument.  */
        if (cleanup_type == NULL_TREE)
! 	{
! 	  tree arg_types;
! 	  
! 	  arg_types = void_list_node;
! 	  if (!flag_new_abi)
! 	    arg_types = tree_cons (NULL_TREE, integer_type_node, arg_types);
! 	  arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
! 	  cleanup_type = (build_pointer_type 
! 			  (build_function_type (void_type_node, arg_types)));
! 	}
  
        if (TYPE_PTR_P (TREE_TYPE (exp)))
  	throw_type = build_eh_type_type (TREE_TYPE (exp));
*************** expand_throw (exp)
*** 949,955 ****
  	  if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
  	    {
  	      cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! 					 dtor_identifier, 0);
  	      cleanup = TREE_VALUE (cleanup);
  	      mark_used (cleanup);
  	      mark_addressable (cleanup);
--- 955,964 ----
  	  if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
  	    {
  	      cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! 					 (flag_new_abi
! 					  ? complete_dtor_identifier
! 					  : dtor_identifier),
! 					 0);
  	      cleanup = TREE_VALUE (cleanup);
  	      mark_used (cleanup);
  	      mark_addressable (cleanup);
*************** expand_throw (exp)
*** 970,976 ****
  	  TREE_TYPE (cleanup) = cleanup_type;
  	}
  
!       fn = get_identifier ("__cp_push_exception");
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
--- 979,985 ----
  	  TREE_TYPE (cleanup) = cleanup_type;
  	}
  
!       fn = cp_push_exception_identifier;
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
Index: exception.cc
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/exception.cc,v
retrieving revision 1.31
diff -c -p -r1.31 exception.cc
*** exception.cc	2000/03/11 09:00:13	1.31
--- exception.cc	2000/04/12 07:38:02
*************** std::unexpected ()
*** 78,83 ****
--- 78,98 ----
    __unexpected_func ();
  }
  
+ /* The type of a function called to clean up an exception object.
+    (These will be destructors.)  Under the old ABI, these take a
+    second argument (the `in-charge' argument), that indicates whether
+    or not do delete the object, and whether or not to destroy virtual
+    bases.  Under the new ABI, there is no second argument.  */
+ #if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
+ typedef void (*cleanup_fn)(void *, int);
+ /* The `2' is the value for the in-charge parameter that indicates
+    that virtual bases should be destroyed.  */
+ #define CALL_CLEANUP(FN, THIS) FN (THIS, 2)
+ #else
+ typedef void (*cleanup_fn)(void *);
+ #define CALL_CLEANUP(FN, THIS) FN (THIS)
+ #endif
+ 
  /* C++-specific state about the current exception.
     This must match init_exception_processing().
  
*************** struct cp_eh_info
*** 90,96 ****
    __eh_info eh_info;
    void *value;
    void *type;
!   void (*cleanup)(void *, int);
    bool caught;
    cp_eh_info *next;
    long handlers;
--- 105,111 ----
    __eh_info eh_info;
    void *value;
    void *type;
!   cleanup_fn cleanup;
    bool caught;
    cp_eh_info *next;
    long handlers;
*************** __cplus_type_matcher (__eh_info *info_, 
*** 202,208 ****
     Used by expand_throw().  */
  
  extern "C" void
! __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
  {
    cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
  
--- 217,223 ----
     Used by expand_throw().  */
  
  extern "C" void
! __cp_push_exception (void *value, void *type, cleanup_fn cleanup)
  {
    cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
  
*************** __cp_pop_exception (cp_eh_info *p)
*** 251,258 ****
    *q = p->next;
  
    if (p->cleanup)
!     /* 2 is a magic value for destructors; see build_delete().  */
!     p->cleanup (p->original_value, 2);  // value may have been adjusted.
  
    if (! __is_pointer (p->type))
      __eh_free (p->original_value);  // value may have been adjusted.
--- 266,273 ----
    *q = p->next;
  
    if (p->cleanup)
!     // value may have been adjusted.
!     CALL_CLEANUP (p->cleanup, p->original_value);
  
    if (! __is_pointer (p->type))
      __eh_free (p->original_value);  // value may have been adjusted.
Index: init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.183
diff -c -p -r1.183 init.c
*** init.c	2000/04/11 16:56:13	1.183
--- init.c	2000/04/12 07:38:04
*************** expand_cleanup_for_base (binfo, flag)
*** 713,720 ****
  
    /* Call the destructor.  */
    expr = (build_scoped_method_call
! 	  (current_class_ref, binfo, dtor_identifier,
! 	   build_tree_list (NULL_TREE, integer_zero_node)));
    if (flag)
      expr = fold (build (COND_EXPR, void_type_node,
  			truthvalue_conversion (flag),
--- 713,719 ----
  
    /* Call the destructor.  */
    expr = (build_scoped_method_call
! 	  (current_class_ref, binfo, base_dtor_identifier, NULL_TREE));
    if (flag)
      expr = fold (build (COND_EXPR, void_type_node,
  			truthvalue_conversion (flag),
*************** build_x_delete (addr, which_delete, virt
*** 2963,2968 ****
--- 2962,3030 ----
    return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
  }
  
+ tree
+ build_dtor_call (exp, in_charge, binfo, flags)
+      tree exp;
+      tree in_charge;
+      tree binfo;
+      int flags;
+ {
+   tree name = NULL_TREE;
+   tree call1;
+   tree call2;
+   tree call3;
+   tree result;
+ 
+   /* First, try to figure out statically which function to call.  */
+   in_charge = fold (in_charge);
+   if (tree_int_cst_equal (in_charge, integer_zero_node))
+     name = base_dtor_identifier;
+   else if (tree_int_cst_equal (in_charge, integer_one_node))
+     name = deleting_dtor_identifier;
+   else if (tree_int_cst_equal (in_charge, integer_two_node))
+     name = complete_dtor_identifier;
+   if (name)
+     {
+       if (!binfo)
+ 	return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags);
+       else
+ 	return build_scoped_method_call (exp, binfo, name, NULL_TREE);
+     }
+ 
+   /* If that didn't work, build the various alternatives.  */
+   if (!binfo)
+     {
+       call1 = build_method_call (exp, complete_dtor_identifier,
+ 				 NULL_TREE, NULL_TREE, flags);
+       call2 = build_method_call (exp, deleting_dtor_identifier,
+ 				 NULL_TREE, NULL_TREE, flags);
+       call3 = build_method_call (exp, base_dtor_identifier,
+ 				 NULL_TREE, NULL_TREE, flags);
+     }
+   else
+     {
+       call1 = build_scoped_method_call (exp, binfo, 
+ 					complete_dtor_identifier, NULL_TREE);
+       call2 = build_scoped_method_call (exp, binfo, 
+ 					deleting_dtor_identifier, NULL_TREE);
+       call3 = build_scoped_method_call (exp, binfo, 
+ 					base_dtor_identifier, NULL_TREE);
+     }
+ 
+   /* Build the conditionals.  */
+   result = build (COND_EXPR, void_type_node,
+ 		  fold (build (BIT_AND_EXPR, integer_type_node,
+ 			       in_charge, integer_two_node)),
+ 		  call1,
+ 		  call3);
+   result = build (COND_EXPR, void_type_node,
+ 		  fold (build (BIT_AND_EXPR, integer_type_node,
+ 			       in_charge, integer_one_node)),
+ 		  call2,
+ 		  result);
+   return result;
+ }
+ 
  /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
     ADDR is an expression which yields the store to be destroyed.
     AUTO_DELETE is nonzero if a call to DELETE should be made or not.
*************** build_delete (type, addr, auto_delete, f
*** 3084,3093 ****
        else
  	passed_auto_delete = auto_delete;
  
!       expr = build_method_call
! 	(ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
! 	 NULL_TREE, flags);
! 
        if (do_delete)
  	expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
  
--- 3146,3152 ----
        else
  	passed_auto_delete = auto_delete;
  
!       expr = build_dtor_call (ref, passed_auto_delete, NULL_TREE, flags);
        if (do_delete)
  	expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
  
*************** build_delete (type, addr, auto_delete, f
*** 3111,3118 ****
        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 parent_auto_delete = auto_delete;
-       tree cond;
  
        /* Set this again before we call anything, as we might get called
  	 recursively.  */
--- 3170,3175 ----
*************** build_delete (type, addr, auto_delete, f
*** 3120,3169 ****
  
        /* If we have member delete or vbases, we call delete in
  	 finish_function.  */
!       if (auto_delete == integer_zero_node)
! 	cond = NULL_TREE;
!       else if (base_binfo == NULL_TREE
! 	       || TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
! 	{
! 	  cond = build (COND_EXPR, void_type_node,
! 			build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
! 			build_builtin_delete_call (addr),
! 			void_zero_node);
! 	}
!       else
! 	cond = NULL_TREE;
! 
!       if (cond)
! 	exprstmt = build_tree_list (NULL_TREE, cond);
! 
!       if (base_binfo
! 	  && ! TREE_VIA_VIRTUAL (base_binfo)
! 	  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
! 	{
! 	  tree this_auto_delete;
! 
! 	  if (BINFO_OFFSET_ZEROP (base_binfo))
! 	    this_auto_delete = parent_auto_delete;
! 	  else
! 	    this_auto_delete = integer_zero_node;
! 
! 	  expr = build_scoped_method_call
! 	    (ref, base_binfo, dtor_identifier,
! 	     build_tree_list (NULL_TREE, this_auto_delete));
! 	  exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
! 	}
  
        /* Take care of the remaining baseclasses.  */
!       for (i = 1; 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, dtor_identifier,
! 	     build_tree_list (NULL_TREE, integer_zero_node));
  
  	  exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
  	}
--- 3177,3195 ----
  
        /* If we have member delete or vbases, we call delete in
  	 finish_function.  */
!       my_friendly_assert (auto_delete == integer_zero_node, 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);
  	}
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.23
diff -c -p -r1.23 optimize.c
*** optimize.c	2000/04/11 20:16:35	1.23
--- optimize.c	2000/04/12 07:38:05
*************** maybe_clone_body (fn)
*** 804,813 ****
        && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
      return 0;
  
-   /* We don't yet handle destructors.  */
-   if (DECL_DESTRUCTOR_P (fn))
-     return 0;
- 
    /* We know that any clones immediately follow FN in the TYPE_METHODS
       list.  */
    for (clone = TREE_CHAIN (fn);
--- 804,809 ----
*************** maybe_clone_body (fn)
*** 850,861 ****
  	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
  	    {
  	      tree in_charge;
! 
! 	      if (DECL_COMPLETE_CONSTRUCTOR_P (clone))
! 		in_charge = integer_one_node;
! 	      else
! 		in_charge = integer_zero_node;
! 
  	      splay_tree_insert (id.decl_map,
  				 (splay_tree_key) parm,
  				 (splay_tree_key) in_charge);
--- 846,852 ----
  	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
  	    {
  	      tree in_charge;
! 	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
  	      splay_tree_insert (id.decl_map,
  				 (splay_tree_key) parm,
  				 (splay_tree_key) in_charge);
Index: search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.172
diff -c -p -r1.172 search.c
*** search.c	2000/04/11 20:16:35	1.172
--- search.c	2000/04/12 07:38:07
*************** lookup_field_queue_p (binfo, data)
*** 1337,1343 ****
    struct lookup_field_info *lfi = (struct lookup_field_info *) data;
  
    /* Don't look for constructors or destructors in base classes.  */
!   if (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
      return NULL_TREE;
  
    /* If this base class is hidden by the best-known value so far, we
--- 1337,1343 ----
    struct lookup_field_info *lfi = (struct lookup_field_info *) data;
  
    /* Don't look for constructors or destructors in base classes.  */
!   if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))
      return NULL_TREE;
  
    /* If this base class is hidden by the best-known value so far, we

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