OSDN Git Service

* cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ...
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 30 Jun 2002 20:41:38 +0000 (20:41 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 30 Jun 2002 20:41:38 +0000 (20:41 +0000)
(CPTI_TYPE_INFO_PTR_TYPE): ... this.
(tinfo_decl_type): Replace with ...
(type_info_ptr_type): ... this.
(import_export_tinfo): Declare.
(tinfo_decl_p): Rename to ...
(unemitted_tinfo_decl_p): ... this.
* decl2.c (import_export_decl): Break out tinfo handling into ...
(import_export_tinfo): ... here. New function.
(finish_file): Adjust.
* rtti.c (TINFO_REAL_NAME): New macro.
(init_rtti_processing): Create the tinfo types.
(get_tinfo_decl_dynamic): Use type_info_ptr_type, get_tinfo_ptr.
(get_tinfo_decl): Adjust.
(get_tinfo_ptr): New function.
(get_type_id): Use it.
(tinfo_base_init): Create vtable decl here, if it doesn't exist.
(ptr_initializer): Use get_tinfo_ptr.
(ptm_initializer): Likewise.
(synthesize_tinfo_var): Break into ...
(get_pseudo_ti_init): ... this. Just create the initializer.
(get_pseudo_ti_desc): .. and this.
(create_real_tinfo_var): Remove.
(create_pseudo_type_info): Don't create the vtable decl here.
(get_vmi_pseudo_type_info): Remove.
(create_tinfo_types): Adjust.
(tinfo_decl_p): Rename to ...
(unemitted_tinfo_decl_p): ... here. Adjust.
(emit_tinfo_decl): Adjust. Create the initializer.

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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/rtti.c

index d9f06b5..18814cf 100644 (file)
@@ -1,3 +1,35 @@
+2002-06-30  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ...
+       (CPTI_TYPE_INFO_PTR_TYPE): ... this.
+       (tinfo_decl_type): Replace with ...
+       (type_info_ptr_type): ... this.
+       (import_export_tinfo): Declare.
+       (tinfo_decl_p): Rename to ...
+       (unemitted_tinfo_decl_p): ... this.
+       * decl2.c (import_export_decl): Break out tinfo handling into ...
+       (import_export_tinfo): ... here. New function.
+       (finish_file): Adjust.
+       * rtti.c (TINFO_REAL_NAME): New macro.
+       (init_rtti_processing): Create the tinfo types.
+       (get_tinfo_decl_dynamic): Use type_info_ptr_type, get_tinfo_ptr.
+       (get_tinfo_decl): Adjust.
+       (get_tinfo_ptr): New function.
+       (get_type_id): Use it.
+       (tinfo_base_init): Create vtable decl here, if it doesn't exist.
+       (ptr_initializer): Use get_tinfo_ptr.
+       (ptm_initializer): Likewise.
+       (synthesize_tinfo_var): Break into ...
+       (get_pseudo_ti_init): ... this. Just create the initializer.
+       (get_pseudo_ti_desc): .. and this.
+       (create_real_tinfo_var): Remove.
+       (create_pseudo_type_info): Don't create the vtable decl here.
+       (get_vmi_pseudo_type_info): Remove.
+       (create_tinfo_types): Adjust.
+       (tinfo_decl_p): Rename to ...
+       (unemitted_tinfo_decl_p): ... here. Adjust.
+       (emit_tinfo_decl): Adjust. Create the initializer.
+
 2002-06-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/6695
index 2c19c09..80b0f43 100644 (file)
@@ -567,7 +567,7 @@ enum cp_tree_index
     CPTI_STD,
     CPTI_ABI,
     CPTI_TYPE_INFO_TYPE,
-    CPTI_TINFO_DECL_TYPE,
+    CPTI_TYPE_INFO_PTR_TYPE,
     CPTI_ABORT_FNDECL,
     CPTI_GLOBAL_DELETE_FNDECL,
     CPTI_AGGR_TAG,
@@ -654,7 +654,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define std_node                       cp_global_trees[CPTI_STD]
 #define abi_node                        cp_global_trees[CPTI_ABI]
 #define type_info_type_node            cp_global_trees[CPTI_TYPE_INFO_TYPE]
-#define tinfo_decl_type                        cp_global_trees[CPTI_TINFO_DECL_TYPE]
+#define type_info_ptr_type             cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE]
 #define abort_fndecl                   cp_global_trees[CPTI_ABORT_FNDECL]
 #define global_delete_fndecl           cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
 #define current_aggr                   cp_global_trees[CPTI_AGGR_TAG]
@@ -3935,6 +3935,7 @@ extern tree coerce_delete_type                    PARAMS ((tree));
 extern void comdat_linkage                     PARAMS ((tree));
 extern void import_export_vtable               PARAMS ((tree, tree, int));
 extern void import_export_decl                 PARAMS ((tree));
+extern void import_export_tinfo                        PARAMS ((tree, tree));
 extern tree build_cleanup                      PARAMS ((tree));
 extern void finish_file                                PARAMS ((void));
 extern tree reparse_absdcl_as_expr             PARAMS ((tree, tree));
@@ -4163,7 +4164,7 @@ extern tree get_tinfo_decl                      PARAMS((tree));
 extern tree get_typeid                         PARAMS((tree));
 extern tree build_dynamic_cast                 PARAMS((tree, tree));
 extern void emit_support_tinfos                 PARAMS((void));
-extern int tinfo_decl_p                         PARAMS((tree, void *));
+extern int unemitted_tinfo_decl_p              PARAMS((tree, void *));
 extern int emit_tinfo_decl                      PARAMS((tree *, void *));
 
 /* in search.c */
index eb1dd00..b37dc8c 100644 (file)
@@ -2509,47 +2509,44 @@ import_export_decl (decl)
       else
        comdat_linkage (decl);
     }
