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]
Other format: [Raw text]

C++ PATCH: ABI tweaks


Our ABI testsuite found a few more problems; fortunately, all can be
fixed in a backwards-compatible way.  These problems were:

(1) Thunks not being emitted, even when they are supposed to be.

(2) Failure to emit VTTs when emitting an ordinary vtable; they should
    always be emitted at the same time.  (Technically, in a single
    COMDAT group, but we don't have support for COMDAT yet...)

Tested on i686-pc-linux-gnu, applied on the mainline.

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

2002-11-03  Mark Mitchell  <mark@codesourcery.com>

	* call.c (build_special_member_call): Do not try to lookup VTTs by
	name.
	* class.c (vtbl_init_data): Add generate_vcall_entries.
	(get_vtable_decl): Do not look up virtual tables by name.
	(copy_virtuals): Do not use BV_USE_VCALL_INDEX_P.
	(set_primary_base): Do not set CLASSTYPE_RTTI.
	(determine_primary_base): Likewise.
	(get_matching_virtual): Remove.
	(get_vcall_index): New function.
	(update_vtable_entry_for_fn): Do not try to use virtual thunks
	when they are not required.  Assign vcall indices at this point.
	(finish_struct_1): Do not set CLASSTYPE_NEEDS_VIRTUAL_REINIT.
	Do update dynamic_classes.
	(build_vtt): Do not add VTTs to the symbol table.
	(build_ctor_vtbl_group): Likewise.
	(build_vtbl_initializer): Simplify handling of vcall indices.
	(build_vcall_offset_vtbl_entries): Pretend to build vcall offsets
	for the most derived class.
	(add_vcall_offset_vtbl_entries_1): But do not actually add them to
	the vtable.
	* cp-tree.h (dynamic_classes): New macro.
	(lang_type_class): Remove rtti.  Add vtables.  Add vcall_indices.
	(CLASSTYPE_RTTI): Remove.
	(CLASSTYPE_NEEDS_VIRTUAL_REINIT): Remove.
	(CLASSTYPE_VCALL_INDICES): New macro.
	(CLASSTYPE_VTABLES): Likewise.
	(BV_USE_VCALL_INDEX_P): Remove.
	(build_vtable_path): Remove.
	* decl2.c (finish_vtable_vardecl): Remove.
	(key_method): Remove #if 0'd code.
	(finish_vtable_vardecl): Rename to ...
	(maybe_emit_vtables): ... this.
	(finish_file): Use it.
	* search.c (look_for_overrides_here): Update comment.

2002-11-03  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/thunk1.C: New test.
	* g++.dg/abi/thunk2.C: Likewise.
	* g++.dg/abi/vtt1.C: Likewise.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.338
diff -c -5 -p -r1.338 call.c
*** cp/call.c	31 Oct 2002 21:38:38 -0000	1.338
--- cp/call.c	4 Nov 2002 01:34:23 -0000
*************** build_special_member_call (tree instance
*** 4710,4720 ****
        tree sub_vtt;
  
        /* If the current function is a complete object constructor
  	 or destructor, then we fetch the VTT directly.
  	 Otherwise, we look it up using the VTT we were given.  */
!       vtt = IDENTIFIER_GLOBAL_VALUE (get_vtt_name (current_class_type));
        vtt = decay_conversion (vtt);
        vtt = build (COND_EXPR, TREE_TYPE (vtt),
  		   build (EQ_EXPR, boolean_type_node,
  			  current_in_charge_parm, integer_zero_node),
  		   current_vtt_parm,
--- 4710,4720 ----
        tree sub_vtt;
  
        /* If the current function is a complete object constructor
  	 or destructor, then we fetch the VTT directly.
  	 Otherwise, we look it up using the VTT we were given.  */
!       vtt = TREE_CHAIN (CLASSTYPE_VTABLES (current_class_type));
        vtt = decay_conversion (vtt);
        vtt = build (COND_EXPR, TREE_TYPE (vtt),
  		   build (EQ_EXPR, boolean_type_node,
  			  current_in_charge_parm, integer_zero_node),
  		   current_vtt_parm,
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.489
diff -c -5 -p -r1.489 class.c
*** cp/class.c	30 Oct 2002 15:54:05 -0000	1.489
--- cp/class.c	4 Nov 2002 01:34:25 -0000
*************** typedef struct vtbl_init_data_s
*** 85,94 ****
--- 85,97 ----
       vtable.  */
    int primary_vtbl_p;
    /* Nonzero if we are building the initializer for a construction
       vtable.  */
    int ctor_vtbl_p;
+   /* True when adding vcall offset entries to the vtable.  False when
+      merely computing the indices.  */
+   bool generate_vcall_entries;
  } vtbl_init_data;
  
  /* The type of a function passed to walk_subobject_offsets.  */
  typedef int (*subobject_offset_fn) PARAMS ((tree, tree, splay_tree));
  
*************** static bool type_requires_array_cookie P
*** 207,216 ****
--- 210,220 ----
  static bool contains_empty_class_p (tree);
  static tree dfs_base_derived_from (tree, void *);
  static bool base_derived_from (tree, tree);
  static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree);
  static tree end_of_base (tree);
+ static tree get_vcall_index (tree, tree);
  
  /* Macros for dfs walking during vtt construction. See
     dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
     and dfs_fixup_binfo_vtbls.  */
  #define VTT_TOP_LEVEL_P(NODE) TREE_UNSIGNED (NODE)
*************** build_vtable (class_type, name, vtable_t
*** 538,562 ****
  tree 
  get_vtable_decl (type, complete)
       tree type;
       int complete;
  {
!   tree name = get_vtable_name (type);
!   tree decl = IDENTIFIER_GLOBAL_VALUE (name);
!   
!   if (decl)
!     {
!       my_friendly_assert (TREE_CODE (decl) == VAR_DECL
!                           && DECL_VIRTUAL_P (decl), 20000118);
!       return decl;
!     }
!   
!   decl = build_vtable (type, name, void_type_node);
!   decl = pushdecl_top_level (decl);
!   my_friendly_assert (IDENTIFIER_GLOBAL_VALUE (name) == decl,
! 		      20000517);
    
    /* At one time the vtable info was grabbed 2 words at a time.  This
       fails on sparc unless you have 8-byte alignment.  (tiemann) */
    DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
  			   DECL_ALIGN (decl));
  
--- 542,559 ----
  tree 
  get_vtable_decl (type, complete)
       tree type;
       int complete;
  {
!   tree decl;
! 
!   if (CLASSTYPE_VTABLES (type))
!     return CLASSTYPE_VTABLES (type);
    
+   decl = build_vtable (type, get_vtable_name (type), void_type_node);
+   CLASSTYPE_VTABLES (type) = decl;
+ 
    /* At one time the vtable info was grabbed 2 words at a time.  This
       fails on sparc unless you have 8-byte alignment.  (tiemann) */
    DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
  			   DECL_ALIGN (decl));
  
*************** copy_virtuals (binfo)
*** 579,592 ****
    tree copies;
    tree t;
  
    copies = copy_list (BINFO_VIRTUALS (binfo));
    for (t = copies; t; t = TREE_CHAIN (t))
!     {
!       BV_VCALL_INDEX (t) = NULL_TREE;
!       BV_USE_VCALL_INDEX_P (t) = 0;
!     }
  
    return copies;
  }
  
  /* Build the primary virtual function table for TYPE.  If BINFO is
--- 576,586 ----
    tree copies;
    tree t;
  
    copies = copy_list (BINFO_VIRTUALS (binfo));
    for (t = copies; t; t = TREE_CHAIN (t))
!     BV_VCALL_INDEX (t) = NULL_TREE;
  
    return copies;
  }
  
  /* Build the primary virtual function table for TYPE.  If BINFO is
*************** set_primary_base (t, binfo)
*** 1557,1567 ****
    CLASSTYPE_PRIMARY_BINFO (t) = binfo;
    basetype = BINFO_TYPE (binfo);
    TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
    TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
    TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
-   CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
  }
  
  /* Determine the primary class for T.  */
  
  static void
--- 1551,1560 ----
*************** determine_primary_base (t)
*** 1583,1598 ****
        tree base_binfo = BINFO_BASETYPE (type_binfo, i);
        tree basetype = BINFO_TYPE (base_binfo);
  
        if (TYPE_CONTAINS_VPTR_P (basetype))
  	{
- 	  /* Even a virtual baseclass can contain our RTTI
- 	     information.  But, we prefer a non-virtual polymorphic
- 	     baseclass.  */
- 	  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
- 	    CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
- 
  	  /* We prefer a non-virtual base, although a virtual one will
  	     do.  */
  	  if (TREE_VIA_VIRTUAL (base_binfo))
  	    continue;
  
--- 1576,1585 ----
*************** find_final_overrider (t, binfo, fn)
*** 2323,2347 ****
      }
  
    return ffod.candidates;
  }
  
! /* Returns the function from the BINFO_VIRTUALS entry in T which matches
!    the signature of FUNCTION_DECL FN, or NULL_TREE if none.  In other words,
!    the function that the slot in T's primary vtable points to.  */
  
- static tree get_matching_virtual PARAMS ((tree, tree));
  static tree
! get_matching_virtual (t, fn)
!      tree t, fn;
  {
!   tree f;
  
!   for (f = BINFO_VIRTUALS (TYPE_BINFO (t)); f; f = TREE_CHAIN (f))
!     if (same_signature_p (BV_FN (f), fn))
!       return BV_FN (f);
!   return NULL_TREE;
  }
  
  /* Update an entry in the vtable for BINFO, which is in the hierarchy
     dominated by T.  FN has been overriden in BINFO; VIRTUALS points to the
     corresponding position in the BINFO_VIRTUALS list.  */
--- 2310,2336 ----
      }
  
    return ffod.candidates;
  }
  
