]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
authorMark Mitchell <mark@codesourcery.com>
Fri, 23 Jun 2000 01:14:40 +0000 (01:14 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 23 Jun 2000 01:14:40 +0000 (01:14 +0000)
* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
(BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
(lang_decl_flags): Add generate_with_vtable_p.  Make vcall_offset
a tree, not an int.
(THUNK_GENERATE_WITH_VTABLE_P): New macro.
(make_thunk): Change prototype.
(emit_thunk): Rename to use_thunk.
(mangle_thunk): Change prototype.
* class.c (get_derived_offset): Simplify.
(copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
BV_GENERATE_THUNK_WITH_VTABLE_P.
(build_primary_vtable): Simplify.
(add_virtual_function): Use BV_FN, rather than TREE_VALUE.
(dfs_find_base): Remove.
(update_vtable_entry_for_fn): Correct bug in finding the base
where a virtual function was first declared.  Figure out whether
or not to emit a vcall-thunk with the vtables in which it appears.
Correct logic for deciding whether to use an ordinary thunk, or a
vcall thunk.
(finish_struct_1): Remove unnecssary code.
(build_vtbl_initializer): Use ssize_int for the running counter of
negative indices.
(build_vtbl_initializer): Only use vcall thunks where necessary.
Mark thunks as needing to be emitted with their vtables, or not.
(build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
indices.  Use size_binop.
(dfs_build_vcall_offset_vtbl_entries): Don't rely on
BINFO_PRIMARY_MARKED_P here.  Use BV_FN consistently.  Use
size_binop.
(build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
(build_vtable_entry): Mark thunks as needing to be emitted with
their vtables, or not.
* decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
* decl2.c (mark_vtable_entries): Use use_thunk instead of
emit_thunk.
* dump.c (dequeue_and_dump): Remove dead code.  Dump new thunk
information.
* error.c (dump_expr): Use BV_FN.
* mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
not an int.
* method.c (make_thunk): Likewise.
(emit_thunk): Rename to use_thunk.  Allow callers to decide
whether or not to actually emit the thunk.  Adjust for changes in
representation of vcall offsets.
* search.c (dfs_get_pure_virtuals): Use BV_FN.
* semantics.c (emit_associated_thunks): New function.
(expand_body): Use it.
* ir.texi: Adjust decriptions of thunks.

From-SVN: r34656

13 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/dump.c
gcc/cp/error.c
gcc/cp/ir.texi
gcc/cp/mangle.c
gcc/cp/method.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/testsuite/g++.old-deja/g++.other/virtual8.C [new file with mode: 0644]

index 1f655b34bb2f1827ed1ae7537519a82f00f4b391..0cebeac3dc9b5b15ced851a3caa69c3ce3c112c6 100644 (file)
@@ -1,3 +1,54 @@
+2000-06-22  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
+       (BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
+       (lang_decl_flags): Add generate_with_vtable_p.  Make vcall_offset
+       a tree, not an int.
+       (THUNK_GENERATE_WITH_VTABLE_P): New macro.
+       (make_thunk): Change prototype.
+       (emit_thunk): Rename to use_thunk.
+       (mangle_thunk): Change prototype.
+       * class.c (get_derived_offset): Simplify.
+       (copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
+       BV_GENERATE_THUNK_WITH_VTABLE_P.
+       (build_primary_vtable): Simplify.
+       (add_virtual_function): Use BV_FN, rather than TREE_VALUE.
+       (dfs_find_base): Remove.
+       (update_vtable_entry_for_fn): Correct bug in finding the base
+       where a virtual function was first declared.  Figure out whether
+       or not to emit a vcall-thunk with the vtables in which it appears.
+       Correct logic for deciding whether to use an ordinary thunk, or a
+       vcall thunk.
+       (finish_struct_1): Remove unnecssary code.
+       (build_vtbl_initializer): Use ssize_int for the running counter of
+       negative indices.
+       (build_vtbl_initializer): Only use vcall thunks where necessary.
+       Mark thunks as needing to be emitted with their vtables, or not.
+       (build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
+       indices.  Use size_binop.
+       (dfs_build_vcall_offset_vtbl_entries): Don't rely on
+       BINFO_PRIMARY_MARKED_P here.  Use BV_FN consistently.  Use
+       size_binop.
+       (build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
+       (build_vtable_entry): Mark thunks as needing to be emitted with
+       their vtables, or not.
+       * decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
+       * decl2.c (mark_vtable_entries): Use use_thunk instead of
+       emit_thunk.
+       * dump.c (dequeue_and_dump): Remove dead code.  Dump new thunk
+       information.
+       * error.c (dump_expr): Use BV_FN.
+       * mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
+       not an int.
+       * method.c (make_thunk): Likewise.
+       (emit_thunk): Rename to use_thunk.  Allow callers to decide
+       whether or not to actually emit the thunk.  Adjust for changes in
+       representation of vcall offsets.
+       * search.c (dfs_get_pure_virtuals): Use BV_FN.
+       * semantics.c (emit_associated_thunks): New function.
+       (expand_body): Use it.
+       * ir.texi: Adjust decriptions of thunks.
+       
 2000-06-22  Jason Merrill  <jason@redhat.com>
 
        * pt.c (tsubst_decl, case FUNCTION_DECL): Clear DECL_SAVED_TREE.
index 387451c54390a5418b26c2d7cc1cd6adb6a9633d..71a5aef57cf07c9a8e89cec8f5c32e418fca9ee1 100644 (file)
@@ -96,7 +96,7 @@ varray_type local_classes;
 static tree get_vfield_name PARAMS ((tree));
 static void finish_struct_anon PARAMS ((tree));
 static tree build_vbase_pointer PARAMS ((tree, tree));
-static tree build_vtable_entry PARAMS ((tree, tree, tree));
+static tree build_vtable_entry PARAMS ((tree, tree, tree, int));
 static tree get_vtable_name PARAMS ((tree));
 static tree get_derived_offset PARAMS ((tree, tree));
 static tree get_basefndecls PARAMS ((tree, tree));
@@ -162,7 +162,6 @@ static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *))
 static void layout_vtable_decl PARAMS ((tree, int));
 static tree dfs_find_final_overrider PARAMS ((tree, void *));
 static tree find_final_overrider PARAMS ((tree, tree, tree));
-static tree dfs_find_base PARAMS ((tree, void *));
 static int make_new_vtable PARAMS ((tree, tree));
 static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
 extern void dump_class_hierarchy PARAMS ((tree));
@@ -685,16 +684,9 @@ get_derived_offset (binfo, type)
 {
   tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   tree offset2;
-  int i;
 
-  while (BINFO_BASETYPES (binfo)
-        && (i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      if (BINFO_TYPE (binfo) == type)
-       break;
-      binfo = TREE_VEC_ELT (binfos, i);
-    }
+  while (!same_type_p (BINFO_TYPE (binfo), type))
+    binfo = BINFO_PRIMARY_BINFO (binfo);
 
   offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   return size_binop (MINUS_EXPR, offset1, offset2);
@@ -778,7 +770,11 @@ copy_virtuals (binfo)
 
   copies = copy_list (BINFO_VIRTUALS (binfo));
   for (t = copies; t; t = TREE_CHAIN (t))
-    BV_VCALL_INDEX (t) = NULL_TREE;
+    {
+      BV_VCALL_INDEX (t) = NULL_TREE;
+      BV_USE_VCALL_INDEX_P (t) = 0;
+      BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+    }
 
   return copies;
 }
@@ -793,7 +789,8 @@ static int
 build_primary_vtable (binfo, type)
      tree binfo, type;
 {
-  tree virtuals, decl;
+  tree decl;
+  tree virtuals;
 
   decl = get_vtable_decl (type, /*complete=*/0);
   
@@ -825,9 +822,7 @@ build_primary_vtable (binfo, type)
      on our first approximation.  */
   TYPE_BINFO_VTABLE (type) = decl;
   TYPE_BINFO_VIRTUALS (type) = virtuals;
-
-  binfo = TYPE_BINFO (type);
-  SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
+  SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
   return 1;
 }
 
@@ -1126,7 +1121,8 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
     /* We've already dealt with this function.  */
     return;
 
-  new_virtual = build_tree_list (NULL_TREE, fndecl);
+  new_virtual = make_node (TREE_LIST);
+  BV_FN (new_virtual) = fndecl;
   BV_DELTA (new_virtual) = integer_zero_node;
 
   if (DECL_VINDEX (fndecl) == error_mark_node)
@@ -2590,18 +2586,6 @@ find_final_overrider (t, binfo, fn)
   return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
 }
 
-/* Called via dfs_walk.  Returns BINFO if BINFO has the same type as
-   DATA (which is really an _TYPE node).  */
-
-static tree
-dfs_find_base (binfo, data)
-     tree binfo;
-     void *data;
-{
-  return (same_type_p (BINFO_TYPE (binfo), (tree) data)
-         ? binfo : NULL_TREE);
-}
-
 /* Update a entry in the vtable for BINFO, which is in the hierarchy
    dominated by T.  FN has been overridden in BINFO; VIRTUALS points
    to the corresponding position in the BINFO_VIRTUALS list.  */
@@ -2615,26 +2599,36 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
 {
   tree b;
   tree overrider;
-  tree vindex;
   tree delta;
-  HOST_WIDE_INT vindex_val;
-  HOST_WIDE_INT i;
+  tree virtual_base;
+  int generate_thunk_with_vtable_p;
 
   /* Find the function which originally caused this vtable
      entry to be present.  */
-  vindex = DECL_VINDEX (fn);
-  b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
-  fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
-  i = first_vfun_index (BINFO_TYPE (b));
-  vindex_val = tree_low_cst (vindex, 0);
-  while (i < vindex_val)
+  b = binfo;
+  while (1)
     {
-      fn = TREE_CHAIN (fn);
-      ++i;
+      tree primary_base;
+      tree f;
+
+      primary_base = BINFO_PRIMARY_BINFO (b);
+      if (!primary_base)
+       break;
+
+      for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
+          f;
+          f = TREE_CHAIN (f))
+       if (same_signature_p (BV_FN (f), fn))
+         break;
+
+      if (!f)
+       break;
+
+      fn = BV_FN (f);
+      b = primary_base;
     }
-  fn = BV_FN (fn);
 
-  /* Handle the case of a virtual function defined in BINFO itself.  */
+  /* Find the final overrider.  */
   overrider = find_final_overrider (t, b, fn);
   if (overrider == error_mark_node)
     return;
@@ -2646,27 +2640,53 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
                      get_derived_offset (binfo,
                                          DECL_VIRTUAL_CONTEXT (fn)),
                      BINFO_OFFSET (binfo));
+
+  /* Assume that we will produce a thunk that convert all the way to
+     the final overrider, and not to an intermediate virtual base.  */
+  virtual_base  = NULL_TREE;
+
+  /* Assume that we will always generate thunks with the vtables that
+     reference them.  */
+  generate_thunk_with_vtable_p = 1;
+
+  /* Under the new ABI, we will convert to an intermediate virtual
+     base first, and then use the vcall offset located there to finish
+     the conversion.  */
   if (flag_new_abi)
     {
-      /* Under the new ABI, we only need to adjust as far as the
-        nearest virtual base.  Then we use the vcall offset in the
-        virtual bases vtable.  */
-      for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
+      while (b)
        {
-         if (TREE_VIA_VIRTUAL (b))
-           break;
+         /* If we find BINFO, then the final overrider is in a class
+            derived from BINFO, so the thunks can be generated with
+            the final overrider.  */
+         if (same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+           generate_thunk_with_vtable_p = 0;
+
+         /* If we find the final overrider, then we can stop
+            walking.  */
          if (same_type_p (BINFO_TYPE (b), 
                           BINFO_TYPE (TREE_VALUE (overrider))))
            break;
+
+         /* If we find a virtual base, and we haven't yet found the
+            overrider, then there is a virtual base between the
+            declaring base and the final overrider.  */
+         if (!virtual_base && TREE_VIA_VIRTUAL (b))
+           {
+             generate_thunk_with_vtable_p = 1;
+             virtual_base = b;
+           }
+
+         b = BINFO_INHERITANCE_CHAIN (b);
        }
     }
   else
-    b = NULL_TREE;
+    virtual_base = NULL_TREE;
 
-  if (b && TREE_VIA_VIRTUAL (b))
+  if (virtual_base)
     /* The `this' pointer needs to be adjusted to the nearest virtual
        base.  */
-    delta = size_diffop (BINFO_OFFSET (b), delta);
+    delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
   else
     /* The `this' pointer needs to be adjusted from pointing to
        BINFO to pointing at the base where the final overrider
@@ -2678,6 +2698,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
                       TREE_PURPOSE (overrider),
                       delta,
                       virtuals);
+
+  if (virtual_base)
+    BV_USE_VCALL_INDEX_P (*virtuals) = 1;
+  if (generate_thunk_with_vtable_p)
+    BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1;
 }
 
 /* Called from modify_all_vtables via dfs_walk.  */
@@ -5074,17 +5099,9 @@ finish_struct_1 (t)
     {
       tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
 
-      /* This class contributes nothing new to the virtual function
-        table.  However, it may have declared functions which
-        went into the virtual function table "inherited" from the
-        base class.  If so, we grab a copy of those updated functions,
-        and pretend they are ours.  */
-
-      /* See if we should steal the virtual info from base class.  */
-      if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
-       TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
-      if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
-       TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
+      /* 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;
     }
@@ -6992,7 +7009,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
   vod.last_init = &vod.inits;
   vod.primary_p = (binfo == TYPE_BINFO (t));
   /* The first vbase or vcall offset is at index -3 in the vtable.  */
-  vod.index = build_int_2 (-3, -1);
+  vod.index = ssize_int (-3);
 
   /* Add entries to the vtable for RTTI.  */
   build_rtti_vtbl_entries (binfo, rtti_binfo, &vod);
@@ -7023,7 +7040,15 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
       /* Pull the offset for `this', and the function to call, out of
         the list.  */
       delta = BV_DELTA (v);
-      vcall_index = BV_VCALL_INDEX (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;
+
       fn = BV_FN (v);
       my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
       my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
@@ -7039,7 +7064,8 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
       /* The address of a function can't change.  */
       TREE_CONSTANT (pfn) = 1;
       /* Enter it in the vtable.  */
-      init = build_vtable_entry (delta, vcall_index, pfn);
+      init = build_vtable_entry (delta, vcall_index, pfn,
+                                BV_GENERATE_THUNK_WITH_VTABLE_P (v));
       /* And add it to the chain of initializers.  */
       vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
     }
@@ -7125,7 +7151,7 @@ build_vbase_offset_vtbl_entries (binfo, vod)
 
       /* Figure out where we can find this vbase offset.  */
       delta = size_binop (MULT_EXPR, 
-                         convert (ssizetype, vod->index),
+                         vod->index,
                          convert (ssizetype,
                                   TYPE_SIZE_UNIT (vtable_entry_type)));
       if (vod->primary_p)
@@ -7146,8 +7172,7 @@ build_vbase_offset_vtbl_entries (binfo, vod)
        }
 
       /* The next vbase will come at a more negative offset.  */
-      vod->index = fold (build (MINUS_EXPR, integer_type_node,
-                               vod->index, integer_one_node));
+      vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1));
 
       /* The initializer is the delta from BINFO to this virtual base.
         The vbase offsets go in reverse inheritance-graph order, and
@@ -7174,8 +7199,11 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
   tree derived_virtuals;
   tree base_virtuals;
   tree binfo_inits;
+  /* If BINFO is a primary base, this is the least derived class of
+     BINFO that is not a primary base.  */
   tree non_primary_binfo;
-  tree b;
+  /* The primary base of BINFO.  */
+  tree primary_binfo;
   int i;
 
   vod = (vcall_offset_data *) data;
@@ -7185,16 +7213,21 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
      hierarchy until we find the class of which we are a primary base:
      it is the BINFO_VIRTUALS there that we need to consider.  */
   non_primary_binfo = binfo;
-  while (BINFO_PRIMARY_MARKED_P (non_primary_binfo))
-    non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+  while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+    {
+      tree b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+      if (BINFO_PRIMARY_BINFO (b) != non_primary_binfo)
+       break;
+      non_primary_binfo = b;
+    }
 
   /* Skip virtuals that we have already handled in a primary base
      class.  */
   base_virtuals = BINFO_VIRTUALS (binfo);
   derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
-  b = BINFO_PRIMARY_BINFO (binfo);
-  if (b)
-    for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
+  primary_binfo = BINFO_PRIMARY_BINFO (binfo);
+  if (primary_binfo)
+    for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (primary_binfo)); ++i)
       {
        base_virtuals = TREE_CHAIN (base_virtuals);
        derived_virtuals = TREE_CHAIN (derived_virtuals);
@@ -7206,7 +7239,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
         base_virtuals = TREE_CHAIN (base_virtuals))
     {
       /* Figure out what function we're looking at.  */
-      tree fn = TREE_VALUE (derived_virtuals);
+      tree fn = BV_FN (derived_virtuals);
       tree base;
       tree base_binfo;
       size_t i;
@@ -7220,7 +7253,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
          tree derived_entry;
 
          derived_entry = VARRAY_TREE (vod->fns, i);
-         if (same_signature_p (TREE_VALUE (derived_entry), fn))
+         if (same_signature_p (BV_FN (derived_entry), fn))
            {
              BV_VCALL_INDEX (derived_virtuals) 
                = BV_VCALL_INDEX (derived_entry);
@@ -7259,8 +7292,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
 
       /* The next vcall offset will be found at a more negative
         offset.  */
-      vod->index = fold (build (MINUS_EXPR, integer_type_node,
-                               vod->index, integer_one_node));
+      vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1));
 
       /* Keep track of this function.  */
       VARRAY_PUSH_TREE (vod->fns, derived_virtuals);
@@ -7383,7 +7415,8 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
         vtable.  */
       init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
       TREE_CONSTANT (init) = 1;
-      init = build_vtable_entry (offset, integer_zero_node, init);
+      init = build_vtable_entry (offset, NULL_TREE, init, 
+                                /*generate_with_vtable_p=*/0);
     }
   *vod->last_init = build_tree_list (NULL_TREE, init);
   vod->last_init = &TREE_CHAIN (*vod->last_init);
@@ -7410,28 +7443,23 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
    ABI.)  */
 
 static tree
-build_vtable_entry (delta, vcall_index, entry)
+build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p)
      tree delta;
      tree vcall_index;
      tree entry;
