OSDN Git Service

Merge in gcc2-ss-010999
[pf3gnuchains/gcc-fork.git] / gcc / cp / tree.c
index b93d9bd..a1928ef 100644 (file)
@@ -28,37 +28,37 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "toplev.h"
 
-extern void compiler_error ();
-
-static tree get_identifier_list PROTO((tree));
 static tree bot_manip PROTO((tree));
 static tree perm_manip PROTO((tree));
 static tree build_cplus_array_type_1 PROTO((tree, tree));
 static void list_hash_add PROTO((int, tree));
 static int list_hash PROTO((tree, tree, tree));
-static tree list_hash_lookup PROTO((int, int, int, int, tree, tree,
-                                   tree));
+static tree list_hash_lookup PROTO((int, tree, tree, tree));
 static void propagate_binfo_offsets PROTO((tree, tree));
 static int avoid_overlap PROTO((tree, tree));
-static int lvalue_p_1 PROTO((tree, int));
-static int equal_functions PROTO((tree, tree));
+static cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
+static tree no_linkage_helper PROTO((tree));
+static tree build_srcloc PROTO((char *, int));
 
 #define CEIL(x,y) (((x) + (y) - 1) / (y))
 
-/* Returns non-zero if REF is an lvalue.  If
-   TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type
-   are considered lvalues.  */
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+   Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
+   non-zero, rvalues of class type are considered lvalues.  */
 
-static int
+static cp_lvalue_kind
 lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
      tree ref;
      int treat_class_rvalues_as_lvalues;
 {
+  cp_lvalue_kind op1_lvalue_kind = clk_none;
+  cp_lvalue_kind op2_lvalue_kind = clk_none;
+
   if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
-    return 1;
+    return clk_ordinary;
 
   if (ref == current_class_ptr && flag_this_is_variable <= 0)
-    return 0;
+    return clk_none;
 
   switch (TREE_CODE (ref))
     {
@@ -66,30 +66,47 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
         what they refer to are valid lvals.  */
     case PREINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
-    case COMPONENT_REF:
     case SAVE_EXPR:
     case UNSAVE_EXPR:
     case TRY_CATCH_EXPR:
     case WITH_CLEANUP_EXPR:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
+    case NOP_EXPR:
       return lvalue_p_1 (TREE_OPERAND (ref, 0),
                         treat_class_rvalues_as_lvalues);
 
+    case COMPONENT_REF:
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+                                   treat_class_rvalues_as_lvalues);
+      if (op1_lvalue_kind 
+         /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
+            situations.  */
+         && TREE_CODE (TREE_OPERAND (ref, 1)) == FIELD_DECL
+         && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
+       {
+         /* Clear the ordinary bit.  If this object was a class
+            rvalue we want to preserve that information.  */
+         op1_lvalue_kind &= ~clk_ordinary;
+         /* The lvalue is for a btifield.  */
+         op1_lvalue_kind |= clk_bitfield;
+       }
+      return op1_lvalue_kind;
+
     case STRING_CST:
-      return 1;
+      return clk_ordinary;
 
     case VAR_DECL:
       if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
          && DECL_LANG_SPECIFIC (ref)
          && DECL_IN_AGGR_P (ref))
-       return 0;
+       return clk_none;
     case INDIRECT_REF:
     case ARRAY_REF:
     case PARM_DECL:
     case RESULT_DECL:
       if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
-       return 1;
+       return clk_ordinary;
       break;
 
       /* A currently unresolved scope ref.  */
@@ -97,72 +114,84 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
       my_friendly_abort (103);
     case OFFSET_REF:
       if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
-       return 1;
-      return (lvalue_p_1 (TREE_OPERAND (ref, 0),
-                         treat_class_rvalues_as_lvalues)
-             && lvalue_p_1 (TREE_OPERAND (ref, 1),
-                            treat_class_rvalues_as_lvalues));
+       return clk_ordinary;
+      /* Fall through.  */
+    case MAX_EXPR:
+    case MIN_EXPR:
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+                                   treat_class_rvalues_as_lvalues);
+      op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+                                   treat_class_rvalues_as_lvalues);
       break;
 
     case COND_EXPR:
-      return (lvalue_p_1 (TREE_OPERAND (ref, 1),
-                         treat_class_rvalues_as_lvalues)
-             && lvalue_p_1 (TREE_OPERAND (ref, 2),
-                            treat_class_rvalues_as_lvalues));
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+                                   treat_class_rvalues_as_lvalues);
+      op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
+                                   treat_class_rvalues_as_lvalues);
+      break;
 
     case MODIFY_EXPR:
-      return 1;
+      return clk_ordinary;
 
     case COMPOUND_EXPR:
       return lvalue_p_1 (TREE_OPERAND (ref, 1),
-                           treat_class_rvalues_as_lvalues);
-
-    case MAX_EXPR:
-    case MIN_EXPR:
-      return (lvalue_p_1 (TREE_OPERAND (ref, 0),
-                         treat_class_rvalues_as_lvalues)
-             && lvalue_p_1 (TREE_OPERAND (ref, 1),
-                            treat_class_rvalues_as_lvalues));
+                        treat_class_rvalues_as_lvalues);
 
     case TARGET_EXPR:
-      return treat_class_rvalues_as_lvalues;
+      return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
 
     case CALL_EXPR:
-      return (treat_class_rvalues_as_lvalues
-             && IS_AGGR_TYPE (TREE_TYPE (ref)));
+      return ((treat_class_rvalues_as_lvalues
+              && IS_AGGR_TYPE (TREE_TYPE (ref)))
+             ? clk_class : clk_none);
 
     case FUNCTION_DECL:
       /* All functions (except non-static-member functions) are
         lvalues.  */