! /* Return the index of the vcall offset for FN when TYPE is used as a
!    virtual base.  */
  
  static tree
! get_vcall_index (tree fn, tree type)
  {
!   tree v;
  
!   for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
!     if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
! 	|| same_signature_p (fn, TREE_PURPOSE (v)))
!       break;
! 
!   /* There should always be an appropriate index.  */
!   my_friendly_assert (v, 20021103);
! 
!   return TREE_VALUE (v);
  }
  
  /* Update an entry in the vtable for BINFO, which is in the hierarchy
     dominated by T.  FN has been overriden in BINFO; VIRTUALS points to the
     corresponding position in the BINFO_VIRTUALS list.  */
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2405,2415 ****
      }
  
    /* Compute the constant adjustment to the `this' pointer.  The
       `this' pointer, when this function is called, will point at BINFO
       (or one of its primary bases, which are at the same offset).  */
- 
    if (virtual_base)
      /* The `this' pointer needs to be adjusted from the declaration to
         the nearest virtual base.  */
      delta = size_diffop (BINFO_OFFSET (virtual_base),
  			 BINFO_OFFSET (first_defn));
--- 2394,2403 ----
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2418,2466 ****
         entry in our vtable.  Except possibly in a constructor vtable,
         if we happen to get our primary back.  In that case, the offset
         will be zero, as it will be a primary base.  */
      delta = size_zero_node;
    else
!     {
!       /* The `this' pointer needs to be adjusted from pointing to
! 	 BINFO to pointing at the base where the final overrider
! 	 appears.  */
!       delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
! 			   BINFO_OFFSET (binfo));
! 
!       if (! integer_zerop (delta))
! 	{
! 	  /* We'll need a thunk.  But if we have a (perhaps formerly)
! 	     primary virtual base, we have a vcall slot for this function,
! 	     so we can use it rather than create a non-virtual thunk.  */
! 	  
! 	  b = get_primary_binfo (first_defn);
! 	  for (; b; b = get_primary_binfo (b))
! 	    {
! 	      tree f = get_matching_virtual (BINFO_TYPE (b), fn);
! 	      if (!f)
! 		/* b doesn't have this function; no suitable vbase.  */
! 		break;
! 	      if (TREE_VIA_VIRTUAL (b))
! 		{
! 		  /* Found one; we can treat ourselves as a virtual base.  */
! 		  virtual_base = binfo;
! 		  delta = size_zero_node;
! 		  break;
! 		}
! 	    }
! 	}
!     }
  
    modify_vtable_entry (t, 
  		       binfo, 
  		       TREE_PURPOSE (overrider),
  		       delta,
  		       virtuals);
  
    if (virtual_base)