+     int generate_with_vtable_p;
 {
-  if (!vcall_index)
-    vcall_index = integer_zero_node;
-
   if (flag_vtable_thunks)
     {
-      HOST_WIDE_INT idelta;
-      HOST_WIDE_INT ivindex;
       tree fn;
 
-      idelta = tree_low_cst (delta, 0);
-      ivindex = tree_low_cst (vcall_index, 0);
       fn = TREE_OPERAND (entry, 0);
-      if ((idelta || ivindex) 
+      if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
          && fn != abort_fndecl
          && !DECL_TINFO_FN_P (fn))
        {
-         entry = make_thunk (entry, idelta, ivindex);
+         entry = make_thunk (entry, delta, vcall_index,
+                             generate_with_vtable_p);
          entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
          TREE_READONLY (entry) = 1;
          TREE_CONSTANT (entry) = 1;
@@ -7449,7 +7477,7 @@ build_vtable_entry (delta, vcall_index, entry)
       tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
 
       /* We don't use vcall offsets when not using vtable thunks.  */
-      my_friendly_assert (integer_zerop (vcall_index), 20000125);
+      my_friendly_assert (vcall_index == NULL_TREE, 20000125);
 
       /* DELTA used to be constructed by `size_int' and/or size_binop,
         which caused overflow problems when it was negative.  That should
index b93a29ec2e4e35ec3b218713d4687185b36b5a8d..89e637eaa9a51eb8ea2215398a0ad886e1b67760 100644 (file)
@@ -45,6 +45,7 @@ Boston, MA 02111-1307, USA.  */
       SCOPE_BEGIN_P (in SCOPE_STMT)
       CTOR_BEGIN_P (in CTOR_STMT)
       DECL_PRETTY_FUNCTION_P (in VAR_DECL)
+      BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
    1: IDENTIFIER_VIRTUAL_P.
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -57,6 +58,7 @@ Boston, MA 02111-1307, USA.  */
       ICS_ELLIPSIS_FLAG (in _CONV)
       STMT_IS_FULL_EXPR_P (in _STMT)
       BINFO_ACCESS (in BINFO)
+      BV_GENERATE_THUNK_WITH_VTABLE_P (in TREE_LIST)
    2: IDENTIFIER_OPNAME_P.
       TYPE_POLYMORHPIC_P (in _TYPE)
       ICS_THIS_FLAG (in _CONV)
@@ -128,7 +130,9 @@ Boston, MA 02111-1307, USA.  */
      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.
+     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.
      When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
@@ -1841,6 +1845,15 @@ struct lang_type
 /* 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 if we should generate this thunk when the vtable that
+   references it is emitted, rather than with the final overrider.  */
+#define BV_GENERATE_THUNK_WITH_VTABLE_P(NODE) \
+  (TREE_LANG_FLAG_1 (NODE))
+
 /* The most derived class.  */
 
 \f
@@ -1901,7 +1914,8 @@ struct lang_decl_flags
   unsigned tinfo_fn_p : 1;
   unsigned assignment_operator_p : 1;
   unsigned anticipated_p : 1;
-  unsigned dummy : 2;
+  unsigned generate_with_vtable_p : 1;
+  unsigned dummy : 1;
 
   tree context;
 
@@ -1924,7 +1938,7 @@ struct lang_decl_flags
 
     /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
        THUNK_VCALL_OFFSET.  */
-    HOST_WIDE_INT vcall_offset;
+    tree vcall_offset;
   } u2;
 };
 
@@ -3141,6 +3155,10 @@ extern int flag_new_for_scope;
 #define THUNK_VCALL_OFFSET(DECL) \
   (DECL_LANG_SPECIFIC (DECL)->decl_flags.u2.vcall_offset)
 
+/* Nonzero if this thunk should be generated with the vtable that
+   references it.  */
+#define THUNK_GENERATE_WITH_VTABLE_P(DECL) \
+  (DECL_LANG_SPECIFIC (DECL)->decl_flags.generate_with_vtable_p)
 
 /* These macros provide convenient access to the various _STMT nodes
    created when parsing template declarations.  */
@@ -4244,8 +4262,8 @@ extern tree build_overload_with_type              PARAMS ((tree, tree));
 extern tree build_destructor_name              PARAMS ((tree));
 extern tree build_opfncall                     PARAMS ((enum tree_code, int, tree, tree, tree));
 extern tree hack_identifier                    PARAMS ((tree, tree));
-extern tree make_thunk                         PARAMS ((tree, int, int));
-extern void emit_thunk                         PARAMS ((tree));
+extern tree make_thunk                         PARAMS ((tree, tree, tree, int));
+extern void use_thunk                          PARAMS ((tree, int));
 extern void synthesize_method                  PARAMS ((tree));
 extern tree get_id_2                           PARAMS ((const char *, tree));
 extern tree implicitly_declare_fn               PARAMS ((special_function_kind, tree, int));
@@ -4718,7 +4736,7 @@ extern tree mangle_typeinfo_string_for_type     PARAMS ((tree));
 extern tree mangle_vtbl_for_type                PARAMS ((tree));
 extern tree mangle_vtt_for_type                 PARAMS ((tree));
 extern tree mangle_ctor_vtbl_for_type           PARAMS ((tree, tree));
-extern tree mangle_thunk                        PARAMS ((tree, int, int)); 
+extern tree mangle_thunk                        PARAMS ((tree, tree, tree)); 
 extern tree mangle_conv_op_name_for_type        PARAMS ((tree));
 extern tree mangle_guard_variable               PARAMS ((tree));
 
index 5451306cc085ae0ee929d244280071095a1b7788..10d9d08d51d38be4bba22dbcf057a494ff12ce32 100644 (file)
@@ -15063,6 +15063,8 @@ lang_mark_tree (t)
              && !DECL_GLOBAL_DTOR_P (t)
              && !DECL_THUNK_P (t))
            ggc_mark_tree (ld->decl_flags.u2.access);