-  else if (tinfo_decl_p (decl, 0))
-    {
-      /* Here, we only decide whether or not the tinfo node should be
-        emitted with the vtable.  The decl we're considering isn't
-        actually the one which gets emitted; that one is generated in
-        create_real_tinfo_var.  */
-
-      tree ctype = TREE_TYPE (DECL_NAME (decl));
-
-      if (IS_AGGR_TYPE (ctype))
-       import_export_class (ctype);
-
-      if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype)
-         && TYPE_POLYMORPHIC_P (ctype)
-         /* If -fno-rtti, we're not necessarily emitting this stuff with
-            the class, so go ahead and emit it now.  This can happen
-            when a class is used in exception handling.  */
-         && flag_rtti
-         /* If the type is a cv-qualified variant of a type, then we
-            must emit the tinfo function in this translation unit
-            since it will not be emitted when the vtable for the type
-            is output (which is when the unqualified version is
-            generated).  */
-         && same_type_p (ctype, TYPE_MAIN_VARIANT (ctype)))
-       {
-         DECL_NOT_REALLY_EXTERN (decl)
-           = ! CLASSTYPE_INTERFACE_ONLY (ctype);
-         DECL_COMDAT (decl) = 0;
-       }
-      else
-       {
-         DECL_NOT_REALLY_EXTERN (decl) = 1;
-         DECL_COMDAT (decl) = 1;
-       }
-    } 
   else
     comdat_linkage (decl);
 
   DECL_INTERFACE_KNOWN (decl) = 1;
 }
 
+/* Here, we only decide whether or not the tinfo node should be
+   emitted with the vtable.  */
+
+void
+import_export_tinfo (decl, type)
+     tree decl;
+     tree type;
+{
+  if (DECL_INTERFACE_KNOWN (decl))
+    return;
+  
+  if (IS_AGGR_TYPE (type))
+    import_export_class (type);
+      
+  if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type)
+      && TYPE_POLYMORPHIC_P (type)
+      /* If -fno-rtti, we're not necessarily emitting this stuff with
+        the class, so go ahead and emit it now.  This can happen when
+        a class is used in exception handling.  */
+      && flag_rtti)
+    {
+      DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type);
+      DECL_COMDAT (decl) = 0;
+    }
+  else
+    {
+      DECL_NOT_REALLY_EXTERN (decl) = 1;
+      DECL_COMDAT (decl) = 1;
+    }
+  DECL_INTERFACE_KNOWN (decl) = 1;
+}
+
 tree
 build_cleanup (decl)
      tree decl;
@@ -3344,7 +3341,7 @@ finish_file ()
       
       /* Write out needed type info variables. Writing out one variable
          might cause others to be needed.  */