!     BV_USE_VCALL_INDEX_P (*virtuals) = 1;
  }
  
  /* Called from modify_all_vtables via dfs_walk.  */
  
  static tree
--- 2406,2431 ----
         entry in our vtable.  Except possibly in a constructor vtable,
         if we happen to get our primary back.  In that case, the offset
         will be zero, as it will be a primary base.  */
      delta = size_zero_node;
    else
!     /* The `this' pointer needs to be adjusted from pointing to
!        BINFO to pointing at the base where the final overrider
!        appears.  */
!     delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
! 			 BINFO_OFFSET (binfo));
  
    modify_vtable_entry (t, 
  		       binfo, 
  		       TREE_PURPOSE (overrider),
  		       delta,
  		       virtuals);
  
    if (virtual_base)
!     BV_VCALL_INDEX (*virtuals) 
!       = get_vcall_index (TREE_PURPOSE (overrider),
! 			 BINFO_TYPE (virtual_base));
  }
  
  /* Called from modify_all_vtables via dfs_walk.  */
  
  static tree
*************** layout_class_type (tree t, tree *virtual
*** 5099,5134 ****
  
    /* Clean up.  */
    splay_tree_delete (empty_base_offsets);
  }
  
! /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
!    (or C++ class declaration).
! 
!    For C++, we must handle the building of derived classes.
!    Also, C++ allows static class members.  The way that this is
!    handled is to keep the field name where it is (as the DECL_NAME
!    of the field), and place the overloaded decl in the bit position
!    of the field.  layout_record and layout_union will know about this.
! 
!    More C++ hair: inline functions have text in their
!    DECL_PENDING_INLINE_INFO nodes which must somehow be parsed into
!    meaningful tree structure.  After the struct has been laid out, set
!    things up so that this can happen.
! 
!    And still more: virtual functions.  In the case of single inheritance,
!    when a new virtual function is seen which redefines a virtual function
!    from the base class, the new virtual function is placed into
!    the virtual function table at exactly the same address that
!    it had in the base class.  When this is extended to multiple
!    inheritance, the same thing happens, except that multiple virtual
!    function tables must be maintained.  The first virtual function
!    table is treated in exactly the same way as in the case of single
!    inheritance.  Additional virtual function tables have different
!    DELTAs, which tell how to adjust `this' to point to the right thing.
! 
!    ATTRIBUTES is the set of decl attributes to be applied, if any.  */
  
  void
  finish_struct_1 (t)
       tree t;
  {
--- 5064,5075 ----
  
    /* Clean up.  */
    splay_tree_delete (empty_base_offsets);
  }
  
! /* Perform processing required when the definition of T (a class type)
!    is complete.  */
  
  void
  finish_struct_1 (t)
       tree t;
  {
*************** finish_struct_1 (t)
*** 5151,5161 ****
    /* If this type was previously laid out as a forward reference,
       make sure we lay it out again.  */
    TYPE_SIZE (t) = NULL_TREE;
    CLASSTYPE_GOT_SEMICOLON (t) = 0;
    CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
-   CLASSTYPE_RTTI (t) = NULL_TREE;
  
    fixup_inline_methods (t);
    
    /* Make assumptions about the class; we'll reset the flags if
       necessary.  */
--- 5092,5101 ----
*************** finish_struct_1 (t)
*** 5208,5235 ****
  	build_primary_vtable (NULL_TREE, t);
        else if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t), t))
  	/* Here we know enough to change the type of our virtual
  	   function table, but we will wait until later this function.  */
  	build_primary_vtable (CLASSTYPE_PRIMARY_BINFO (t), t);
- 
-       /* If this type has basetypes with constructors, then those
- 	 constructors might clobber the virtual function table.  But
- 	 they don't if the derived class shares the exact vtable of the base
- 	 class.  */
-       CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
-     }
-   /* If we didn't need a new vtable, see if we should copy one from
-      the base.  */
-   else if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-     {
-       tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
- 
-       /* If this class uses a different vtable than its primary base
- 	 then when we will need to initialize our vptr after the base
- 	 class constructor runs.  */
-       if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
- 	CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
      }
  
    if (TYPE_CONTAINS_VPTR_P (t))
      {
        int vindex;
--- 5148,5157 ----
*************** finish_struct_1 (t)
*** 5251,5260 ****
--- 5173,5185 ----
  	   fn = TREE_CHAIN (fn), 
  	     vindex += (TARGET_VTABLE_USES_DESCRIPTORS
  			? TARGET_VTABLE_USES_DESCRIPTORS : 1))
  	if (TREE_CODE (DECL_VINDEX (BV_FN (fn))) != INTEGER_CST)
  	  DECL_VINDEX (BV_FN (fn)) = build_shared_int_cst (vindex);
+ 
+       /* Add this class to the list of dynamic classes.  */
+       dynamic_classes = tree_cons (NULL_TREE, t, dynamic_classes);
      }
  
    finish_struct_bits (t);
  
    /* Complete the rtl for any static member objects of the type we're
*************** build_vtt (t)
*** 7066,7077 ****
    type = build_index_type (size_int (list_length (inits) - 1));
    type = build_cplus_array_type (const_ptr_type_node, type);
  				 
    /* Now, build the VTT object itself.  */
    vtt = build_vtable (t, get_vtt_name (t), type);
-   pushdecl_top_level (vtt);
    initialize_array (vtt, inits);
  
    dump_vtt (t, vtt);
  }
  
  /* The type corresponding to BASE_BINFO is a base of the type of BINFO, but
--- 6991,7004 ----
    type = build_index_type (size_int (list_length (inits) - 1));
    type = build_cplus_array_type (const_ptr_type_node, type);
  				 
    /* Now, build the VTT object itself.  */
    vtt = build_vtable (t, get_vtt_name (t), type);
    initialize_array (vtt, inits);
+   /* Add the VTT to the vtables list.  */
+   TREE_CHAIN (vtt) = TREE_CHAIN (CLASSTYPE_VTABLES (t));
+   TREE_CHAIN (CLASSTYPE_VTABLES (t)) = vtt;
  
    dump_vtt (t, vtt);
  }
  
  /* The type corresponding to BASE_BINFO is a base of the type of BINFO, but
*************** build_ctor_vtbl_group (binfo, t)
*** 7402,7412 ****
    type = build_index_type (size_int (list_length (inits) - 1));
    type = build_cplus_array_type (vtable_entry_type, type);
    TREE_TYPE (vtbl) = type;
  
    /* Initialize the construction vtable.  */
!   pushdecl_top_level (vtbl);
    initialize_array (vtbl, inits);
    dump_vtable (t, binfo, vtbl);
  }
  
  /* Add the vtbl initializers for BINFO (and its bases other than
--- 7329,7339 ----
    type = build_index_type (size_int (list_length (inits) - 1));
    type = build_cplus_array_type (vtable_entry_type, type);
    TREE_TYPE (vtbl) = type;
  
    /* Initialize the construction vtable.  */
!   CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
    initialize_array (vtbl, inits);
    dump_vtable (t, binfo, vtbl);
  }
  
  /* Add the vtbl initializers for BINFO (and its bases other than
*************** build_vtbl_initializer (binfo, orig_binf
*** 7619,7628 ****
--- 7546,7556 ----
    vid.derived = t;
    vid.rtti_binfo = rtti_binfo;
    vid.last_init = &vid.inits;
    vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
    vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+   vid.generate_vcall_entries = true;
    /* The first vbase or vcall offset is at index -3 in the vtable.  */
    vid.index = ssize_int (-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
  
    /* Add entries to the vtable for RTTI.  */
    build_rtti_vtbl_entries (binfo, &vid);
*************** build_vtbl_initializer (binfo, orig_binf
*** 7702,7719 ****
        if (! init)
  	{
  	  /* Pull the offset for `this', and the function to call, out of
  	     the list.  */
  	  delta = BV_DELTA (v);
