patch for complex MI vtable names

Mike Stump mrs@wrs.com
Mon Oct 6 18:54:00 GMT 1997


Here is one I'v been meaning to do for years, but never got around to
it, well, I finally got around to it!  :-)

I solved this in such a way as to be perfectly backwards compatible
with prior releases, and yet beefy enough to never fail (even in
complex cases).

Could you put this one in?  Thanks.


1997-10-06  Mike Stump  <mrs@wrs.com>

	    * class.c (build_type_pathname): Remove.
	    (prepare_fresh_vtable): Fix problem with complex MI vtable names.

Doing diffs in testsuite/g++.old-deja/g++.mike/virt6.C.~1~:
*** testsuite/g++.old-deja/g++.mike/virt6.C.~1~	Mon Oct  6 17:59:31 1997
--- testsuite/g++.old-deja/g++.mike/virt6.C	Mon Oct  6 17:57:26 1997
***************
*** 0 ****
--- 1,39 ----
+ // This testcase ensures that we can build vtable names for complex MI
+ // classes.
+ 
+ class C_A {
+ public:
+   virtual int foo(void *) { }
+ } a;
+  
+ class C_B : public C_A {
+ } b;
+  
+ class C_C : public C_A {
+ } c;
+  
+ class C_D : public C_A {
+ } d;
+  
+ class C_E : public C_C, public C_B {
+ public:
+   virtual int foo(void *) { }
+ } e;
+  
+ class C_F : public C_D, public C_B {
+ public:
+   virtual int foo(void *) { }
+ } f;
+  
+ class C_G : public C_A {
+ public:
+   virtual int foo(void *) { }
+ } g;
+  
+ class C_H : public C_G, public C_E, public C_F {
+ public:
+   virtual int foo(void *) { }
+ } h;
+  
+ int main() {
+ }
--------------
Doing diffs in cp/class.c.~1~:
*** cp/class.c.~1~	Thu Oct  2 15:15:47 1997
--- cp/class.c	Mon Oct  6 17:34:00 1997
*************** static tree get_derived_offset PROTO((tr
*** 96,102 ****
  static tree get_basefndecls PROTO((tree, tree));
  static void set_rtti_entry PROTO((tree, tree, tree));
  static tree build_vtable PROTO((tree, tree));
- static tree build_type_pathname PROTO((char *, 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));
--- 96,101 ----
*************** get_vtable_name (type)
*** 586,593 ****
       tree type;
  {
    tree type_id = build_typename_overload (type);
!   char *buf = (char *)alloca (strlen (VTABLE_NAME_FORMAT)
! 			      + IDENTIFIER_LENGTH (type_id) + 2);
    char *ptr = IDENTIFIER_POINTER (type_id);
    int i;
    for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
--- 585,592 ----
       tree type;
  {
    tree type_id = build_typename_overload (type);
!   char *buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT)
! 			       + IDENTIFIER_LENGTH (type_id) + 2);
    char *ptr = IDENTIFIER_POINTER (type_id);
    int i;
    for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
*************** build_vtable (binfo, type)
*** 735,803 ****
    return decl;
  }
  
- /* Given a base type PARENT, and a derived type TYPE, build
-    a name which distinguishes exactly the PARENT member of TYPE's type.
- 
-    FORMAT is a string which controls how sprintf formats the name
-    we have generated.
- 
-    For example, given
- 
- 	class A; class B; class C : A, B;
- 
-    it is possible to distinguish "A" from "C's A".  And given
- 
- 	class L;
- 	class A : L; class B : L; class C : A, B;
- 
-    it is possible to distinguish "L" from "A's L", and also from
-    "C's L from A".
- 
-    Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the
-    type, as template have DECL_NAMEs like: X<int>, whereas the
-    DECL_ASSEMBLER_NAME is set to be something the assembler can handle.  */
- 
- static tree
- build_type_pathname (format, parent, type)
-      char *format;
-      tree parent, type;
- {
-   extern struct obstack temporary_obstack;
-   char *first, *base, *name;
-   int i;
-   tree id;
- 
-   parent = TYPE_MAIN_VARIANT (parent);
- 
-   /* Remember where to cut the obstack to.  */
-   first = obstack_base (&temporary_obstack);
- 
-   /* Put on TYPE+PARENT.  */
-   obstack_grow (&temporary_obstack,
- 		TYPE_ASSEMBLER_NAME_STRING (type),
- 		TYPE_ASSEMBLER_NAME_LENGTH (type));
- #ifdef JOINER
-   obstack_1grow (&temporary_obstack, JOINER);
- #else
-   obstack_1grow (&temporary_obstack, '_');
- #endif
-   obstack_grow0 (&temporary_obstack,
- 		 TYPE_ASSEMBLER_NAME_STRING (parent),
- 		 TYPE_ASSEMBLER_NAME_LENGTH (parent));
-   i = obstack_object_size (&temporary_obstack);
-   base = obstack_base (&temporary_obstack);
-   obstack_finish (&temporary_obstack);
- 
-   /* Put on FORMAT+TYPE+PARENT.  */
-   obstack_blank (&temporary_obstack, strlen (format) + i + 1);
-   name = obstack_base (&temporary_obstack);
-   sprintf (name, format, base);
-   id = get_identifier (name);
-   obstack_free (&temporary_obstack, first);
- 
-   return id;
- }
- 
  extern tree signed_size_zero_node;
  
  /* Give TYPE a new virtual function table which is initialized
--- 734,739 ----
*************** extern tree signed_size_zero_node;
*** 808,827 ****
     FOR_TYPE is the derived type which caused this table to
     be needed.
  
!    BINFO is the type association which provided TYPE for FOR_TYPE.  */
  
  static void
  prepare_fresh_vtable (binfo, for_type)
       tree binfo, for_type;
  {
!   tree basetype = BINFO_TYPE (binfo);
    tree orig_decl = BINFO_VTABLE (binfo);
!   /* This name is too simplistic.  We can have multiple basetypes for
!      for_type, and we really want different names.  (mrs) */
!   tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type);
!   tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
    tree offset;
  
    /* Remember which class this vtable is really for.  */
    DECL_CONTEXT (new_decl) = for_type;
  
--- 744,826 ----
     FOR_TYPE is the derived type which caused this table to
     be needed.
  
!    BINFO is the type association which provided TYPE for FOR_TYPE.
! 
!    The order in which vtables are built (by calling this function) for
!    an object must remain the same, otherwise a binary incompatibility
!    can result.  */
  
  static void
  prepare_fresh_vtable (binfo, for_type)
       tree binfo, for_type;
  {
!   tree basetype;
    tree orig_decl = BINFO_VTABLE (binfo);
!   tree name;
!   tree new_decl;
    tree offset;
+   tree path = binfo;
+   char *buf, *buf2;
+   char joiner = '_';
+   int i;
+ 
+ #ifdef JOINER
+   joiner = JOINER;
+ #endif
+ 
+   basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo));
+ 
+   buf2 = TYPE_ASSEMBLER_NAME_STRING (basetype);
+   i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1;
+ 
+   /* We know that the vtable that we are going to create doesn't exist
+      yet in the global namespace, and when we finish, it will be
+      pushed into the global namespace.  In complex MI hierarchies, we
+      have to loop while the name we are thinking of adding is globally
+      defined, adding more name components to the vtable name as we
+      loop, until the name is unique.  This is because in complex MI
+      cases, we might have the same base more than once.  This means
+      that the order in which this function is called for vtables must
+      remain the same, otherwise binary compatibility can be
+      compromised.  */
+ 
+   while (1)
+     {
+       char *buf1 = (char *) alloca (TYPE_ASSEMBLER_NAME_LENGTH (for_type) + 1 + i);
+       char *new_buf2;
+ 
+       sprintf (buf1, "%s%c%s", TYPE_ASSEMBLER_NAME_STRING (for_type), joiner,
+ 	       buf2);
+       buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT) + strlen (buf1) + 1);
+       sprintf (buf, VTABLE_NAME_FORMAT, buf1);
+       name = get_identifier (buf);
+ 
+       /* If this name doesn't clash, then we can use it, otherwise
+ 	 we add more to the name until it is unique.  */
+ 
+       if (! IDENTIFIER_GLOBAL_VALUE (name))
+ 	break;
+ 
+       /* Set values for next loop through, if the name isn't unique.  */
+ 
+       path = BINFO_INHERITANCE_CHAIN (path);
+ 
+       /* We better not run out of stuff to make it unique.  */
+       my_friendly_assert (path != NULL_TREE, 368);
+ 
+       basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (path));
+ 
+       /* We better not run out of stuff to make it unique.  */
+       my_friendly_assert (for_type != basetype, 369);
+ 
+       i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i;
+       new_buf2 = (char *) alloca (i);
+       sprintf (new_buf2, "%s%c%s",
+ 	       TYPE_ASSEMBLER_NAME_STRING (basetype), joiner, buf2);
+       buf2 = new_buf2;
+     }
  
