OSDN Git Service

In include:
[pf3gnuchains/gcc-fork.git] / gcc / cp / rtti.c
index 5ee1d11..94e67a5 100644 (file)
@@ -62,14 +62,17 @@ static tree throw_bad_typeid PARAMS((void));
 static tree get_tinfo_decl_dynamic PARAMS((tree));
 static tree tinfo_from_decl PARAMS((tree));
 static int qualifier_flags PARAMS((tree));
+static int target_incomplete_p PARAMS((tree));
 static tree tinfo_base_init PARAMS((tree, tree));
 static tree generic_initializer PARAMS((tree, tree));
-static tree ptr_initializer PARAMS((tree, tree));
-static tree ptmd_initializer PARAMS((tree, tree));
+static tree ptr_initializer PARAMS((tree, tree, int *));
+static tree ptm_initializer PARAMS((tree, tree, int *));
+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, tree));
-static tree create_real_tinfo_var PARAMS((tree, tree, tree));
+static tree create_real_tinfo_var PARAMS((tree, tree, tree, int));
 static tree create_pseudo_type_info PARAMS((const char *, int, ...));
 static tree get_vmi_pseudo_type_info PARAMS((int));
 static void create_tinfo_types PARAMS((void));
@@ -93,14 +96,16 @@ init_rtti_processing ()
           (build_qualified_type
             (type_info_type_node, TYPE_QUAL_CONST)),
          void_list_node);
+      tinfo_var_id = get_identifier ("__ti");
     }
   else
     {
+      /* FIXME: These identifier prefixes are not set in stone yet.  */
       tinfo_decl_id = get_identifier ("__ti");
+      tinfo_var_id = get_identifier ("__tn");
       tinfo_decl_type = build_qualified_type
                           (type_info_type_node, TYPE_QUAL_CONST);
     }
-  tinfo_var_id = get_identifier ("__ti");
 }
 
 /* Given a pointer to an object with at least one virtual table
@@ -132,6 +137,7 @@ build_headof (exp)
   tree type = TREE_TYPE (exp);
   tree aref;
   tree offset;
+  tree index;
 
   my_friendly_assert (TREE_CODE (type) == POINTER_TYPE, 20000112);
   type = TREE_TYPE (type);
@@ -151,7 +157,15 @@ build_headof (exp)
   /* We use this a couple of times below, protect it.  */
   exp = save_expr (exp);
 
-  aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node);
+  /* Under the new ABI, the offset-to-top field is at index -2 from
+     the vptr.  */
+  if (new_abi_rtti_p ())
+    index = build_int_2 (-2, -1);
+  /* But under the old ABI, it is at offset zero.  */
+  else
+    index = integer_zero_node;
+
+  aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), index);
 
   if (flag_vtable_thunks)
     offset = aref;
@@ -219,7 +233,7 @@ get_tinfo_decl_dynamic (exp)
   /* Peel off cv qualifiers.  */
   type = TYPE_MAIN_VARIANT (type);
   
-  if (type != void_type_node)
+  if (!VOID_TYPE_P (type))
     type = complete_type_or_else (type, exp);
   
   if (!type)
@@ -230,6 +244,7 @@ get_tinfo_decl_dynamic (exp)
     {
       /* build reference to type_info from vtable.  */
       tree t;
+      tree index;
 
       if (! flag_rtti)
        error ("taking dynamic typeid of object with -fno-rtti");
@@ -247,10 +262,15 @@ get_tinfo_decl_dynamic (exp)
          exp = build_indirect_ref (exp, NULL_PTR);
        }
 
-      if (flag_vtable_thunks)
-       t = build_vfn_ref ((tree *) 0, exp, integer_one_node);
+      /* The RTTI information is always in the vtable, but it's at
+        different indices depending on the ABI.  */
+      if (new_abi_rtti_p ())
+       index = minus_one_node;
+      else if (flag_vtable_thunks)
+       index = integer_one_node;
       else
-       t = build_vfn_ref ((tree *) 0, exp, integer_zero_node);
+       index = integer_zero_node;
+      t = build_vfn_ref ((tree *) 0, exp, index);
       TREE_TYPE (t) = build_pointer_type (tinfo_decl_type);
       return t;
     }