+         else if (DECL_THUNK_P (t))
+           ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
          ggc_mark_tree (ld->decl_flags.context);
          if (TREE_CODE (t) != NAMESPACE_DECL)
            ggc_mark_tree (ld->decl_flags.u.template_info);
index b034d7858ae1a076e1c07180d2826f7bd12c5aeb..8fe160ea889aabac45513e35e74dec88beb6c2c5 100644 (file)
@@ -2425,11 +2425,12 @@ mark_vtable_entries (decl)
 
       fn = TREE_OPERAND (fnaddr, 0);
       TREE_ADDRESSABLE (fn) = 1;
-      if (DECL_THUNK_P (fn) && DECL_EXTERNAL (fn))
-       {
-         DECL_EXTERNAL (fn) = 0;
-         emit_thunk (fn);
-       }
+      /* When we don't have vcall offsets, we output thunks whenever
+        we output the vtables that contain them.  With vcall offsets,
+        we know all the thunks we'll need when we emit a virtual
+        function, so we emit the thunks there instead.  */
+      if (DECL_THUNK_P (fn)) 
+       use_thunk (fn, THUNK_GENERATE_WITH_VTABLE_P (fn));
       mark_used (fn);
     }
 }
index ca3baa0a3c220aae335e47802056c906ca6d663c..9b711062070639eb66b2f5298c9269719b44b5bc 100644 (file)
@@ -566,7 +566,7 @@ dequeue_and_dump (di)
        dump_string(di, "extern");
       else
        dump_string (di, "static");