! 
! 	  if (BV_USE_VCALL_INDEX_P (v))
! 	    {
! 	      vcall_index = BV_VCALL_INDEX (v);
! 	      my_friendly_assert (vcall_index != NULL_TREE, 20000621);
! 	    }
! 	  else
! 	    vcall_index = NULL_TREE;
  
  	  my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
  	  my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
  
  	  /* You can't call an abstract virtual function; it's abstract.
--- 7630,7640 ----
        if (! init)
  	{
  	  /* Pull the offset for `this', and the function to call, out of
  	     the list.  */
  	  delta = BV_DELTA (v);
! 	  vcall_index = BV_VCALL_INDEX (v);
  
  	  my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
  	  my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
  
  	  /* You can't call an abstract virtual function; it's abstract.
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 7898,7932 ****
  static void
  build_vcall_offset_vtbl_entries (binfo, vid)
       tree binfo;
       vtbl_init_data *vid;
  {
!   /* We only need these entries if this base is a virtual base.  */
!   if (!TREE_VIA_VIRTUAL (binfo))
!     return;
! 
!   /* We need a vcall offset for each of the virtual functions in this
!      vtable.  For example:
! 
!        class A { virtual void f (); };
!        class B1 : virtual public A { virtual void f (); };
!        class B2 : virtual public A { virtual void f (); };
!        class C: public B1, public B2 { virtual void f (); };
! 
!      A C object has a primary base of B1, which has a primary base of A.  A
!      C also has a secondary base of B2, which no longer has a primary base
!      of A.  So the B2-in-C construction vtable needs a secondary vtable for
!      A, which will adjust the A* to a B2* to call f.  We have no way of
!      knowing what (or even whether) this offset will be when we define B2,
!      so we store this "vcall offset" in the A sub-vtable and look it up in
!      a "virtual thunk" for B2::f.
! 
!      We need entries for all the functions in our primary vtable and
!      in our non-virtual bases' secondary vtables.  */
!   vid->vbase = binfo;
!   /* Now, walk through the non-virtual bases, adding vcall offsets.  */
!   add_vcall_offset_vtbl_entries_r (binfo, vid);
  }
  
  /* Build vcall offsets, starting with those for BINFO.  */
  
  static void
--- 7819,7859 ----
  static void
  build_vcall_offset_vtbl_entries (binfo, vid)
       tree binfo;
       vtbl_init_data *vid;
  {
!   /* We only need these entries if this base is a virtual base.  We
!      compute the indices -- but do not add to the vtable -- when
!      building the main vtable for a class.  */
!   if (TREE_VIA_VIRTUAL (binfo) || binfo == TYPE_BINFO (vid->derived))
!     {
!       /* We need a vcall offset for each of the virtual functions in this
! 	 vtable.  For example:
! 
! 	   class A { virtual void f (); };
! 	   class B1 : virtual public A { virtual void f (); };
! 	   class B2 : virtual public A { virtual void f (); };
! 	   class C: public B1, public B2 { virtual void f (); };
! 
! 	 A C object has a primary base of B1, which has a primary base of A.  A
! 	 C also has a secondary base of B2, which no longer has a primary base
! 	 of A.  So the B2-in-C construction vtable needs a secondary vtable for
! 	 A, which will adjust the A* to a B2* to call f.  We have no way of
! 	 knowing what (or even whether) this offset will be when we define B2,
! 	 so we store this "vcall offset" in the A sub-vtable and look it up in
! 	 a "virtual thunk" for B2::f.
! 
! 	 We need entries for all the functions in our primary vtable and
! 	 in our non-virtual bases' secondary vtables.  */
!       vid->vbase = binfo;
!       /* If we are just computing the vcall indices -- but do not need
! 	 the actual entries -- not that.  */
!       if (!TREE_VIA_VIRTUAL (binfo))
! 	vid->generate_vcall_entries = false;
!       /* Now, walk through the non-virtual bases, adding vcall offsets.  */
!       add_vcall_offset_vtbl_entries_r (binfo, vid);
!     }
  }
  
  /* Build vcall offsets, starting with those for BINFO.  */
  
  static void