@@ -357,8 +377,14 @@ static tree
 tinfo_name (type)
      tree type;
 {
-  const char *name = build_overload_name (type, 1, 1);
-  tree name_string = combine_strings (build_string (strlen (name) + 1, name));
+  const char *name;
+  tree name_string;
+
+  if (flag_new_abi)
+    name = mangle_type_string (type);
+  else
+    name = build_overload_name (type, 1, 1);
+  name_string = combine_strings (build_string (strlen (name) + 1, name));
   return name_string;
 }
 
@@ -383,20 +409,23 @@ get_tinfo_decl (type)
     type = build_function_type (TREE_TYPE (type),
                                TREE_CHAIN (TYPE_ARG_TYPES (type)));
 
-  name = build_overload_with_type (tinfo_decl_id, type);
+  if (flag_new_abi)
+    name = mangle_typeinfo_for_type (type);
+  else
+    name = build_overload_with_type (tinfo_decl_id, type);
 
   d = IDENTIFIER_GLOBAL_VALUE (name);
   if (d)
     /* OK */;
   else if (!new_abi_rtti_p ())
     {
-      /* The tinfo decl is a function returning a reference to the type_info
-         object.  */
+      /* The tinfo decl is a function returning a reference to the
+        type_info object.  */
       d = push_library_fn (name, tinfo_decl_type);
       DECL_NOT_REALLY_EXTERN (d) = 1;
       SET_DECL_TINFO_FN_P (d);
       TREE_TYPE (name) = type;
-      mark_inline_for_output (d);
+      defer_fn (d);
     }
   else
     {
@@ -409,6 +438,7 @@ get_tinfo_decl (type)
       
       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;
@@ -420,6 +450,7 @@ get_tinfo_decl (type)
       pushdecl_top_level (d);
       /* Remember the type it is for.  */
       TREE_TYPE (name) = type;
+      TREE_USED (name) = 1;
     }
   return d;
 }
@@ -482,7 +513,7 @@ get_typeid (type)
      that is the operand of typeid are always ignored.  */
   type = TYPE_MAIN_VARIANT (type);
 
-  if (type != void_type_node)
+  if (!VOID_TYPE_P (type))
     type = complete_type_or_else (type, NULL_TREE);
   
   if (!type)
@@ -513,30 +544,38 @@ get_base_offset (binfo, parent)
      tree binfo;
      tree parent;
 {
-  tree offset;
-  
-  if (!TREE_VIA_VIRTUAL (binfo))
-    offset = BINFO_OFFSET (binfo);
-  else if (!vbase_offsets_in_vtable_p ())
+  if (! TREE_VIA_VIRTUAL (binfo))
+    return BINFO_OFFSET (binfo);
+  else if (! vbase_offsets_in_vtable_p ())
     {
-      tree t = BINFO_TYPE (binfo);
       const char *name;
+      tree result;
       tree field;
     
-      FORMAT_VBASE_NAME (name, t);
+      FORMAT_VBASE_NAME (name, BINFO_TYPE (binfo));
       field = lookup_field (parent, get_identifier (name), 0, 0);
-      offset = size_binop (FLOOR_DIV_EXPR, bit_position (field), 
-                          bitsize_int (BITS_PER_UNIT));
-      offset = convert (sizetype, offset);
+      result = byte_position (field);
+      
+      if (DECL_CONTEXT (field) != parent)
+        {
+          /* The vbase pointer might be in a non-virtual base of PARENT.
+           * Adjust for the offset of that base in PARENT.  */
+          tree path;
+          
+          get_base_distance (DECL_CONTEXT (field), parent, -1, &path);
+          result = build (PLUS_EXPR, TREE_TYPE (result),
+                          result, BINFO_OFFSET (path));
+          result = fold (result);
+        }
+      return result;
     }
   else
-    {
-      /* Under the new ABI, we store the vtable offset at which
-         the virtual base offset can be found.  */
-      tree vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), parent);
-      offset = convert (sizetype, BINFO_VPTR_FIELD (vbase));
-    }
-  return offset;
+    /* Under the new ABI, we store the vtable offset at which
+       the virtual base offset can be found.  */
+    return convert (sizetype,
+                   BINFO_VPTR_FIELD (binfo_for_vbase (BINFO_TYPE (binfo),
+                                                      parent)));
+
 }
 
 /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