-      return !DECL_NONSTATIC_MEMBER_FUNCTION_P (ref);
+      return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) 
+             ? clk_none : clk_ordinary);
 
     default:
       break;
     }
 
-  return 0;
+  /* If one operand is not an lvalue at all, then this expression is
+     not an lvalue.  */
+  if (!op1_lvalue_kind || !op2_lvalue_kind)
+    return clk_none;
+
+  /* Otherwise, it's an lvalue, and it has all the odd properties
+     contributed by either operand.  */
+  op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind;
+  /* It's not an ordinary lvalue if it involves either a bit-field or
+     a class rvalue.  */
+  if ((op1_lvalue_kind & ~clk_ordinary) != clk_none)
+    op1_lvalue_kind &= ~clk_ordinary;
+  return op1_lvalue_kind;
 }
 
-/* Return nonzero if REF is an lvalue valid for this language.
-   Lvalues can be assigned, unless they have TREE_READONLY, or unless
-   they are FUNCTION_DECLs.  Lvalues can have their address taken,
-   unless they have DECL_REGISTER.  */
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+   Otherwise, returns clk_none.  Lvalues can be assigned, unless they
+   have TREE_READONLY, or unless they are FUNCTION_DECLs.  Lvalues can
+   have their address taken, unless they have DECL_REGISTER.  */
 
-int
+cp_lvalue_kind
 real_lvalue_p (ref)
      tree ref;
 {
   return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
 }
 
-/* This differs from real_lvalue_p in that class rvalues are considered
-   lvalues.  */
+/* This differs from real_lvalue_p in that class rvalues are
+   considered lvalues.  */
 
 int
 lvalue_p (ref)
      tree ref;
 {
-  return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1);
+  return 
+    (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
 }
 
 /* Return nonzero if REF is an lvalue valid for this language;
@@ -191,18 +220,36 @@ build_cplus_new (type, init)
      tree type;
      tree init;
 {
+  tree fn;
   tree slot;
   tree rval;
 
+  /* Make sure that we're not trying to create an instance of an
+     abstract class.  */
+  abstract_virtuals_error (NULL_TREE, type);
+
   if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
-    return init;
+    return convert (type, init);
 
   slot = build (VAR_DECL, type);
   DECL_ARTIFICIAL (slot) = 1;
   layout_decl (slot, 0);
