OSDN Git Service

* cp-tree.h (dfs_skip_vbases): New function.
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Jan 2000 20:56:15 +0000 (20:56 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Jan 2000 20:56:15 +0000 (20:56 +0000)
(find_vbase_instance): Likewise.
* class.c (determine_primary_base): Allow a nearly empty base to
serve as a primary base class under the new ABI.
(get_class_offset_1): Rename to ...
(dfs_get_class_offset): ... this.  Simplify.  Don't issue error
messages here.
(get_class_offset): Use it.  Issue error messages here.
(dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to
find the right copies of virtual bases.
(fixup_vtable_deltas1): Rename to ...
(dfs_fixup_vtable_deltas): ... this.  Adjust to handle virtual
bases as primary bases.
(fixup_vtable_deltas): Remove.
(override_one_vtable): Handle virtual bases as primary bases.
(merge_overrides): Likewise.
(finish_struct_1): Likewise.
(dump_class_hierarchy): Dump primary-ness of bases as well.
* search.c (mark_primary_bases): Use a pre-order traversal to
handle primary virtual bases.
(dfs_skip_vbases): New fiunction.
(expand_upcast_fixups): Adjust to handle primary virtual bases.
(fixup_virtual_upcast_offsets): Likewise.
(fixup_all_virtual_upcast_offsets): Likewise.
(dfs_find_vbase_instances): New function.
(find_vbase_instance): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31360 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/search.c

index 53bf525..89b7400 100644 (file)
@@ -1,3 +1,32 @@
+2000-01-12  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (dfs_skip_vbases): New function.
+       (find_vbase_instance): Likewise.
+       * class.c (determine_primary_base): Allow a nearly empty base to
+       serve as a primary base class under the new ABI.
+       (get_class_offset_1): Rename to ...
+       (dfs_get_class_offset): ... this.  Simplify.  Don't issue error
+       messages here.
+       (get_class_offset): Use it.  Issue error messages here.
+       (dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to
+       find the right copies of virtual bases.
+       (fixup_vtable_deltas1): Rename to ...
+       (dfs_fixup_vtable_deltas): ... this.  Adjust to handle virtual
+       bases as primary bases.
+       (fixup_vtable_deltas): Remove.
+       (override_one_vtable): Handle virtual bases as primary bases.
+       (merge_overrides): Likewise.
+       (finish_struct_1): Likewise.
+       (dump_class_hierarchy): Dump primary-ness of bases as well.
+       * search.c (mark_primary_bases): Use a pre-order traversal to
+       handle primary virtual bases.
+       (dfs_skip_vbases): New fiunction.
+       (expand_upcast_fixups): Adjust to handle primary virtual bases.
+       (fixup_virtual_upcast_offsets): Likewise.
+       (fixup_all_virtual_upcast_offsets): Likewise.
+       (dfs_find_vbase_instances): New function.
+       (find_vbase_instance): Likewise.
+       
 2000-01-11  Mumit Khan  <khan@xraylith.wisc.edu>
 
        * lex.c (DIR_SEPARATOR): Delete macro.
index 023cf1a..7d9ab93 100644 (file)
@@ -82,8 +82,7 @@ static tree get_basefndecls PROTO((tree, tree));
 static void set_rtti_entry PROTO((tree, tree, tree));
 static void build_vtable PROTO((tree, tree));
 static void prepare_fresh_vtable PROTO((tree, tree));
-static void fixup_vtable_deltas1 PROTO((tree, tree));
-static void fixup_vtable_deltas PROTO((tree, int, tree));
+static tree dfs_fixup_vtable_deltas PROTO((tree, void *));
 static tree dfs_finish_vtbls PROTO((tree, void *));
 static void finish_vtbls PROTO((tree));
 static void modify_vtable_entry PROTO((tree, tree, tree));
@@ -100,7 +99,7 @@ static void merge_overrides PROTO((tree, tree, int, tree));
 static void override_one_vtable PROTO((tree, tree, tree));
 static void mark_overriders PROTO((tree, tree));
 static void check_for_override PROTO((tree, tree));
-static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
+static tree dfs_get_class_offset PROTO((tree, void *));
 static tree get_class_offset PROTO((tree, tree, tree, tree));
 static void modify_one_vtable PROTO((tree, tree, tree));
 static tree dfs_modify_vtables PROTO((tree, void *));
@@ -1672,9 +1671,25 @@ determine_primary_base (t, has_virtual_p)
   if (!TYPE_VFIELD (t))
     CLASSTYPE_VFIELD_PARENT (t) = -1;
 
-  /* Now that we know what the primary base class is, we can run
-     through the entire hierarchy marking the primary bases for future
-     reference.  */
+  /* The new ABI allows for the use of a "nearly-empty" virtual base
+     class as the primary base class if no non-virtual polymorphic
+     base can be found.  */
+  if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
+    for (i = 0; i < n_baseclasses; ++i)
+      {
+       tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
+       tree basetype = BINFO_TYPE (base_binfo);
+
+       if (TREE_VIA_VIRTUAL (base_binfo) 
+           && CLASSTYPE_NEARLY_EMPTY_P (basetype))
+         {
+           set_primary_base (t, i, has_virtual_p);
+           CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
+           break;
+         }
+      }
+
+  /* Mark the primary base classes at this point.  */
   mark_primary_bases (t);
 }
 \f
@@ -2266,6 +2281,9 @@ overrides (fndecl, base_fndecl)
   return 0;
 }
 
+/* Returns the BINFO_OFFSET for the base of BINFO that has the same
+   type as CONTEXT.  */
+
 static tree
 get_class_offset_1 (parent, binfo, context, t, fndecl)
      tree parent, binfo, context, t, fndecl;
@@ -2311,14 +2329,37 @@ get_class_offset_1 (parent, binfo, context, t, fndecl)
   return rval;
 }
 