@@ -547,10 +586,10 @@ build_dynamic_cast_1 (type, expr)
      tree type, expr;
 {
   enum tree_code tc = TREE_CODE (type);
-  tree exprtype;
+  tree exprtype = TREE_TYPE (expr);
   tree dcast_fn;
   tree old_expr = expr;
-  char* errstr = NULL;
+  const char *errstr = NULL;
 
   /* T shall be a pointer or reference to a complete class type, or
      `pointer to cv void''.  */
@@ -578,10 +617,10 @@ build_dynamic_cast_1 (type, expr)
     }
 
   if (TREE_CODE (expr) == OFFSET_REF)
-    expr = resolve_offset_ref (expr);
-
-  exprtype = TREE_TYPE (expr);
-  assert (exprtype != NULL_TREE);
+    {
+      expr = resolve_offset_ref (expr);
+      exprtype = TREE_TYPE (expr);
+    }
 
   if (tc == POINTER_TYPE)
     expr = convert_from_reference (expr);
@@ -665,7 +704,12 @@ build_dynamic_cast_1 (type, expr)
       }
 
     if (distance >= 0)
-      return build_vbase_path (PLUS_EXPR, type, expr, path, 0);
+      {
+       expr = build_vbase_path (PLUS_EXPR, type, expr, path, 0);
+       if (TREE_CODE (exprtype) == POINTER_TYPE)
+         expr = non_lvalue (expr);
+       return expr;
+      }
   }
 
   /* Otherwise *exprtype must be a polymorphic class (have a vtbl).  */
@@ -673,8 +717,7 @@ build_dynamic_cast_1 (type, expr)
     {
       tree expr1;
       /* if TYPE is `void *', return pointer to complete object.  */
-      if (tc == POINTER_TYPE
-         && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+      if (tc == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (type)))
        {
          /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b.  */
          if (TREE_CODE (expr) == ADDR_EXPR
@@ -803,11 +846,7 @@ build_dynamic_cast_1 (type, expr)
                          (NULL_TREE, ptrdiff_type_node, void_list_node))));
                }
              tmp = build_function_type (ptr_type_node, tmp);
-             if (new_abi_rtti_p ())
-               /* We want its name mangling.  */
-               dcast_fn = build_cp_library_fn_ptr (name, tmp);
-             else
-               dcast_fn = build_library_fn_ptr (name, tmp);
+             dcast_fn = build_library_fn_ptr (name, tmp);
               pop_nested_namespace (ns);
               dynamic_cast_node = dcast_fn;
            }
@@ -911,11 +950,6 @@ expand_class_desc (tdecl, type)
   int i = CLASSTYPE_N_BASECLASSES (type);
   int base_cnt = 0;
   tree binfos = TYPE_BINFO_BASETYPES (type);
-#if 0
-  /* See code below that used these.  */
-  tree vb = CLASSTYPE_VBASECLASSES (type);
-  int n_base = i;
-#endif
   tree base, elems, access, offset, isvir;
   tree elt, elts = NULL_TREE;
 
@@ -928,23 +962,23 @@ expand_class_desc (tdecl, type)
       base_desc_type_node = make_aggr_type (RECORD_TYPE);
 
       /* Actually const __user_type_info * */
-      fields [0] = build_lang_decl
+      fields [0] = build_decl
        (FIELD_DECL, NULL_TREE,
         build_pointer_type (build_qualified_type
                             (type_info_type_node,
                              TYPE_QUAL_CONST)));
-      fields [1] = build_lang_decl
+      fields [1] = build_decl
        (FIELD_DECL, NULL_TREE, 
         flag_new_abi ? intSI_type_node : unsigned_intSI_type_node);
       DECL_BIT_FIELD (fields[1]) = 1;
       DECL_SIZE (fields[1]) = bitsize_int (29);
 
-      fields [2] = build_lang_decl (FIELD_DECL, NULL_TREE, boolean_type_node);
+      fields [2] = build_decl (FIELD_DECL, NULL_TREE, boolean_type_node);
       DECL_BIT_FIELD (fields[2]) = 1;
-      DECL_SIZE (fields[2]) = bitsize_int (1);
+      DECL_SIZE (fields[2]) = bitsize_one_node;
 
       /* Actually enum access */
-      fields [3] = build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node);
+      fields [3] = build_decl (FIELD_DECL, NULL_TREE, integer_type_node);
       DECL_BIT_FIELD (fields[3]) = 1;
       DECL_SIZE (fields[3]) = bitsize_int (2);
 