-  rval = build (AGGR_INIT_EXPR, type,
-               TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
+
+  /* We split the CALL_EXPR into its function and its arguments here.
+     Then, in expand_expr, we put them back together.  The reason for
+     this is that this expression might be a default argument
+     expression.  In that case, we need a new temporary every time the
+     expression is used.  That's what break_out_target_exprs does; it
+     replaces every AGGR_INIT_EXPR with a copy that uses a fresh
+     temporary slot.  Then, expand_expr builds up a call-expression
+     using the new slot.  */
+  fn = TREE_OPERAND (init, 0);
+  rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
   TREE_SIDE_EFFECTS (rval) = 1;
+  AGGR_INIT_VIA_CTOR_P (rval) 
+    = (TREE_CODE (fn) == ADDR_EXPR
+       && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+       && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
   rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (rval) = 1;
 
@@ -376,21 +423,23 @@ build_cplus_method_type (basetype, rettype, argtypes)
 
   TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
   TREE_TYPE (t) = rettype;
-  if (IS_SIGNATURE (basetype))
-    ptype = build_signature_pointer_type (basetype);
-  else
-    ptype = build_pointer_type (basetype);
+  ptype = build_pointer_type (basetype);
 
   /* The actual arglist for this function includes a "hidden" argument
-     which is "this".  Put it into the list of argument types.  */
-
+     which is "this".  Put it into the list of argument types.  Make
+     sure that the new argument list is allocated on the same obstack
+     as the type.  */
+  push_obstacks (TYPE_OBSTACK (t), TYPE_OBSTACK (t));
   argtypes = tree_cons (NULL_TREE, ptype, argtypes);
   TYPE_ARG_TYPES (t) = argtypes;
   TREE_SIDE_EFFECTS (argtypes) = 1;  /* Mark first argtype as "artificial".  */
+  pop_obstacks ();
 
   /* If we already have such a type, use the old one and free this one.
      Note that it also frees up the above cons cell if found.  */
-  hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes);
+  hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
+    type_hash_list (argtypes);
+
   t = type_hash_canon (hashcode, t);
 
   if (TYPE_SIZE (t) == 0)
@@ -404,18 +453,18 @@ build_cplus_array_type_1 (elt_type, index_type)
      tree elt_type;
      tree index_type;
 {
-  register struct obstack *ambient_obstack = current_obstack;
-  register struct obstack *ambient_saveable_obstack = saveable_obstack;
   tree t;
 
-  /* We need a new one.  If both ELT_TYPE and INDEX_TYPE are permanent,
+  if (elt_type == error_mark_node || index_type == error_mark_node)
+    return error_mark_node;
+
+  push_obstacks_nochange ();
+
+  /* If both ELT_TYPE and INDEX_TYPE are permanent,
      make this permanent too.  */
   if (TREE_PERMANENT (elt_type)
       && (index_type == 0 || TREE_PERMANENT (index_type)))
-    {
-      current_obstack = &permanent_obstack;
-      saveable_obstack = &permanent_obstack;
-    }
+    end_temporary_allocation ();
 
   if (processing_template_decl 
       || uses_template_parms (elt_type) 
@@ -430,10 +479,11 @@ build_cplus_array_type_1 (elt_type, index_type)
 
   /* Push these needs up so that initialization takes place
      more easily.  */
-  TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
-  TYPE_NEEDS_DESTRUCTOR (t) = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
-  current_obstack = ambient_obstack;
-  saveable_obstack = ambient_saveable_obstack;
+  TYPE_NEEDS_CONSTRUCTING (t) 
+    = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
+  TYPE_NEEDS_DESTRUCTOR (t) 
+    = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
+  pop_obstacks ();
   return t;
 }
 
@@ -455,53 +505,118 @@ build_cplus_array_type (elt_type, index_type)
   return t;
 }
 \f
-/* Make a variant type in the proper way for C/C++, propagating qualifiers
-   down to the element type of an array.  */
+/* Make a variant of TYPE, qualified with the TYPE_QUALS.  Handles
+   arrays correctly.  In particular, if TYPE is an array of T's, and
+   TYPE_QUALS is non-empty, returns an array of qualified T's.  If
+   at attempt is made to qualify a type illegally, and COMPLAIN is
+   non-zero, an error is issued.  If COMPLAIN is zero, error_mark_node
+   is returned.  */
 
 tree
-cp_build_qualified_type (type, type_quals)
+cp_build_qualified_type_real (type, type_quals, complain)
      tree type;
      int type_quals;
+     int complain;
 {
+  tree result;
+
   if (type == error_mark_node)
     return type;
-  
+
+  if (type_quals == TYPE_QUALS (type))
+    return type;
+
   /* A restrict-qualified pointer type must be a pointer (or reference)
      to object or incomplete type.  */
   if ((type_quals & TYPE_QUAL_RESTRICT)
+      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
       && (!POINTER_TYPE_P (type)
          || TYPE_PTRMEM_P (type)
          || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
     {
-      cp_error ("`%T' cannot be `restrict'-qualified", type);
+      if (complain)
+       cp_error ("`%T' cannot be `restrict'-qualified", type);
+      else
+       return error_mark_node;
+
       type_quals &= ~TYPE_QUAL_RESTRICT;
     }
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
+  if (type_quals != TYPE_UNQUALIFIED
+      && TREE_CODE (type) == FUNCTION_TYPE)
     {
-      tree real_main_variant = TYPE_MAIN_VARIANT (type);
+      if (complain)
+       cp_error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
+      else
+       return error_mark_node;
+      type_quals = TYPE_UNQUALIFIED;
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* In C++, the qualification really applies to the array element
+        type.  Obtain the appropriately qualified element type.  */
+      tree t;
+      tree element_type 
+       = cp_build_qualified_type_real (TREE_TYPE (type), 
+                                       type_quals,
+                                       complain);
 
-      push_obstacks (TYPE_OBSTACK (real_main_variant),
-                    TYPE_OBSTACK (real_main_variant));
-      type = build_cplus_array_type_1 (cp_build_qualified_type 
-                                      (TREE_TYPE (type), type_quals),
-                                      TYPE_DOMAIN (type));
+      if (element_type == error_mark_node)
+       return error_mark_node;
 
-      /* TYPE must be on same obstack as REAL_MAIN_VARIANT.  If not,
-        make a copy.  (TYPE might have come from the hash table and
-        REAL_MAIN_VARIANT might be in some function's obstack.)  */
+      /* See if we already have an identically qualified type.  */
+      for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+       if (CP_TYPE_QUALS (t) == type_quals)
+         break;
 
-      if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+      /* If we didn't already have it, create it now.  */
+      if (!t)
        {
-         type = copy_node (type);
-         TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+         /* Make a new array type, just like the old one, but with the
+            appropriately qualified element type.  */
+         t = build_type_copy (type);
+         TREE_TYPE (t) = element_type;
        }
 
-      TYPE_MAIN_VARIANT (type) = real_main_variant;
-      pop_obstacks ();
-      return type;
+      /* Even if we already had this variant, we update
+        TYPE_NEEDS_CONSTRUCTING and TYPE_NEEDS_DESTRUCTOR in case
+        they changed since the variant was originally created.  
+        
+        This seems hokey; if there is some way to use a previous
+        variant *without* coming through here,
+        TYPE_NEEDS_CONSTRUCTING will never be updated.  */
+      TYPE_NEEDS_CONSTRUCTING (t) 
+       = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
+      TYPE_NEEDS_DESTRUCTOR (t) 
+       = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
+      return t;
     }
-  return build_qualified_type (type, type_quals);
+  else if (TYPE_PTRMEMFUNC_P (type))
+    {
+      /* For a pointer-to-member type, we can't just return a
+        cv-qualified version of the RECORD_TYPE.  If we do, we
+        haven't change the field that contains the actual pointer to
+        a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong.  */
+      tree t;
+
+      t = TYPE_PTRMEMFUNC_FN_TYPE (type);
+      t = cp_build_qualified_type_real (t, type_quals, complain);
+      return build_ptrmemfunc_type (t);
+    }
+
+  /* Retrieve (or create) the appropriately qualified variant.  */
+  result = build_qualified_type (type, type_quals);
+
+  /* If this was a pointer-to-method type, and we just made a copy,
+     then we need to clear the cached associated
+     pointer-to-member-function type; it is not valid for the new
+     type.  */
+  if (result != type 
+      && TREE_CODE (type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+    TYPE_SET_PTRMEMFUNC_TYPE (result, NULL_TREE);
+
+  return result;
 }
 
 /* Returns the canonical version of TYPE.  In other words, if TYPE is
@@ -640,7 +755,7 @@ layout_basetypes (rec, max)
      TREE_VALUE slot holds the virtual baseclass type.  Note that
      get_vbase_types makes copies of the virtual base BINFOs, so that
      the vbase_types are unshared.  */
-  CLASSTYPE_VBASECLASSES (rec) = vbase_types = get_vbase_types (rec);
+  vbase_types = CLASSTYPE_VBASECLASSES (rec);
 
   my_friendly_assert (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST, 19970302);
   const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec));
@@ -790,7 +905,7 @@ build_base_fields (rec)
       if (TREE_VIA_VIRTUAL (base_binfo))
        continue;
 
-      decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, basetype);
+      decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
       DECL_ARTIFICIAL (decl) = 1;
       DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = rec;
       DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
@@ -881,7 +996,7 @@ build_vbase_pointer_fields (rec)
       if (TREE_VIA_VIRTUAL (base_binfo))
        {
          int j;
-         char *name;
+         const char *name;
 
          /* The offset for a virtual base class is only used in computing
             virtual function tables and for initializing virtual base
@@ -902,8 +1017,8 @@ build_vbase_pointer_fields (rec)
                goto got_it;
            }
          FORMAT_VBASE_NAME (name, basetype);
-         decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
-                                       build_pointer_type (basetype));
+         decl = build_lang_decl (FIELD_DECL, get_identifier (name),
+                                 build_pointer_type (basetype));
          /* If you change any of the below, take a look at all the
             other VFIELD_BASEs and VTABLE_BASEs in the code, and change
             them too.  */
@@ -913,7 +1028,7 @@ build_vbase_pointer_fields (rec)
          DECL_FIELD_CONTEXT (decl) = rec;
          DECL_CLASS_CONTEXT (decl) = rec;
          DECL_FCONTEXT (decl) = basetype;
-         DECL_SAVED_INSNS (decl) = NULL_RTX;
+         DECL_SAVED_INSNS (decl) = 0;
          DECL_FIELD_SIZE (decl) = 0;
          DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node);
          TREE_CHAIN (decl) = vbase_decls;
@@ -979,18 +1094,14 @@ list_hash (purpose, value, chain)
    If one is found, return it.  Otherwise return 0.  */
 
 static tree
-list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
-                 purpose, value, chain)
-     int hashcode, via_public, via_virtual, via_protected;
+list_hash_lookup (hashcode, purpose, value, chain)
+     int hashcode;
      tree purpose, value, chain;
 {
   register struct list_hash *h;
 
   for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
     if (h->hashcode == hashcode
-       && TREE_VIA_VIRTUAL (h->list) == via_virtual
-       && TREE_VIA_PUBLIC (h->list) == via_public
-       && TREE_VIA_PROTECTED (h->list) == via_protected
        && TREE_PURPOSE (h->list) == purpose
        && TREE_VALUE (h->list) == value
        && TREE_CHAIN (h->list) == chain)
@@ -1015,24 +1126,16 @@ list_hash_add (hashcode, list)
   list_hash_table[hashcode % TYPE_HASH_SIZE] = h;
 }
 
-/* Given TYPE, and HASHCODE its hash code, return the canonical
-   object for an identical list if one already exists.
-   Otherwise, return TYPE, and record it as the canonical object
-   if it is a permanent object.
-
-   To use this function, first create a list of the sort you want.
-   Then compute its hash code from the fields of the list that
-   make it different from other similar lists.
-   Then call this function and use the value.
-   This function frees the list you pass in if it is a duplicate.  */
+/* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical
+   object for an identical list if one already exists.  Otherwise, build a
+   new one, and record it as the canonical object.  */
 
 /* Set to 1 to debug without canonicalization.  Never set by program.  */
 
 static int debug_no_list_hash = 0;
 
 tree
-hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
-     int via_public, via_virtual, via_protected;
+hash_tree_cons (purpose, value, chain)
      tree purpose, value, chain;
 {
   struct obstack *ambient_obstack = current_obstack;
@@ -1042,8 +1145,7 @@ hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
   if (! debug_no_list_hash)
     {
       hashcode = list_hash (purpose, value, chain);
-      t = list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
-                           purpose, value, chain);
+      t = list_hash_lookup (hashcode, purpose, value, chain);
       if (t)
        return t;
     }
@@ -1051,9 +1153,6 @@ hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
   current_obstack = &class_obstack;
 
   t = tree_cons (purpose, value, chain);
-  TREE_VIA_PUBLIC (t) = via_public;
-  TREE_VIA_PROTECTED (t) = via_protected;
-  TREE_VIA_VIRTUAL (t) = via_virtual;
 
   /* If this is a new list, record it for later reuse.  */
   if (! debug_no_list_hash)
@@ -1069,7 +1168,7 @@ tree
 hash_tree_chain (value, chain)
      tree value, chain;
 {
-  return hash_tree_cons (0, 0, 0, NULL_TREE, value, chain);
+  return hash_tree_cons (NULL_TREE, value, chain);
 }
 
 /* Similar, but used for concatenating two lists.  */
@@ -1087,60 +1186,6 @@ hash_chainon (list1, list2)
   return hash_tree_chain (TREE_VALUE (list1),
                          hash_chainon (TREE_CHAIN (list1), list2));
 }
