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: correct BINFO_OFFSETs



BINFO_OFFSET was not being set correctly for all bases.  That's what
was causing us to miss an error in `ambig2.C'.  This patch fixes that,
and makes it easier to calculate relative positions of bases, etc.

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

2000-01-10  Mark Mitchell  <mitchell@dumbledore.codesourcery.com>

	* class.c (build_vbase_path): Simplify.
	(dfs_propagate_binfo_offsets): New function.
	(propagate_binfo_offsets): Use it.
	(remove_base_field): Simplify.
	(dfs_set_offset_for_vbases): Remove.
	(dfs_set_offset_for_shared_vbases): New function.
	(dfs_set_offset_for_unshared_vbases): Likewise.
	(layout_virtual_bases): Use them.
	(layout_basetypes): Don't call propagate_binfo_offsets.
	* search.c (dfs_get_vbase_types): Clone completely fresh binfos
	for the vbases.

Index: testsuite/g++.old-deja/g++.other/ambig2.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.other/ambig2.C,v
retrieving revision 1.3
diff -c -p -r1.3 ambig2.C
*** ambig2.C	1999/09/08 08:50:57	1.3
--- ambig2.C	2000/01/11 04:12:19
***************
*** 1,5 ****
  // Build don't link:
! // Copyright (C) 1999 Free Software Foundation, Inc.
  // Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org>
  
  // We should spot all ambiguities
--- 1,5 ----
  // Build don't link:
! // Copyright (C) 1999, 2000 Free Software Foundation, Inc.
  // Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org>
  
  // We should spot all ambiguities
*************** struct D3 : B, C { int m; };
*** 14,20 ****
  
  void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3)
  {
!   A *a0 = d0;   // ERROR - A is an ambiguous base XFAIL
    A *a1 = d1;   // ERROR - A is an ambiguous base
    A *a2 = d2;   // ERROR - A is an ambiguous base
    A *a3 = d3;   // ERROR - A is an ambiguous base
--- 14,20 ----
  
  void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3)
  {
!   A *a0 = d0;   // ERROR - A is an ambiguous base
    A *a1 = d1;   // ERROR - A is an ambiguous base
    A *a2 = d2;   // ERROR - A is an ambiguous base
    A *a3 = d3;   // ERROR - A is an ambiguous base
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.226
diff -c -p -r1.226 class.c
*** class.c	2000/01/11 03:15:32	1.226
--- class.c	2000/01/11 04:12:36
*************** static void layout_class_type PROTO((tre
*** 138,149 ****
  static void fixup_pending_inline PROTO((struct pending_inline *));
  static void fixup_inline_methods PROTO((tree));
  static void set_primary_base PROTO((tree, int, int *));
  static void propagate_binfo_offsets PROTO((tree, tree));
  static void layout_basetypes PROTO((tree));
- static tree dfs_set_offset_for_vbases PROTO((tree, void *));
  static void layout_virtual_bases PROTO((tree));
  static void remove_base_field PROTO((tree, tree, tree *));
  static void remove_base_fields PROTO((tree));
  
  /* Variables shared between class.c and call.c.  */
  
--- 138,151 ----
  static void fixup_pending_inline PROTO((struct pending_inline *));
  static void fixup_inline_methods PROTO((tree));
  static void set_primary_base PROTO((tree, int, int *));
+ static void dfs_propagate_binfo_offsets PROTO((tree, tree));
  static void propagate_binfo_offsets PROTO((tree, tree));
  static void layout_basetypes PROTO((tree));
  static void layout_virtual_bases PROTO((tree));
  static void remove_base_field PROTO((tree, tree, tree *));
  static void remove_base_fields PROTO((tree));
+ static void dfs_set_offset_for_shared_vbases PROTO((tree, void *));
+ static void dfs_set_offset_for_unshared_vbases PROTO((tree, void *));
  
  /* Variables shared between class.c and call.c.  */
  
*************** build_vbase_path (code, type, expr, path
*** 335,350 ****
  	}
      }
    else
!     {
!       if (last_virtual)
! 	{
! 	  offset = BINFO_OFFSET (BINFO_FOR_VBASE (last_virtual, 
! 						  basetype));
! 	  offset = size_binop (PLUS_EXPR, offset, BINFO_OFFSET (last));
! 	}
!       else
! 	offset = BINFO_OFFSET (last);
!     }
  
    if (TREE_INT_CST_LOW (offset))
      {
--- 337,343 ----
  	}
      }
    else
!     offset = BINFO_OFFSET (last);
  
    if (TREE_INT_CST_LOW (offset))
      {
*************** fixup_inline_methods (type)
*** 4141,4148 ****
      fixup_pending_inline (DECL_PENDING_INLINE_INFO (TREE_VALUE (method)));
    CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
  }
  
! /* Add OFFSET to all base types of T.
  
     OFFSET, which is a type offset, is number of bytes.
  
--- 4134,4160 ----
      fixup_pending_inline (DECL_PENDING_INLINE_INFO (TREE_VALUE (method)));
    CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
  }
+ 
+ /* Called from propagate_binfo_offsets via dfs_walk.  */
+ 
+ static tree
+ dfs_propagate_binfo_offsets (binfo, data)
+      tree binfo; 
+      void *data;
+ {
+   tree offset = (tree) data;
+ 
+   /* Update the BINFO_OFFSET for this base.  */
+   BINFO_OFFSET (binfo) 
+     = size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), offset);
+ 
+   SET_BINFO_MARKED (binfo);
+ 
+   return NULL_TREE;
+ }
  
! /* Add OFFSET to all base types of BINFO which is a base in the
!    hierarchy dominated by T.
  
     OFFSET, which is a type offset, is number of bytes.
  
*************** propagate_binfo_offsets (binfo, offset)
*** 4154,4240 ****
       tree binfo;
       tree offset;
  {
!   tree binfos = BINFO_BASETYPES (binfo);
!   int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
! 
!   if (flag_new_abi)
!     {
!       for (i = 0; i < n_baselinks; ++i)
! 	{
! 	  tree base_binfo;
! 
! 	  /* Figure out which base we're looking at.  */
! 	  base_binfo = TREE_VEC_ELT (binfos, i);
! 
! 	  /* Skip non-primary virtual bases.  Their BINFO_OFFSET
! 	     doesn't matter since they are always reached by using
! 	     offsets looked up at run-time.  */
! 	  if (TREE_VIA_VIRTUAL (base_binfo) 
! 	      && i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)))
! 	    continue;
! 
! 	  /* Whatever offset this class used to have in its immediate
! 	     derived class, it is now at OFFSET more bytes in its
! 	     final derived class, since the immediate derived class is
! 	     already at the indicated OFFSET.  */
! 	  BINFO_OFFSET (base_binfo)
! 	    = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset);
! 
! 	  propagate_binfo_offsets (base_binfo, offset);
! 	}
!     }
!   else
!     {
!       /* This algorithm, used for the old ABI, is neither simple, nor
! 	 general.  For example, it mishandles the case of:
!        
!            struct A;
! 	   struct B : public A;
! 	   struct C : public B;
! 	   
! 	 if B is at offset zero in C, but A is not in offset zero in
! 	 B.  In that case, it sets the BINFO_OFFSET for A to zero.
! 	 (This sitution arises in the new ABI if B has virtual
! 	 functions, but A does not.)  Rather than change this
! 	 algorithm, and risking breaking the old ABI, it is preserved
! 	 here.  */
!       for (i = 0; i < n_baselinks; /* note increment is done in the
! 				      loop.  */)
! 	{
! 	  tree base_binfo = TREE_VEC_ELT (binfos, i);
! 
! 	  if (TREE_VIA_VIRTUAL (base_binfo))
! 	    i += 1;
! 	  else
! 	    {
! 	      int j;
! 	      tree delta = NULL_TREE;
! 
! 	      for (j = i+1; j < n_baselinks; j++)
! 		if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
! 		  {
! 		    /* The next basetype offset must take into account
! 		       the space between the classes, not just the
! 		       size of each class.  */
! 		    delta = size_binop (MINUS_EXPR,
! 					BINFO_OFFSET (TREE_VEC_ELT (binfos, 
! 								    j)),
! 					BINFO_OFFSET (base_binfo));
! 		    break;
! 		  }
! 
! 	      BINFO_OFFSET (base_binfo) = offset;
! 
! 	      propagate_binfo_offsets (base_binfo, offset);
! 
! 	      /* Go to our next class that counts for offset
!                  propagation.  */
! 	      i = j;
! 	      if (i < n_baselinks)
! 		offset = size_binop (PLUS_EXPR, offset, delta);
! 	    }
! 	}
!     }
  }
  
  /* Remove *FIELD (which corresponds to the base given by BINFO) from
--- 4166,4179 ----
       tree binfo;
       tree offset;
  {
!   dfs_walk (binfo, 
! 	    dfs_propagate_binfo_offsets, 
! 	    dfs_skip_nonprimary_vbases_unmarkedp,
! 	    offset);
!   dfs_walk (binfo,
! 	    dfs_unmark,
! 	    dfs_skip_nonprimary_vbases_markedp,
! 	    NULL);
  }
  
  /* Remove *FIELD (which corresponds to the base given by BINFO) from
*************** remove_base_field (t, binfo, field)
*** 4258,4264 ****
    offset
      = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
  		      BITS_PER_UNIT));
-   BINFO_OFFSET (binfo) = offset;
    propagate_binfo_offsets (binfo, offset);
  
    /* Remove this field.  */
--- 4197,4202 ----
*************** remove_base_fields (t)
*** 4317,4343 ****
      }
  }
  
! /* Called via dfs_walk from layout_virtual_bases.  */
  
  static tree
! dfs_set_offset_for_vbases (binfo, data)
       tree binfo;
       void *data;
  {
!   /* If this is a primary virtual base that we have not encountered
!      before, give it an offset.  */
!   if (TREE_VIA_VIRTUAL (binfo) 
!       && BINFO_PRIMARY_MARKED_P (binfo)
!       && !BINFO_MARKED (binfo))
      {
!       tree vbase;
  
!       vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
!       BINFO_OFFSET (vbase) = BINFO_OFFSET (binfo);
!       SET_BINFO_VBASE_MARKED (binfo);
      }
  
!   SET_BINFO_MARKED (binfo);
  
    return NULL_TREE;
  }
--- 4255,4301 ----
      }
  }
  
! /* Called via dfs_walk from layout_virtual bases.  */
  
  static tree
! dfs_set_offset_for_shared_vbases (binfo, data)
       tree binfo;
       void *data;
  {
!   if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
      {
!       /* Update the shared copy.  */
!       tree shared_binfo;
  
!       shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
!       BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
      }
  
!   return NULL_TREE;
! }
! 
! /* Called via dfs_walk from layout_virtual bases.  */
! 
! static tree
! dfs_set_offset_for_unshared_vbases (binfo, data)
!      tree binfo;
!      void *data;
! {
!   /* If this is a virtual base, make sure it has the same offset as
!      the shared copy.  If it's a primary base, then we know it's
!      correct.  */
!   if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
!     {
!       tree t = (tree) data;
!       tree vbase;
!       tree offset;
!       
!       vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
!       offset = ssize_binop (MINUS_EXPR, 
! 			    BINFO_OFFSET (vbase),
! 			    BINFO_OFFSET (binfo));
!       propagate_binfo_offsets (binfo, offset);
!     }
  
    return NULL_TREE;
  }
*************** layout_virtual_bases (t)
*** 4357,4366 ****
    /* Make every class have alignment of at least one.  */
    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
  
    for (vbase = CLASSTYPE_VBASECLASSES (t); 
         vbase; 
         vbase = TREE_CHAIN (vbase))
!     if (!BINFO_PRIMARY_MARKED_P (vbase))
        {
  	/* This virtual base is not a primary base of any class in the
  	   hierarchy, so we have to add space for it.  */
--- 4315,4326 ----
    /* Make every class have alignment of at least one.  */
    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
  
+   /* Go through the virtual bases, allocating space for each virtual
+      base that is not already a primary base class.  */
    for (vbase = CLASSTYPE_VBASECLASSES (t); 
         vbase; 
         vbase = TREE_CHAIN (vbase))
!     if (!BINFO_VBASE_PRIMARY_P (vbase))
        {
  	/* This virtual base is not a primary base of any class in the
  	   hierarchy, so we have to add space for it.  */
*************** layout_virtual_bases (t)
*** 4375,4398 ****
  	   appropriately aligned offset.  */
  	dsize = CEIL (dsize, desired_align) * desired_align;
  	/* And compute the offset of the virtual base.  */
! 	BINFO_OFFSET (vbase) = size_int (CEIL (dsize, BITS_PER_UNIT));
  	/* Every virtual baseclass takes a least a UNIT, so that we can
  	   take it's address and get something different for each base.  */
  	dsize += MAX (BITS_PER_UNIT,
  		      TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
        }
  
    /* Now, make sure that the total size of the type is a multiple of
       its alignment.  */
    dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t);
    TYPE_SIZE (t) = size_int (dsize);
    TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
  				   size_int (BITS_PER_UNIT));
- 
-   /* Run through the hierarchy now, setting up all the BINFO_OFFSETs
-      for those virtual base classes that we did not allocate above.  */
-   dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_vbases, unmarkedp, t);
-   dfs_walk (TYPE_BINFO (t), dfs_vbase_unmark, markedp, NULL);
  }
  
  /* Finish the work of layout_record, now taking virtual bases into account.
--- 4335,4370 ----
  	   appropriately aligned offset.  */
  	dsize = CEIL (dsize, desired_align) * desired_align;
  	/* And compute the offset of the virtual base.  */
! 	propagate_binfo_offsets (vbase, 
! 				 size_int (CEIL (dsize, BITS_PER_UNIT)));
  	/* Every virtual baseclass takes a least a UNIT, so that we can
  	   take it's address and get something different for each base.  */
  	dsize += MAX (BITS_PER_UNIT,
  		      TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
        }
  
+   /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
+      BINFO_OFFSET set correctly.  Those we just allocated certainly
+      will.  The others are primary baseclasses; we walk the hierarchy
+      to find the primary copies and update the shared copy.  */
+   dfs_walk (TYPE_BINFO (t), 
+ 	    dfs_set_offset_for_shared_vbases, 
+ 	    dfs_unmarked_real_bases_queue_p,
+ 	    t);
+ 
+   /* Now, go through the TYPE_BINFO hierarchy again, setting the
+      BINFO_OFFSETs correctly for all non-primary copies of the virtual
+      bases and their direct and indirect bases.  The ambiguity checks
+      in get_base_distance depend on the BINFO_OFFSETs being set
+      correctly.  */
+   dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
+ 
    /* Now, make sure that the total size of the type is a multiple of
       its alignment.  */
    dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t);
    TYPE_SIZE (t) = size_int (dsize);
    TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
  				   size_int (BITS_PER_UNIT));
  }
  
  /* Finish the work of layout_record, now taking virtual bases into account.
*************** layout_basetypes (rec)
*** 4426,4442 ****
       the vbase_types are unshared.  */
    for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
         vbase_types = TREE_CHAIN (vbase_types))
!     {
!       propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
! 
!       if (extra_warnings)
! 	{
! 	  tree basetype = BINFO_TYPE (vbase_types);
! 	  if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
! 	    cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
! 			basetype, rec);
! 	}
!     }
  }
  
  /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
--- 4398,4410 ----
       the vbase_types are unshared.  */
    for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
         vbase_types = TREE_CHAIN (vbase_types))
!     if (extra_warnings)
!       {
! 	tree basetype = BINFO_TYPE (vbase_types);
! 	if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
! 	  cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
! 		      basetype, rec);
!       }
  }
  
  /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.144
diff -c -p -r1.144 search.c
*** search.c	2000/01/11 02:43:00	1.144
--- search.c	2000/01/11 04:12:37
*************** dfs_get_vbase_types (binfo, data)
*** 3046,3052 ****
  
    if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
      {
!       tree new_vbase = make_binfo (integer_zero_node, binfo,
  				   BINFO_VTABLE (binfo),
  				   BINFO_VIRTUALS (binfo));
        unshare_base_binfos (new_vbase);
--- 3046,3053 ----
  
    if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
      {
!       tree new_vbase = make_binfo (integer_zero_node, 
! 				   BINFO_TYPE (binfo),
  				   BINFO_VTABLE (binfo),
  				   BINFO_VIRTUALS (binfo));
        unshare_base_binfos (new_vbase);

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