@@ -981,39 +1015,6 @@ expand_class_desc (tdecl, type)
       elts = tree_cons (NULL_TREE, elt, elts);
       base_cnt++;
     }
-#if 0
-  i = n_base;
-  while (vb)
-    {
-      tree b;
-      access = access_public_node;
-      while (--i >= 0)
-       {
-         b = TREE_VEC_ELT (binfos, i);
-         if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))
-           {
-             if (TREE_VIA_PUBLIC (b))
-               access = access_public_node;
-             else if (TREE_VIA_PROTECTED (b))
-               access = access_protected_node;
-             else
-               access = access_private_node;
-             break;
-           }
-       }
-      base = build_t_desc (BINFO_TYPE (vb), 1);
-      offset = BINFO_OFFSET (vb);
-      isvir = build_int_2 (1, 0);
-
-      base_list = tree_cons (NULL_TREE, base, base_list);
-      isvir_list = tree_cons (NULL_TREE, isvir, isvir_list);
-      acc_list = tree_cons (NULL_TREE, access, acc_list);
-      off_list = tree_cons (NULL_TREE, offset, off_list);
-
-      base_cnt++;
-      vb = TREE_CHAIN (vb);
-    }
-#endif
 
   name_string = tinfo_name (type);
 
@@ -1190,6 +1191,7 @@ synthesize_tinfo_fn (fndecl)
   DECL_COMMON (tdecl) = 1;
   TREE_USED (tdecl) = 1;
   DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node);
+  DECL_USER_ALIGN (tdecl) = 0;
   cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0);
 
   /* Begin processing the function.  */
@@ -1211,7 +1213,7 @@ synthesize_tinfo_fn (fndecl)
   if_stmt = begin_if_stmt ();
   tmp = cp_convert (build_pointer_type (ptr_type_node), addr);
   tmp = build_indirect_ref (tmp, 0);
-  tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node);
+  tmp = cp_build_binary_op (EQ_EXPR, tmp, integer_zero_node);
   finish_if_stmt_cond (tmp, if_stmt);
   then_clause = begin_compound_stmt (/*has_no_scope=*/0);
 
@@ -1258,7 +1260,7 @@ synthesize_tinfo_fn (fndecl)
   finish_return_stmt (tmp);
   /* Finish the function body.  */
   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
-  expand_body (finish_function (lineno, 0));
+  expand_body (finish_function (0));
 }
 
 /* Return the runtime bit mask encoding the qualifiers of TYPE.  */
@@ -1275,28 +1277,86 @@ qualifier_flags (type)
     flags |= 1;
   if (quals & TYPE_QUAL_VOLATILE)
     flags |= 2;
+  if (quals & TYPE_QUAL_RESTRICT)
+    flags |= 4;
   return flags;
 }
 