-
-static tree
-get_identifier_list (value)
-     tree value;
-{
-  tree list = IDENTIFIER_AS_LIST (value);
-  if (list != NULL_TREE
-      && (TREE_CODE (list) != TREE_LIST
-         || TREE_VALUE (list) != value))
-    list = NULL_TREE;
-  else if (IDENTIFIER_HAS_TYPE_VALUE (value)
-          && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE
-          && IDENTIFIER_TYPE_VALUE (value)
-             == TYPE_MAIN_VARIANT (IDENTIFIER_TYPE_VALUE (value)))
-    {
-      tree type = IDENTIFIER_TYPE_VALUE (value);
-
-      if (TYPE_PTRMEMFUNC_P (type))
-       list = NULL_TREE;
-      else if (type == current_class_type)
-       /* Don't mess up the constructor name.  */
-       list = tree_cons (NULL_TREE, value, NULL_TREE);
-      else
-       {
-         if (! CLASSTYPE_ID_AS_LIST (type))
-           CLASSTYPE_ID_AS_LIST (type)
-             = perm_tree_cons (NULL_TREE, TYPE_IDENTIFIER (type), NULL_TREE);
-         list = CLASSTYPE_ID_AS_LIST (type);
-       }
-    }
-  return list;
-}
-
-tree
-get_decl_list (value)
-     tree value;
-{
-  tree list = NULL_TREE;
-
-  if (TREE_CODE (value) == IDENTIFIER_NODE)
-    list = get_identifier_list (value);
-  else if (TREE_CODE (value) == RECORD_TYPE
-          && TYPE_LANG_SPECIFIC (value)
-          && value == TYPE_MAIN_VARIANT (value))
-    list = CLASSTYPE_AS_LIST (value);
-
-  if (list != NULL_TREE)
-    {
-      my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 301);
-      return list;
-    }
-
-  return build_decl_list (NULL_TREE, value);
-}
 \f
 /* Build an association between TYPE and some parameters:
 
@@ -1241,11 +1286,11 @@ debug_binfo (elem)
   fprintf (stderr, "virtuals:\n");
   virtuals = BINFO_VIRTUALS (elem);
 
-  n = skip_rtti_stuff (&virtuals);
+  n = skip_rtti_stuff (&virtuals, BINFO_TYPE (elem));
 
   while (virtuals)
     {
-      tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
+      tree fndecl = TREE_VALUE (virtuals);
       fprintf (stderr, "%s [%ld =? %ld]\n",
               IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
               (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
@@ -1295,21 +1340,11 @@ int
 is_overloaded_fn (x)
      tree x;
 {
-  /* XXX A baselink is also considered an overloaded function.
-     As is a placeholder from push_class_decls.
-     As is an expression like X::f.  */
-  if (TREE_CODE (x) == TREE_LIST)
-    {
-      if (TREE_PURPOSE (x) == error_mark_node)
-       {
-         x = TREE_VALUE (x);
-         my_friendly_assert (TREE_CODE (x) == TREE_LIST, 981121);
-       }
-      my_friendly_assert (TREE_CODE (TREE_PURPOSE (x)) == TREE_VEC
-                         || TREE_CODE (TREE_PURPOSE (x)) == IDENTIFIER_NODE,
-                         388);
-      x = TREE_VALUE (x);
-    }
+  /* A baselink is also considered an overloaded function.  */
+  if (TREE_CODE (x) == OFFSET_REF)
+    x = TREE_OPERAND (x, 1);
+  if (BASELINK_P (x))
+    x = TREE_VALUE (x);
   return (TREE_CODE (x) == FUNCTION_DECL
          || TREE_CODE (x) == TEMPLATE_ID_EXPR
          || DECL_FUNCTION_TEMPLATE_P (x)
@@ -1320,9 +1355,10 @@ int
 really_overloaded_fn (x)
      tree x;
 {     
-  /* A baselink is also considered an overloaded function.
-     This might also be an ambiguous class member. */
-  if (TREE_CODE (x) == TREE_LIST)
+  /* A baselink is also considered an overloaded function.  */
+  if (TREE_CODE (x) == OFFSET_REF)
+    x = TREE_OPERAND (x, 1);
+  if (BASELINK_P (x))
     x = TREE_VALUE (x);
   return (TREE_CODE (x) == OVERLOAD 
          && (TREE_CHAIN (x) != NULL_TREE
@@ -1335,7 +1371,7 @@ get_first_fn (from)
 {
   my_friendly_assert (is_overloaded_fn (from), 9);
   /* A baselink is also considered an overloaded function. */
-  if (TREE_CODE (from) == TREE_LIST)
+  if (BASELINK_P (from))
     from = TREE_VALUE (from);
   return OVL_CURRENT (from);
 }
@@ -1396,20 +1432,6 @@ build_overload (decl, chain)
   return ovl_cons (decl, chain);
 }
 
-/* Returns true iff functions are equivalent. Equivalent functions are
-   not identical only if one is a function-local extern function.
-   This assumes that function-locals don't have TREE_PERMANENT.  */
-
-static int
-equal_functions (fn1, fn2)
-     tree fn1;
-     tree fn2;
-{
-  if (!TREE_PERMANENT (fn1) || !TREE_PERMANENT (fn2))
-    return decls_match (fn1, fn2);
-  return fn1 == fn2;
-}
-
 /* True if fn is in ovl. */
 
 int
@@ -1420,9 +1442,9 @@ ovl_member (fn, ovl)
   if (ovl == NULL_TREE)
     return 0;
   if (TREE_CODE (ovl) != OVERLOAD)
-    return equal_functions (ovl, fn);
+    return ovl == fn;
   for (; ovl; ovl = OVL_CHAIN (ovl))
-    if (equal_functions (OVL_FUNCTION (ovl), fn))
+    if (OVL_FUNCTION (ovl) == fn)
       return 1;
   return 0;
 }
@@ -1438,7 +1460,7 @@ is_aggr_type_2 (t1, t2)
 \f
 #define PRINT_RING_SIZE 4
 
-char *
+const char *
 lang_printable_name (decl, v)
      tree decl;
      int v;
@@ -1493,25 +1515,9 @@ build_exception_variant (type, raises)
   int type_quals = TYPE_QUALS (type);
 
   for (; v; v = TYPE_NEXT_VARIANT (v))
-    {
-      tree t;
-      tree u;
-
-      if (TYPE_QUALS (v) != type_quals)
-       continue;
-
-      for (t = TYPE_RAISES_EXCEPTIONS (v), u = raises;
-          t != NULL_TREE && u != NULL_TREE;
-          t = TREE_CHAIN (t), u = TREE_CHAIN (v))
-       if (((TREE_VALUE (t) != NULL_TREE) 
-            != (TREE_VALUE (u) != NULL_TREE))
-           || !same_type_p (TREE_VALUE (t), TREE_VALUE (u)))
-         break;
-
-      if (!t && !u)
-       /* There's a memory leak here; RAISES is not freed.  */
-       return v;
-    }
+    if (TYPE_QUALS (v) == type_quals
+        && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1))
+      return v;
 
   /* Need to build a new variant.  */
   v = build_type_copy (type);
@@ -1534,8 +1540,7 @@ copy_template_template_parm (t)
   tree t2;
 
   /* Make sure these end up on the permanent_obstack.  */
-  push_obstacks_nochange ();
-  end_temporary_allocation ();
+  push_permanent_obstack ();
   
   t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
   template = copy_node (template);
@@ -1565,14 +1570,30 @@ search_tree (t, func)
 #define TRY(ARG) if (tmp=search_tree (ARG, func), tmp != NULL_TREE) return tmp
 
   tree tmp;
+  enum tree_code code; 
 
   if (t == NULL_TREE)
     return t;
-
-  if (tmp = func (t), tmp != NULL_TREE)
+  
+  tmp = func (t);
+  if (tmp)
     return tmp;
 
-  switch (TREE_CODE (t))
+  /* Handle some common cases up front.  */
+  code = TREE_CODE (t);
+  if (TREE_CODE_CLASS (code) == '1')
+    {
+      TRY (TREE_OPERAND (t, 0));
+      return NULL_TREE;
+    }
+  else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+    {
+      TRY (TREE_OPERAND (t, 0));
+      TRY (TREE_OPERAND (t, 1));
+      return NULL_TREE;
+    }
+
+  switch (code)
     {
     case ERROR_MARK:
       break;
@@ -1636,35 +1657,11 @@ search_tree (t, func)
       TRY (TREE_OPERAND (t, 2));
       break;
 
-    case MODIFY_EXPR:
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case TRUNC_MOD_EXPR:
-    case MIN_EXPR:
-    case MAX_EXPR:
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case BIT_AND_EXPR:
-    case BIT_ANDTC_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-    case LT_EXPR:
-    case LE_EXPR:
-    case GT_EXPR:
-    case GE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case CEIL_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case ROUND_MOD_EXPR:
-    case COMPOUND_EXPR:
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
@@ -1674,36 +1671,31 @@ search_tree (t, func)
     case TRY_CATCH_EXPR:
     case WITH_CLEANUP_EXPR:
     case CALL_EXPR:
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+    case INIT_EXPR:
       TRY (TREE_OPERAND (t, 0));
       TRY (TREE_OPERAND (t, 1));
       break;
 
     case SAVE_EXPR:
-    case CONVERT_EXPR:
     case ADDR_EXPR:
     case INDIRECT_REF:
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
-    case NOP_EXPR:
-    case NON_LVALUE_EXPR:
     case COMPONENT_REF:
     case CLEANUP_POINT_EXPR:
     case LOOKUP_EXPR:
-    case SIZEOF_EXPR:
-    case ALIGNOF_EXPR:
+    case THROW_EXPR:
+    case EXIT_EXPR:
+    case LOOP_EXPR:
       TRY (TREE_OPERAND (t, 0));
       break;
 
     case MODOP_EXPR:
-    case CAST_EXPR:
-    case REINTERPRET_CAST_EXPR:
-    case CONST_CAST_EXPR:
-    case STATIC_CAST_EXPR:
-    case DYNAMIC_CAST_EXPR:
     case ARROW_EXPR:
     case DOTSTAR_EXPR:
     case TYPEID_EXPR:
+    case PSEUDO_DTOR_EXPR:
       break;
 
     case COMPLEX_CST:
@@ -1721,6 +1713,7 @@ search_tree (t, func)
       break;
 
     case BIND_EXPR:
+    case STMT_EXPR:
       break;
 
     case REAL_TYPE:
@@ -1763,13 +1756,8 @@ search_tree (t, func)
        TRY (TYPE_PTRMEMFUNC_FN_TYPE (t));
       break;
       
-      /*  This list is incomplete, but should suffice for now.
-         It is very important that `sorry' not call
-         `report_error_function'.  That could cause an infinite loop.  */
     default:
-      sorry ("initializer contains unrecognized tree code");
-      return error_mark_node;
-
+      my_friendly_abort (19990803);
     }
 
   return NULL_TREE;
@@ -1798,6 +1786,11 @@ tree
 no_linkage_check (t)
      tree t;
 {
+  /* There's no point in checking linkage on template functions; we
+     can't know their complete types.  */
+  if (processing_template_decl)
+    return NULL_TREE;
+
   t = search_tree (t, no_linkage_helper);
   if (t != error_mark_node)
     return t;
@@ -1805,10 +1798,8 @@ no_linkage_check (t)
 }
 
 
-/* Subroutine of copy_to_permanent
-
-   Assuming T is a node build bottom-up, make it all exist on
-   permanent obstack, if it is not permanent already.  */
+/* Make copies of all the nodes below T.  If FUNC is non-NULL, call it
+   for each node.  */
 
 tree
 mapcar (t, func)
@@ -1816,12 +1807,35 @@ mapcar (t, func)
      tree (*func) PROTO((tree));
 {
   tree tmp;
+  enum tree_code code; 
 
   if (t == NULL_TREE)
     return t;
 
-  if (tmp = func (t), tmp != NULL_TREE)
-    return tmp;
+  if (func) 
+    {
+      tmp = func (t);
+      if (tmp)
+       return tmp;
+    }
+
+  /* Handle some common cases up front.  */
+  code = TREE_CODE (t);
+  if (TREE_CODE_CLASS (code) == '1')
+    {
+      t = copy_node (t);
+      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      return t;
+    }
+  else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+    {
+      t = copy_node (t);
+      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+      return t;
+    }
 
   switch (TREE_CODE (t))
     {
@@ -1909,40 +1923,11 @@ mapcar (t, func)
       TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
       return t;
 
-    case SAVE_EXPR:
-      t = copy_node (t);
-      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
-      return t;
-
-    case MODIFY_EXPR:
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case TRUNC_MOD_EXPR:
-    case MIN_EXPR:
-    case MAX_EXPR:
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case BIT_AND_EXPR:
-    case BIT_ANDTC_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-    case LT_EXPR:
-    case LE_EXPR:
-    case GT_EXPR:
-    case GE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case CEIL_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case ROUND_MOD_EXPR:
-    case COMPOUND_EXPR:
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
@@ -1951,6 +1936,9 @@ mapcar (t, func)
     case SCOPE_REF:
     case TRY_CATCH_EXPR:
     case WITH_CLEANUP_EXPR:
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+    case INIT_EXPR:
       t = copy_node (t);
       TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
       TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
@@ -1961,25 +1949,17 @@ mapcar (t, func)
       TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
       TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
       TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
-
-      /* tree.def says that operand two is RTL, but
-        make_call_declarator puts trees in there.  */
-      if (TREE_OPERAND (t, 2)
-         && TREE_CODE (TREE_OPERAND (t, 2)) == TREE_LIST)
-       TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
-      else
-       TREE_OPERAND (t, 2) = NULL_TREE;
+      TREE_OPERAND (t, 2) = NULL_TREE;
       return t;
 
-    case CONVERT_EXPR:
+    case SAVE_EXPR:
     case ADDR_EXPR:
     case INDIRECT_REF:
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
-    case NOP_EXPR:
     case COMPONENT_REF:
     case CLEANUP_POINT_EXPR:
+    case THROW_EXPR:
+    case STMT_EXPR:
       t = copy_node (t);
       TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
       TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
@@ -2042,29 +2022,41 @@ mapcar (t, func)
       return t;
 
     case LOOKUP_EXPR:
+    case EXIT_EXPR:
+    case LOOP_EXPR:
       t = copy_node (t);
       TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
       return t;
 
+    case RTL_EXPR:
+      t = copy_node (t);
+      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+      return t;
+
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_P (t))
        return build_ptrmemfunc_type
          (mapcar (TYPE_PTRMEMFUNC_FN_TYPE (t), func));
       /* else fall through */
-      
-      /*  This list is incomplete, but should suffice for now.
-         It is very important that `sorry' not call
-         `report_error_function'.  That could cause an infinite loop.  */
-    default:
-      sorry ("initializer contains unrecognized tree code");
-      return error_mark_node;
 
+    default:
+      my_friendly_abort (19990815);
     }
   my_friendly_abort (107);
   /* NOTREACHED */
   return NULL_TREE;
 }
 