-/* Get the offset to the CONTEXT subobject that is related to the
-   given BINFO.  */
+/* Called from get_class_offset via dfs_walk.  */
+
+static tree
+dfs_get_class_offset (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree list = (tree) data;
+  tree context = TREE_TYPE (list);
+
+  if (same_type_p (BINFO_TYPE (binfo), context))
+    {
+      if (TREE_VALUE (list))
+       return error_mark_node;
+      else
+       TREE_VALUE (list) = BINFO_OFFSET (binfo);
+    }
+  
+  SET_BINFO_MARKED (binfo);
+
+  return NULL_TREE;
+}
+
+/* Returns the BINFO_OFFSET for the subobject of BINFO that has the
+   type given by CONTEXT.  */
 
 static tree
 get_class_offset (context, t, binfo, fndecl)
      tree context, t, binfo, fndecl;
 {
-  tree first_binfo = binfo;
+  tree list;
   tree offset;
   int i;
 
@@ -2338,11 +2379,28 @@ get_class_offset (context, t, binfo, fndecl)
        return BINFO_OFFSET (binfo);
     }
 
-  /* Ok, not found in the less derived binfos, now check the more
-     derived binfos.  */
-  offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
-  if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
-    my_friendly_abort (999);   /* we have to find it.  */
+  list = build_tree_list (t, NULL_TREE);
+  TREE_TYPE (list) = context;
+  offset = dfs_walk (TYPE_BINFO (t),
+                    dfs_get_class_offset,
+                    dfs_unmarked_real_bases_queue_p,
+                    list);
+  dfs_walk (TYPE_BINFO (t), dfs_unmark, dfs_marked_real_bases_queue_p, t);
+
+  if (offset == error_mark_node)
+    {
+      error ("every virtual function must have a unique final overrider");
+      cp_error ("  found two (or more) `%T' class subobjects in `%T'", 
+               context, t);
+      cp_error ("  with virtual `%D' from virtual base class", fndecl);
+      offset = integer_zero_node;
+    }
+  else
+    offset = TREE_VALUE (list);
+
+  my_friendly_assert (offset != NULL_TREE, 999);
+  my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 999);
+
   return offset;
 }
 