-      if (TREE_CODE (t) == FUNCTION_DECL)
+      if (!DECL_THUNK_P (t))
        {
          if (DECL_FUNCTION_MEMBER_P (t))
            dump_string (di, "member");
@@ -578,13 +578,6 @@ dequeue_and_dump (di)
            dump_string (di, "operator");
          if (DECL_CONV_FN_P (t))
            dump_string (di, "conversion");
-         if (DECL_THUNK_P (t))
-           {
-             dump_string (di, "thunk");
-             dump_int (di, "dlta", THUNK_DELTA (t));
-             dump_int (di, "vcll", THUNK_VCALL_OFFSET (t));
-             dump_child ("fn", DECL_INITIAL (t));
-           }
          if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t))
            {
              if (DECL_GLOBAL_CTOR_P (t))
@@ -600,8 +593,10 @@ dequeue_and_dump (di)
        }
       else
        {
+         dump_string (di, "thunk");
          dump_int (di, "dlta", THUNK_DELTA (t));
-         dump_child ("init", DECL_INITIAL (t));
+         dump_child ("vcll", THUNK_VCALL_OFFSET (t));
+         dump_child ("fn", DECL_INITIAL (t));
        }
       break;
 
index 8d2ad61225dacda7069b6a3bd97924b0488ee78e..37c8dd625234a4992020d6eba866a3c7434a21d5 100644 (file)
@@ -1867,7 +1867,7 @@ dump_expr (t, flags)
                }
              if (virtuals)
                {
-                 dump_expr (TREE_VALUE (virtuals),
+                 dump_expr (BV_FN (virtuals),
                             flags | TS_EXPR_PARENS);
                  break;
                }
index 429c155411266138f4d063b2fd3f640496bc8c5c..343dfc86408d0eadee081857a3698a68e3f31230 100644 (file)
@@ -1040,8 +1040,8 @@ returning to the thunk.  The first parameter to the thunk is always the
 value.  (The @code{THUNK_DELTA} is an @code{int}, not an
 @code{INTEGER_CST}.)  
 
-Then, if @code{THUNK_VCALL_OFFSET} (also an @code{int}) is non-zero the
-adjusted @code{this} pointer must be adjusted again.  The complete
+Then, if @code{THUNK_VCALL_OFFSET} (an @code{INTEGER_CST}) is non-zero
+the adjusted @code{this} pointer must be adjusted again.  The complete
 calculation is given by the following pseudo-code:
 
 @example
index d6c7181f55b2d135a99347dc4a634f58c6702652..a1d1d552dd08b69b71fbe330db7c8b01a793a8ee 100644 (file)
@@ -2076,7 +2076,7 @@ mangle_ctor_vtbl_for_type (type, binfo)
 
 /* Return an identifier for the mangled name of a thunk to FN_DECL.
    OFFSET is the initial adjustment to this used to find the vptr.  If
-   VCALL_OFFSET is non-zero, this is a virtual thunk, and it is the
+   VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
    vtbl offset in bytes.  
 
     <special-name> ::= Th <offset number> _ <base encoding>
@@ -2087,8 +2087,8 @@ mangle_ctor_vtbl_for_type (type, binfo)
 tree
 mangle_thunk (fn_decl, offset, vcall_offset)
      tree fn_decl;
-     int offset;
-     int vcall_offset;
+     tree offset;
+     tree vcall_offset;
 {
   const char *result;
   
@@ -2104,14 +2104,14 @@ mangle_thunk (fn_decl, offset, vcall_offset)
     write_char ('h');
 
   /* For either flavor, write the offset to this.  */
-  write_signed_number (offset);
+  write_integer_cst (offset);
   write_char ('_');
 
   /* For a virtual thunk, add the vcall offset.  */
-  if (vcall_offset != 0)
+  if (vcall_offset)
     {
       /* Virtual thunk.  Write the vcall offset and base type name.  */
-      write_signed_number (vcall_offset);
+      write_integer_cst (vcall_offset);
       write_char ('_');
     }
 
index 04685d45fe3e92e11c623be64a188addc9eafec0..33ad29a8211795e04b510bcebb4ee2cc0d223bc4 100644 (file)
@@ -2063,15 +2063,29 @@ hack_identifier (value, name)
    DELTA is the offset to this and VCALL_INDEX is zero.  */
 
 tree
-make_thunk (function, delta, vcall_index)
+make_thunk (function, delta, vcall_index, generate_with_vtable_p)
      tree function;
-     int delta;
-     int vcall_index;
+     tree delta;
+     tree vcall_index;
+     int generate_with_vtable_p;
 {
   tree thunk_id;
   tree thunk;
   tree func_decl;
-  int vcall_offset = vcall_index * int_size_in_bytes (vtable_entry_type);
+  tree vcall_offset;
+  HOST_WIDE_INT d;
+
+  /* Scale the VCALL_INDEX to be in terms of bytes.  */
+  if (vcall_index)
+    vcall_offset 
+      = size_binop (MULT_EXPR,
+                   vcall_index,
+                   convert (ssizetype,
+                            TYPE_SIZE_UNIT (vtable_entry_type)));
+  else
+    vcall_offset = NULL_TREE;
+
+  d = tree_low_cst (delta, 0);
 
   if (TREE_CODE (function) != ADDR_EXPR)
     abort ();
@@ -2080,22 +2094,23 @@ make_thunk (function, delta, vcall_index)
     abort ();
 
   if (flag_new_abi) 
-    thunk_id = mangle_thunk (TREE_OPERAND (function, 0),  delta, vcall_offset);
+    thunk_id = mangle_thunk (TREE_OPERAND (function, 0), 
+                            delta, vcall_offset);
   else
     {
       OB_INIT ();
       OB_PUTS ("__thunk_");
-      if (delta > 0)
+      if (d > 0)
        {
          OB_PUTC ('n');
-         icat (delta);
+         icat (d);
        }
       else
-       icat (-delta);
+       icat (-d);
       OB_PUTC ('_');
       if (vcall_index)
        {
-         icat (vcall_index);
+         icat (tree_low_cst (vcall_index, 0));
          OB_PUTC ('_');
        }
       OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
@@ -2121,8 +2136,9 @@ make_thunk (function, delta, vcall_index)
       comdat_linkage (thunk);
       SET_DECL_THUNK_P (thunk);
       DECL_INITIAL (thunk) = function;
-      THUNK_DELTA (thunk) = delta;
+      THUNK_DELTA (thunk) = d;
       THUNK_VCALL_OFFSET (thunk) = vcall_offset;
+      THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p;
       /* The thunk itself is not a constructor or destructor, even if
        the thing it is thunking to is.  */
       DECL_INTERFACE_KNOWN (thunk) = 1;
@@ -2142,6 +2158,8 @@ make_thunk (function, delta, vcall_index)
       DECL_DEFERRED_FN (thunk) = 0;
       /* So that finish_file can write out any thunks that need to be: */
       pushdecl_top_level (thunk);
+      /* Create RTL for this thunk so that its address can be taken.  */
+      make_function_rtl (thunk);
     }
   return thunk;
 }
@@ -2149,17 +2167,20 @@ make_thunk (function, delta, vcall_index)
 /* Emit the definition of a C++ multiple inheritance vtable thunk.  */
 
 void
-emit_thunk (thunk_fndecl)
+use_thunk (thunk_fndecl, emit_p)
      tree thunk_fndecl;
+     int emit_p;
+     
 {
   tree fnaddr;
   tree function;
-  int delta;
-  int vcall_offset;
+  tree vcall_offset;
+  HOST_WIDE_INT delta;
 
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
-
+  
+  fnaddr = DECL_INITIAL (thunk_fndecl);
   if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
     /* We already turned this thunk into an ordinary function.
        There's no need to process this thunk again.  (We can't just
@@ -2167,16 +2188,25 @@ emit_thunk (thunk_fndecl)
        FNADDR_FROM_VTABLE_ENTRY and friends.)  */
     return;
 
-  fnaddr = DECL_INITIAL (thunk_fndecl);
-  function = TREE_OPERAND (fnaddr, 0);
-  delta = THUNK_DELTA (thunk_fndecl);
-  vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
+  /* Thunks are always addressable; they only appear in vtables.  */
+  TREE_ADDRESSABLE (thunk_fndecl) = 1;
 
+  /* Figure out what function is being thunked to.  It's referenced in
+     this translation unit.  */
+  function = TREE_OPERAND (fnaddr, 0);
   TREE_ADDRESSABLE (function) = 1;
   mark_used (function);
+  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
+  if (!emit_p)
+    return;
 
-  if (current_function_decl)
-    abort ();
+  delta = THUNK_DELTA (thunk_fndecl);
+  vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
+
+  /* And, if we need to emit the thunk, it's used.  */
+  mark_used (thunk_fndecl);
+  /* This thunk is actually defined.  */
+  DECL_EXTERNAL (thunk_fndecl) = 0;
 
   if (flag_syntax_only)
     {
@@ -2184,14 +2214,13 @@ emit_thunk (thunk_fndecl)
       return;
     }
 
+  push_to_top_level ();
+
 #ifdef ASM_OUTPUT_MI_THUNK
-  if (vcall_offset == 0)
+  if (!vcall_offset)
     {
       const char *fnname;
       current_function_decl = thunk_fndecl;
-      /* Make sure we build up its RTL before we go onto the
-        temporary obstack.  */
-      make_function_rtl (thunk_fndecl);
       DECL_RESULT (thunk_fndecl)
        = build_decl (RESULT_DECL, 0, integer_type_node);
       fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
@@ -2230,17 +2259,15 @@ emit_thunk (thunk_fndecl)
     DECL_ARGUMENTS (thunk_fndecl) = a;
     DECL_RESULT (thunk_fndecl) = NULL_TREE;
 
-    push_to_top_level ();
     start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
     store_parm_decls ();
 
     /* Adjust the this pointer by the constant.  */
     t = ssize_int (delta);
-    TREE_TYPE (t) = signed_type (sizetype);
     t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
     /* If there's a vcall offset, look up that value in the vtable and
        adjust the `this' pointer again.  */
-    if (vcall_offset != 0)
+    if (!integer_zerop (vcall_offset))
       {
        tree orig_this;
 
@@ -2254,7 +2281,7 @@ emit_thunk (thunk_fndecl)
        /* Form the vtable address.  */
        t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
        /* Find the entry with the vcall offset.  */
-       t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset));
+       t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
        /* Calculate the offset itself.  */
        t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
        /* Adjust the `this' pointer.  */
@@ -2281,8 +2308,9 @@ emit_thunk (thunk_fndecl)
     BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
       = DECL_ARGUMENTS (thunk_fndecl);
     expand_body (finish_function (0));
-    pop_from_top_level ();
   }
+
+  pop_from_top_level ();
 }
 \f
 /* Code for synthesizing methods which have default semantics defined.  */