-      if (walk_globals (tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
+      if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
        reconsider = 1;
 
       /* The list of objects with static storage duration is built up
index 317a44d..3be44c5 100644 (file)
@@ -1,5 +1,5 @@
 /* RunTime Type Identification
-   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Mostly written by Jason Merrill (jason@cygnus.com).
 
@@ -30,16 +30,46 @@ Boston, MA 02111-1307, USA.  */
 #include "assert.h"
 #include "toplev.h"
 
+/* C++ returns type information to the user in struct type_info
+   objects. We also use type information to implement dynamic_cast and
+   exception handlers. Type information for a particular type is
+   indicated with an ABI defined structure derived from type_info.
+   This would all be very straight forward, but for the fact that the
+   runtime library provides the definitions of the type_info structure
+   and the ABI defined derived classes. We cannot build declarations
+   of them directly in the compiler, but we need to layout objects of
+   their type.  Somewhere we have to lie.
+
+   We define layout compatible POD-structs with compiler-defined names
+   and generate the appropriate initializations for them (complete
+   with explicit mention of their vtable). When we have to provide a
+   type_info to the user we reinterpret_cast the internal compiler
+   type to type_info.  A well formed program can only explicitly refer
+   to the type_infos of complete types (& cv void).  However, we chain
+   pointer type_infos to the pointed-to-type, and that can be
+   incomplete.  We only need the addresses of such incomplete
+   type_info objects for static initialization.
+
+   The type information VAR_DECL of a type is held on the
+   IDENTIFIER_GLOBAL_VALUE of the type's mangled name. That VAR_DECL
+   will be the internal type.  It will usually have the correct
+   internal type reflecting the kind of type it represents (pointer,
+   array, function, class, inherited class, etc).  When the type it
+   represents is incomplete, it will have the internal type
+   corresponding to type_info.  That will only happen at the end of
+   translation, when we are emitting the type info objects.  */
+
 /* Accessors for the type_info objects. We need to remember several things
    about each of the type_info types. The global tree nodes such as
    bltn_desc_type_node are TREE_LISTs, and these macros are used to access
    the required information. */
 /* The RECORD_TYPE of a type_info derived class. */
 #define TINFO_PSEUDO_TYPE(NODE) TREE_TYPE (NODE)
-/* The VAR_DECL of the vtable for the type_info derived class. */
+/* The VAR_DECL of the vtable for the type_info derived class.
+   This is only filled in at the end of the translation. */
 #define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
-
-extern struct obstack permanent_obstack;
+/* The IDENTIFIER_NODE naming the real class. */
+#define TINFO_REAL_NAME(NODE) TREE_PURPOSE (NODE)
 
 static tree build_headof PARAMS((tree));
 static tree ifnonnull PARAMS((tree, tree));
@@ -48,7 +78,8 @@ static tree build_dynamic_cast_1 PARAMS((tree, tree));
 static tree throw_bad_cast PARAMS((void));
 static tree throw_bad_typeid PARAMS((void));
 static tree get_tinfo_decl_dynamic PARAMS((tree));
-static bool typeid_ok_p PARAMS ((void));
+static tree get_tinfo_ptr PARAMS((tree));
+static bool typeid_ok_p PARAMS((void));
 static int qualifier_flags PARAMS((tree));
 static int target_incomplete_p PARAMS((tree));
 static tree tinfo_base_init PARAMS((tree, tree));
@@ -59,15 +90,21 @@ static tree dfs_class_hint_mark PARAMS ((tree, void *));
 static tree dfs_class_hint_unmark PARAMS ((tree, void *));
 static int class_hint_flags PARAMS((tree));
 static tree class_initializer PARAMS((tree, tree, tree));
-static tree synthesize_tinfo_var PARAMS((tree));
-static tree create_real_tinfo_var PARAMS((tree, tree, tree, tree, int));
 static tree create_pseudo_type_info PARAMS((const char *, int, ...));
-static tree get_vmi_pseudo_type_info PARAMS((int));
+static tree get_pseudo_ti_init PARAMS ((tree, tree, int *));
+static tree get_pseudo_ti_desc PARAMS((tree));
 static void create_tinfo_types PARAMS((void));
 static int typeinfo_in_lib_p PARAMS((tree));
 
 static int doing_runtime = 0;
 \f
+
+/* Declare language defined type_info type and a pointer to const
+   type_info.  This is incomplete here, and will be completed when
+   the user #includes <typeinfo>.  There are language defined
+   restrictions on what can be done until that is included.  Create
+   the internal versions of the ABI types.  */
+
 void
 init_rtti_processing ()
 {
@@ -76,8 +113,11 @@ init_rtti_processing ()
     = xref_tag (class_type, get_identifier ("type_info"),
                /*attributes=*/NULL_TREE, 1);
   pop_namespace ();
-  tinfo_decl_type = 
-    build_qualified_type (type_info_type_node, TYPE_QUAL_CONST);
+  type_info_ptr_type = 
+    build_pointer_type
+     (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST));
+
+  create_tinfo_types ();
 }
 
 /* Given the expression EXP of type `class *', return the head of the
@@ -184,13 +224,12 @@ get_tinfo_decl_dynamic (exp)
       /* The RTTI information is at index -1.  */
       index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
       t = build_vtbl_ref (exp, index);
-      TREE_TYPE (t) = build_pointer_type (tinfo_decl_type);
+      TREE_TYPE (t) = type_info_ptr_type;
       return t;
     }
 
-  /* otherwise return the type_info for the static type of the expr.  */
-  exp = get_tinfo_decl (TYPE_MAIN_VARIANT (type));
-  return build_unary_op (ADDR_EXPR, exp, 0);
+  /* Otherwise return the type_info for the static type of the expr.  */
+  return get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
 }
 
 static bool
@@ -264,9 +303,9 @@ tinfo_name (type)
   return name_string;
 }
 
-/* Returns a decl for the type_info variable for TYPE.  You must
-   arrange that the decl is mark_used, if actually use it --- decls in
-   vtables are only used if the vtable is output.  */ 
+/* Return a VAR_DECL for the internal ABI defined type_info object for
+   TYPE. You must arrange that the decl is mark_used, if actually use
+   it --- decls in vtables are only used if the vtable is output.  */ 
 
 tree
 get_tinfo_decl (type)
@@ -279,7 +318,7 @@ get_tinfo_decl (type)
       && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
     {
       error ("cannot create type information for type `%T' because its size is variable", 
-               type);
+            type);
       return error_mark_node;
     }
 
@@ -292,36 +331,44 @@ get_tinfo_decl (type)
   name = mangle_typeinfo_for_type (type);
 
   d = IDENTIFIER_GLOBAL_VALUE (name);