*************** add_vcall_offset_vtbl_entries_1 (binfo, 
*** 8023,8034 ****
  	 derived_virtuals = TREE_CHAIN (derived_virtuals),
  	 orig_virtuals = TREE_CHAIN (orig_virtuals))
      {
        tree orig_fn;
        tree fn;
-       tree base;
-       tree base_binfo;
        size_t i;
        tree vcall_offset;
  
        /* Find the declaration that originally caused this function to
  	 be present in BINFO_TYPE (binfo).  */
--- 7950,7959 ----
*************** add_vcall_offset_vtbl_entries_1 (binfo, 
*** 8055,8108 ****
  	  if (same_signature_p (BV_FN (derived_entry), fn)
  	      /* We only use one vcall offset for virtual destructors,
  		 even though there are two virtual table entries.  */
  	      || (DECL_DESTRUCTOR_P (BV_FN (derived_entry))
  		  && DECL_DESTRUCTOR_P (fn)))
! 	    {
! 	      if (!vid->ctor_vtbl_p)
!   	        BV_VCALL_INDEX (derived_virtuals) 
! 		  = BV_VCALL_INDEX (derived_entry);
! 	      break;
! 	    }
  	}
        if (i != VARRAY_ACTIVE_SIZE (vid->fns))
  	continue;
  
!       /* The FN comes from BASE.  So, we must calculate the adjustment from
! 	 vid->vbase to BASE.  We can just look for BASE in the complete
! 	 object because we are converting from a virtual base, so if there
! 	 were multiple copies, there would not be a unique final overrider
! 	 and vid->derived would be ill-formed.  */
!       base = DECL_CONTEXT (fn);
!       base_binfo = lookup_base (vid->derived, base, ba_any, NULL);
! 
!       /* Compute the vcall offset.  */
!       /* As mentioned above, the vbase we're working on is a primary base of
! 	 vid->binfo.  But it might be a lost primary, so its BINFO_OFFSET
!          might be wrong, so we just use the BINFO_OFFSET from vid->binfo.  */
!       vcall_offset = BINFO_OFFSET (vid->binfo);
!       vcall_offset = size_diffop (BINFO_OFFSET (base_binfo),
! 		                  vcall_offset);
!       vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
!     			           vcall_offset));
!       
!       *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
!       vid->last_init = &TREE_CHAIN (*vid->last_init);
! 
!       /* Keep track of the vtable index where this vcall offset can be
! 	 found.  For a construction vtable, we already made this
! 	 annotation when we built the original vtable.  */
!       if (!vid->ctor_vtbl_p)
! 	BV_VCALL_INDEX (derived_virtuals) = vid->index;
  
        /* The next vcall offset will be found at a more negative
  	 offset.  */
        vid->index = size_binop (MINUS_EXPR, vid->index,
  			       ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
  
        /* Keep track of this function.  */
        VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
      }
  }
  
  /* Return vtbl initializers for the RTTI entries coresponding to the
     BINFO's vtable.  The RTTI entries should indicate the object given
--- 7980,8037 ----
  	  if (same_signature_p (BV_FN (derived_entry), fn)
  	      /* We only use one vcall offset for virtual destructors,
  		 even though there are two virtual table entries.  */
  	      || (DECL_DESTRUCTOR_P (BV_FN (derived_entry))
  		  && DECL_DESTRUCTOR_P (fn)))
! 	    break;
  	}
        if (i != VARRAY_ACTIVE_SIZE (vid->fns))
  	continue;
  
!       /* If we are building these vcall offsets as part of building
! 	 the vtable for the most derived class, remember the vcall
! 	 offset.  */
!       if (vid->binfo == TYPE_BINFO (vid->derived))
! 	CLASSTYPE_VCALL_INDICES (vid->derived) 
! 	  = tree_cons (fn, vid->index, CLASSTYPE_VCALL_INDICES (vid->derived));
  
        /* The next vcall offset will be found at a more negative
  	 offset.  */
        vid->index = size_binop (MINUS_EXPR, vid->index,
  			       ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
  
        /* Keep track of this function.  */
        VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+ 
+       if (vid->generate_vcall_entries)
+ 	{
+ 	  tree base;
+ 	  tree base_binfo;
+ 
+ 	  /* The FN comes from BASE.  So, we must calculate the
+ 	     adjustment from vid->vbase to BASE.  We can just look for
+ 	     BASE in the complete object because we are converting
+ 	     from a virtual base, so if there were multiple copies,
+ 	     there would not be a unique final overrider and
+ 	     vid->derived would be ill-formed.  */
+ 	  base = DECL_CONTEXT (fn);
+ 	  base_binfo = lookup_base (vid->derived, base, ba_any, NULL);
+ 
+ 	  /* Compute the vcall offset.  */
+ 	  /* As mentioned above, the vbase we're working on is a
+ 	     primary base of vid->binfo.  But it might be a lost
+ 	     primary, so its BINFO_OFFSET might be wrong, so we just
+ 	     use the BINFO_OFFSET from vid->binfo.  */
+ 	  vcall_offset = BINFO_OFFSET (vid->binfo);
+ 	  vcall_offset = size_diffop (BINFO_OFFSET (base_binfo),
+ 				      vcall_offset);
+ 	  vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
+ 				       vcall_offset));
+ 
+ 	  *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
+ 	  vid->last_init = &TREE_CHAIN (*vid->last_init);
+ 	}
      }
  }
  
  /* Return vtbl initializers for the RTTI entries coresponding to the
     BINFO's vtable.  The RTTI entries should indicate the object given
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.768
diff -c -5 -p -r1.768 cp-tree.h
*** cp/cp-tree.h	31 Oct 2002 21:38:38 -0000	1.768
--- cp/cp-tree.h	4 Nov 2002 01:34:27 -0000
*************** struct diagnostic_context;
*** 45,55 ****
        TREE_INDIRECT_USING (in NAMESPACE_DECL).
        LOCAL_BINDING_P (in CPLUS_BINDING)
        ICS_USER_FLAG (in _CONV)
        CLEANUP_P (in TRY_BLOCK)
        AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR)
-       BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
        PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF)
        PARMLIST_ELLIPSIS_P (in PARMLIST)
     1: IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
--- 45,54 ----
*************** struct diagnostic_context;
*** 131,143 ****
       overriden version of a base class method, then it is assumed
       that, prior to adjustment, the this pointer points to an object
       of the base class.
  
       The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
!      index of the vcall offset for this entry.  If
!      BV_USE_VCALL_INDEX_P then the corresponding vtable entry should
!      use a virtual thunk, as opposed to an ordinary thunk.
  
       The BV_FN is the declaration for the virtual function itself.
  
     BINFO_VTABLE
       This is an expression with POINTER_TYPE that gives the value
--- 130,140 ----
       overriden version of a base class method, then it is assumed
       that, prior to adjustment, the this pointer points to an object
       of the base class.
  
       The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
!      index of the vcall offset for this entry.  
  
       The BV_FN is the declaration for the virtual function itself.
  
     BINFO_VTABLE
       This is an expression with POINTER_TYPE that gives the value
*************** enum cp_tree_index
*** 613,622 ****
--- 610,621 ----
      CPTI_CALL_UNEXPECTED,
      CPTI_ATEXIT,
      CPTI_DSO_HANDLE,
      CPTI_DCAST,
  
+     CPTI_DYNAMIC_CLASSES,
+ 
      CPTI_MAX
  };
  
  extern GTY(()) tree cp_global_trees[CPTI_MAX];
  
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 743,752 ****
--- 742,755 ----
  
  /* The type of the vtt parameter passed to subobject constructors and
     destructors.  */
  #define vtt_parm_type                   cp_global_trees[CPTI_VTT_PARM_TYPE]
  
