From: chip@tct.COM (Chip Salzenberg)
Subject: Fix for G++ 2.3.1 copy constructor bug
Organization: GNUs Not Usenet
Distribution: gnu
Date: Fri, 6 Nov 1992 09:00:16 GMT

G++ 2.3.1, when creating default copy constructors, fails to call the
copy constructors of base classes and member objects.  The below patch
fixes this omission.

This patch has been tested on a fairly large application.  However, it
has not been tested with virtual inheritance, which we do not use.

=======================================================================
Thu Nov  5 12:23:37 1992  Chip Salzenberg  (chip@tct.com)

	* cp-class.c (needs_const_ctor): Eliminate as meaningless.
	(finish_struct) Always generate default functions.
	Generate exactly one copy constructor: either "X(X&)" or
	"X(const X&)", but not both.
	* cp-lex.c (cons_up_default_function): Take list of fields
	as a new parameter.  Use default_copy_constructor_body.
	Set TREE_PUBLIC and DECL_EXTERNAL correctly for usage with
	#pragma interface.	
	(default_copy_constructor_body): New function.

Index: cp-class.c
*************** struct base_info
*** 1429,1433 ****
    char needs_default_ctor;
    char cant_have_default_ctor;
-   char needs_const_ctor;
    char cant_have_const_ctor;
    char members_need_dtors;
--- 1429,1432 ----
*************** finish_base_struct (t, b, binfos)
*** 1496,1502 ****
        else if (TYPE_HAS_CONSTRUCTOR (basetype))
  	b->cant_have_default_ctor = 1;
!       if (TYPE_GETS_CONST_INIT_REF (basetype))
! 	b->needs_const_ctor = 1;
!       else if (TYPE_GETS_INIT_REF (basetype))
  	b->cant_have_const_ctor = 1;
  
--- 1495,1500 ----
        else if (TYPE_HAS_CONSTRUCTOR (basetype))
  	b->cant_have_default_ctor = 1;
!       if (TYPE_GETS_INIT_REF (basetype)
! 	  && !TYPE_GETS_CONST_INIT_REF (basetype))
  	b->cant_have_const_ctor = 1;
  
