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 constructors



In C++, virtual base classes must only be constructed once.
Traditionally, constructors took a parameter which indicated whether
or not to construct virtual bases.  When constructing a complete
object, this parameter was passed in as one; that constructor
constructed the virtual bases, and then passed down zero to the base
class constructors, so that the virtual bases didn't constructed more
than once.

Unfortunately, that makes for an extra test in each constructor.  Even
if all of the base class constructors are inlined, you still need at
least one test if the outermost constructor is not inlined.

The new ABI provides, instead, two entry points for each constructor:
one which constructs virtual bases and one which does not, which
speeds up object construction a little bit.

I've implemented the multiple entry points by actually cloning the
function bodies.  It would be better to have multiple entry points
into a single routine, but we don't have support for that yet in the
back-end, and we can always change the method used later without
breaking the ABI.  I was able to leverage the tree-based inliner very
effectively -- we still create constructors as we did under the old
ABI, but then inline them into the two specialized versions.  By
setting things up right, we avoid any extra copies when doing this;
see maybe_clone_body for details.  Very clean.

That said, this is a tricky enough change that problems wouldn't
surprise me, for folks using the new ABI.  We'll track 'em down.

Destructor cloning (which is entirely analagous) should be relatively
simple given this, and will be coming soon.

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

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

	* cp-tree.h (cp_tree_index): Add CPTI_DTOR_IDENTIFIER.
	(complete_dtor_identifier): New macro.
	(CLASSTYPE_FIRST_CONVERSION): Remove.
	(CLASSTYPE_CONSTRUCTOR_SLOT): New macro.
	(CLASSTYPE_DESTRUCTOR_SLOT): Likewise.
	(CLASSTYPE_FIRST_CONVERSION_SLOT): Likewise.
	(CLASSTYPE_CONSTRUCTORS): Likewise.
	(CLASSTYPE_DESTRUCTORS): Likewise.
	(lang_decl): Add cloned_function.
	(DECL_COMPLETE_CONSTRUCTOR_P): New macro.
	(DECL_BASE_CONSTRUCTOR_P): Likewise.
	(DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P): Likewise.
	(DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P): Likewise.
	(DECL_CLONED_FUNCTION_P): Likewise.
	(DECL_CLONED_FUNCTION): Likewise.
	(clone_function_decl): Declare.
	(maybe_clone_body): Likewise.
	* call.c (build_user_type_conversion_1): Call complete object
	constructors in the new ABI.
	(build_new_method_call): Don't add in-charge parameters under the
	new ABI.
	* class.c (add_method): Use DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P,
	DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P, CLASSTYPE_CONSTRUCTOR_SLOT, and
	CLASSTYPE_DESTRUCTOR_SLOT.
	(build_clone): New function.
	(clone_function_decl): Likewise.
	(clone_constructors_and_destructors): Likewise.
	(check_bases_and_members): Use it.
	* decl.c (iniitialize_predefined_identifiers): Initialize
	complete_dtor_identifier.
	(finish_function): Don't add extra code to a clone.
	(lang_mark_tree): Mark cloned_function.
	* decl2.c (mark_used): Don't bother trying to instantiate things
	we synthesized.
	* dump.c (dequeue_and_dump): Don't dump CP_DECL_CONTEXT twice.
	* method.c (set_mangled_name_for_decl): Don't treat clones as
	constructors.
	(synthesize_method): Sythesize cloned functions, not the clones.
	* optimize.c (inline_data): Update comment on ret_label.
	(remap_block): Don't assume DECL_INITIAL exists.
	(copy_body_r): Allow ret_label to be NULL.
	(maybe_clone_body): Define.
	* pt.c (tsubst_decl): Handle clones.
	(instantiate_clone): New function.
	(instantiate_template): Use it.
	(set_mangled_name_for_template_decl): Don't treat clones as
	constructors.
	* search.c (lookup_fnfields_1): Use CLASSTYPE_CONSTRUCTOR_SLOT,
	CLASSTYPE_DESTRUCTOR_SLOT, and CLASSTYPE_FIRST_CONVERSION_SLOT.
	* semantics.c (expand_body): Clone function bodies as necessary.