@@ -2473,9 +2531,6 @@ dfs_modify_vtables (binfo, data)
       && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
     {
       tree list = (tree) data;
-
-      if (TREE_VIA_VIRTUAL (binfo))
-       binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
       modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list)); 
     }
 
@@ -2499,13 +2554,23 @@ modify_all_vtables (t, fndecl)
 
 /* Fixup all the delta entries in this one vtable that need updating.  */
 
-static void
-fixup_vtable_deltas1 (binfo, t)
-     tree binfo, t;
+static tree
+dfs_fixup_vtable_deltas (binfo, data)
+     tree binfo;
+     void *data;
 {
   tree virtuals;
   unsigned HOST_WIDE_INT n;
-  
+  tree t = (tree) data;
+
+  while (BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
+      /* If BINFO is virtual then we'll handle this base later.  */
+      if (TREE_VIA_VIRTUAL (binfo))
+       return NULL_TREE;
+    }
+
   virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
 
   while (virtuals)
@@ -2559,33 +2624,8 @@ fixup_vtable_deltas1 (binfo, t)
       ++n;
       virtuals = TREE_CHAIN (virtuals);
     }
-}
-
-/* Fixup all the delta entries in all the direct vtables that need updating.
-   This happens when we have non-overridden virtual functions from a
-   virtual base class, that are at a different offset, in the new
-   hierarchy, because the layout of the virtual bases has changed.  */
 
-static void
-fixup_vtable_deltas (binfo, init_self, t)
-     tree binfo;
-     int init_self;
-     tree t;
-{
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  for (i = 0; i < n_baselinks; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      int is_not_base_vtable
-       = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
-      if (! TREE_VIA_VIRTUAL (base_binfo))
-       fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
-    }
-  /* Should we use something besides CLASSTYPE_VFIELDS? */
-  if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
-    fixup_vtable_deltas1 (binfo, t);
+  return NULL_TREE;
 }
 
 /* Here, we already know that they match in every respect.
@@ -2622,8 +2662,26 @@ override_one_vtable (binfo, old, t)
 {
   tree virtuals;
   tree old_virtuals;
+  tree orig_binfo;
+  tree orig_virtuals;
   enum { REUSE_NEW, REUSE_OLD, UNDECIDED, NEITHER } choose = UNDECIDED;
 
+  /* Either or both of BINFO or OLD might be primary base classes
+     because merge_overrides is called with a vbase from the class we
+     are definining and the corresponding vbase from one of its direct
+     bases.  */
+  orig_binfo = binfo;
+  while (BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
+      /* If BINFO is virtual, then we'll handle this virtual base when
+        later.  */
+      if (TREE_VIA_VIRTUAL (binfo))
+       return;
+    }
+  while (BINFO_PRIMARY_MARKED_P (old))
+    old = BINFO_INHERITANCE_CHAIN (old);
+
   /* If we have already committed to modifying it, then don't try and
      reuse another vtable.  */
   if (BINFO_NEW_VTABLE_MARKED (binfo))
@@ -2631,8 +2689,9 @@ override_one_vtable (binfo, old, t)
 
   virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL);
   old_virtuals = skip_rtti_stuff (old, BINFO_TYPE (binfo), NULL);
+  orig_virtuals = skip_rtti_stuff (orig_binfo, BINFO_TYPE (binfo), NULL);
 
-  while (virtuals)
+  while (orig_virtuals)
     {
       tree fndecl = TREE_VALUE (virtuals);
       tree old_fndecl = TREE_VALUE (old_virtuals);
@@ -2705,6 +2764,7 @@ override_one_vtable (binfo, old, t)
        }
       virtuals = TREE_CHAIN (virtuals);
       old_virtuals = TREE_CHAIN (old_virtuals);