+/* Return non-zero, if the pointer chain TYPE ends at an incomplete type, or
+   contains a pointer to member of an incomplete class.  */
+
+static int
+target_incomplete_p (type)
+     tree type;
+{
+  while (TREE_CODE (type) == POINTER_TYPE)
+    if (TYPE_PTRMEM_P (type))
+      {
+        if (!COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)))
+          return 1;
+        type = TYPE_PTRMEM_POINTED_TO_TYPE (type);
+      }
+    else
+      type = TREE_TYPE (type);
+  if (!COMPLETE_OR_VOID_TYPE_P (type))
+    return 1;
+  
+  return 0;
+}
+
 /* Return a CONSTRUCTOR for the common part of the type_info objects. This
-   is the vtable pointer and NTBS name.  */
+   is the vtable pointer and NTBS name.  The NTBS name is emitted as a
+   comdat const char array, so it becomes a unique key for the type. Generate
+   and emit that VAR_DECL here.  (We can't always emit the type_info itself
+   as comdat, because of pointers to incomplete.) */
 
 static tree
 tinfo_base_init (desc, target)
      tree desc;
      tree target;
 {
-  tree name_string = tinfo_name (target);
   tree init = NULL_TREE;
+  tree name_decl;
+  
+  {
+    tree name_name;
+    
+    /* Generate the NTBS array variable.  */
+    tree name_type = build_cplus_array_type
+                     (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+                     NULL_TREE);
+    tree name_string = tinfo_name (target);
+
+    if (flag_new_abi)
+      name_name = mangle_typeinfo_for_type (target);
+    else
+      name_name = build_overload_with_type (tinfo_var_id, target);
+    name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
+    
+    DECL_ARTIFICIAL (name_decl) = 1;
+    TREE_READONLY (name_decl) = 1;
+    TREE_STATIC (name_decl) = 1;
+    DECL_EXTERNAL (name_decl) = 0;
+    TREE_PUBLIC (name_decl) = 1;
+    comdat_linkage (name_decl);
+    if (flag_new_abi)
+      /* The new ABI specifies the external name of the string
+        containing the type's name.  */
+      DECL_ASSEMBLER_NAME (name_decl) 
+       = mangle_typeinfo_string_for_type (target);
+    else
+      DECL_ASSEMBLER_NAME (name_decl) = DECL_NAME (name_decl);
+    DECL_INITIAL (name_decl) = name_string;
+    cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
+  }
   
   if (TINFO_VTABLE_DECL (desc))
     {
-      tree vtbl_ptr = build_unary_op (ADDR_EXPR, TINFO_VTABLE_DECL (desc), 0);
-  
+      tree vtbl_ptr = TINFO_VTABLE_DECL (desc);
       init = tree_cons (NULL_TREE, vtbl_ptr, init);
     }
   
-  init = tree_cons (NULL_TREE, decay_conversion (name_string), init);
+  init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
   
   init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
   TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
@@ -1326,14 +1386,21 @@ generic_initializer (desc, target)
    which adds target type and qualifier flags members to the type_info base.  */
 
 static tree
-ptr_initializer (desc, target)
+ptr_initializer (desc, target, non_public_ptr)
      tree desc;
      tree target;
+     int *non_public_ptr;
 {
   tree init = tinfo_base_init (desc, target);
   tree to = TREE_TYPE (target);
   int flags = qualifier_flags (to);
+  int incomplete = target_incomplete_p (to);
   
+  if (incomplete)
+    {
+      flags |= 8;
+      *non_public_ptr = 1;
+    }
   init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
   init = tree_cons (NULL_TREE,
                     build_unary_op (ADDR_EXPR,
@@ -1347,49 +1414,110 @@ ptr_initializer (desc, target)
 
 /* Return the CONSTRUCTOR expr for a type_info of pointer to member data TYPE.
    DESC provides information about the particular type_info derivation,
-   which adds target type and qualifier flags members to the type_info base.  */
+   which adds class, target type and qualifier flags members to the type_info
+   base.  */
 
 static tree
-ptmd_initializer (desc, target)
+ptm_initializer (desc, target, non_public_ptr)
      tree desc;
      tree target;
+     int *non_public_ptr;
 {
   tree init = tinfo_base_init (desc, target);
   tree to = TYPE_PTRMEM_POINTED_TO_TYPE (target);
   tree klass = TYPE_PTRMEM_CLASS_TYPE (target);
   int flags = qualifier_flags (to);
+  int incomplete = target_incomplete_p (to);
   
-  init = tree_cons (NULL_TREE,
-                    build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
-                    init);  
+  if (incomplete)
+    {
+      flags |= 0x8;
+      *non_public_ptr = 1;
+    }
+  if (!COMPLETE_TYPE_P (klass))
+    {
+      flags |= 0x10;
+      *non_public_ptr = 1;
+    }
+  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),
                     init);
-  init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
+  init = tree_cons (NULL_TREE,
+                    build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
+                    init);  
   
   init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
   TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
   return init;  
 }
 
-/* Determine the hint flags describing the features of a class's heirarchy.
-   FIXME: better set the hint_flags here!  For now set them
-   to safe 'don't know' values.  The specification is under
-   review.  Don't forget to check the runtime dynamic_cast and
-   catch machinery if these change.  */
+/* Check base BINFO to set hint flags in *DATA, which is really an int.
+   We use CLASSTYPE_MARKED to tag types we've found as non-virtual bases and
+   CLASSTYPE_MARKED2 to tag those which are virtual bases. Remember it is
+   possible for a type to be both a virtual and non-virtual base.  */
+
+static tree
+dfs_class_hint_mark (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree basetype = BINFO_TYPE (binfo);
+  int *hint = (int *) data;
+  
+  if (TREE_VIA_VIRTUAL (binfo))
+    {
+      if (CLASSTYPE_MARKED (basetype))
+        *hint |= 1;
+      if (CLASSTYPE_MARKED2 (basetype))
+        *hint |= 2;
+      SET_CLASSTYPE_MARKED2 (basetype);
+    }
+  else
+    {
+      if (CLASSTYPE_MARKED (basetype) || CLASSTYPE_MARKED2 (basetype))
+        *hint |= 1;
+      SET_CLASSTYPE_MARKED (basetype);
+    }
+  if (!TREE_VIA_PUBLIC (binfo) && TYPE_BINFO (basetype) != binfo)
+    *hint |= 4;
+  return NULL_TREE;
+};
+
+/* Clear the base's dfs marks, after searching for duplicate bases. */
+
+static tree
+dfs_class_hint_unmark (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  tree basetype = BINFO_TYPE (binfo);
+  
+  CLEAR_CLASSTYPE_MARKED (basetype);
+  CLEAR_CLASSTYPE_MARKED2 (basetype);
+  return NULL_TREE;
+}
+
+/* Determine the hint flags describing the features of a class's heirarchy.  */
 
 static int
 class_hint_flags (type)
      tree type;
 {
   int hint_flags = 0;
-  hint_flags |= 0x1;  /* contains multiply inherited sub object */
-  hint_flags |= 0x4;  /* has virtual bases */
-  hint_flags |= 0x8;  /* has private base */
-  if (TYPE_POLYMORPHIC_P (type))
-    hint_flags |= 0x2;
+  int i;
   
+  dfs_walk (TYPE_BINFO (type), dfs_class_hint_mark, NULL, &hint_flags);
+  dfs_walk (TYPE_BINFO (type), dfs_class_hint_unmark, NULL, NULL);
+  
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); ++i)
+    {
+      tree base_binfo = BINFO_BASETYPE (TYPE_BINFO (type), i);
+      
+      if (TREE_VIA_PUBLIC (base_binfo))
+        hint_flags |= 0x8;
+    }
   return hint_flags;
 }
         