+/* Returns T if T is allocated on the permanent obstack, NULL_TREE
+   otherwise.  */
+
+tree
+permanent_p (t)
+     tree t;
+{
+  return TREE_PERMANENT (t) ? t : NULL_TREE;
+}
+
 static tree
 perm_manip (t)
      tree t;
@@ -2097,11 +2089,8 @@ copy_to_permanent (t)
   if (t == NULL_TREE || TREE_PERMANENT (t))
     return t;
 
-  push_obstacks_nochange ();
-  end_temporary_allocation ();
-
+  push_permanent_obstack ();
   t = mapcar (t, perm_manip);
-
   pop_obstacks ();
 
   return t;
@@ -2132,17 +2121,10 @@ print_lang_statistics ()
 
 void
 __eprintf (string, expression, line, filename)
-#ifdef __STDC__
      const char *string;
      const char *expression;
      unsigned line;
      const char *filename;
-#else
-     char *string;
-     char *expression;
-     unsigned line;
-     char *filename;
-#endif
 {
   fprintf (stderr, string, expression, line, filename);
   fflush (stderr);
@@ -2225,7 +2207,7 @@ break_out_target_exprs (t)
 tree
 build_min_nt VPROTO((enum tree_code code, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
 #endif
   register struct obstack *ambient_obstack = expression_obstack;
@@ -2236,7 +2218,7 @@ build_min_nt VPROTO((enum tree_code code, ...))
 
   VA_START (p, code);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum tree_code);
 #endif
 
@@ -2263,7 +2245,7 @@ build_min_nt VPROTO((enum tree_code code, ...))
 tree
 build_min VPROTO((enum tree_code code, tree tt, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
   tree tt;
 #endif
@@ -2275,7 +2257,7 @@ build_min VPROTO((enum tree_code code, tree tt, ...))
 
   VA_START (p, tt);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum tree_code);
   tt = va_arg (p, tree);
 #endif
@@ -2604,7 +2586,7 @@ build_int_wrapper (i)
   return t;
 }
 
-tree
+static tree
 build_srcloc (file, line)
      char *file;
      int line;
@@ -2640,6 +2622,17 @@ push_expression_obstack ()
   current_obstack = expression_obstack;
 }
 
+/* Begin allocating on the permanent obstack.  When you're done
+   allocating there, call pop_obstacks to return to the previous set
+   of obstacks.  */
+
+void
+push_permanent_obstack ()
+{
+  push_obstacks_nochange ();
+  end_temporary_allocation ();
+}
+
 /* The type of ARG when used as an lvalue.  */
 
 tree
@@ -2700,7 +2693,7 @@ tree
 build_dummy_object (type)
      tree type;
 {
-  tree decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
+  tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node);
   return build_indirect_ref (decl, NULL_PTR);
 }
 