index efb8e6a53d9d8d04938dd50a1d965d7bbec45302..78fb5a44e82adb257e1a4e7ee58ed9156ffec36a 100644 (file)
@@ -2295,9 +2295,9 @@ dfs_get_pure_virtuals (binfo, data)
       for (virtuals = BINFO_VIRTUALS (binfo);
           virtuals;
           virtuals = TREE_CHAIN (virtuals))
-       if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
+       if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
          CLASSTYPE_PURE_VIRTUALS (type) 
-           = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
+           = tree_cons (NULL_TREE, BV_FN (virtuals),
                         CLASSTYPE_PURE_VIRTUALS (type));
     }
   
@@ -2341,7 +2341,7 @@ get_pure_virtuals (type)
           virtuals;
           virtuals = TREE_CHAIN (virtuals))
        {
-         tree base_fndecl = TREE_VALUE (virtuals);
+         tree base_fndecl = BV_FN (virtuals);
          if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
            cp_error ("`%#D' needs a final overrider", base_fndecl);
        }
index 5cebea6cd83d193d3afe55d4422420e2c86f6dae..68dac42219d9d2572eedf559592416114356b90b 100644 (file)
@@ -50,6 +50,7 @@ static tree expand_cond PARAMS ((tree));
 static tree maybe_convert_cond PARAMS ((tree));
 static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
 static void deferred_type_access_control PARAMS ((void));
