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]

bug 3089


Hi,
this fixes bug 3089. It builds and tests ok on i686-pc-linux-gnu,
I'm running a bootstrap now.

The problem is when generating the E-in-F ctor vtable in the following
heirarchy.
F (0x40164980) 0 nearly-empty
    vptridx=0 vptr=((&F::_ZTV1F) + 32)
  E (0x401649c0) 0 nearly-empty virtual canonical
      primary-for F (0x40164980)
      subvttidx=24 vptridx=4 vbaseoffset=-32
    C (0x40164a80) 0 nearly-empty virtual canonical
        primary-for E (0x401649c0)
        subvttidx=44 vptridx=8 vbaseoffset=-24
      B (0x40164b00) 0 nearly-empty virtual canonical
          primary-for C (0x40164a80)
          vptridx=12 vbaseoffset=-16
      A (0x40164ac0) 4 nearly-empty virtual non-canonical
          vptr=((&C::_ZTV1C) + 40)
    D (0x40164a00) 4 nearly-empty virtual canonical
        subvttidx=56 vptridx=16 vbaseoffset=-28 vptr=((&F::_ZTV1F) + 56)
      A (0x40164a40) 4 nearly-empty virtual canonical
          primary-for D (0x40164a00)
          vptridx=20 vbaseoffset=-20
We do an inheritance graph walk of E's virtual bases which gives us
C, B, A, D. The problem is A. A is the primary base of D, and we
find D's binfo when looking back up the hierarchy. However, as we've not
yet walked D for the ctor-vtable, it's vtable indicates D's vtable pointer
in the complete object F. Hence the ICE. What we want is the D-in-E's
vtable during E's construction.

We can detect this case during the ctor primary base walk, and track
the equivalent ORIG_BINFO (the D-in-complete-E binfo). For this case
we then recursively call dfs_accumulate_vtbl_inits to generate that
vtable. During the inheritance walk when we do the D-in-E case, we
discover we've already generated the vtable.

The equivalent problem does not exist in the complete E case, even though
the hierarchy is identical, because all the BINFO_PRIMARY_BASE_OF
stuff is correct then.

ok?

nathan
-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 9 Jun 2001 <nathan@codesourcery.com>

// Bug 3089. We ICE'd in construction vtables.

int failed;

void fail (int val)
{
  if (!failed)
    failed = val;
}

struct A
{
  virtual ~A();
  A ();
  virtual void check (void *whole, void *base);
};

A::A ()
{
  check (this, this);
}
A::~A ()
{
  check (this, this);
}

void A::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (1);
  else if (this != base)
    fail (2);
}

struct B
{
  virtual ~B ();
  B ();
  virtual void check (void *whole, void *base);
};

B::B ()
{
  check (this, this);
}
B::~B ()
{
  check (this, this);
}
void B::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (3);
  else if (this != base)
    fail (4);
}

struct C : virtual public B, virtual public A
{
  virtual ~C ();
  C ();
  virtual void check (void *whole, void *base);
};
C::C ()
{
  check (this, this);
}
C::~C ()
{
  check (this, this);
}
void C::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (5);
  else if (this != base)
    fail (6);
  A::check (whole, static_cast <A *> (this));
  B::check (whole, static_cast <B *> (this));
}

struct D : virtual public A
{
  virtual ~D ();
  D ();
  virtual void check (void *whole, void *base);
};
D::D ()
{
  check (this, this);
}
D::~D ()
{
  check (this, this);
}
void D::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (5);
  else if (this != base)
    fail (6);
  A::check (whole, static_cast <A *> (this));
}

struct E : virtual public C, virtual public D
{
  virtual ~E ();
  E ();
  virtual void check (void *whole, void *base);
};
E::E ()
{
  check (this, this);
}
E::~E ()
{
  check (this, this);
}
void E::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (5);
  else if (this != base)
    fail (6);
  C::check (whole, static_cast <C *> (this));
  D::check (whole, static_cast <D *> (this));
}

struct F : virtual public E
{
  virtual ~F ();
  F ();
  virtual void check (void *whole, void *base);
};
F::F ()
{
  check (this, this);
}
F::~F ()
{
  check (this, this);
}
void F::check (void *whole, void *base)
{
  if (dynamic_cast <void *> (this) != whole)
    fail (5);
  else if (this != base)
    fail (6);
  E::check (whole, static_cast <F *> (this));
}

int main ()
{
  A a;
  B b;
  C c;
  D d;
  E e;
  F f;
  
  return failed;
}
2001-06-11  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/3089
	* class.c (dfs_accumulate_vtbl_inits): Always walk down the
	hierarchy looking for primary bases for a ctor
	vtable. Recursively call oneself, if we meet our primary via
	this route and haven't met it yet via inheritance graph order.

Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.358.2.22
diff -c -3 -p -r1.358.2.22 class.c
*** class.c	2001/06/08 11:09:01	1.358.2.22
--- class.c	2001/06/11 14:46:41
*************** build_ctor_vtbl_group (binfo, t)
*** 7425,7431 ****
    tree id;
    tree vbase;
  