+      orig_virtuals = TREE_CHAIN (orig_virtuals);
     }
 
   /* Let's reuse the old vtable.  */
@@ -2739,8 +2799,8 @@ merge_overrides (binfo, old, do_self, t)
     {
       tree base_binfo = TREE_VEC_ELT (binfos, i);
       tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
-      int is_not_base_vtable
-       = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+      int is_not_base_vtable 
+       = !BINFO_PRIMARY_MARKED_P (base_binfo);
       if (! TREE_VIA_VIRTUAL (base_binfo))
        merge_overrides (base_binfo, old_base_binfo, is_not_base_vtable, t);
     }
@@ -4563,9 +4623,15 @@ finish_struct_1 (t)
            vbases = CLASSTYPE_VBASECLASSES (basetype);
            while (vbases)
              {
-               merge_overrides (binfo_member (BINFO_TYPE (vbases),
-                                              CLASSTYPE_VBASECLASSES (t)),
-                                vbases, 1, t);
+               tree vbase;
+               tree basetype_vbase;
+
+               vbase 
+                 = find_vbase_instance (BINFO_TYPE (vbases), t);
+               basetype_vbase 
+                 = find_vbase_instance (BINFO_TYPE (vbases), basetype);
+
+               merge_overrides (vbase, basetype_vbase, 1, t);
                vbases = TREE_CHAIN (vbases);
              }
          }
@@ -4613,11 +4679,14 @@ finish_struct_1 (t)
       vbases = CLASSTYPE_VBASECLASSES (t);
       while (vbases)
        {
+         tree vbase;
+
          /* We might be able to shorten the amount of work we do by
             only doing this for vtables that come from virtual bases
             that have differing offsets, but don't want to miss any
             entries.  */
-         fixup_vtable_deltas (vbases, 1, t);
+         vbase = find_vbase_instance (BINFO_TYPE (vbases), t);
+         dfs_walk (vbase, dfs_fixup_vtable_deltas, dfs_skip_vbases, t);
          vbases = TREE_CHAIN (vbases);
        }
     }
@@ -6015,10 +6084,11 @@ dump_class_hierarchy (binfo, indent)
 {
   int i;
 
-  fprintf (stderr, "%*s0x%x (%s) %d\n", indent, "",
+  fprintf (stderr, "%*s0x%x (%s) %d %s\n", indent, "",
           (unsigned int) binfo,
           type_as_string (binfo, TS_PLAIN),
-          TREE_INT_CST_LOW (BINFO_OFFSET (binfo)));
+          TREE_INT_CST_LOW (BINFO_OFFSET (binfo)),
+          BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
 
   for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
     dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
index beaa416..88b49a0 100644 (file)
@@ -3954,8 +3954,10 @@ extern tree dfs_skip_nonprimary_vbases_unmarkedp PROTO((tree, void *));
 extern tree dfs_skip_nonprimary_vbases_markedp  PROTO((tree, void *));
 extern tree dfs_unmarked_real_bases_queue_p     PROTO((tree, void *));
 extern tree dfs_marked_real_bases_queue_p       PROTO((tree, void *));
+extern tree dfs_skip_vbases                     PROTO((tree, void *));
 extern void mark_primary_bases                  PROTO((tree));
 extern tree convert_pointer_to_vbase            PROTO((tree, tree));
+extern tree find_vbase_instance                 PROTO((tree, tree));
 
 /* in semantics.c */
 extern void finish_expr_stmt                    PROTO((tree));
index abd6867..1d6efed 100644 (file)
@@ -151,6 +151,7 @@ static int template_self_reference_p PROTO ((tree, tree));
 static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
 static tree dfs_mark_primary_bases PROTO((tree, void *));
 static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
+static tree dfs_find_vbase_instance PROTO((tree, void *));
 
 /* Allocate a level of searching.  */
 
@@ -2189,9 +2190,14 @@ mark_primary_bases (type)
 {
   tree vbase;
 
-  /* Mark the TYPE_BINFO hierarchy.  */
-  dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases, 
-           dfs_skip_nonprimary_vbases_unmarkedp, type);
+  /* Mark the TYPE_BINFO hierarchy.  We need to mark primary bases in
+     pre-order to deal with primary virtual bases.  (The virtual base
+     would be skipped if it were not marked as primary, and that
+     requires getting to dfs_mark_primary_bases before
+     dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+     virtual base.)  */
+  dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+                dfs_skip_nonprimary_vbases_unmarkedp, type);
 
   /* Now go through the virtual base classes.  Any that are not
      already primary will need to be allocated in TYPE, and so we need
@@ -2289,6 +2295,20 @@ dfs_marked_real_bases_queue_p (binfo, data)
   return binfo ? markedp (binfo, NULL) : NULL_TREE;
 }
 
+/* A queue function that skips all virtual bases (and their 
+   bases).  */
+
+tree
+dfs_skip_vbases (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo))
+    return NULL_TREE;
+
+  return binfo;
+}
+
 /* Called via dfs_walk from dfs_get_pure_virtuals.  */
 
 static tree