Index: call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.208
diff -c -p -r1.208 call.c
*** call.c	2000/04/11 16:56:13	1.208
--- call.c	2000/04/11 20:02:18
*************** build_user_type_conversion_1 (totype, ex
*** 2277,2283 ****
    tree templates = NULL_TREE;
  
    if (IS_AGGR_TYPE (totype))
!     ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
    if (IS_AGGR_TYPE (fromtype)
        && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
      convs = lookup_conversions (fromtype);
--- 2277,2288 ----
    tree templates = NULL_TREE;
  
    if (IS_AGGR_TYPE (totype))
!     ctors = lookup_fnfields (TYPE_BINFO (totype),
! 			     (flag_new_abi 
! 			      ? complete_ctor_identifier
! 			      : ctor_identifier),
! 			     0);
! 
    if (IS_AGGR_TYPE (fromtype)
        && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
      convs = lookup_conversions (fromtype);
*************** build_new_method_call (instance, name, a
*** 4253,4274 ****
        || name == base_ctor_identifier)
      {
        pretty_name = constructor_name (basetype);
!       /* 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
      pretty_name = name;
--- 4258,4283 ----
        || 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
      pretty_name = name;
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.289
diff -c -p -r1.289 class.c
*** class.c	2000/04/11 16:27:37	1.289
--- class.c	2000/04/11 20:02:22
*************** static void build_vcall_and_vbase_vtbl_e
*** 174,179 ****
--- 174,180 ----
  							vcall_offset_data *));
  static tree dfs_mark_primary_bases PARAMS ((tree, void *));
  static void mark_primary_bases PARAMS ((tree));
+ static tree build_clone PARAMS ((tree, tree));
  
  /* Variables shared between class.c and call.c.  */
  
*************** add_method (type, fields, method)
*** 1150,1163 ****
        method_vec = CLASSTYPE_METHOD_VEC (type);
        len = TREE_VEC_LENGTH (method_vec);
  
!       if (DECL_NAME (method) == constructor_name (type))
! 	/* A new constructor or destructor.  Constructors go in 
! 	   slot 0; destructors go in slot 1.  */
! 	slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
        else
  	{
  	  /* See if we already have an entry with this name.  */
! 	  for (slot = 2; slot < len; ++slot)
  	    if (!TREE_VEC_ELT (method_vec, slot)
  		|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
  							  slot))) 
--- 1151,1165 ----
        method_vec = CLASSTYPE_METHOD_VEC (type);
        len = TREE_VEC_LENGTH (method_vec);
  
!       /* Constructors and destructors go in special slots.  */
!       if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
! 	slot = CLASSTYPE_CONSTRUCTOR_SLOT;
!       else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
! 	slot = CLASSTYPE_DESTRUCTOR_SLOT;
        else
  	{
  	  /* See if we already have an entry with this name.  */
! 	  for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
  	    if (!TREE_VEC_ELT (method_vec, slot)
  		|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
  							  slot))) 
*************** check_methods (t)
*** 3855,3860 ****
--- 3857,4007 ----
      }
  }
  