@@ -1404,9 +1532,7 @@ class_initializer (desc, target, trail)
      tree trail;
 {
   tree init = tinfo_base_init (desc, target);
-  int flags = class_hint_flags (target);
   
-  trail = tree_cons (NULL_TREE, build_int_2 (flags, 0), trail);
   TREE_CHAIN (init) = trail;
   init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, init);
   TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
@@ -1426,6 +1552,7 @@ synthesize_tinfo_var (target_type, real_name)
 {
   tree var_init = NULL_TREE;
   tree var_type = NULL_TREE;
+  int non_public = 0;
   
   my_friendly_assert (new_abi_rtti_p (), 20000118);
 
@@ -1434,8 +1561,8 @@ synthesize_tinfo_var (target_type, real_name)
     case POINTER_TYPE:
       if (TYPE_PTRMEM_P (target_type))
         {
-          var_type = ptmd_desc_type_node;
-          var_init = ptmd_initializer (var_type, target_type);
+          var_type = ptm_desc_type_node;
+          var_init = ptm_initializer (var_type, target_type, &non_public);
         }
       else
         {
@@ -1450,7 +1577,7 @@ synthesize_tinfo_var (target_type, real_name)
             /* These are in the runtime.  */
             return NULL_TREE;
           var_type = ptr_desc_type_node;
-          var_init = ptr_initializer (var_type, target_type);
+          var_init = ptr_initializer (var_type, target_type, &non_public);
         }
       break;
     case ENUMERAL_TYPE:
@@ -1467,10 +1594,17 @@ synthesize_tinfo_var (target_type, real_name)
       break;
     case UNION_TYPE:
     case RECORD_TYPE:
-      if (!COMPLETE_TYPE_P (target_type))
+      if (TYPE_PTRMEMFUNC_P (target_type))
         {
-          /* FIXME: incomplete type. Awaiting specification.  */
-          return NULL_TREE;
+          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))
         {
@@ -1512,8 +1646,11 @@ synthesize_tinfo_var (target_type, real_name)
                 }
               is_simple = 0;
               
-              base_init = tree_cons
-                  (NULL_TREE, build_int_2 (flags, 0), base_init);
+              /* combine offset and flags into one field */
+              offset = cp_build_binary_op (LSHIFT_EXPR, offset,
+                                          build_int_2 (8, 0));
+              offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
+                                          build_int_2 (flags, 0));
               base_init = tree_cons (NULL_TREE, offset, base_init);
               base_init = tree_cons (NULL_TREE, tinfo, base_init);
               base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