-  if (d)
-    /* OK */;
-  else
+  if (!d)
     {
-      /* The tinfo decl is the type_info object itself.  We make all
-         tinfo objects look as type_info, even though they will end up
-         being a subclass of that when emitted.  This means that we'll
-         erroneously think we know the dynamic type -- be careful in the
-         runtime.  */
-      d = build_lang_decl (VAR_DECL, name, tinfo_decl_type);
+      tree var_desc = get_pseudo_ti_desc (type);
+
+      d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
       
       DECL_ARTIFICIAL (d) = 1;
-      DECL_ALIGN (d) = TYPE_ALIGN (ptr_type_node);
-      DECL_USER_ALIGN (d) = 0;
       TREE_READONLY (d) = 1;
       TREE_STATIC (d) = 1;
       DECL_EXTERNAL (d) = 1;
-      TREE_PUBLIC (d) = 1;
       SET_DECL_ASSEMBLER_NAME (d, name);
-      DECL_COMDAT (d) = 1;
       cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
 
       pushdecl_top_level (d);
+
       /* Remember the type it is for.  */
       TREE_TYPE (name) = type;
-      TREE_USED (name) = 1;
     }
+
   return d;
 }
 
+/* Return a pointer to a type_info object describing TYPE, suitably
+   cast to the language defined type.  */
+
+static tree
+get_tinfo_ptr (type)
+     tree type;
+{
+  tree exp = get_tinfo_decl (type);
+  
+   /* Convert to type_info type.  */
+  exp = build_unary_op (ADDR_EXPR, exp, 0);
+  exp = ocp_convert (type_info_ptr_type, exp, CONV_REINTERPRET, 0);
+
+  return exp;
+}
+
 /* Return the type_info object for TYPE.  */
 
 tree
@@ -350,7 +397,7 @@ get_typeid (type)
   if (!type)
     return error_mark_node;
 
-  return get_tinfo_decl (type);
+  return build_indirect_ref (get_tinfo_ptr (type), NULL);
 }
 
 /* Check whether TEST is null before returning RESULT.  If TEST is used in
@@ -684,6 +731,7 @@ tinfo_base_init (desc, target)
 {
   tree init = NULL_TREE;
   tree name_decl;
+  tree vtable_ptr;
   
   {
     tree name_name;
@@ -711,12 +759,41 @@ tinfo_base_init (desc, target)
     cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
     pushdecl_top_level (name_decl);
   }
-  
-  if (TINFO_VTABLE_DECL (desc))
+
+  vtable_ptr = TINFO_VTABLE_DECL (desc);
+  if (!vtable_ptr)
     {
-      tree vtbl_ptr = TINFO_VTABLE_DECL (desc);
-      init = tree_cons (NULL_TREE, vtbl_ptr, init);
+      tree real_type;
+  
+      push_nested_namespace (abi_node);
+      real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),
+                           /*attributes=*/NULL_TREE, 1);
+      pop_nested_namespace (abi_node);
+  
+      if (!COMPLETE_TYPE_P (real_type))
+       {
+          /* We never saw a definition of this type, so we need to
+            tell the compiler that this is an exported class, as
+            indeed all of the __*_type_info classes are.  */
+         SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
+         CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
+       }
+
+      vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
+      vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);
+
+      /* We need to point into the middle of the vtable.  */
+      vtable_ptr = build
+       (PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
+        size_binop (MULT_EXPR,
+                    size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
+                    TYPE_SIZE_UNIT (vtable_entry_type)));
+      TREE_CONSTANT (vtable_ptr) = 1;
+
+      TINFO_VTABLE_DECL (desc) = vtable_ptr;
     }
+
+  init = tree_cons (NULL_TREE, vtable_ptr, init);
   
   init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
   
@@ -765,8 +842,7 @@ ptr_initializer (desc, target, non_public_ptr)
     }
   init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
   init = tree_cons (NULL_TREE,
-                    build_unary_op (ADDR_EXPR,
-                                    get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
+                    get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                     init);
   
   init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
@@ -803,12 +879,11 @@ ptm_initializer (desc, target, non_public_ptr)
     }
   init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
   init = tree_cons (NULL_TREE,
-                    build_unary_op (ADDR_EXPR,
-                                    get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
+                   get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                     init);
   init = tree_cons (NULL_TREE,
-                    build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
-                    init);  
+                   get_tinfo_ptr (klass),
+                   init);  
   
   init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
   TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
@@ -929,81 +1004,63 @@ typeinfo_in_lib_p (type)
     }
 }
 
-/* Generate a pseudo_type_info VAR_DECL suitable for the supplied
-   TARGET_TYPE and corresponding to PUBLIC_DECL. This is the structure expected by
-   the runtime, and therefore has additional fields.  If we need not emit a
-   definition (because the runtime must contain it), return NULL_TREE,
-   otherwise return the VAR_DECL.  */
+/* Generate the initializer for the type info describing
+   TYPE. VAR_DESC is a . NON_PUBLIC_P is set non-zero, if the VAR_DECL
+   should not be exported from this object file.  This should only be
+   called at the end of translation, when we know that no further
+   types will be completed.  */
 
 static tree