+ /* A TREE_LIST of all of the dynamic classes in the program.  */
+ 
+ #define dynamic_classes                 cp_global_trees[CPTI_DYNAMIC_CLASSES]
+ 
  /* Global state.  */
  
  struct saved_scope GTY(())
  {
    tree old_bindings;
*************** struct lang_type_class GTY(())
*** 1151,1166 ****
       remove a flag.  */
    unsigned dummy : 4;
  
    tree primary_base;
    tree vfields;
    tree vbases;
    tree tags;
    tree as_base;
    tree pure_virtuals;
    tree friend_classes;
-   tree rtti;
    tree methods;
    tree decl_list;
    tree template_info;
    tree befriending_classes;
  };
--- 1154,1170 ----
       remove a flag.  */
    unsigned dummy : 4;
  
    tree primary_base;
    tree vfields;
+   tree vcall_indices;
+   tree vtables;
    tree vbases;
    tree tags;
    tree as_base;
    tree pure_virtuals;
    tree friend_classes;
    tree methods;
    tree decl_list;
    tree template_info;
    tree befriending_classes;
  };
*************** struct lang_type GTY(())
*** 1255,1267 ****
  #define TYPE_BEING_DEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->being_defined)
  /* Nonzero means that this type has been redefined.  In this case, if
     convenient, don't reprocess any methods that appear in its redefinition.  */
  #define TYPE_REDEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->redefined)
  
- /* The is the basetype that contains NODE's rtti.  */
- #define CLASSTYPE_RTTI(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->rtti)
- 
  /* Nonzero means that this _CLASSTYPE node overloads operator().  */
  #define TYPE_OVERLOADS_CALL_EXPR(NODE) \
    (LANG_TYPE_CLASS_CHECK (NODE)->has_call_overloaded)
  
  /* Nonzero means that this _CLASSTYPE node overloads operator[].  */
--- 1259,1268 ----
*************** struct lang_type GTY(())
*** 1429,1445 ****
  #define CLASSTYPE_PURE_VIRTUALS(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->pure_virtuals)
  
  /* Nonzero means that this aggr type has been `closed' by a semicolon.  */
  #define CLASSTYPE_GOT_SEMICOLON(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->got_semicolon)
  
- /* Nonzero means that the main virtual function table pointer needs to be
-    set because base constructors have placed the wrong value there.
-    If this is zero, it means that they placed the right value there,
-    and there is no need to change it.  */
- #define CLASSTYPE_NEEDS_VIRTUAL_REINIT(NODE) \
-   (LANG_TYPE_CLASS_CHECK (NODE)->needs_virtual_reinit)
- 
  /* Nonzero means that this type has an X() constructor.  */
  #define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE) \
    (LANG_TYPE_CLASS_CHECK (NODE)->h.has_default_ctor)
  
  /* Nonzero means that this type contains a mutable member */
--- 1430,1439 ----
*************** struct lang_type GTY(())
*** 1627,1636 ****
--- 1621,1645 ----
  #define BINFO_INDIRECT_PRIMARY_P(NODE) TREE_USED (NODE)
  
  /* Used by various search routines.  */
  #define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE)
  
+ /* A TREE_LIST of the vcall indices associated with the class NODE.
+    The TREE_PURPOSE of each node is a FUNCTION_DECL for a virtual
+    function.  The TREE_VALUE is the index into the virtual table where
+    the vcall offset for that function is stored, when NODE is a
+    virtual base.  If NODE has a direct or indirect primary base that
+    is also virtual, the entries for that class are not present on this
+    list.  */
+ #define CLASSTYPE_VCALL_INDICES(NODE) \
+   (LANG_TYPE_CLASS_CHECK (NODE)->vcall_indices)
+ 
+ /* The various vtables for the class NODE.  The primary vtable will be
+    first, followed by the construction vtables and VTT, if any.  */
+ #define CLASSTYPE_VTABLES(NODE) \
+   (LANG_TYPE_CLASS_CHECK (NODE)->vtables)
+ 
  /* Accessor macros for the vfield slots in structures.  */
  
  /* List of virtual table fields that this type contains (both the primary
     and secondaries). The TREE_VALUE is the class type where the vtable
     field was introduced. For a vtable field inherited from the primary
*************** struct lang_type GTY(())
*** 1662,1673 ****
  #define BV_VCALL_INDEX(NODE) (TREE_TYPE (NODE))
  
  /* The function to call.  */
  #define BV_FN(NODE) (TREE_VALUE (NODE))
  
- /* Nonzero if we should use a virtual thunk for this entry.  */
- #define BV_USE_VCALL_INDEX_P(NODE) (TREE_LANG_FLAG_0 (NODE))
  
  /* Nonzero for TREE_LIST node means that this list of things
     is a list of parameters, as opposed to a list of expressions.  */
  #define TREE_PARMLIST(NODE) (TREE_LANG_FLAG_2 (NODE))
  
--- 1671,1680 ----
*************** extern tree strip_top_quals             
*** 3544,3554 ****
  extern tree perform_implicit_conversion         PARAMS ((tree, tree));
  
  /* in class.c */
  extern tree build_base_path			PARAMS ((enum tree_code, tree, tree, int));
  extern tree convert_to_base                     (tree, tree, bool);