!   /* See if we've already create this construction vtable group.  */
    id = mangle_ctor_vtbl_for_type (t, binfo);
    if (IDENTIFIER_GLOBAL_VALUE (id))
      return;
--- 7425,7431 ----
    tree id;
    tree vbase;
  
!   /* See if we've already created this construction vtable group.  */
    id = mangle_ctor_vtbl_for_type (t, binfo);
    if (IDENTIFIER_GLOBAL_VALUE (id))
      return;
*************** dfs_accumulate_vtbl_inits (binfo, orig_b
*** 7541,7631 ****
    tree vtbl = NULL_TREE;
    int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
  
!   if (ctor_vtbl_p
!       && TREE_VIA_VIRTUAL (orig_binfo) && BINFO_PRIMARY_P (orig_binfo))
      {
!       /* In the hierarchy of BINFO_TYPE (RTTI_BINFO), this is a primary
!          virtual base.  If it is not the same primary in the hierarchy of T,
!          we'll need to generate a ctor vtable for it, to place at its
!          location in T.  If it is the same primary, we still need a VTT
!          entry for the vtable, but it should point to the ctor vtable for the
! 	 base it is a primary for within the sub-hierarchy of RTTI_BINFO.
! 
! 	 There are three possible cases:
! 
!          1) We are in the same place.
! 	 2) We are a primary base within a lost primary virtual base of
! 	    RTTI_BINFO.
! 	 3) We are not primary to anything else in RTTI_BINFO.  */
! 
!       tree primary = NULL_TREE;
!       if (tree_int_cst_equal (BINFO_OFFSET (orig_binfo),
! 			      size_diffop (BINFO_OFFSET (binfo),
! 					   BINFO_OFFSET (rtti_binfo))))
  	{
! 	  /* Case 1: We're in the same place relative to RTTI_BINFO as we
! 	     were in the complete type, so we are primary either to
! 	     RTTI_BINFO or one of its secondary bases.  */
! 
! 	  tree b = BINFO_PRIMARY_BASE_OF (binfo);
! 
! 	  /* Walk down our until we either find the last primary base or
! 	     rtti_binfo.  */
! 	  for (; b; b = BINFO_PRIMARY_BASE_OF (b))
  	    {
! 	      primary = b;
! 	      if (b == rtti_binfo)
! 		break;
  	    }
!         }
!       else
! 	{
! 	  /* Case 2 or 3: We're not in the same place.  We might still be
! 	     primary to something within a lost primary virtual base of
! 	     RTTI_BINFO.  */
! 
! 	  tree b = BINFO_PRIMARY_BASE_OF (binfo);
! 	  tree last;
! 
! 	  /* First, look through the bases we are primary to for a virtual
! 	     base.  */
! 	  for (; b; b = BINFO_PRIMARY_BASE_OF (b))
  	    {
! 	      last = b;
! 	      if (TREE_VIA_VIRTUAL (b))
! 		break;
  	    }
- 	  /* If we run out of primary links, keep looking down our
- 	     inheritance chain; we might be an indirect primary of a
- 	     virtual base.  */
- 	  if (b == NULL_TREE)
- 	    for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b))
- 	      if (TREE_VIA_VIRTUAL (b))
- 		break;
- 
- 	  /* If we found a virtual base B and it is a base of RTTI_BINFO, we
- 	     share our vtable with LAST, i.e. the derived-most base within
- 	     B of which we are a primary.  Otherwise, we get our own.  */
- 	  if (b && binfo_for_vbase (BINFO_TYPE (b),
- 				    BINFO_TYPE (rtti_binfo)))
- 	    primary = last;
  	}
! 
!       if (primary)
  	{
-           vtbl = BINFO_VTABLE (primary);
- 	  /* If we haven't already been here for our primary derivation,
- 	     all bets are off.  Especially for case 2 above, we need
- 	     the derived vtable to have been generated.  */
- 	  my_friendly_assert (TREE_CODE (vtbl) == TREE_LIST
- 			      && TREE_PURPOSE (vtbl) == rtti_binfo,
- 			      20010126);
  	  vtbl = TREE_VALUE (vtbl);
  	}
      }
    else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo, BINFO_TYPE (rtti_binfo)))
      return inits;