-synthesize_tinfo_var (public_decl)
-     tree public_decl;
+get_pseudo_ti_init (type, var_desc, non_public_p)
+     tree type;
+     tree var_desc;
+     int *non_public_p;
 {
-  tree var_init = NULL_TREE;
-  tree var_type = NULL_TREE;
-  int non_public = 0;
-  tree target_type = TREE_TYPE (DECL_NAME (public_decl));
-  my_friendly_assert (target_type != NULL_TREE, 20000120);
-  
-  /* Say we've dealt with it.  */
-  TREE_TYPE (DECL_NAME (public_decl)) = NULL_TREE;
-  
-  switch (TREE_CODE (target_type))
+  my_friendly_assert (at_eof, 20021120);
+  switch (TREE_CODE (type))
     {
     case POINTER_TYPE:
-      if (TYPE_PTRMEM_P (target_type))
-        {
-          var_type = ptm_desc_type_node;
-          var_init = ptm_initializer (var_type, target_type, &non_public);
-        }
+      if (TYPE_PTRMEM_P (type))
+       return ptm_initializer (var_desc, type, non_public_p);
       else
-        {
-          if (typeinfo_in_lib_p (target_type) && !doing_runtime)
-            /* These are in the runtime.  */
-            return NULL_TREE;
-          var_type = ptr_desc_type_node;
-          var_init = ptr_initializer (var_type, target_type, &non_public);
-        }
+       return ptr_initializer (var_desc, type, non_public_p);
       break;
     case ENUMERAL_TYPE:
-      var_type = enum_desc_type_node;
-      var_init = generic_initializer (var_type, target_type);
+      return generic_initializer (var_desc, type);
       break;
     case FUNCTION_TYPE:
-      var_type = func_desc_type_node;
-      var_init = generic_initializer (var_type, target_type);
+      return generic_initializer (var_desc, type);
       break;
     case ARRAY_TYPE:
-      var_type = ary_desc_type_node;
-      var_init = generic_initializer (var_type, target_type);
+      return generic_initializer (var_desc, type);
       break;
     case UNION_TYPE:
     case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (target_type))
+      if (TYPE_PTRMEMFUNC_P (type))
+       return ptm_initializer (var_desc, type, non_public_p);
+      else if (var_desc == class_desc_type_node)
         {
-          var_type = ptm_desc_type_node;
-          var_init = ptm_initializer (var_type, target_type, &non_public);
-        }
-      else if (!COMPLETE_TYPE_P (target_type))
-        {
-          /* Emit a non-public class_type_info.  */
-          non_public = 1;
-          var_type = class_desc_type_node;
-          var_init = class_initializer (var_type, target_type, NULL_TREE);
-        }
-      else if (!CLASSTYPE_N_BASECLASSES (target_type))
-        {
-          var_type = class_desc_type_node;
-          var_init = class_initializer (var_type, target_type, NULL_TREE);
+         if (!COMPLETE_TYPE_P (type))
+           /* Emit a non-public class_type_info.  */
+           *non_public_p = 1;
+         return class_initializer (var_desc, type, NULL_TREE);
         }
+      else if (var_desc == si_class_desc_type_node)
+       {
+          tree base_binfos = BINFO_BASETYPES (TYPE_BINFO (type));
+         tree base_binfo = TREE_VEC_ELT (base_binfos, 0);
+         tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
+         tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
+         
+         return class_initializer (var_desc, type, base_inits);
+       }
       else
         {
-          /* if this has a single public non-virtual base, it's easier */
-          tree binfo = TYPE_BINFO (target_type);
+         int hint = class_hint_flags (type);
+         tree binfo = TYPE_BINFO (type);
           int nbases = BINFO_N_BASETYPES (binfo);
           tree base_binfos = BINFO_BASETYPES (binfo);
           tree base_inits = NULL_TREE;
-          int is_simple = nbases == 1;
           int ix;
           
           /* Generate the base information initializer.  */
@@ -1017,28 +1074,19 @@ synthesize_tinfo_var (public_decl)
               
               if (TREE_PUBLIC (base_binfo))
                 flags |= 2;
-              tinfo = get_tinfo_decl (BINFO_TYPE (base_binfo));
-              tinfo = build_unary_op (ADDR_EXPR, tinfo, 0);
+              tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
              if (TREE_VIA_VIRTUAL (base_binfo))
                {
                   /* We store the vtable offset at which the virtual
                              base offset can be found.  */
-                 offset = BINFO_VPTR_FIELD (binfo_for_vbase (BINFO_TYPE (base_binfo),
-                                                             target_type));
+                 offset = BINFO_VPTR_FIELD
+                   (binfo_for_vbase (BINFO_TYPE (base_binfo), type));
                  offset = convert (sizetype, offset);
                  flags |= 1;
                }
              else
                offset = BINFO_OFFSET (base_binfo);
               
-              /* is it a single public inheritance? */
-              if (is_simple && flags == 2 && integer_zerop (offset))
-                {
-                  base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
-                  break;
-                }
-              is_simple = 0;
-              
               /* combine offset and flags into one field */
               offset = cp_build_binary_op (LSHIFT_EXPR, offset,
                                           build_int_2 (8, 0));
@@ -1049,88 +1097,23 @@ synthesize_tinfo_var (public_decl)
               base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
               base_inits = tree_cons (NULL_TREE, base_init, base_inits);
             }
-          
-          if (is_simple)
-            var_type = si_class_desc_type_node;
-          else
-            {
-              int hint = class_hint_flags (target_type);
-              
-              base_inits = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_inits);
-              base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
-              /* Prepend the number of bases.  */
-              base_inits = tree_cons (NULL_TREE,
-                                      build_int_2 (nbases, 0), base_inits);
-              /* Prepend the hint flags. */
-              base_inits = tree_cons (NULL_TREE,
-                                      build_int_2 (hint, 0), base_inits);
-              var_type = get_vmi_pseudo_type_info (nbases);
-            }
-          var_init = class_initializer (var_type, target_type, base_inits);
+         base_inits = build (CONSTRUCTOR,
+                             NULL_TREE, NULL_TREE, base_inits);
+         base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
+         /* Prepend the number of bases.  */
+         base_inits = tree_cons (NULL_TREE,
+                                 build_int_2 (nbases, 0), base_inits);
+         /* Prepend the hint flags. */
+         base_inits = tree_cons (NULL_TREE,
+                                 build_int_2 (hint, 0), base_inits);
+
+          return class_initializer (var_desc, type, base_inits);
         }
       break;
 
     default:
-      if (typeinfo_in_lib_p (target_type))
-       {
-         if (!doing_runtime)
-           /* These are guaranteed to be in the runtime.  */
-           return NULL_TREE;
-         var_type = bltn_desc_type_node;
-         var_init = generic_initializer (var_type, target_type);
-         break;
-       }
-      abort ();
+      return generic_initializer (var_desc, type);
     }
-  
-  return create_real_tinfo_var (target_type,
-                               public_decl, TINFO_PSEUDO_TYPE (var_type),
-                                var_init, non_public);
-}
-
-/* Create the real typeinfo variable.  NON_PUBLIC indicates that we cannot
-   make this variable public (comdat). */
-
-static tree
-create_real_tinfo_var (target_type, public_decl, type, init, non_public)
-     tree target_type;
-     tree public_decl;
-     tree type;
-     tree init;
-     int non_public;
-{
-  static int count = 0;
-  tree decl;
-  tree hidden_name;
-  char hidden[30];
-  tree name = DECL_ASSEMBLER_NAME (public_decl);
-
-  /* We cannot give this the name NAME, as that already is globally
-     bound to the tinfo_decl we originally created for this type in
-     get_tinfo_decl. */
-  sprintf (hidden, "__ti_%d", count++);
-  hidden_name = get_identifier (hidden);
-  
-  decl = build_lang_decl (VAR_DECL, hidden_name,
-                          build_qualified_type (type, TYPE_QUAL_CONST));
-  DECL_ARTIFICIAL (decl) = 1;
-  TREE_READONLY (decl) = 1;
-  TREE_STATIC (decl) = 1;
-  DECL_EXTERNAL (decl) = 0;
-  
-  if (!non_public)
-    {
-      TREE_PUBLIC (decl) = 1;
-      if (flag_weak
-         || (DECL_COMDAT (public_decl) && !typeinfo_in_lib_p (target_type)))
-       comdat_linkage (decl);
-    }
-  SET_DECL_ASSEMBLER_NAME (decl, name);
-  DECL_INITIAL (decl) = init;
-  cp_finish_decl (decl, init, NULL_TREE, 0);
-  pushdecl_top_level (decl);
-  TREE_USED (decl) = 1;
-  return decl;
 }
 
 /* Generate the RECORD_TYPE containing the data layout of a type_info
@@ -1139,7 +1122,10 @@ create_real_tinfo_var (target_type, public_decl, type, init, non_public)
    type's vtable. We explicitly manage the vtable member, and name it for
    real type as used in the runtime. The RECORD type has a different name,
    to avoid collisions.  Return a TREE_LIST who's TINFO_PSEUDO_TYPE
-   is the generated type and TINFO_VTABLE_DECL is the vtable decl.
+   is the generated type and TINFO_VTABLE_NAME is the name of the
+   vtable.  We have to delay generating the VAR_DECL of the vtable
+   until the end of the translation, when we'll have seen the library
+   definition, if there was one.
    
    REAL_NAME is the runtime's name of the type. Trailing arguments are
    additional FIELD_DECL's for the structure. The final argument must be
@@ -1148,9 +1134,8 @@ create_real_tinfo_var (target_type, public_decl, type, init, non_public)
 static tree
 create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
 {
-  tree real_type, pseudo_type;
+  tree pseudo_type;
   char *pseudo_name;
-  tree vtable_decl;
   int ix;
   tree fields[10];
   tree field_decl;
@@ -1167,29 +1152,6 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
   if (ident)
     sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);
   
-  /* Get the vtable decl. */
-  real_type = xref_tag (class_type, get_identifier (real_name), 
-                       /*attributes=*/NULL_TREE, 1);
-  if (! TYPE_SIZE (real_type))
-    {
-      /* We never saw a definition of this type, so we need to tell the
-        compiler that this is an exported class, as indeed all of the
-        __*_type_info classes are.  */
-      SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
-      CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
-    }
-
-  vtable_decl = get_vtable_decl (real_type, /*complete=*/1);
-  vtable_decl = build_unary_op (ADDR_EXPR, vtable_decl, 0);
-
-  /* We need to point into the middle of the vtable.  */
-  vtable_decl
-    = build (PLUS_EXPR, TREE_TYPE (vtable_decl), vtable_decl,
-            size_binop (MULT_EXPR,
-                        size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
-                        TYPE_SIZE_UNIT (vtable_entry_type)));
-  TREE_CONSTANT (vtable_decl) = 1;
-
   /* First field is the pseudo type_info base class. */
   fields[0] = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
   