+ /* FN is a constructor or destructor.  Clone the declaration to create
+    a specialized in-charge or not-in-charge version, as indicated by
+    NAME.  */
+ 
+ static tree
+ build_clone (fn, name)
+      tree fn;
+      tree name;
+ {
+   tree parms;
+   tree clone;
+ 
+   /* Copy the function.  */
+   clone = copy_decl (fn);
+   /* Remember where this function came from.  */
+   DECL_CLONED_FUNCTION (clone) = fn;
+   /* Reset the function name.  */
+   DECL_NAME (clone) = name;
+   DECL_ASSEMBLER_NAME (clone) = DECL_NAME (clone);
+   /* There's no pending inline data for this function.  */
+   DECL_PENDING_INLINE_INFO (clone) = NULL;
+   DECL_PENDING_INLINE_P (clone) = 0;
+   /* And it hasn't yet been deferred.  */
+   DECL_DEFERRED_FN (clone) = 0;
+ 
+   /* If there was an in-charge paramter, drop it from the function
+      type.  */
+   if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+     {
+       tree basetype;
+       tree parmtypes;
+       tree exceptions;
+ 
+       exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
+       basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
+       parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
+       /* Skip the `this' parameter.  */
+       parmtypes = TREE_CHAIN (parmtypes);
+       /* Skip the in-charge parameter.  */
+       parmtypes = TREE_CHAIN (parmtypes);
+       TREE_TYPE (clone) 
+ 	= build_cplus_method_type (basetype,
+ 				   TREE_TYPE (TREE_TYPE (clone)),
+ 				   parmtypes);
+       if (exceptions)
+ 	TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone),
+ 						     exceptions);
+     }
+ 
+   /* Copy the function parameters.  But, DECL_ARGUMENTS aren't
+      function parameters; instead, those are the template parameters.  */
+   if (TREE_CODE (clone) != TEMPLATE_DECL)
+     {
+       DECL_ARGUMENTS (clone) = copy_list (DECL_ARGUMENTS (clone));
+       /* Remove the in-charge parameter.  */
+       if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+ 	{
+ 	  TREE_CHAIN (DECL_ARGUMENTS (clone))
+ 	    = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
+ 	  DECL_HAS_IN_CHARGE_PARM_P (clone) = 0;
+ 	}
+       for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms))
+ 	{
+ 	  DECL_CONTEXT (parms) = clone;
+ 	  copy_lang_decl (parms);
+ 	}
+     }
+ 
+   /* Mangle the function name.  */
+   set_mangled_name_for_decl (clone);
+ 
+   /* Create the RTL for this function.  */
+   DECL_RTL (clone) = NULL_RTX;
+   rest_of_decl_compilation (clone, NULL, /*top_level=*/1, at_eof);
+   
+   /* Make it easy to find the CLONE given the FN.  */
+   TREE_CHAIN (clone) = TREE_CHAIN (fn);
+   TREE_CHAIN (fn) = clone;
+ 
+   /* If this is a template, handle the DECL_TEMPLATE_RESULT as well.  */
+   if (TREE_CODE (clone) == TEMPLATE_DECL)
+     {
+       tree result;
+ 
+       DECL_TEMPLATE_RESULT (clone) 
+ 	= build_clone (DECL_TEMPLATE_RESULT (clone), name);
+       result = DECL_TEMPLATE_RESULT (clone);
+       DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
+       DECL_TI_TEMPLATE (result) = clone;
+     }
+ 
+   return clone;
+ }
+ 
+ /* Produce declarations for all appropriate clones of FN.  If
+    UPDATE_METHOD_VEC_P is non-zero, the clones are added to the
+    CLASTYPE_METHOD_VEC as well.  */
+ 
+ void
+ clone_function_decl (fn, update_method_vec_p)
+      tree fn;
+      int update_method_vec_p;
+ {
+   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);
+       clone = build_clone (fn, base_ctor_identifier);
+       if (update_method_vec_p)
+ 	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
+    in-charge and not-in-charge variant.  */
+ 
+ static void
+ clone_constructors_and_destructors (t)
+      tree t;
+ {
+   tree fns;
+ 
+   /* We only clone constructors and destructors under the new ABI.  */
+   if (!flag_new_abi)
+     return;
+ 
+   /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
+      out now.  */
+   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.  */
  
  static void
*************** check_bases_and_members (t, empty_p)
*** 3949,3954 ****
--- 4096,4105 ----
    add_implicitly_declared_members (t, cant_have_default_ctor,
  				   cant_have_const_ctor,
  				   no_const_asn_ref);
+ 
+   /* Create the in-charge and not-in-charge variants of constructors
+      and destructors.  */
+   clone_constructors_and_destructors (t);
  
    /* Process the using-declarations.  */
    for (; access_decls; access_decls = TREE_CHAIN (access_decls))
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.440
diff -c -p -r1.440 cp-tree.h
*** cp-tree.h	2000/04/11 16:56:13	1.440
--- cp-tree.h	2000/04/11 20:02:26
*************** enum cp_tree_index
*** 559,564 ****
--- 559,565 ----
      CPTI_COMPLETE_CTOR_IDENTIFIER,
      CPTI_BASE_CTOR_IDENTIFIER,
      CPTI_DTOR_IDENTIFIER,
+     CPTI_COMPLETE_DTOR_IDENTIFIER,
      CPTI_BASE_DTOR_IDENTIFIER,
      CPTI_DELETING_DTOR_IDENTIFIER,
      CPTI_DELTA2_IDENTIFIER,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 653,666 ****
     frequently.  */
  
  /* The name of a constructor that takes an in-charge parameter to
!    decide whether or not to call virtual base classes.  */
  #define ctor_identifier                 cp_global_trees[CPTI_CTOR_IDENTIFIER]
  /* The name of a constructor that constructs virtual base classes.  */
  #define complete_ctor_identifier        cp_global_trees[CPTI_COMPLETE_CTOR_IDENTIFIER]
  /* The name of a constructor that does not construct virtual base classes.  */
  #define base_ctor_identifier            cp_global_trees[CPTI_BASE_CTOR_IDENTIFIER]
! /* The name of a destructor that destroys virtual base classes.  */
  #define dtor_identifier                 cp_global_trees[CPTI_DTOR_IDENTIFIER]
  /* The name of a destructor that does not destroy virtual base
     classes.  */
  #define base_dtor_identifier            cp_global_trees[CPTI_BASE_DTOR_IDENTIFIER]
--- 654,671 ----
     frequently.  */
  
  /* The name of a constructor that takes an in-charge parameter to
!    decide whether or not to construct virtual base classes.  */
  #define ctor_identifier                 cp_global_trees[CPTI_CTOR_IDENTIFIER]
  /* The name of a constructor that constructs virtual base classes.  */
  #define complete_ctor_identifier        cp_global_trees[CPTI_COMPLETE_CTOR_IDENTIFIER]
  /* The name of a constructor that does not construct virtual base classes.  */
  #define base_ctor_identifier            cp_global_trees[CPTI_BASE_CTOR_IDENTIFIER]
! /* The name of a destructor that takes an in-charge parameter to
!    decide whether or not to destroy virtual base classes and whether
!    or not to delete the object.  */
  #define dtor_identifier                 cp_global_trees[CPTI_DTOR_IDENTIFIER]
+ /* The name of a destructor that destroys virtual base classes.  */
+ #define complete_dtor_identifier        cp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER]
  /* The name of a destructor that does not destroy virtual base
     classes.  */
  #define base_dtor_identifier            cp_global_trees[CPTI_BASE_DTOR_IDENTIFIER]
*************** struct lang_type
*** 1475,1492 ****
     either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
     functions with the same name end up in the same slot.  The first
     two elements are for constructors, and destructors, respectively.
!    These are followed by ordinary member functions.  There may be
!    empty entries at the end of the vector.  */
  #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
  
! /* The first type conversion operator in the class (the others can be
!    searched with TREE_CHAIN), or the first non-constructor function if
!    there are no type conversion operators.  */
! #define CLASSTYPE_FIRST_CONVERSION(NODE) \
!   TREE_VEC_LENGTH (CLASSTYPE_METHOD_VEC (NODE)) > 2 \
!     ? TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), 2) \
!     : NULL_TREE;
  
  /* Mark bits for depth-first and breath-first searches.  */
  
  /* Get the value of the Nth mark bit.  */