@@ -2743,7 +2736,7 @@ is_dummy_object (ob)
   if (TREE_CODE (ob) == INDIRECT_REF)
     ob = TREE_OPERAND (ob, 0);
   return (TREE_CODE (ob) == NOP_EXPR
-         && TREE_OPERAND (ob, 0) == error_mark_node);
+         && TREE_OPERAND (ob, 0) == void_zero_node);
 }
 
 /* Returns 1 iff type T is a POD type, as defined in [basic.types].  */
@@ -2752,29 +2745,166 @@ int
 pod_type_p (t)
      tree t;
 {
-  tree f;
-
   while (TREE_CODE (t) == ARRAY_TYPE)
     t = TREE_TYPE (t);
 
-  if (! IS_AGGR_TYPE (t))
+  if (INTEGRAL_TYPE_P (t))
+    return 1;  /* integral, character or enumeral type */
+  if (FLOAT_TYPE_P (t))
     return 1;
-
-  if (CLASSTYPE_NON_AGGREGATE (t)
-      || TYPE_HAS_COMPLEX_ASSIGN_REF (t)
-      || TYPE_HAS_DESTRUCTOR (t))
+  if (TYPE_PTR_P (t))
+    return 1; /* pointer to non-member */
+  if (TYPE_PTRMEM_P (t))
+    return 1; /* pointer to member object */
+  if (TYPE_PTRMEMFUNC_P (t))
+    return 1; /* pointer to member function */
+  
+  if (! CLASS_TYPE_P (t))
+    return 0; /* other non-class type (reference or function) */
+  if (CLASSTYPE_NON_POD_P (t))
     return 0;
+  return 1;
+}
 