- extern tree build_vbase_path			PARAMS ((enum tree_code, tree, tree, tree, int));
  extern tree build_vtbl_ref			PARAMS ((tree, tree));
  extern tree build_vfn_ref			PARAMS ((tree, tree));
  extern tree get_vtable_decl                     PARAMS ((tree, int));
  extern void add_method				PARAMS ((tree, tree, int));
  extern int currently_open_class			PARAMS ((tree));
--- 3551,3560 ----
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.570
diff -c -5 -p -r1.570 decl2.c
*** cp/decl2.c	2 Nov 2002 02:17:39 -0000	1.570
--- cp/decl2.c	4 Nov 2002 01:34:27 -0000
*************** typedef struct priority_info_s {
*** 58,68 ****
    int destructions_p;
  } *priority_info;
  
  static void mark_vtable_entries PARAMS ((tree));
  static void grok_function_init PARAMS ((tree, tree));
! static int finish_vtable_vardecl PARAMS ((tree *, void *));
  static int is_namespace_ancestor PARAMS ((tree, tree));
  static void add_using_namespace PARAMS ((tree, tree, int));
  static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
  static tree build_anon_union_vars PARAMS ((tree, tree*, int, int));
  static int acceptable_java_type PARAMS ((tree));
--- 58,68 ----
    int destructions_p;
  } *priority_info;
  
  static void mark_vtable_entries PARAMS ((tree));
  static void grok_function_init PARAMS ((tree, tree));
! static int maybe_emit_vtables (tree);
  static int is_namespace_ancestor PARAMS ((tree, tree));
  static void add_using_namespace PARAMS ((tree, tree, int));
  static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
  static tree build_anon_union_vars PARAMS ((tree, tree*, int, int));
  static int acceptable_java_type PARAMS ((tree));
*************** key_method (type)
*** 1656,1671 ****
  
    for (method = TYPE_METHODS (type); method != NULL_TREE;
         method = TREE_CHAIN (method))
      if (DECL_VINDEX (method) != NULL_TREE
  	&& ! DECL_DECLARED_INLINE_P (method)
! 	&& (! DECL_PURE_VIRTUAL_P (method)
! #if 0
! 	    /* This would be nice, but we didn't think of it in time.  */
! 	    || DECL_DESTRUCTOR_P (method)
! #endif
! 	    ))
        return method;
  
    return NULL_TREE;
  }
  
--- 1656,1666 ----
  
    for (method = TYPE_METHODS (type); method != NULL_TREE;
         method = TREE_CHAIN (method))
      if (DECL_VINDEX (method) != NULL_TREE
  	&& ! DECL_DECLARED_INLINE_P (method)
! 	&& ! DECL_PURE_VIRTUAL_P (method))
        return method;
  
    return NULL_TREE;
  }
  
*************** output_vtable_inherit (vars)
*** 1803,1834 ****
      abort ();
  
    assemble_vtable_inherit (child_rtx, parent_rtx);
  }
  
  static int
! finish_vtable_vardecl (t, data)
!      tree *t;
!      void *data ATTRIBUTE_UNUSED;
  {
!   tree vars = *t;
!   tree ctype = DECL_CONTEXT (vars);
    import_export_class (ctype);
!   import_export_vtable (vars, ctype, 1);
  
!   if (! DECL_EXTERNAL (vars)
!       && DECL_NEEDED_P (vars)
!       && ! TREE_ASM_WRITTEN (vars))
!     {
!       if (TREE_TYPE (vars) == void_type_node)
!         /* It is a dummy vtable made by get_vtable_decl. Ignore it.  */
!         return 0;
!       
        /* Write it out.  */
!       mark_vtable_entries (vars);
!       if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
! 	store_init_value (vars, DECL_INITIAL (vars));
  
        if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
  	{
  	  /* Mark the VAR_DECL node representing the vtable itself as a
  	     "gratuitous" one, thereby forcing dwarfout.c to ignore it.
--- 1798,1853 ----
      abort ();
  
    assemble_vtable_inherit (child_rtx, parent_rtx);
  }
  
+ /* If necessary, write out the vtables for the dynamic class CTYPE.
+    Returns non-zero if any vtables were emitted.  */
+ 
  static int
! maybe_emit_vtables (tree ctype)
  {
!   tree vtbl;
!   tree primary_vtbl;
! 
!   /* If the vtables for this class have already been emitted there is
!      nothing more to do.  */
!   primary_vtbl = CLASSTYPE_VTABLES (ctype);
!   if (TREE_ASM_WRITTEN (primary_vtbl))
!     return 0;
!   /* Ignore dummy vtables made by get_vtable_decl.  */
!   if (TREE_TYPE (primary_vtbl) == void_type_node)
!     return 0;
! 
    import_export_class (ctype);
!   import_export_vtable (primary_vtbl, ctype, 1);
  
!   /* See if any of the vtables are needed.  */
!   for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
!     if (!DECL_EXTERNAL (vtbl) && DECL_NEEDED_P (vtbl))
!       break;
!   
!   if (!vtbl)
!     {
!       /* If the references to this class' vtables are optimized away,
! 	 still emit the appropriate debugging information.  See
! 	 dfs_debug_mark.  */
!       if (DECL_COMDAT (primary_vtbl) 
! 	  && CLASSTYPE_DEBUG_REQUESTED (ctype))
! 	note_debug_info_needed (ctype);
!       return 0;
!     }
! 
!   /* The ABI requires that we emit all of the vtables if we emit any
!      of them.  */
!   for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
!     {
        /* Write it out.  */
!       import_export_vtable (vtbl, ctype, 1);
!       mark_vtable_entries (vtbl);
!       if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
! 	store_init_value (vtbl, DECL_INITIAL (vtbl));
  
        if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
  	{
  	  /* Mark the VAR_DECL node representing the vtable itself as a
  	     "gratuitous" one, thereby forcing dwarfout.c to ignore it.
*************** finish_vtable_vardecl (t, data)
*** 1849,1889 ****
  	      We might be able to arrange to have the "vtable static member"
  	      attached to the member list for `S' before the debug info for
  	      `S' get written (which would solve the problem) but that would
  	      require more intrusive changes to the g++ front end.  */
  
! 	  DECL_IGNORED_P (vars) = 1;
  	}
  
        /* Always make vtables weak.  */
        if (flag_weak)
! 	comdat_linkage (vars);
  
!       rest_of_decl_compilation (vars, NULL, 1, 1);
  
        if (flag_vtable_gc)
! 	output_vtable_inherit (vars);
  
        /* Because we're only doing syntax-checking, we'll never end up
  	 actually marking the variable as written.  */
        if (flag_syntax_only)
! 	TREE_ASM_WRITTEN (vars) = 1;
! 
!       /* Since we're writing out the vtable here, also write the debug 
! 	 info.  */
!       note_debug_info_needed (ctype);
! 
!       return 1;
      }
  
!   /* If the references to this class' vtables were optimized away, still
!      emit the appropriate debugging information.  See dfs_debug_mark.  */
!   if (DECL_COMDAT (vars)
!       && CLASSTYPE_DEBUG_REQUESTED (ctype))
!     note_debug_info_needed (ctype);
  
!   return 0;
  }
  
  /* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
     inline function or template instantiation at end-of-file.  */
  
--- 1868,1900 ----
  	      We might be able to arrange to have the "vtable static member"
  	      attached to the member list for `S' before the debug info for
  	      `S' get written (which would solve the problem) but that would
  	      require more intrusive changes to the g++ front end.  */
  
! 	  DECL_IGNORED_P (vtbl) = 1;
  	}
  
        /* Always make vtables weak.  */
        if (flag_weak)
! 	comdat_linkage (vtbl);
  
!       rest_of_decl_compilation (vtbl, NULL, 1, 1);
  
        if (flag_vtable_gc)
! 	output_vtable_inherit (vtbl);
  
        /* Because we're only doing syntax-checking, we'll never end up
  	 actually marking the variable as written.  */
        if (flag_syntax_only)
! 	TREE_ASM_WRITTEN (vtbl) = 1;
      }
  
!   /* Since we're writing out the vtable here, also write the debug
!      info.  */
!   note_debug_info_needed (ctype);
  
!   return 1;
  }
  
  /* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
     inline function or template instantiation at end-of-file.  */
  