@@ -1524,12 +1661,16 @@ synthesize_tinfo_var (target_type, real_name)
             var_type = si_class_desc_type_node;
           else
             {
-              /* Prepend the number of bases.  */
+              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);
@@ -1550,32 +1691,48 @@ synthesize_tinfo_var (target_type, real_name)
       my_friendly_abort (20000117);
     }
   
-  return create_real_tinfo_var (real_name, TINFO_PSEUDO_TYPE (var_type), var_init);
+  
+  return create_real_tinfo_var (real_name, TINFO_PSEUDO_TYPE (var_type),
+                                var_init, non_public);
 }
 
-/* Create the real typeinfo variable.  */
+/* Create the real typeinfo variable.  NON_PUBLIC indicates that we cannot
+   make this variable public (comdat). */
 
 static tree
-create_real_tinfo_var (name, type, init)
+create_real_tinfo_var (name, type, init, non_public)
      tree name;
      tree type;
      tree init;
+     int non_public;
 {
+  static int count = 0;
   tree decl;
+  tree hidden_name;
+  char hidden[30];
+  
+  sprintf (hidden, "%.*s_%d",
+           IDENTIFIER_LENGTH (tinfo_decl_id), IDENTIFIER_POINTER (tinfo_decl_id),
+           count++);
+  hidden_name = get_identifier (hidden);
   
-  decl = build_lang_decl (VAR_DECL, name,
+  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;
-  TREE_PUBLIC (decl) = 1;
   DECL_EXTERNAL (decl) = 0;
   
-  comdat_linkage (decl);
+  if (!non_public)
+    {
+      TREE_PUBLIC (decl) = 1;
+      comdat_linkage (decl);
+    }
   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;
 }
 
@@ -1623,9 +1780,23 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
   /* Get the vtable decl. */
   real_type = xref_tag (class_type_node, get_identifier (real_name), 1);
   vtable_decl = get_vtable_decl (real_type, /*complete=*/1);
-  
+  vtable_decl = build_unary_op (ADDR_EXPR, vtable_decl, 0);
+
+  /* Under the new ABI, we need to point into the middle of the
+     vtable.  */
+  if (flag_new_abi)
+    {
+      vtable_decl = build (PLUS_EXPR,
+                          TREE_TYPE (vtable_decl),
+                          vtable_decl,
+                          size_binop (MULT_EXPR,
+                                      size_int (2),
+                                      TYPE_SIZE_UNIT (vtable_entry_type)));
+      TREE_CONSTANT (vtable_decl) = 1;
+    }
+
   /* First field is the pseudo type_info base class. */
-  fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
+  fields[0] = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
   
   /* Now add the derived fields.  */
   for (ix = 0; (field_decl = va_arg (ap, tree));)
@@ -1675,9 +1846,9 @@ get_vmi_pseudo_type_info (num_bases)
 
   desc = create_pseudo_type_info
             ("__vmi_class_type_info", num_bases,
-             build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-             build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-             build_lang_decl (FIELD_DECL, NULL_TREE, base_array),
+             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);
@@ -1708,8 +1879,8 @@ create_tinfo_types ()
     tree fields[2];
 
     ti_desc_type_node = make_aggr_type (RECORD_TYPE);
-    fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);
-    fields[1] = build_lang_decl (FIELD_DECL, NULL_TREE, const_string_type_node);
+    fields[0] = build_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);
+    fields[1] = build_decl (FIELD_DECL, NULL_TREE, const_string_type_node);
     finish_builtin_type (ti_desc_type_node, "__type_info_pseudo",
                          fields, 1, ptr_type_node);
     TYPE_HAS_CONSTRUCTOR (ti_desc_type_node) = 1;
@@ -1720,14 +1891,6 @@ create_tinfo_types ()
       ("__fundamental_type_info", 0,
        NULL);
 