*************** finish_struct (t, list_of_fieldlists, em
*** 2179,2185 ****
    int old;
    int round_up_size = 1;
-   /* Set non-zero to debug using default functions.
-      Not set by program.  */
-   static int debug_default_functions = 0;
  
    enum tree_code code = TREE_CODE (t);
--- 2177,2180 ----
*************** finish_struct (t, list_of_fieldlists, em
*** 2198,2202 ****
    int needs_default_ctor;
    int cant_have_default_ctor;
-   int needs_const_ctor;
    int cant_have_const_ctor;
  
--- 2193,2196 ----
*************** finish_struct (t, list_of_fieldlists, em
*** 2295,2299 ****
        needs_default_ctor = base_info.needs_default_ctor;
        cant_have_default_ctor = base_info.cant_have_default_ctor;
-       needs_const_ctor = base_info.needs_const_ctor;
        cant_have_const_ctor = base_info.cant_have_const_ctor;
        members_need_dtors = base_info.members_need_dtors;
--- 2289,2292 ----
*************** finish_struct (t, list_of_fieldlists, em
*** 2312,2316 ****
        needs_default_ctor = 0;
        cant_have_default_ctor = 0;
-       needs_const_ctor = 0;
        cant_have_const_ctor = 0;
        members_need_dtors = 0;
--- 2305,2308 ----
*************** finish_struct (t, list_of_fieldlists, em
*** 2507,2513 ****
  		  if (TYPE_HAS_DEFAULT_CONSTRUCTOR (TREE_TYPE (x)))
  		    needs_default_ctor = 1;
! 		  if (TYPE_GETS_CONST_INIT_REF (TREE_TYPE (x)))
! 		    needs_const_ctor = 1;
! 		  else if (TYPE_GETS_INIT_REF (TREE_TYPE (x)))
  		    cant_have_const_ctor = 1;
  		}
--- 2499,2504 ----
  		  if (TYPE_HAS_DEFAULT_CONSTRUCTOR (TREE_TYPE (x)))
  		    needs_default_ctor = 1;
! 		  if (TYPE_GETS_INIT_REF (TREE_TYPE (x))
! 		      && !TYPE_GETS_CONST_INIT_REF (TREE_TYPE (x)))
  		    cant_have_const_ctor = 1;
  		}
*************** finish_struct (t, list_of_fieldlists, em
*** 2692,2696 ****
      {
        /* Here we must cons up a destructor on the fly.  */
!       tree dtor = cons_up_default_function (t, name,
  					    needs_virtual_dtor != 0);
  
--- 2683,2687 ----
      {
        /* Here we must cons up a destructor on the fly.  */
!       tree dtor = cons_up_default_function (t, name, fields,
  					    needs_virtual_dtor != 0);
  
*************** finish_struct (t, list_of_fieldlists, em
*** 2718,2745 ****
      }
  
!   if (debug_default_functions)
      {
!       if ((TYPE_NEEDS_CONSTRUCTOR (t) || TYPE_HAS_CONSTRUCTOR (t) || needs_ctor)
! 	  && ! TYPE_HAS_INIT_REF (t))
! 	{
! 	  tree default_fn = cons_up_default_function (t, name, 4);
! 	  TREE_CHAIN (default_fn) = fn_fields;
! 	  fn_fields = default_fn;
! 	  TYPE_HAS_INIT_REF (t) = 1;
! 	  default_fn = cons_up_default_function (t, name, 3);
! 	  TREE_CHAIN (default_fn) = fn_fields;
! 	  fn_fields = default_fn;
! 	  nonprivate_method = 1;
! 	}
  
!       if (! TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
! 	  && needs_default_ctor && ! cant_have_default_ctor)
! 	{
! 	  tree default_fn = cons_up_default_function (t, name, 2);
! 	  TREE_CHAIN (default_fn) = fn_fields;
! 	  fn_fields = default_fn;
! 	  TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1;
! 	  nonprivate_method = 1;
! 	}
      }
  
--- 2709,2738 ----
      }
  
!   /* Create default constructor, if needed.  */
! 
!   if (! TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
!       && needs_default_ctor && ! cant_have_default_ctor)
      {
!       tree default_fn = cons_up_default_function (t, name, fields, 2);
!       TREE_CHAIN (default_fn) = fn_fields;
!       fn_fields = default_fn;
!       TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1;
!       nonprivate_method = 1;
!     }
  
!   /* Create default copy constructor, if needed.  */
! 
!   if ((TYPE_NEEDS_CONSTRUCTOR (t) || TYPE_HAS_CONSTRUCTOR (t) || needs_ctor)
!       && ! TYPE_HAS_INIT_REF (t))
!     {
!       /* ARM 12.18: You get either X(X&) or X(const X&), but
! 	 not both.  --Chip  */
!       tree default_fn =
! 	cons_up_default_function (t, name, fields,
! 				  cant_have_const_ctor ? 4 : 3);
!       TREE_CHAIN (default_fn) = fn_fields;
!       fn_fields = default_fn;
!       TYPE_HAS_INIT_REF (t) = 1;
!       nonprivate_method = 1;
      }
  

Index: cp-lex.c
*************** extern int *token_count;
*** 125,129 ****
  
  /* Textual definition used for default functions.  */
! static char default_def[] = "{}";
  
  /* Return something to represent absolute declarators containing a *.
--- 125,129 ----
  
  /* Textual definition used for default functions.  */
! static void default_copy_constructor_body ();
  
  /* Return something to represent absolute declarators containing a *.
*************** reinit_parse_for_block (yychar, obstackp
*** 1443,1452 ****
  
  tree
! cons_up_default_function (type, name, kind)
!      tree type, name;
       int kind;
  {
    extern tree void_list_node, constructor_name ();
!   int len;
    tree declspecs = NULL_TREE;
    tree fn, args;
--- 1443,1453 ----
  
  tree
! cons_up_default_function (type, name, fields, kind)
!      tree type, name, fields;
       int kind;
  {
    extern tree void_list_node, constructor_name ();
!   char *def_buf = "{}";
!   int def_len = 2;
    tree declspecs = NULL_TREE;
    tree fn, args;
*************** cons_up_default_function (type, name, ki
*** 1475,1480 ****
        args = tree_cons (NULL_TREE,
  			build_tree_list (hash_tree_chain (argtype, NULL_TREE),
! 					 get_identifier ("arg")),
  			void_list_node);
        break;
  
--- 1476,1482 ----
        args = tree_cons (NULL_TREE,
  			build_tree_list (hash_tree_chain (argtype, NULL_TREE),
! 					 get_identifier ("_ctor_arg")),
  			void_list_node);
+       default_copy_constructor_body (&def_buf, &def_len, type, fields);
        break;
  
*************** cons_up_default_function (type, name, ki
*** 1492,1497 ****
    current_member_init_list = NULL_TREE;
  
-   len = 3;
- 
    {
      struct pending_inline *t;
--- 1494,1497 ----
*************** cons_up_default_function (type, name, ki
*** 1499,1504 ****
      t = (struct pending_inline *) obstack_alloc (&inline_text_obstack,
  						 sizeof (struct pending_inline));
!     t->buf = default_def;
!     t->len = len;
      t->lineno = lineno;
      t->filename = input_filename;
--- 1499,1504 ----
      t = (struct pending_inline *) obstack_alloc (&inline_text_obstack,
  						 sizeof (struct pending_inline));
!     t->buf = def_buf;
!     t->len = def_len + 1;
      t->lineno = lineno;
      t->filename = input_filename;
*************** cons_up_default_function (type, name, ki
*** 1510,1515 ****
  		    : (interface_only ? 0 : 2));
      store_pending_inline (fn, t);
!     /* We make this declaration private (static in the C sense).  */
!     TREE_PUBLIC (fn) = 0;
    }
    finish_method (fn);
--- 1510,1520 ----
  		    : (interface_only ? 0 : 2));
      store_pending_inline (fn, t);
!     if (interface_unknown)
!       TREE_PUBLIC (fn) = 0;
!     else
!       {
! 	TREE_PUBLIC (fn) = 1;
! 	DECL_EXTERNAL (fn) = interface_only;
!       }
    }
    finish_method (fn);
*************** cons_up_default_function (type, name, ki
*** 1518,1521 ****
--- 1523,1633 ----
    DECL_SOURCE_LINE (fn) = 0;
    return fn;
+ }
+ 
+ /* Construct the body of a default copy constructor.  */
+ static void
+ default_copy_constructor_body(bufp, lenp, type, fields)
+      char **bufp;
+      int *lenp;
+      tree type, fields;
+ {
+   char *buf;
+   int alloc, len;
+   int n_bases = 0;
+   char sep = ':';
+ 
+   if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+     n_bases = CLASSTYPE_N_BASECLASSES (type);
+ 
+   buf = xmalloc (alloc = 100);
+   len = 0;
+ 
+   /* Call base class constructors.  */
+ 
+   if (n_bases)
+     {
+       int i;
+ 
+       for (i = 0; i < n_bases; ++i)
+ 	{
+ 	  tree base = TYPE_BINFO_BASETYPE (type, i);
+ 
+ 	  if (TYPE_HAS_CONSTRUCTOR (base))
+ 	    {
+ 	      char *basename =
+ 		IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base)));
+ 
+ 	      while (len + strlen(basename) + 30 > alloc)
+ 		buf = xrealloc (buf, alloc *= 2);
+ 
+ 	      buf[len++] = sep;
+ 	      sep = ',';
+ 
+ 	      sprintf (buf + len, "%s(_ctor_arg)", basename);
+ 	      len += strlen (buf + len);
+ 	    }
+ 	}
+     }
+ 
+   /* Construct fields.  */
+ 
+   if (fields)
+     {
+       tree f;
+ 
+       for (f = fields; f; f = TREE_CHAIN (f))
+ 	{
+ 	  if (TREE_CODE (f) == FIELD_DECL && DECL_NAME (f))
+ 	    {
+ 	      char *fieldname = IDENTIFIER_POINTER (DECL_NAME (f));
+ 
+ 	      while (len + (strlen (fieldname) * 2) + 30 > alloc)
+ 		buf = xrealloc (buf, alloc *= 2);
+ 
+ 	      buf[len++] = sep;
+ 	      sep = ',';
+ 
+ 	      sprintf (buf + len, "%s(_ctor_arg.%s)", fieldname, fieldname);
+ 	      len += strlen(buf + len);
+ 	    }
+ 	}
+     }
+ 
+   /* Begin constructor body.  */
+ 
+   buf[len++] = '{';
+ 
+   /* Copy members of base classes without constructors.  */
+ 
+   if (n_bases)
+     {
+       int i;
+ 
+       for (i = 0; i < n_bases; ++i)
+ 	{
+ 	  tree base = TYPE_BINFO_BASETYPE (type, i);
+ 
+ 	  if (!TYPE_HAS_CONSTRUCTOR (base))
+ 	    {
+ 	      char *basename =
+ 		IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base)));
+ 
+ 	      while (len + (strlen(basename) * 2) + 30 > alloc)
+ 		buf = xrealloc (buf, alloc *= 2);
+ 
+ 	      sprintf (buf + len, "*(%s*)this=(%s&)_ctor_arg;",
+ 		       basename, basename);
+ 	      len += strlen (buf + len);
+ 	    }
+ 	}
+     }
+ 
+   /* End constructor body.  */
+ 
+   buf[len++] = '}';
+   buf[len] = '\0';
+ 
+   *bufp = buf;
+   *lenp = len;
  }
  

-- 
Chip Salzenberg at Teltronics/TCT  <chip@tct.com>, <73717.366@compuserve.com>