*************** finish_file ()
*** 2753,2775 ****
  
    emit_support_tinfos ();
    
    do 
      {
        reconsider = 0;
  
        /* If there are templates that we've put off instantiating, do
  	 them now.  */
        instantiate_pending_templates ();
  
        /* Write out virtual tables as required.  Note that writing out
  	 the virtual table for a template class may cause the
  	 instantiation of members of that class.  */
!       if (walk_vtables (vtable_decl_p,
! 			finish_vtable_vardecl,
! 			/*data=*/0))
! 	reconsider = 1;
        
        /* Write out needed type info variables. Writing out one variable
           might cause others to be needed.  */
        if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
  	reconsider = 1;
--- 2764,2787 ----
  
    emit_support_tinfos ();
    
    do 
      {
+       tree t;
+ 
        reconsider = 0;
  
        /* If there are templates that we've put off instantiating, do
  	 them now.  */
        instantiate_pending_templates ();
  
        /* Write out virtual tables as required.  Note that writing out
  	 the virtual table for a template class may cause the
  	 instantiation of members of that class.  */
!       for (t = dynamic_classes; t; t = TREE_CHAIN (t))
! 	if (maybe_emit_vtables (TREE_VALUE (t)))
! 	  reconsider = 1;
        
        /* Write out needed type info variables. Writing out one variable
           might cause others to be needed.  */
        if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
  	reconsider = 1;
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.239
diff -c -5 -p -r1.239 search.c
*** cp/search.c	30 Sep 2002 16:52:14 -0000	1.239
--- cp/search.c	4 Nov 2002 01:34:28 -0000
*************** look_for_overrides (type, fndecl)
*** 1953,1965 ****
          found += look_for_overrides_r (basetype, fndecl);
      }
    return found;
  }
  
! /* Look in TYPE for virtual functions with the same signature as FNDECL.
!    This differs from get_matching_virtual in that it will only return
!    a function from TYPE.  */
  
  tree
  look_for_overrides_here (type, fndecl)
       tree type, fndecl;
  {
--- 1953,1964 ----
          found += look_for_overrides_r (basetype, fndecl);
      }
    return found;
  }
  
! /* Look in TYPE for virtual functions with the same signature as
!    FNDECL.  */
  
  tree
  look_for_overrides_here (type, fndecl)
       tree type, fndecl;
  {
Index: testsuite/g++.dg/abi/thunk1.C
===================================================================
RCS file: testsuite/g++.dg/abi/thunk1.C
diff -N testsuite/g++.dg/abi/thunk1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/thunk1.C	4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,22 ----
+ // { dg-do compile { target i?86-*-* } }
+ 
+ struct A {
+   virtual void f ();
+ };
+ 
+ struct B : public virtual A {
+   virtual void f ();
+ };
+ 
+ struct C {
+   virtual void g ();
+ };
+ 
+ struct D : public C, public B {
+   virtual void f ();
+ };
+ 
+ void D::f () {}
+ 
+ // { dg-final { scan-assembler _ZThn4_N1D1fEv } }
+ // { dg-final { scan-assembler _ZTv0_n12_N1D1fEv } }
Index: testsuite/g++.dg/abi/thunk2.C
===================================================================
RCS file: testsuite/g++.dg/abi/thunk2.C
diff -N testsuite/g++.dg/abi/thunk2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/thunk2.C	4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,26 ----
+ // { dg-do compile { target i?86-*-* } }
+ // { dg-options -w }
+ 
+ struct A {
+   virtual void f2 ();
+   virtual void f3 ();
+ };
+ 
+ struct B : virtual public A {
+   virtual void f3 ();
+ };
+ 
+ struct C : public A, public B {
+   virtual void f4 ();
+ };
+ 
+ struct D : virtual public B, virtual public C, virtual public A 
+ {
+   virtual void f5 ();
+   virtual void f6 ();
+   virtual void f3 ();
+ };
+ 
+ void D::f3 () {}
+ 
+ // { dg-final { scan-assembler _ZTvn4_n20_N1D2f3Ev } }
Index: testsuite/g++.dg/abi/vtt1.C
===================================================================
RCS file: testsuite/g++.dg/abi/vtt1.C
diff -N testsuite/g++.dg/abi/vtt1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/vtt1.C	4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,11 ----
+ // { dg-do compile }
+ 
+ struct A {
+ };
+ 
+ struct B : virtual public A {
+ };
+ 
+ B b;
+ 
+ // { dg-final { scan-assembler _ZTT1B } }


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