--- 1480,1509 ----
     either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
     functions with the same name end up in the same slot.  The first
     two elements are for constructors, and destructors, respectively.
!    Any conversion operators are next, followed by ordinary member
!    functions.  There may be empty entries at the end of the vector.  */
  #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
+ 
+ /* The slot in the CLASSTYPE_METHOD_VEC where constructors go.  */
+ #define CLASSTYPE_CONSTRUCTOR_SLOT 0
  
! /* The slot in the CLASSTYPE_METHOD_VEC where destructors go.  */
! #define CLASSTYPE_DESTRUCTOR_SLOT 1
  
+ /* The first slot in the CLASSTYPE_METHOD_VEC where conversion
+    operators can appear.  */
+ #define CLASSTYPE_FIRST_CONVERSION_SLOT 2
+ 
+ /* A FUNCTION_DECL or OVERLOAD for the constructors for NODE.  These
+    are the constructors that take an in-charge parameter.  */
+ #define CLASSTYPE_CONSTRUCTORS(NODE) \
+   (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT))
+ 
+ /* A FUNCTION_DECL for the destructor for NODE.  These are te
+    destructors that take an in-charge parameter.  */
+ #define CLASSTYPE_DESTRUCTORS(NODE) \
+   (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT))
+ 
  /* Mark bits for depth-first and breath-first searches.  */
  
  /* Get the value of the Nth mark bit.  */
*************** struct lang_decl
*** 1882,1887 ****
--- 1899,1907 ----
    /* In a FUNCTION_DECL, this is DECL_SAVED_TREE.  */
    tree saved_tree;
  
+   /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */
+   tree cloned_function;
+ 
    union
    {
      tree sorted_fields;
*************** struct lang_decl
*** 1909,1914 ****
--- 1929,1952 ----
  /* For FUNCTION_DECLs: nonzero means that this function is a constructor.  */
  #define DECL_CONSTRUCTOR_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_attr)
  
+ /* Nonzero if NODE (a FUNCTION_DECL) is a constructor for a complete
+    object.  */
+ #define DECL_COMPLETE_CONSTRUCTOR_P(NODE)		\
+   (DECL_CONSTRUCTOR_P (NODE) 				\
+    && DECL_NAME (NODE) == complete_ctor_identifier)
+ 
+ /* Nonzero if NODE (a FUNCTION_DECL) is a constructor for a base
+    object.  */
+ #define DECL_BASE_CONSTRUCTOR_P(NODE)		\
+   (DECL_CONSTRUCTOR_P (NODE)			\
+    && DECL_NAME (NODE) == base_ctor_identifier)
+ 
+ /* Nonzero if NODE (a FUNCTION_DECL) is a constructor, but not either the
+    specialized in-charge constructor or the specialized not-in-charge
+    constructor.  */
+ #define DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P(NODE)		\
+   (DECL_CONSTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE))
+ 
  /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor.  */
  #define DECL_COPY_CONSTRUCTOR_P(NODE) \
    (DECL_CONSTRUCTOR_P (NODE) && copy_args_p (NODE))
*************** struct lang_decl
*** 1919,1924 ****
--- 1957,1978 ----
    (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (NODE))	\
     && DECL_LANGUAGE (NODE) == lang_cplusplus)
  
+ /* Nonzero if NODE (a FUNCTION_DECL) is a destructor, but not the
+    specialized in-charge constructor, in-charge deleting constructor,
+    or the the base destructor.  */
+ #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 cloned constructor or
+    destructor.  */
+ #define DECL_CLONED_FUNCTION_P(NODE) \
+   (DECL_CLONED_FUNCTION (NODE) != NULL_TREE)
+ 
+ /* If DECL_CLONED_FUNCTION_P holds, this is the function that was
+    cloned.  */
+ #define DECL_CLONED_FUNCTION(NODE) \
+   (DECL_LANG_SPECIFIC (NODE)->cloned_function)
+ 
  /* Non-zero if NODE is a user-defined conversion operator.  */
  #define DECL_CONV_FN_P(NODE)						     \
    (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)) && TREE_TYPE (DECL_NAME (NODE)))