@@ -1203,53 +1165,96 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
   TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
 
   result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
-  TINFO_VTABLE_DECL (result) = vtable_decl;
-  TINFO_PSEUDO_TYPE (result) = pseudo_type;
+  TINFO_REAL_NAME (result) = get_identifier (real_name);
+  TINFO_PSEUDO_TYPE (result) =
+    cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
   
   VA_CLOSE (ap);
   return result;
 }
 
-/* Return a descriptor for a vmi type with NUM_BASES bases.  */
+/* Return a pseudo type info type node used to describe TYPE.  TYPE
+   must be a complete type (or cv void), except at the end of the
+   translation unit.  */
 
 static tree
-get_vmi_pseudo_type_info (num_bases)
-     int num_bases;
+get_pseudo_ti_desc (type)
+     tree type;
 {
-  tree desc;
-  tree array_domain, base_array;
-  
-  if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
+  switch (TREE_CODE (type))
     {
-      int ix;
-      tree extend = make_tree_vec (num_bases + 5);
-      
-      for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
-        TREE_VEC_ELT (extend, ix) = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
-      vmi_class_desc_type_node = extend;
-    }
-  desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
-  
-  if (desc)
-    return desc;
+    case POINTER_TYPE:
+      return TYPE_PTRMEM_P (type) ? ptm_desc_type_node : ptr_desc_type_node;
+    case ENUMERAL_TYPE:
+      return enum_desc_type_node;
+    case FUNCTION_TYPE:
+      return func_desc_type_node;
+    case ARRAY_TYPE:
+      return ary_desc_type_node;
+    case UNION_TYPE:
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (type))
+       return ptm_desc_type_node;
+      else if (!COMPLETE_TYPE_P (type))
+       {
+         my_friendly_assert (at_eof, 20020609);
+         return class_desc_type_node;
+       }
+      else if (!CLASSTYPE_N_BASECLASSES (type))
+       return class_desc_type_node;
+      else
+       {
+         tree base_binfo =
+           TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)), 0);
+         int num_bases = BINFO_N_BASETYPES (TYPE_BINFO (type));
+         
+         if (num_bases == 1
+             && TREE_PUBLIC (base_binfo)
+             && !TREE_VIA_VIRTUAL (base_binfo)
+             && integer_zerop (BINFO_OFFSET (base_binfo)))
+           /* single non-virtual public. */
+           return si_class_desc_type_node;
+         else
+           {
+             tree var_desc;
+             tree array_domain, base_array;
+             
+             if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
+               {
+                 int ix;
+                 tree extend = make_tree_vec (num_bases + 5);
+                 
+                 for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
+                   TREE_VEC_ELT (extend, ix)
+                     = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
+                 vmi_class_desc_type_node = extend;
+               }
+             var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
+             if (var_desc)
+               return var_desc;
   
-  /* Add number of bases and trailing array of base_class_type_info.  */
-  array_domain = build_index_type (size_int (num_bases));
-  base_array = build_array_type (base_desc_type_node, array_domain);
-
-  push_nested_namespace (abi_node);
-
-  desc = create_pseudo_type_info
-            ("__vmi_class_type_info", num_bases,
-             build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-             build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-             build_decl (FIELD_DECL, NULL_TREE, base_array),
-             NULL);
-
-  pop_nested_namespace (abi_node);
-
-  TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = desc;
-  return desc;
+             /* Add number of bases and trailing array of
+                base_class_type_info.  */
+             array_domain = build_index_type (size_int (num_bases));
+             base_array =
+               build_array_type (base_desc_type_node, array_domain);
+
+             push_nested_namespace (abi_node);
+             var_desc = create_pseudo_type_info
+               ("__vmi_class_type_info", num_bases,
+                build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
+                build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
+                build_decl (FIELD_DECL, NULL_TREE, base_array),
+                NULL);
+             pop_nested_namespace (abi_node);
+
+             TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;
+             return var_desc;
+           }
+       }
+    default:
+      return bltn_desc_type_node;
+    }
 }
 
 /* Make sure the required builtin types exist for generating the type_info
@@ -1258,15 +1263,9 @@ get_vmi_pseudo_type_info (num_bases)
 static void
 create_tinfo_types ()
 {
-  tree ptr_type_info;
-  
-  if (bltn_desc_type_node)
-    return;
-  push_nested_namespace (abi_node);
+  my_friendly_assert (!ti_desc_type_node, 20020609);
 
-  ptr_type_info = build_pointer_type
-                    (build_qualified_type
-                      (type_info_type_node, TYPE_QUAL_CONST));
+  push_nested_namespace (abi_node);
   
   /* Create the internal type_info structure. This is used as a base for
      the other structures.  */