+static void emit_associated_thunks PARAMS ((tree));
 
 /* Record the fact that STMT was the last statement added to the
    statement tree.  */
@@ -2962,6 +2963,53 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
   return NULL_TREE;
 }
 
+/* Emit all thunks to FN that should be emitted when FN is emitted.  */
+
+static void
+emit_associated_thunks (fn)
+     tree fn;
+{
+  /* When we use vcall offsets, we emit thunks with the virtual
+     functions to which they thunk. The whole point of vcall offsets
+     is so that you can know statically the entire set of thunks that
+     will ever be needed for a given virtual function, thereby
+     enabling you to output all the thunks with the function itself.  */
+  if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
+    {
+      tree binfo;
+      tree v;
+
+      for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
+          binfo;
+          binfo = TREE_CHAIN (binfo))
+       for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
+         if (BV_FN (v) == fn
+             && (!integer_zerop (BV_DELTA (v))
+                 || BV_VCALL_INDEX (v)))
+           {
+             tree thunk;
+             tree vcall_index;
+
+             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;
+
+             thunk = make_thunk (build1 (ADDR_EXPR,
+                                         vfunc_ptr_type_node,
+                                         fn),
+                                 BV_DELTA (v),
+                                 vcall_index,
+                                 /*generate_with_vtable_p=*/0);
+             use_thunk (thunk, /*emit_p=*/1);
+           }
+    }
+}
+
+
 /* Generate RTL for FN.  */
 
 void
@@ -3037,6 +3085,9 @@ expand_body (fn)
       return;
     }
 
+  /* Emit any thunks that should be emitted at the same time as FN.  */
+  emit_associated_thunks (fn);
+
   timevar_push (TV_INTEGRATION);
 
   /* Optimize the body of the function before expanding it.  */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/virtual8.C b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C
new file mode 100644 (file)
index 0000000..9f32ca0
--- /dev/null
@@ -0,0 +1,31 @@
+extern "C" void printf (const char*, ...);
+
+struct A
+{
+  virtual void f () {
+    printf ("%x\n", this);
+  }
+};
+
+struct B : public A
+{
+};
+
+struct C : public A
+{
+};
+
+struct D : virtual public B, public C
+{
+};
+
+int main ()
+{
+  D d;
+
+  A* a1 = (A*) (B*) &d;
+  A* a2 = (A*) (C*) &d;
+
+  a1->f ();
+  a2->f ();
+}