*************** extern tree build_type_conversion		PARAM
*** 3723,3728 ****
--- 3777,3783 ----
  extern tree build_expr_type_conversion		PARAMS ((int, tree, int));
  extern tree type_promotes_to			PARAMS ((tree));
  extern tree perform_qualification_conversions   PARAMS ((tree, tree));
+ extern void clone_function_decl                 PARAMS ((tree, int));
  
  /* decl.c */
  /* resume_binding_level */
*************** extern tree implicitly_declare_fn       
*** 4093,4098 ****
--- 4148,4154 ----
  /* In optimize.c */
  extern void optimize_function                   PARAMS ((tree));
  extern int calls_setjmp_p                       PARAMS ((tree));
+ extern int maybe_clone_body                     PARAMS ((tree));
  
  /* in pt.c */
  extern void init_pt                             PARAMS ((void));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.588
diff -c -p -r1.588 decl.c
*** decl.c	2000/04/11 16:56:13	1.588
--- decl.c	2000/04/11 20:02:35
*************** initialize_predefined_identifiers () 
*** 6063,6068 ****
--- 6063,6069 ----
      { "__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 },
*************** finish_function (flags)
*** 13966,13972 ****
        store_parm_decls ();
      }
  
!   if (building_stmt_tree ())
      {
        if (DECL_CONSTRUCTOR_P (fndecl))
  	{
--- 13967,13977 ----
        store_parm_decls ();
      }
  
!   /* For a cloned function, we've already got all the code we need;
!      there's no need to add any extra bits.  */
!   if (building_stmt_tree () && DECL_CLONED_FUNCTION_P (fndecl))
!     ;
!   else if (building_stmt_tree ())
      {
        if (DECL_CONSTRUCTOR_P (fndecl))
  	{
*************** lang_mark_tree (t)
*** 14763,14768 ****
--- 14768,14774 ----
  	    {
  	      ggc_mark_tree (ld->befriending_classes);
  	      ggc_mark_tree (ld->saved_tree);
+ 	      ggc_mark_tree (ld->cloned_function);
  	      if (TREE_CODE (t) == TYPE_DECL)
  		ggc_mark_tree (ld->u.sorted_fields);
  	      else if (TREE_CODE (t) == FUNCTION_DECL
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.332
diff -c -p -r1.332 decl2.c
*** decl2.c	2000/04/11 16:56:13	1.332
--- decl2.c	2000/04/11 20:02:38
*************** mark_used (decl)
*** 5228,5234 ****
        && ! DECL_INITIAL (decl)
        /* Kludge: don't synthesize for default args.  */
        && current_function_decl)
!     synthesize_method (decl);
  
    /* If this is a function or variable that is an instance of some
       template, we now know that we will need to actually do the
--- 5228,5239 ----
        && ! DECL_INITIAL (decl)
        /* Kludge: don't synthesize for default args.  */
        && current_function_decl)
!     {
!       synthesize_method (decl);
!       /* If we've already synthesized the method we don't need to
! 	 instantiate it, so we can return right away.  */
!       return;
!     }
  
    /* If this is a function or variable that is an instance of some
       template, we now know that we will need to actually do the
Index: dump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/dump.c,v
retrieving revision 1.41
diff -c -p -r1.41 dump.c
*** dump.c	2000/04/06 00:51:24	1.41
--- dump.c	2000/04/11 20:02:38
*************** dequeue_and_dump (di)
*** 557,563 ****
  
      case FUNCTION_DECL:
      case THUNK_DECL:
-       dump_child ("scpe", CP_DECL_CONTEXT (t));
        dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
        dump_child ("args", DECL_ARGUMENTS (t));
        if (DECL_EXTERNAL (t))
--- 557,562 ----
Index: method.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v
retrieving revision 1.147
diff -c -p -r1.147 method.c
*** method.c	2000/04/11 16:56:14	1.147
--- method.c	2000/04/11 20:02:40
*************** set_mangled_name_for_decl (decl)
*** 1748,1754 ****
    DECL_ASSEMBLER_NAME (decl)
      = build_decl_overload (DECL_NAME (decl), parm_types, 
  			   DECL_FUNCTION_MEMBER_P (decl)
! 			   + DECL_CONSTRUCTOR_P (decl));
  }
  
  /* Build an overload name for the type expression TYPE.  */
--- 1748,1754 ----
    DECL_ASSEMBLER_NAME (decl)
      = build_decl_overload (DECL_NAME (decl), parm_types, 
  			   DECL_FUNCTION_MEMBER_P (decl)
! 			   + DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl));
  }
  
  /* Build an overload name for the type expression TYPE.  */
*************** synthesize_method (fndecl)
*** 2358,2363 ****
--- 2358,2372 ----
  
    if (at_eof)
      import_export_decl (fndecl);
+ 
+   /* If we've been asked to synthesize a clone, just synthesize the
+      cloned function instead.  Doing so will automatically fill in the
+      body for the clone.  */
+   if (DECL_CLONED_FUNCTION_P (fndecl))
+     {
+       synthesize_method (DECL_CLONED_FUNCTION (fndecl));
+       return;
+     }
  
    if (! context)
      push_to_top_level ();
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.22
diff -c -p -r1.22 optimize.c
*** optimize.c	2000/04/11 17:29:54	1.22
--- optimize.c	2000/04/11 20:02:40
*************** typedef struct inline_data
*** 50,56 ****
       inlining the body of `h', the stack will contain, `h', followed
       by `g', followed by `f'.  */
    varray_type fns;
!   /* The label to jump to when a return statement is encountered.  */
    tree ret_label;
    /* The map from local declarations in the inlined function to
       equivalents in the function into which it is being inlined.  */
--- 50,58 ----
       inlining the body of `h', the stack will contain, `h', followed
       by `g', followed by `f'.  */
    varray_type fns;
!   /* The label to jump to when a return statement is encountered.  If
!      this value is NULL, then return statements will simply be
!      remapped as return statements, rather than as jumps.  */
    tree ret_label;
    /* The map from local declarations in the inlined function to
       equivalents in the function into which it is being inlined.  */
*************** remap_block (scope_stmt, decls, id)
*** 157,162 ****
--- 159,165 ----
        tree old_block;
        tree new_block;
        tree old_var;
+       tree *first_block;
        tree fn;
  
        /* Make the new block.  */
*************** remap_block (scope_stmt, decls, id)
*** 175,183 ****
  
  	  /* Remap the variable.  */
  	  new_var = remap_decl (old_var, id);
! 	  if (!new_var)
! 	    /* We didn't remap this variable, so we can't mess with
! 	       its TREE_CHAIN.  */
  	    ;
  	  else
  	    {
--- 178,189 ----
  
  	  /* Remap the variable.  */
  	  new_var = remap_decl (old_var, id);
! 	  /* If we didn't remap this variable, so we can't mess with
! 	     its TREE_CHAIN.  If we remapped this variable to
! 	     something other than a declaration (say, if we mapped it
! 	     to a constant), then we must similarly omit any mention
! 	     of it here.  */
! 	  if (!new_var || !DECL_P (new_var))
  	    ;
  	  else
  	    {
*************** remap_block (scope_stmt, decls, id)
*** 191,198 ****
  	 function into which this block is being inlined.  In
  	 rest_of_compilation we will straighten out the BLOCK tree.  */
        fn = VARRAY_TREE (id->fns, 0);
!       BLOCK_CHAIN (new_block) = BLOCK_CHAIN (DECL_INITIAL (fn));
!       BLOCK_CHAIN (DECL_INITIAL (fn)) = new_block;
        /* Remember the remapped block.  */
        splay_tree_insert (id->decl_map,
  			 (splay_tree_key) old_block,
--- 197,208 ----
  	 function into which this block is being inlined.  In
  	 rest_of_compilation we will straighten out the BLOCK tree.  */
        fn = VARRAY_TREE (id->fns, 0);
!       if (DECL_INITIAL (fn))
! 	first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
!       else
! 	first_block = &DECL_INITIAL (fn);
!       BLOCK_CHAIN (new_block) = *first_block;
!       *first_block = new_block;
        /* Remember the remapped block.  */
        splay_tree_insert (id->decl_map,
  			 (splay_tree_key) old_block,
*************** copy_body_r (tp, walk_subtrees, data)
*** 261,267 ****
  
    /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
       GOTO_STMT with the RET_LABEL as its target.  */
!   if (TREE_CODE (*tp) == RETURN_STMT)
      {
        tree return_stmt = *tp;
        tree goto_stmt;
--- 271,277 ----
  
    /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
       GOTO_STMT with the RET_LABEL as its target.  */
!   if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label)
      {
        tree return_stmt = *tp;
        tree goto_stmt;
*************** calls_setjmp_p (fn)
*** 774,776 ****
--- 784,889 ----
  	  != NULL_TREE);
  }
  
+ /* FN is a function that has a complete body.  Clone the body as
+    necessary.  Returns non-zero if there's no longer any need to
+    process the main body.  */
+ 
+ int
+ maybe_clone_body (fn)
+      tree fn;
+ {
+   inline_data id;
+   tree clone;
+ 
+   /* We don't clone constructors and destructors under the old ABI.  */
+   if (!flag_new_abi)
+     return 0;
+ 
+   /* We only clone constructors and destructors.  */
+   if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
+       && !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);
+        clone && DECL_CLONED_FUNCTION_P (clone);
+        clone = TREE_CHAIN (clone))
+     {
+       tree parm;
+       tree clone_parm;
+       int parmno;
+ 
+       /* Update CLONE's source position information to match FN's.  */
+       DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
+       DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn);
+ 
+       /* Start processing the function.  */
+       push_to_top_level ();
+       start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
+       store_parm_decls ();
+ 
+       /* Just clone the body, as if we were making an inline call.
+ 	 But, remap the parameters in the callee to the parameters of
+ 	 caller.  If there's an in-charge parameter, map it to an
+ 	 appropriate constant.  */
+       memset (&id, 0, sizeof (id));
+       VARRAY_TREE_INIT (id.fns, 2, "fns");
+       VARRAY_PUSH_TREE (id.fns, clone);
+       VARRAY_PUSH_TREE (id.fns, fn);
+ 
+       /* Remap the parameters.  */
+       id.decl_map = splay_tree_new (splay_tree_compare_pointers,
+ 				    NULL, NULL);
+       for (parmno = 0,
+ 	     parm = DECL_ARGUMENTS (fn),
+ 	     clone_parm = DECL_ARGUMENTS (clone);
+ 	   parm;
+ 	   ++parmno,
+ 	     parm = TREE_CHAIN (parm))
+ 	{
+ 	  /* Map the in-charge parameter to an appropriate constant.  */
+ 	  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);
+ 	    }
+ 	  /* Map other parameters to their equivalents in the cloned
+ 	     function.  */
+ 	  else
+ 	    {
+ 	      splay_tree_insert (id.decl_map,
+ 				 (splay_tree_key) parm,
+ 				 (splay_tree_value) clone_parm);
+ 	      clone_parm = TREE_CHAIN (clone_parm);
+ 	    }
+ 	}
+ 
+       /* Actually copy the body.  */
+       TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
+ 
+       /* Clean up.  */
+       splay_tree_delete (id.decl_map);
+       VARRAY_FREE (id.fns);
+ 
+       /* Now, expand this function into RTL, if appropriate.  */
+       current_function_name_declared = 1;
+       expand_body (finish_function (0));
+       pop_from_top_level ();
+     }
+   
+   /* We don't need to process the original function any further.  */
+   return 1;
+ }
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.419
diff -c -p -r1.419 pt.c
*** pt.c	2000/04/11 16:56:14	1.419
--- pt.c	2000/04/11 20:04:25
*************** static int template_args_equal PARAMS ((
*** 159,164 ****
--- 159,165 ----
  static void print_template_context PARAMS ((int));
  static void tsubst_default_arguments PARAMS ((tree));
  static tree for_each_template_parm_r PARAMS ((tree *, int *, void *));
+ static tree instantiate_clone PARAMS ((tree, tree));
  
  /* Called once to initialize pt.c.  */
  
*************** tsubst_decl (t, args, type, in_decl)
*** 5708,5713 ****
--- 5709,5721 ----
  	DECL_PENDING_INLINE_INFO (r) = 0;
  	DECL_PENDING_INLINE_P (r) = 0;
  	TREE_USED (r) = 0;
+ 	if (DECL_CLONED_FUNCTION (r))
+ 	  {
+ 	    DECL_CLONED_FUNCTION (r) = tsubst (DECL_CLONED_FUNCTION (t),
+ 					       args, /*complain=*/1, t);
+ 	    TREE_CHAIN (r) = TREE_CHAIN (DECL_CLONED_FUNCTION (r));
+ 	    TREE_CHAIN (DECL_CLONED_FUNCTION (r)) = r;
+ 	  }
  
  	/* Set up the DECL_TEMPLATE_INFO for R and compute its mangled
  	   name.  There's no need to do this in the special friend
*************** tsubst_expr (t, args, complain, in_decl)
*** 7367,7372 ****
--- 7375,7417 ----
    return NULL_TREE;
  }
  
+ /* TMPL is a TEMPLATE_DECL for a cloned constructor or destructor.
+    Instantiate it with the ARGS.  */
+ 
+ static tree
+ instantiate_clone (tmpl, args)
+      tree tmpl;
+      tree args;
+ {
+   tree spec;
+   tree clone;
+ 
+   /* Instantiated the cloned function, rather than the clone.  */
+   spec = instantiate_template (DECL_CLONED_FUNCTION (tmpl), args);
+ 
+   /* Then, see if we've already cloned the instantiation.  */
+   for (clone = TREE_CHAIN (spec);
+        clone && DECL_CLONED_FUNCTION_P (clone);
+        clone = TREE_CHAIN (clone))
+     if (DECL_NAME (clone) == DECL_NAME (tmpl))
+       return clone;
+ 
+   /* If we haven't, do so know.  */
+   if (!clone)
+     clone_function_decl (spec, /*update_method_vec_p=*/0);
+ 
+   /* Look again.  */
+   for (clone = TREE_CHAIN (spec);
+        clone && DECL_CLONED_FUNCTION_P (clone);
+        clone = TREE_CHAIN (clone))
+     if (DECL_NAME (clone) == DECL_NAME (tmpl))
+       return clone;
+ 
+   /* We should always have found the clone by now.  */
+   my_friendly_abort (20000411);
+   return NULL_TREE;
+ }
+ 
  /* Instantiate the indicated variable or function template TMPL with
     the template arguments in TARG_PTR.  */
  
*************** instantiate_template (tmpl, targ_ptr)
*** 7385,7390 ****
--- 7430,7439 ----
  
    my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
  
+   /* If this function is a clone, handle it specially.  */
+   if (DECL_CLONED_FUNCTION_P (tmpl))
+     return instantiate_clone (tmpl, targ_ptr);
+ 
    /* Check to see if we already have this specialization.  */
    spec = retrieve_specialization (tmpl, targ_ptr);
    if (spec != NULL_TREE)
*************** instantiate_decl (d, defer_ok)
*** 9389,9394 ****
--- 9438,9448 ----
    my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
  		      || TREE_CODE (d) == VAR_DECL, 0);
  
+   /* Don't instantiate cloned functions.  Instead, instantiate the
+      functions they cloned.  */
+   if (TREE_CODE (d) == FUNCTION_DECL && DECL_CLONED_FUNCTION_P (d))
+     d = DECL_CLONED_FUNCTION (d);
+ 
    if (DECL_TEMPLATE_INSTANTIATED (d))
      /* D has already been instantiated.  It might seem reasonable to
         check whether or not D is an explict instantiation, and, if so,
*************** set_mangled_name_for_template_decl (decl
*** 9935,9941 ****
      = build_decl_overload_real (DECL_NAME (decl), parm_types, ret_type,
  				tparms, targs, 
  				DECL_FUNCTION_MEMBER_P (decl) 
! 				+ DECL_CONSTRUCTOR_P (decl));
  
    /* Restore the previously active namespace.  */
    current_namespace = saved_namespace;
--- 9989,9995 ----
      = build_decl_overload_real (DECL_NAME (decl), parm_types, ret_type,
  				tparms, targs, 
  				DECL_FUNCTION_MEMBER_P (decl) 
! 				+ DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl));
  
    /* Restore the previously active namespace.  */
    current_namespace = saved_namespace;