-  for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f))
+/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific
+   attribute for either declaration DECL or type TYPE and 0 otherwise.
+   Plugged into valid_lang_attribute.  */
+
+int
+cp_valid_lang_attribute (attr_name, attr_args, decl, type)
+  tree attr_name;
+  tree attr_args ATTRIBUTE_UNUSED;
+  tree decl ATTRIBUTE_UNUSED;
+  tree type ATTRIBUTE_UNUSED;
+{
+  if (is_attribute_p ("com_interface", attr_name))
     {
-      if (TREE_CODE (f) != FIELD_DECL)
-       continue;
+      if (! flag_vtable_thunks)
+       {
+         error ("`com_interface' only supported with -fvtable-thunks");
+         return 0;
+       }
 
-      if (TREE_CODE (TREE_TYPE (f)) == REFERENCE_TYPE
-         || TYPE_PTRMEMFUNC_P (TREE_TYPE (f))
-         || TYPE_PTRMEM_P (TREE_TYPE (f)))
-       return 0;
+      if (attr_args != NULL_TREE
+         || decl != NULL_TREE
+         || ! CLASS_TYPE_P (type)
+         || type != TYPE_MAIN_VARIANT (type))
+       {
+         warning ("`com_interface' attribute can only be applied to class definitions");
+         return 0;
+       }
+
+      CLASSTYPE_COM_INTERFACE (type) = 1;
+      return 1;
     }
+  else if (is_attribute_p ("init_priority", attr_name))
+    {
+      tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
+      int pri;
 
-  return 1;
+      if (initp_expr)
+       STRIP_NOPS (initp_expr);
+         
+      if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
+       {
+         error ("requested init_priority is not an integer constant");
+         return 0;
+       }
+
+      pri = TREE_INT_CST_LOW (initp_expr);
+       
+      while (TREE_CODE (type) == ARRAY_TYPE)
+       type = TREE_TYPE (type);
+
+      if (decl == NULL_TREE
+         || TREE_CODE (decl) != VAR_DECL
+         || ! TREE_STATIC (decl)
+         || DECL_EXTERNAL (decl)
+         || (TREE_CODE (type) != RECORD_TYPE
+             && TREE_CODE (type) != UNION_TYPE)
+         /* Static objects in functions are initialized the
+            first time control passes through that
+            function. This is not precise enough to pin down an
+            init_priority value, so don't allow it. */
+         || current_function_decl) 
+       {
+         error ("can only use init_priority attribute on file-scope definitions of objects of class type");
+         return 0;
+       }
+
+      if (pri > MAX_INIT_PRIORITY || pri <= 0)
+       {
+         error ("requested init_priority is out of range");
+         return 0;
+       }
+
+      /* Check for init_priorities that are reserved for
+        language and runtime support implementations.*/
+      if (pri <= MAX_RESERVED_INIT_PRIORITY)
+       {
+         warning 
+           ("requested init_priority is reserved for internal use");
+       }
+
+      DECL_INIT_PRIORITY (decl) = pri;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
+   thing pointed to by the constant.  */
+
+tree
+make_ptrmem_cst (type, member)
+     tree type;
+     tree member;
+{
+  tree ptrmem_cst = make_node (PTRMEM_CST);
+  /* If would seem a great convenience if make_node would set
+     TREE_CONSTANT for things of class `c', but it does not.  */
+  TREE_CONSTANT (ptrmem_cst) = 1;
+  TREE_TYPE (ptrmem_cst) = type;
+  PTRMEM_CST_MEMBER (ptrmem_cst) = member;
+  return ptrmem_cst;
+}
+
+/* Initialize unsave for C++. */
+void
+init_cplus_unsave ()
+{
+  lang_unsave_expr_now = cplus_unsave_expr_now;
 }
+
+/* The C++ version of unsave_expr_now.
+   See gcc/tree.c:unsave_expr_now for comments. */
+
+void
+cplus_unsave_expr_now (expr)
+     tree expr;
+{
+  if (expr == NULL)
+    return;
+
+  else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
+    {
+      unsave_expr_now (TREE_OPERAND (expr,0));
+      if (TREE_OPERAND (expr, 1)
+         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+       {
+         tree exp = TREE_OPERAND (expr, 1);
+         while (exp)
+           {
+             unsave_expr_now (TREE_VALUE (exp));
+             exp = TREE_CHAIN (exp);
+           }
+       }
+      unsave_expr_now (TREE_OPERAND (expr,2));
+      return;
+    }
+
+  else
+    return;
+}
+