@@ -2798,7 +2818,14 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
   tree vc;
   tree delta;
   unsigned HOST_WIDE_INT n;
-  
+
+  while (BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
+      if (TREE_VIA_VIRTUAL (binfo))
+       return;
+    }
+
   delta = purpose_member (vbase, *vbase_offsets);
   if (! delta)
     {
@@ -2925,7 +2952,7 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
       tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
       tree base_binfo = TREE_VEC_ELT (binfos, i);
       int is_not_base_vtable
-       = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+       = !BINFO_PRIMARY_MARKED_P (real_base_binfo);
       if (! TREE_VIA_VIRTUAL (real_base_binfo))
        fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
                                      is_not_base_vtable, can_elide, addr,
@@ -2979,15 +3006,17 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr)
        ;
       else
        {
+         tree vbase;
          tree vbase_offsets;
          tree addr;
 
+         vbase = find_vbase_instance (BINFO_TYPE (vbases), type);
          vbase_offsets = NULL_TREE;
-         addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr);
-         fixup_virtual_upcast_offsets (vbases,
+         addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr);
+         fixup_virtual_upcast_offsets (vbase,
                                        TYPE_BINFO (BINFO_TYPE (vbases)),
                                        1, 0, addr, decl_ptr,
-                                       type, vbases, &vbase_offsets);
+                                       type, vbase, &vbase_offsets);
        }
     }
 
@@ -3074,6 +3103,43 @@ get_vbase_types (type)
   CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
   dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
 }
+
+/* Called from find_vbase_instance via dfs_walk.  */
+
+static tree
+dfs_find_vbase_instance (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree base = TREE_VALUE ((tree) data);
+
+  if (BINFO_PRIMARY_MARKED_P (binfo)
+      && same_type_p (BINFO_TYPE (binfo), base))
+    return binfo;
+
+  return NULL_TREE;
+}
+
+/* Find the real occurrence of the virtual BASE (a class type) in the
+   hierarchy dominated by TYPE.  */
+
+tree
+find_vbase_instance (base, type)
+     tree base;
+     tree type;
+{
+  tree instance;
+
+  instance = BINFO_FOR_VBASE (base, type);
+  if (!BINFO_VBASE_PRIMARY_P (instance))
+    return instance;
+
+  return dfs_walk (TYPE_BINFO (type), 
+                  dfs_find_vbase_instance, 
+                  NULL,
+                  build_tree_list (type, base));
+}
+
 \f
 /* Debug info for C++ classes can get very large; try to avoid
    emitting it everywhere.