!   
    if (!vtbl)
      {
        tree index;
--- 7541,7658 ----
    tree vtbl = NULL_TREE;
    int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
  
!   if (ctor_vtbl_p)
      {
!       tree primary = binfo;
!       tree orig_primary = orig_binfo;
!       
!       if (TREE_VIA_VIRTUAL (orig_binfo) && BINFO_PRIMARY_P (orig_binfo))
  	{
! 	  /* In the hierarchy of BINFO_TYPE (RTTI_BINFO), this is a
!              primary virtual base.  If it is not the same primary in
!              the hierarchy of T, we'll need to generate a ctor vtable
!              for it, to place at its location in T.  If it is the same
!              primary, we still need a VTT entry for the vtable, but it
!              should point to the ctor vtable for the base it is a
!              primary for within the sub-hierarchy of RTTI_BINFO.
! 	      
! 	     There are three possible cases:
! 	      
!              1) We are in the same place.
! 	     2) We are a primary base within a lost primary virtual base of
! 	     RTTI_BINFO.
! 	     3) We are not primary to anything else in RTTI_BINFO.  */
! 	  
! 	  if (tree_int_cst_equal (BINFO_OFFSET (orig_binfo),
! 				  size_diffop (BINFO_OFFSET (binfo),
! 					       BINFO_OFFSET (rtti_binfo))))
  	    {
! 	      /* Case 1: We're in the same place relative to
! 	     	 RTTI_BINFO as we were in the complete type, so we are
! 	     	 primary either to RTTI_BINFO or one of its secondary
! 	     	 bases.  */
! 	      
! 	      /* Walk down our until we either find the last
! 	     	 primary base or rtti_binfo.  */
! 	      tree b = BINFO_PRIMARY_BASE_OF (binfo);
! 
! 	      for (; b; b = BINFO_PRIMARY_BASE_OF (b))
! 		{
! 		  primary = b;
! 		  orig_primary = BINFO_PRIMARY_BASE_OF (orig_primary);
! 		  if (b == rtti_binfo)
! 		    break;
! 		}
  	    }
! 	  else
  	    {
! 	      /* Case 2 or 3: We're not in the same place.  We might
! 	         still be primary to something within a lost primary
! 	         virtual base of RTTI_BINFO.  */
! 	      tree b;
! 	      tree last, orig_last;
! 
! 	      /* First, look through the bases we are primary to for a
! 	     	 virtual base.  */
! 	      for (b = BINFO_PRIMARY_BASE_OF (binfo), orig_last = orig_binfo;
! 		   b;
! 		   b = BINFO_PRIMARY_BASE_OF (b))
! 		{
! 		  last = b;
! 		  if (orig_last)
! 		    orig_last = BINFO_PRIMARY_BASE_OF (orig_last);
! 		  if (TREE_VIA_VIRTUAL (b))
! 		    break;
! 		}
! 	      /* If we run out of primary links, keep looking down our
! 	     	 inheritance chain; we might be an indirect primary of
! 	     	 a virtual base.  */
! 	      if (b == NULL_TREE)
! 		for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b))
! 		  if (TREE_VIA_VIRTUAL (b))
! 		    break;
! 
! 	      /* If we found a virtual base B and it is a base of
! 	     	 RTTI_BINFO, we share our vtable with LAST, i.e. the
! 	     	 derived-most base within B of which we are a primary.
! 	     	 Otherwise, we get our own.  */
! 	      if (b && binfo_for_vbase (BINFO_TYPE (b),
! 					BINFO_TYPE (rtti_binfo)))
! 		{
! 		  my_friendly_assert (orig_last, 20010611);
! 		  primary = last;
! 		  orig_primary = orig_last;
! 		}
  	    }
  	}
!       
!       vtbl = BINFO_VTABLE (primary);
!       if (vtbl && TREE_CODE (vtbl) == TREE_LIST
! 	  && TREE_PURPOSE (vtbl) == rtti_binfo)
  	{
  	  vtbl = TREE_VALUE (vtbl);
+ 	  if (primary == binfo)
+ 	    /* We created this vtable because we met its primary base
+ 	       earlier in the inheritance graph walk of
+ 	       RTTI_BINFO.  */
+ 	    return inits;
  	}
+       else if (primary != binfo)
+ 	{
+ 	  /* We're the primary of some binfo that we've not yet
+ 	     met in the inheritance graph walk of RTTI_BINFO. We
+ 	     must create that vtable now. */
+ 	  inits = dfs_accumulate_vtbl_inits (primary, orig_primary,
+ 					     rtti_binfo, t, l);
+ 	  vtbl = BINFO_VTABLE (primary);
+ 	  vtbl = TREE_VALUE (vtbl);
+ 	}
+       else
+ 	vtbl = NULL;
      }
    else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo, BINFO_TYPE (rtti_binfo)))
      return inits;
! 
    if (!vtbl)
      {
        tree index;
*************** dfs_accumulate_vtbl_inits (binfo, orig_b
*** 7650,7668 ****
        TREE_CONSTANT (vtbl) = 1;
      }
  
!   if (!ctor_vtbl_p)
!     {
!       /* For an ordinary vtable, set BINFO_VTABLE.  */
!       if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))
! 	inits = NULL_TREE;
!       else
! 	BINFO_VTABLE (binfo) = vtbl;
!     }
!   else
      /* For a construction vtable, we can't overwrite BINFO_VTABLE.
         So, we make a TREE_LIST.  Later, dfs_fixup_binfo_vtbls will
         straighten this out.  */
      BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
  
    return inits;
  }
--- 7677,7692 ----
        TREE_CONSTANT (vtbl) = 1;
      }
  
!   if (ctor_vtbl_p)
      /* For a construction vtable, we can't overwrite BINFO_VTABLE.
         So, we make a TREE_LIST.  Later, dfs_fixup_binfo_vtbls will
         straighten this out.  */
      BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
+   else if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))
+     inits = NULL_TREE;
+   else
+      /* For an ordinary vtable, set BINFO_VTABLE.  */
+     BINFO_VTABLE (binfo) = vtbl;
  
    return inits;
  }


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