-  /* Pointer type_info. Adds two fields, qualification mask
-     and pointer to the pointed to type.  */
-  ptr_desc_type_node = create_pseudo_type_info
-      ("__pointer_type_info", 0,
-       build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-       build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
-       NULL);
-
   /* Array, function and enum type_info. No additional fields. */
   ary_desc_type_node = create_pseudo_type_info
       ("__array_type_info", 0,
@@ -1742,40 +1905,48 @@ create_tinfo_types ()
   /* Class type_info. Add a flags field.  */
   class_desc_type_node = create_pseudo_type_info
         ("__class_type_info", 0,
-         build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
          NULL);
   
-  /* Single public non-virtual base class. Add pointer to base class.  */
+  /* Single public non-virtual base class. Add pointer to base class. 
+     This is really a descendant of __class_type_info.  */
   si_class_desc_type_node = create_pseudo_type_info
            ("__si_class_type_info", 0,
-            build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
-            build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+            build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
             NULL);
   
   /* Base class internal helper. Pointer to base type, offset to base,
      flags. */
   {
-    tree fields[3];
+    tree fields[2];
     
-    fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
-    fields[1] = build_lang_decl (FIELD_DECL, NULL_TREE, ptrdiff_type_node),
-    fields[2] = build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
+    fields[0] = build_decl (FIELD_DECL, NULL_TREE, ptr_type_info);
+    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",
-                         fields, 2, ptr_type_node);
+                         fields, 1, ptr_type_node);
     TYPE_HAS_CONSTRUCTOR (base_desc_type_node) = 1;
   }
   
   /* General heirarchy is created as necessary in this vector. */
   vmi_class_desc_type_node = make_tree_vec (10);
   
-  /* Pointer to member data type_info.  Add pointer to the class, pointer
-     to the member's type info and qualifications flags.  */
-  ptmd_desc_type_node = create_pseudo_type_info
+  /* Pointer type_info. Adds two fields, qualification mask
+     and pointer to the pointed to type.  This is really a descendant of
+     __pbase_type_info. */
+  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),
+       NULL);
+
+  /* Pointer to member data type_info.  Add qualifications flags,
+     pointer to the member's type info and pointer to the class.
+     This is really a descendant of __pbase_type_info.  */
+  ptm_desc_type_node = create_pseudo_type_info
        ("__pointer_to_member_type_info", 0,
-        build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
-        build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
-        build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
+        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),
         NULL);
 
   pop_nested_namespace (abi_node);
@@ -1795,23 +1966,12 @@ emit_support_tinfos ()
     &void_type_node,
     &boolean_type_node,
     &wchar_type_node,
-    #if 0
-    &signed_wchar_type_node, &unsigned_wchar_type_node,
-    #endif
     &char_type_node, &signed_char_type_node, &unsigned_char_type_node,
     &short_integer_type_node, &short_unsigned_type_node,
     &integer_type_node, &unsigned_type_node,
     &long_integer_type_node, &long_unsigned_type_node,
     &long_long_integer_type_node, &long_long_unsigned_type_node,
     &float_type_node, &double_type_node, &long_double_type_node,
-
-    /* GCC extension types */
-    #if 0
-    &complex_integer_type_node,
-    &complex_float_type_node, &complex_double_type_node,
-    &complex_long_double_type_node,
-    #endif
-    
     0
   };
   int ix;
@@ -1868,7 +2028,7 @@ tinfo_decl_p (t, data)
    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
-   definitions might cause other declarations to be emitted.
+   definition might cause other definitions to be required.
    
    We need to do things this way, because we're trying to do something like
    
@@ -1915,16 +2075,11 @@ emit_tinfo_decl (decl_ptr, data)
   tinfo_type = TREE_TYPE (DECL_NAME (tinfo_decl));
   my_friendly_assert (tinfo_type != NULL_TREE, 20000120);
   
+  if (!DECL_NEEDED_P (tinfo_decl))
+    return 0;
   /* Say we've dealt with it.  */
   TREE_TYPE (DECL_NAME (tinfo_decl)) = NULL_TREE;
   
-  if (!DECL_NEEDED_P (tinfo_decl))
-    return 0;
-  if (TREE_CODE (tinfo_type) == RECORD_TYPE && TYPE_POLYMORPHIC_P (tinfo_type)
-      && !CLASSTYPE_VTABLE_NEEDS_WRITING (tinfo_type))
-    /* A polymorphic type only needs its type_info emitted when the vtable
-       is.  */
-    return 0;
   create_tinfo_types ();
   decl = synthesize_tinfo_var (tinfo_type, DECL_ASSEMBLER_NAME (tinfo_decl));