@@ -1306,7 +1305,7 @@ create_tinfo_types ()
      This is really a descendant of __class_type_info.  */
   si_class_desc_type_node = create_pseudo_type_info
            ("__si_class_type_info", 0,
-            build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+            build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
             NULL);
   
   /* Base class internal helper. Pointer to base type, offset to base,
@@ -1314,7 +1313,7 @@ create_tinfo_types ()
   {
     tree fields[2];
     
-    fields[0] = build_decl (FIELD_DECL, NULL_TREE, ptr_type_info);
+    fields[0] = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);
     fields[1] = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
     base_desc_type_node = make_aggr_type (RECORD_TYPE);
     finish_builtin_type (base_desc_type_node, "__base_class_type_info_pseudo",
@@ -1331,7 +1330,7 @@ create_tinfo_types ()
   ptr_desc_type_node = create_pseudo_type_info
       ("__pointer_type_info", 0,
        build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-       build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+       build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
        NULL);
 
   /* Pointer to member data type_info.  Add qualifications flags,
@@ -1340,8 +1339,8 @@ create_tinfo_types ()
   ptm_desc_type_node = create_pseudo_type_info
        ("__pointer_to_member_type_info", 0,
         build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-        build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
-        build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+        build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
+        build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
         NULL);
 
   pop_nested_namespace (abi_node);
@@ -1410,72 +1409,59 @@ emit_support_tinfos ()
    definition emitted for it.  */
 
 int
-tinfo_decl_p (t, data)
+unemitted_tinfo_decl_p (t, data)
      tree t;
      void *data ATTRIBUTE_UNUSED;
 {
-  return TREE_CODE (t) == VAR_DECL
-         && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == (t)
-         && TREE_TYPE (t) == tinfo_decl_type
-         && TREE_TYPE (DECL_NAME (t));
+  if (/* It's a var decl */
+      TREE_CODE (t) == VAR_DECL
+      /* whos name points back to itself */
+      && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
+      /* whos name's type is non-null */
+      && TREE_TYPE (DECL_NAME (t))
+      /* and whos type is a struct */
+      && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
+      /* with a first field of our pseudo type info */
+      && TREE_TYPE (TYPE_FIELDS (TREE_TYPE (t))) == ti_desc_type_node)
+    return 1;
+  return 0;
 }
 
-/* Emit a suitable type_info definition for the type_info decl pointed to by
-   DECL_PTR. We emit a completely new variable, of the correct type for the
-   actual type this is describing. The DECL_ASSEMBLER_NAME of the generated
-   definition is set to that of the supplied decl, so that they can be tied
-   up. Mark the supplied decl as having been dealt with. Emitting one
-   definition might cause other definitions to be required.
-   
-   We need to do things this way, because we're trying to do something like
-   
-      struct B : A {
-        ...
-      };
-   
-      extern const A tinfo_var;
-   
-      const B tinfo_var = {...};
-   
-   which is not permitted. Also, we've not necessarily seen the definition of B.
-   So we do something like the following,
-   
-      extern const A tinfo_var;
-   
-      struct pseudo_A {
-        const void *vtable_ptr;
-        const char *name;
-      };
-      struct pseudo_B {
-        pseudo_A base;
-        ...
-      };
-      
-      const pseudo_B proxy_tinfo_var attribute((assembler_name="tinfo_var")) =
-      {
-        {&B::vtable, "..."},
-        ...
-      };
-   
-   pseudo_A and pseudo_B must be layout equivalent to the real definitions in
-   the runtime.  */
+/* Finish a type info decl. DECL_PTR is a pointer to an unemitted
+   tinfo decl.  Determine whether it needs emitting, and if so
+   generate the initializer.  */
 
 int
 emit_tinfo_decl (decl_ptr, data)
      tree *decl_ptr;
      void *data ATTRIBUTE_UNUSED;
 {
-  tree tinfo_decl = *decl_ptr;
-  tree decl;
+  tree decl = *decl_ptr;
+  tree type = TREE_TYPE (DECL_NAME (decl));
+  int non_public;
+  tree var_desc, var_init;
   
-  my_friendly_assert (TREE_TYPE (tinfo_decl) == tinfo_decl_type, 20000121);
+  import_export_tinfo (decl, type);
+  if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
+    return 0;
 
-  import_export_decl (tinfo_decl);
-  if (DECL_REALLY_EXTERN (tinfo_decl) || !DECL_NEEDED_P (tinfo_decl))
+  if (!doing_runtime && typeinfo_in_lib_p (type))
     return 0;
 
-  create_tinfo_types ();
-  decl = synthesize_tinfo_var (tinfo_decl);
+  non_public = 0;
+  var_desc = get_pseudo_ti_desc (type);
+  var_init = get_pseudo_ti_init (type, var_desc, &non_public);
+  DECL_EXTERNAL (decl) = 0;
+  TREE_PUBLIC (decl) = !non_public;
+  if (!non_public
+      && (flag_weak || (DECL_COMDAT (decl) && !typeinfo_in_lib_p (type))))
+    comdat_linkage (decl);
   
-  return decl != 0;
+  DECL_INITIAL (decl) = var_init;
+  cp_finish_decl (decl, var_init, NULL_TREE, 0);
+  
+  /* Say we've dealt with it.  */
+  TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
+
+  return 1;
 }