Index: search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.171
diff -c -p -r1.171 search.c
*** search.c	2000/04/09 00:27:16	1.171
--- search.c	2000/04/11 20:04:27
*************** lookup_fnfields_1 (type, name)
*** 1688,1700 ****
  
        /* Constructors are first...  */
        if (name == ctor_identifier)
! 	return methods[0] ? 0 : -1;
! 
        /* and destructors are second.  */
        if (name == dtor_identifier)
! 	return methods[1] ? 1 : -1;
  
!       for (i = 2; i < len && methods[i]; ++i)
  	{
  #ifdef GATHER_STATISTICS
  	  n_outer_fields_searched++;
--- 1688,1703 ----
  
        /* Constructors are first...  */
        if (name == ctor_identifier)
! 	return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] 
! 		? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
        /* and destructors are second.  */
        if (name == dtor_identifier)
! 	return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
! 		? CLASSTYPE_DESTRUCTOR_SLOT : -1);
  
!       for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
! 	   i < len && methods[i]; 
! 	   ++i)
  	{
  #ifdef GATHER_STATISTICS
  	  n_outer_fields_searched++;
*************** lookup_fnfields_1 (type, name)
*** 1737,1743 ****
  	 above so that we will always find specializations first.)  */
        if (IDENTIFIER_TYPENAME_P (name)) 
  	{
! 	  for (i = 2; i < len && methods[i]; ++i)
  	    {
  	      tmp = OVL_CURRENT (methods[i]);
  	      if (! DECL_CONV_FN_P (tmp))
--- 1740,1748 ----
  	 above so that we will always find specializations first.)  */
        if (IDENTIFIER_TYPENAME_P (name)) 
  	{
! 	  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
! 	       i < len && methods[i]; 
! 	       ++i)
  	    {
  	      tmp = OVL_CURRENT (methods[i]);
  	      if (! DECL_CONV_FN_P (tmp))
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.137
diff -c -p -r1.137 semantics.c
*** semantics.c	2000/04/11 16:27:42	1.137
--- semantics.c	2000/04/11 20:04:28
*************** expand_body (fn)
*** 2717,2722 ****
--- 2717,2732 ----
    /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */
    walk_tree (&DECL_SAVED_TREE (fn), simplify_aggr_init_exprs_r, NULL);
  
+   /* If this is a constructor or destructor body, we have to clone it
+      under the new ABI.  */
+   if (maybe_clone_body (fn))
+     {
+       /* We don't want to process FN again, so pretend we've written
+ 	 it out, even though we haven't.  */
+       TREE_ASM_WRITTEN (fn) = 1;
+       return;
+     }
+ 
    /* There's no reason to do any of the work here if we're only doing
       semantic analysis; this code just generates RTL.  */
    if (flag_syntax_only)

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