+   new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
    /* Remember which class this vtable is really for.  */
    DECL_CONTEXT (new_decl) = for_type;
  
*************** get_vfield_name (type)
*** 5405,5412 ****
      binfo = BINFO_BASETYPE (binfo, 0);
  
    type = BINFO_TYPE (binfo);
!   buf = (char *)alloca (sizeof (VFIELD_NAME_FORMAT)
! 			+ TYPE_NAME_LENGTH (type) + 2);
    sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
    return get_identifier (buf);
  }
--- 5404,5411 ----
      binfo = BINFO_BASETYPE (binfo, 0);
  
    type = BINFO_TYPE (binfo);
!   buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
! 			 + TYPE_NAME_LENGTH (type) + 2);
    sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
    return get_identifier (buf);
  }
--------------
Doing diffs in cp/typeck2.c.~1~:
*** cp/typeck2.c.~1~	Mon Aug 25 08:33:32 1997
--- cp/typeck2.c	Mon Oct  6 17:34:00 1997
*************** ack (s, v, v2)
*** 301,307 ****
     silly.  So instead, we just do the equivalent of a call to fatal in the
     same situation (call exit).  */
  
! /* First used: 0 (reserved), Last used: 367.  Free: */
  
  static int abortcount = 0;
  
--- 301,307 ----
     silly.  So instead, we just do the equivalent of a call to fatal in the
     same situation (call exit).  */
  
! /* First used: 0 (reserved), Last used: 369.  Free: */
  
  static int abortcount = 0;
  
--------------



More information about the Gcc-bugs mailing list