OSDN Git Service

Merge in gcc2-ss-010999
[pf3gnuchains/gcc-fork.git] / gcc / cp / tree.c
index de15c07..a1928ef 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-dependent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -28,44 +28,37 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "toplev.h"
 
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-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 void unshare_base_binfos PROTO((tree));
 static int avoid_overlap 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))
 
-/* Return nonzero if REF is an lvalue valid for this language.
-   Lvalues can be assigned, unless they have TREE_READONLY.
-   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.  If TREAT_CLASS_RVALUES_AS_LVALUES is
+   non-zero, rvalues of class type are considered lvalues.  */
 
-int
-real_lvalue_p (ref)
+static cp_lvalue_kind
+lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
      tree ref;
+     int treat_class_rvalues_as_lvalues;
 {
-  if (! language_lvalue_valid (ref))
-    return 0;
-  
+  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))
     {
@@ -73,29 +66,47 @@ real_lvalue_p (ref)
         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:
-      return real_lvalue_p (TREE_OPERAND (ref, 0));
+    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:
-    case ERROR_MARK:
-      if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
-         && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
-       return 1;
+      if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
+       return clk_ordinary;
       break;
 
       /* A currently unresolved scope ref.  */
@@ -103,119 +114,84 @@ real_lvalue_p (ref)
       my_friendly_abort (103);
     case OFFSET_REF:
       if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
-       return 1;
-      return real_lvalue_p (TREE_OPERAND (ref, 0))
-       && real_lvalue_p (TREE_OPERAND (ref, 1));
+       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 (real_lvalue_p (TREE_OPERAND (ref, 1))
-             && real_lvalue_p (TREE_OPERAND (ref, 2)));
+      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 real_lvalue_p (TREE_OPERAND (ref, 1));
-
-    case MAX_EXPR:
-    case MIN_EXPR:
-      return (real_lvalue_p (TREE_OPERAND (ref, 0))
-             && real_lvalue_p (TREE_OPERAND (ref, 1)));
-
-    default:
-      break;
-    }
-
-  return 0;
-}
-
-/* This differs from real_lvalue_p in that class rvalues are considered
-   lvalues.  */
-int
-lvalue_p (ref)
-     tree ref;
-{
-  if (! language_lvalue_valid (ref))
-    return 0;
-  
-  if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
-    return 1;
-
-  if (ref == current_class_ptr && flag_this_is_variable <= 0)
-    return 0;
-
-  switch (TREE_CODE (ref))
-    {
-      /* preincrements and predecrements are valid lvals, provided
-        what they refer to are valid lvals.  */
-    case PREINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-    case COMPONENT_REF:
-    case SAVE_EXPR:
-    case UNSAVE_EXPR:
-    case TRY_CATCH_EXPR:
-    case WITH_CLEANUP_EXPR:
-      return lvalue_p (TREE_OPERAND (ref, 0));
-
-    case STRING_CST:
-      return 1;
-
-    case VAR_DECL:
-      if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
-         && DECL_LANG_SPECIFIC (ref)
-         && DECL_IN_AGGR_P (ref))
-       return 0;
-    case INDIRECT_REF:
-    case ARRAY_REF:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case ERROR_MARK:
-      if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
-         && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
-       return 1;
-      break;
+      return lvalue_p_1 (TREE_OPERAND (ref, 1),
+                        treat_class_rvalues_as_lvalues);
 
     case TARGET_EXPR:
-      return 1;
+      return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
 
     case CALL_EXPR:
-      if (IS_AGGR_TYPE (TREE_TYPE (ref)))
-       return 1;
-      break;
+      return ((treat_class_rvalues_as_lvalues
+              && IS_AGGR_TYPE (TREE_TYPE (ref)))
+             ? clk_class : clk_none);
 
-      /* A currently unresolved scope ref.  */
-    case SCOPE_REF:
-      my_friendly_abort (103);
-    case OFFSET_REF:
-      if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
-       return 1;
-      return lvalue_p (TREE_OPERAND (ref, 0))
-       && lvalue_p (TREE_OPERAND (ref, 1));
+    case FUNCTION_DECL:
+      /* All functions (except non-static-member functions) are
+        lvalues.  */
+      return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) 
+             ? clk_none : clk_ordinary);
+
+    default:
       break;
+    }
 
-    case COND_EXPR:
-      return (lvalue_p (TREE_OPERAND (ref, 1))
-             && lvalue_p (TREE_OPERAND (ref, 2)));
+  /* 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;
 
-    case MODIFY_EXPR:
-      return 1;
+  /* 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;
+}
 
-    case COMPOUND_EXPR:
-      return lvalue_p (TREE_OPERAND (ref, 1));
+/* 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.  */
 
-    case MAX_EXPR:
-    case MIN_EXPR:
-      return (lvalue_p (TREE_OPERAND (ref, 0))
-             && lvalue_p (TREE_OPERAND (ref, 1)));
+cp_lvalue_kind
+real_lvalue_p (ref)
+     tree ref;
+{
+  return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
+}
 
-    default:
-      break;
-    }
+/* This differs from real_lvalue_p in that class rvalues are
+   considered lvalues.  */
 
-  return 0;
+int
+lvalue_p (ref)
+     tree ref;
+{
+  return 
+    (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
 }
 
 /* Return nonzero if REF is an lvalue valid for this language;
@@ -224,7 +200,7 @@ lvalue_p (ref)
 int
 lvalue_or_else (ref, string)
      tree ref;
-     char *string;
+     const char *string;
 {
   int win = lvalue_p (ref);
   if (! win)
@@ -244,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;
 
@@ -429,23 +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 (TYPE_MAIN_VARIANT (basetype),
-                                         TYPE_READONLY (basetype),
-                                         TYPE_VOLATILE (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)
@@ -459,20 +453,21 @@ 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
+  if (processing_template_decl 
+      || uses_template_parms (elt_type) 
       || uses_template_parms (index_type))
     {
       t = make_node (ARRAY_TYPE);
@@ -484,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;
 }
 
@@ -497,54 +493,142 @@ build_cplus_array_type (elt_type, index_type)
      tree index_type;
 {
   tree t;
-  int constp = TYPE_READONLY (elt_type);
-  int volatilep = TYPE_VOLATILE (elt_type);
+  int type_quals = CP_TYPE_QUALS (elt_type);
+
   elt_type = TYPE_MAIN_VARIANT (elt_type);
 
   t = build_cplus_array_type_1 (elt_type, index_type);
 
-  if (constp || volatilep)
-    t = cp_build_type_variant (t, constp, volatilep);
+  if (type_quals != TYPE_UNQUALIFIED)
+    t = cp_build_qualified_type (t, type_quals);
 
   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_type_variant (type, constp, volatilep)
+cp_build_qualified_type_real (type, type_quals, complain)
      tree type;
-     int constp, volatilep;
+     int type_quals;
+     int complain;
 {
+  tree result;
+
   if (type == error_mark_node)
     return type;
-  
-  if (TREE_CODE (type) == ARRAY_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))
     {
-      tree real_main_variant = TYPE_MAIN_VARIANT (type);
+      if (complain)
+       cp_error ("`%T' cannot be `restrict'-qualified", type);
+      else
+       return error_mark_node;
+
+      type_quals &= ~TYPE_QUAL_RESTRICT;
+    }
 
-      push_obstacks (TYPE_OBSTACK (real_main_variant),
-                    TYPE_OBSTACK (real_main_variant));
-      type = build_cplus_array_type_1 (cp_build_type_variant
-                                      (TREE_TYPE (type), constp, volatilep),
-                                      TYPE_DOMAIN (type));
+  if (type_quals != TYPE_UNQUALIFIED
+      && TREE_CODE (type) == FUNCTION_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);
+
+      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;
+    }
+  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);
     }
-  return build_type_variant (type, constp, volatilep);
+
+  /* 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
+   a typedef, returns the underlying type.  The cv-qualification of
+   the type returned matches the type input; they will always be
+   compatible types.  */
+
+tree
+canonical_type_variant (t)
+     tree t;
+{
+  return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), CP_TYPE_QUALS (t));
 }
 \f
 /* Add OFFSET to all base types of T.
@@ -594,7 +678,7 @@ propagate_binfo_offsets (binfo, offset)
          BINFO_OFFSET (base_binfo) = offset;
 #endif
 
-         unshare_base_binfos (base_binfo);
+         propagate_binfo_offsets (base_binfo, offset);
 
          /* Go to our next class that counts for offset propagation.  */
          i = j;
@@ -604,40 +688,35 @@ propagate_binfo_offsets (binfo, offset)
     }
 }
 
-/* Makes new binfos for the indirect bases under BASE_BINFO, and updates
+/* Makes new binfos for the indirect bases under BINFO, and updates
    BINFO_OFFSET for them and their bases.  */
 
-static void
-unshare_base_binfos (base_binfo)
-     tree base_binfo;
+void
+unshare_base_binfos (binfo)
+     tree binfo;
 {
-  if (BINFO_BASETYPES (base_binfo))
-    {
-      tree base_binfos = BINFO_BASETYPES (base_binfo);
-      tree chain = NULL_TREE;
-      int j;
+  tree binfos = BINFO_BASETYPES (binfo);
+  tree new_binfo;
+  int j;
 
-      /* Now unshare the structure beneath BASE_BINFO.  */
-      for (j = TREE_VEC_LENGTH (base_binfos)-1;
-          j >= 0; j--)
-       {
-         tree base_base_binfo = TREE_VEC_ELT (base_binfos, j);
-         if (! TREE_VIA_VIRTUAL (base_base_binfo))
-           TREE_VEC_ELT (base_binfos, j)
-             = make_binfo (BINFO_OFFSET (base_base_binfo),
-                           base_base_binfo,
-                           BINFO_VTABLE (base_base_binfo),
-                           BINFO_VIRTUALS (base_base_binfo),
-                           chain);
-         chain = TREE_VEC_ELT (base_binfos, j);
-         TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
-         TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
-         BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
-       }
+  if (binfos == NULL_TREE)
+    return;
 
-      /* Completely unshare potentially shared data, and
-        update what is ours.  */
-      propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
+  /* Now unshare the structure beneath BINFO.  */
+  for (j = TREE_VEC_LENGTH (binfos)-1;
+       j >= 0; j--)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, j);
+      new_binfo = TREE_VEC_ELT (binfos, j)
+       = make_binfo (BINFO_OFFSET (base_binfo),
+                     base_binfo,
+                     BINFO_VTABLE (base_binfo),
+                     BINFO_VIRTUALS (base_binfo));
+      TREE_VIA_PUBLIC (new_binfo) = TREE_VIA_PUBLIC (base_binfo);
+      TREE_VIA_PROTECTED (new_binfo) = TREE_VIA_PROTECTED (base_binfo);
+      TREE_VIA_VIRTUAL (new_binfo) = TREE_VIA_VIRTUAL (base_binfo);
+      BINFO_INHERITANCE_CHAIN (new_binfo) = binfo;
+      unshare_base_binfos (new_binfo);
     }
 }
 
@@ -657,9 +736,7 @@ layout_basetypes (rec, max)
   tree binfos = TYPE_BINFO_BASETYPES (rec);
   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
 
-  /* Get all the virtual base types that this type uses.
-     The TREE_VALUE slot holds the virtual baseclass type.  */
-  tree vbase_types = get_vbase_types (rec);
+  tree vbase_types;
 
   unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
   unsigned int desired_align;
@@ -674,7 +751,11 @@ layout_basetypes (rec, max)
     record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
 #endif
 
-  CLASSTYPE_VBASECLASSES (rec) = vbase_types;
+  /* Get all the virtual base types that this type uses.  The
+     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.  */
+  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));
@@ -740,10 +821,15 @@ layout_basetypes (rec, max)
        continue;
 
       my_friendly_assert (TREE_TYPE (field) == basetype, 23897);
+
+      if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
+       cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
+                   basetype, rec);
+
       BINFO_OFFSET (base_binfo)
        = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)),
                          BITS_PER_UNIT));
-      unshare_base_binfos (base_binfo);
+      propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
       TYPE_FIELDS (rec) = TREE_CHAIN (field);
     }
 
@@ -752,6 +838,15 @@ layout_basetypes (rec, max)
     {
       BINFO_INHERITANCE_CHAIN (vbase_types) = TYPE_BINFO (rec);
       unshare_base_binfos (vbase_types);
+      propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
+
+      if (extra_warnings)
+       {
+         tree basetype = BINFO_TYPE (vbase_types);
+         if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
+           cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
+                       basetype, rec);
+       }
     }
 
   return max;
@@ -810,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);
@@ -827,7 +922,7 @@ build_base_fields (rec)
          base_align = MAX (base_align, DECL_ALIGN (decl));
          DECL_SIZE (decl)
            = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
-                            base_align));
+                            (int) base_align));
        }
       else if (DECL_SIZE (decl) == integer_zero_node)
        saw_empty = 1;
@@ -901,8 +996,7 @@ build_vbase_pointer_fields (rec)
       if (TREE_VIA_VIRTUAL (base_binfo))
        {
          int j;
-         char *name = (char *)alloca (TYPE_NAME_LENGTH (basetype)
-                                      + sizeof (VBASE_NAME) + 1);
+         const char *name;
 
          /* The offset for a virtual base class is only used in computing
             virtual function tables and for initializing virtual base
@@ -922,9 +1016,9 @@ build_vbase_pointer_fields (rec)
                                   ))
                goto got_it;
            }
-         sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype));
-         decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
-                                       build_pointer_type (basetype));
+         FORMAT_VBASE_NAME (name, 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.  */
@@ -934,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;
@@ -1000,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)
@@ -1036,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;
@@ -1063,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;
     }
@@ -1072,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)
@@ -1090,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.  */
@@ -1108,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:
 
@@ -1176,17 +1200,14 @@ get_decl_list (value)
    VTABLE is the virtual function table with which to initialize
    sub-objects of type TYPE.
 
-   VIRTUALS are the virtual functions sitting in VTABLE.
-
-   CHAIN are more associations we must retain.  */
+   VIRTUALS are the virtual functions sitting in VTABLE.  */
 
 tree
-make_binfo (offset, binfo, vtable, virtuals, chain)
+make_binfo (offset, binfo, vtable, virtuals)
      tree offset, binfo;
      tree vtable, virtuals;
-     tree chain;
 {
-  tree new_binfo = make_tree_vec (6);
+  tree new_binfo = make_tree_vec (7);
   tree type;
 
   if (TREE_CODE (binfo) == TREE_VEC)
@@ -1194,13 +1215,9 @@ make_binfo (offset, binfo, vtable, virtuals, chain)
   else
     {
       type = binfo;
-      binfo = TYPE_BINFO (binfo);
+      binfo = CLASS_TYPE_P (type) ? TYPE_BINFO (binfo) : NULL_TREE;
     }
 
-  TREE_CHAIN (new_binfo) = chain;
-  if (chain)
-    TREE_USED (new_binfo) = TREE_USED (chain);
-
   TREE_TYPE (new_binfo) = TYPE_MAIN_VARIANT (type);
   BINFO_OFFSET (new_binfo) = offset;
   BINFO_VTABLE (new_binfo) = vtable;
@@ -1229,17 +1246,24 @@ binfo_value (elem, type)
   return get_binfo (elem, type, 0);
 }
 
+/* Return a reversed copy of the BINFO-chain given by PATH.  (If the 
+   BINFO_INHERITANCE_CHAIN points from base classes to derived
+   classes, it will instead point from derived classes to base
+   classes.)  Returns the first node in the reversed chain.  */
+
 tree
 reverse_path (path)
      tree path;
 {
-  register tree prev = 0, tmp, next;
-  for (tmp = path; tmp; tmp = next)
+  register tree prev = NULL_TREE, cur;
+  push_expression_obstack ();
+  for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
     {
-      next = BINFO_INHERITANCE_CHAIN (tmp);
-      BINFO_INHERITANCE_CHAIN (tmp) = prev;
-      prev = tmp;
+      tree r = copy_node (cur);
+      BINFO_INHERITANCE_CHAIN (r) = prev;
+      prev = r;
     }
+  pop_obstacks ();
   return prev;
 }
 
@@ -1250,9 +1274,9 @@ debug_binfo (elem)
   unsigned HOST_WIDE_INT n;
   tree virtuals;
 
-  fprintf (stderr, "type \"%s\"; offset = %d\n",
+  fprintf (stderr, "type \"%s\"; offset = %ld\n",
           TYPE_NAME_STRING (BINFO_TYPE (elem)),
-          TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
+          (long) TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
   fprintf (stderr, "vtable type:\n");
   debug_tree (BINFO_TYPE (elem));
   if (BINFO_VTABLE (elem))
@@ -1262,14 +1286,14 @@ 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);
-      fprintf (stderr, "%s [%d =? %d]\n",
+      tree fndecl = TREE_VALUE (virtuals);
+      fprintf (stderr, "%s [%ld =? %ld]\n",
               IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
-              n, TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
+              (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
       ++n;
       virtuals = TREE_CHAIN (virtuals);
     }
@@ -1316,15 +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.  */
-  if (TREE_CODE (x) == TREE_LIST)
-    {
-      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)
@@ -1335,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. */
-  while (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
@@ -1350,11 +1371,22 @@ 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);
 }
 
+/* Returns nonzero if T is a ->* or .* expression that refers to a
+   member function.  */
+
+int
+bound_pmf_p (t)
+     tree t;
+{
+  return (TREE_CODE (t) == OFFSET_REF
+         && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (t, 1))));
+}
+
 /* Return a new OVL node, concatenating it with the old one. */
 
 tree
@@ -1393,9 +1425,9 @@ build_overload (decl, chain)
      tree decl;
      tree chain;
 {
-  if (!chain)
+  if (! chain && TREE_CODE (decl) != TEMPLATE_DECL)
     return decl;
-  if (TREE_CODE (chain) != OVERLOAD)
+  if (chain && TREE_CODE (chain) != OVERLOAD)
     chain = ovl_cons (chain, NULL_TREE);
   return ovl_cons (decl, chain);
 }
@@ -1407,10 +1439,10 @@ ovl_member (fn, ovl)
      tree fn;
      tree ovl;
 {
-  if (fn == ovl)
-    return 1;
-  if (!ovl || TREE_CODE (ovl) != OVERLOAD)
+  if (ovl == NULL_TREE)
     return 0;
+  if (TREE_CODE (ovl) != OVERLOAD)
+    return ovl == fn;
   for (; ovl; ovl = OVL_CHAIN (ovl))
     if (OVL_FUNCTION (ovl) == fn)
       return 1;
@@ -1428,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;
@@ -1480,34 +1512,18 @@ build_exception_variant (type, raises)
      tree raises;
 {
   tree v = TYPE_MAIN_VARIANT (type);
-  int constp = TYPE_READONLY (type);
-  int volatilep = TYPE_VOLATILE (type);
+  int type_quals = TYPE_QUALS (type);
 
   for (; v; v = TYPE_NEXT_VARIANT (v))
-    {
-      if (TYPE_READONLY (v) != constp
-         || TYPE_VOLATILE (v) != volatilep)
-       continue;
-
-      /* @@ This should do set equality, not exact match.  */
-      if (simple_cst_list_equal (TYPE_RAISES_EXCEPTIONS (v), raises))
-       /* List of exceptions raised matches previously found list.
-
-          @@ Nice to free up storage used in consing up the
-          @@ list of exceptions raised.  */
-       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);
 
   if (raises && ! TREE_PERMANENT (raises))
-    {
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
-      raises = copy_list (raises);
-      pop_obstacks ();
-    }
+    raises = copy_to_permanent (raises);
 
   TYPE_RAISES_EXCEPTIONS (v) = raises;
   return v;
@@ -1521,64 +1537,335 @@ copy_template_template_parm (t)
      tree t;
 {
   tree template = TYPE_NAME (t);
-  tree t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+  tree t2;
+
+  /* Make sure these end up on the permanent_obstack.  */
+  push_permanent_obstack ();
+  
+  t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
   template = copy_node (template);
   copy_lang_decl (template);
+
+  pop_obstacks ();
+
   TREE_TYPE (template) = t2;
   TYPE_NAME (t2) = template;
   TYPE_STUB_DECL (t2) = template;
 
   /* No need to copy these */
   TYPE_FIELDS (t2) = TYPE_FIELDS (t);
-  CLASSTYPE_TEMPLATE_INFO (t2) = CLASSTYPE_TEMPLATE_INFO (t);
+  TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) 
+    = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
   return t2;
 }
 
-/* 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.  */
+/* Walk through the tree structure T, applying func.  If func ever returns
+   non-null, return that value.  */
 
 tree
-mapcar (t, func)
+search_tree (t, func)
      tree t;
      tree (*func) PROTO((tree));
 {
+#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:
-      return error_mark_node;
+      break;
+
+    case IDENTIFIER_NODE:
+      break;
 
     case VAR_DECL:
     case FUNCTION_DECL:
     case CONST_DECL:
-      /* Rather than aborting, return error_mark_node.  This allows us
-        to report a sensible error message on code like this:
+    case TEMPLATE_DECL:
+    case NAMESPACE_DECL:
+      break;
 
-        void g() { int i; f<i>(7); } 
+    case TYPE_DECL:
+      TRY (TREE_TYPE (t));
+      break;
 
-         In a case like:
+    case PARM_DECL:
+      TRY (TREE_TYPE (t));
+      TRY (TREE_CHAIN (t));
+      break;
 
-           void g() { const int i = 7; f<i>(7); }
+    case TREE_LIST:
+      TRY (TREE_PURPOSE (t));
+      TRY (TREE_VALUE (t));
+      TRY (TREE_CHAIN (t));
+      break;
 
-        however, we must actually return the constant initializer.  */
-      tmp = decl_constant_value (t);
-      if (tmp != t)
-       return mapcar (tmp, func);
-      else
-       return error_mark_node;
+    case OVERLOAD:
+      TRY (OVL_FUNCTION (t));
+      TRY (OVL_CHAIN (t));
+      break;
 
-    case PARM_DECL:
+    case TREE_VEC:
       {
-       tree chain = TREE_CHAIN (t);
+       int len = TREE_VEC_LENGTH (t);
+
+       t = copy_node (t);
+       while (len--)
+         TRY (TREE_VEC_ELT (t, len));
+      }
+      break;
+
+    case INTEGER_CST:
+    case REAL_CST:
+    case STRING_CST:
+    case DEFAULT_ARG:
+      break;
+
+    case PTRMEM_CST:
+      TRY (TREE_TYPE (t));
+      break;
+
+    case COND_EXPR:
+    case TARGET_EXPR:
+    case AGGR_INIT_EXPR:
+    case NEW_EXPR:
+      TRY (TREE_OPERAND (t, 0));
+      TRY (TREE_OPERAND (t, 1));
+      TRY (TREE_OPERAND (t, 2));
+      break;
+
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case ARRAY_REF:
+    case SCOPE_REF:
+    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 ADDR_EXPR:
+    case INDIRECT_REF:
+    case TRUTH_NOT_EXPR:
+    case COMPONENT_REF:
+    case CLEANUP_POINT_EXPR:
+    case LOOKUP_EXPR:
+    case THROW_EXPR:
+    case EXIT_EXPR:
+    case LOOP_EXPR:
+      TRY (TREE_OPERAND (t, 0));
+      break;
+
+    case MODOP_EXPR:
+    case ARROW_EXPR:
+    case DOTSTAR_EXPR:
+    case TYPEID_EXPR:
+    case PSEUDO_DTOR_EXPR:
+      break;
+
+    case COMPLEX_CST:
+      TRY (TREE_REALPART (t));
+      TRY (TREE_IMAGPART (t));
+      break;
+
+    case CONSTRUCTOR:
+      TRY (CONSTRUCTOR_ELTS (t));
+      break;
+
+    case TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_PARM_INDEX:
+    case TEMPLATE_TYPE_PARM:
+      break;
+
+    case BIND_EXPR:
+    case STMT_EXPR:
+      break;
+
+    case REAL_TYPE:
+    case COMPLEX_TYPE:
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+    case TYPENAME_TYPE:
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case TYPEOF_TYPE:
+      break;
+
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      TRY (TREE_TYPE (t));
+      break;
+
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+      TRY (TREE_TYPE (t));
+      TRY (TYPE_ARG_TYPES (t));
+      break;
+
+    case ARRAY_TYPE:
+      TRY (TREE_TYPE (t));
+      TRY (TYPE_DOMAIN (t));
+      break;
+
+    case INTEGER_TYPE:
+      TRY (TYPE_MAX_VALUE (t));
+      break;
+
+    case OFFSET_TYPE:
+      TRY (TREE_TYPE (t));
+      TRY (TYPE_OFFSET_BASETYPE (t));
+      break;
+
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (t))
+       TRY (TYPE_PTRMEMFUNC_FN_TYPE (t));
+      break;
+      
+    default:
+      my_friendly_abort (19990803);
+    }
+
+  return NULL_TREE;
+
+#undef TRY
+}
+
+/* Passed to search_tree.  Checks for the use of types with no linkage.  */
+
+static tree
+no_linkage_helper (t)
+     tree t;
+{
+  if (TYPE_P (t)
+      && (IS_AGGR_TYPE (t) || TREE_CODE (t) == ENUMERAL_TYPE)
+      && (decl_function_context (TYPE_MAIN_DECL (t))
+         || ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))))
+    return t;
+  return NULL_TREE;
+}
+
+/* Check if the type T depends on a type with no linkage and if so, return
+   it.  */
+
+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;
+  return NULL_TREE;
+}
+
+
+/* Make copies of all the nodes below T.  If FUNC is non-NULL, call it
+   for each node.  */
+
+tree
+mapcar (t, func)
+     tree t;
+     tree (*func) PROTO((tree));
+{
+  tree tmp;
+  enum tree_code code; 
+
+  if (t == NULL_TREE)
+    return t;
+
+  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))
+    {
+    case ERROR_MARK:
+      return error_mark_node;
+
+    case VAR_DECL:
+    case FUNCTION_DECL:
+    case CONST_DECL:
+      /* Rather than aborting, return error_mark_node.  This allows us
+        to report a sensible error message on code like this:
+
+        void g() { int i; f<i>(7); } 
+
+         In a case like:
+
+           void g() { const int i = 7; f<i>(7); }
+
+        however, we must actually return the constant initializer.  */
+      if (TREE_READONLY_DECL_P (t))
+       {
+         tmp = decl_constant_value (t);
+         if (tmp != t)
+           return mapcar (tmp, func);
+       }
+      return error_mark_node;
+
+    case PARM_DECL:
+      {
+       tree chain = TREE_CHAIN (t);
        t = copy_node (t);
        TREE_CHAIN (t) = mapcar (chain, func);
        TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
@@ -1621,6 +1908,12 @@ mapcar (t, func)
     case STRING_CST:
       return copy_node (t);
 
+    case PTRMEM_CST:
+      t = copy_node (t);
+      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+      PTRMEM_CST_MEMBER (t) = mapcar (PTRMEM_CST_MEMBER (t), func);
+      return t;
+
     case COND_EXPR:
     case TARGET_EXPR:
     case AGGR_INIT_EXPR:
@@ -1630,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:
@@ -1672,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);
@@ -1682,56 +1949,49 @@ 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
-        build_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);
       return t;
 
     case POINTER_TYPE:
       tmp = build_pointer_type (mapcar (TREE_TYPE (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
     case REFERENCE_TYPE:
       tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
     case FUNCTION_TYPE:
       tmp = build_function_type (mapcar (TREE_TYPE (t), func),
                                 mapcar (TYPE_ARG_TYPES (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
     case ARRAY_TYPE:
       tmp = build_cplus_array_type (mapcar (TREE_TYPE (t), func),
                                    mapcar (TYPE_DOMAIN (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, CP_TYPE_QUALS (t));
     case INTEGER_TYPE:
       tmp = build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
     case OFFSET_TYPE:
       tmp = build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
                               mapcar (TREE_TYPE (t), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
     case METHOD_TYPE:
       tmp = build_cplus_method_type
        (mapcar (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), func),
         mapcar (TREE_TYPE (t), func),
         mapcar (TREE_CHAIN (TYPE_ARG_TYPES (t)), func));
-      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
 
     case COMPLEX_CST:
       t = copy_node (t);
@@ -1754,25 +2014,49 @@ mapcar (t, func)
       TREE_OPERAND (t, 2) = NULL_TREE;
       return t;
 
+    case NEW_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);
+      TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), 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;
@@ -1805,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;
@@ -1840,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);
@@ -1933,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;
@@ -1944,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
 
@@ -1971,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
@@ -1983,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
@@ -1992,7 +2266,7 @@ build_min VPROTO((enum tree_code code, tree tt, ...))
 
   t = make_node (code);
   length = tree_code_length[(int) code];
-  TREE_TYPE (t) = tt;
+  TREE_TYPE (t) = copy_to_permanent (tt);
   TREE_COMPLEXITY (t) = lineno;
 
   for (i = 0; i < length; i++)
@@ -2069,7 +2343,7 @@ vec_binfo_member (elem, vec)
 
   if (vec)
     for (i = 0; i < TREE_VEC_LENGTH (vec); ++i)
-      if (comptypes (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i)), 1))
+      if (same_type_p (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i))))
        return TREE_VEC_ELT (vec, i);
 
   return NULL_TREE;
@@ -2089,6 +2363,24 @@ hack_decl_function_context (decl)
   return decl_function_context (decl);
 }
 
+/* Returns the namespace that contains DECL, whether directly or
+   indirectly.  */
+
+tree
+decl_namespace_context (decl)
+     tree decl;
+{
+  while (1)
+    {
+      if (TREE_CODE (decl) == NAMESPACE_DECL)
+       return decl;
+      else if (TYPE_P (decl))
+       decl = CP_DECL_CONTEXT (TYPE_MAIN_DECL (decl));
+      else
+       decl = CP_DECL_CONTEXT (decl);
+    }
+}
+
 /* Return truthvalue of whether T1 is the same tree structure as T2.
    Return 1 if they are the same.
    Return 0 if they are understandably different.
@@ -2142,7 +2434,7 @@ cp_tree_equal (t1, t2)
       /* We need to do this when determining whether or not two
         non-type pointer to member function template arguments
         are the same.  */
-      if (!(comptypes (TREE_TYPE (t1), TREE_TYPE (t2), 1)
+      if (!(same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
            /* The first operand is RTL.  */
            && TREE_OPERAND (t1, 0) == TREE_OPERAND (t2, 0)))
        return 0;
@@ -2210,9 +2502,15 @@ cp_tree_equal (t1, t2)
       if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
        return 0;
       if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t1, 0))) == 't')
-       return comptypes (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), 1);
+       return same_type_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
       break;
 
+    case PTRMEM_CST:
+      /* Two pointer-to-members are the same if they point to the same
+        field or function in the same class.  */
+      return (PTRMEM_CST_MEMBER (t1) == PTRMEM_CST_MEMBER (t2)
+             && same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2)));
+
     default:
       break;
     }
@@ -2239,17 +2537,17 @@ cp_tree_equal (t1, t2)
   return -1;
 }
 
-/* Similar to make_tree_vec, but build on a temporary obstack.  */
+/* Similar to make_tree_vec, but build on the momentary_obstack.
+   Thus, these vectors are really and truly temporary.  */
 
 tree
 make_temp_vec (len)
      int len;
 {
   register tree node;
-  register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = expression_obstack;
+  push_expression_obstack ();
   node = make_tree_vec (len);
-  current_obstack = ambient_obstack;
+  pop_obstacks ();
   return node;
 }
 
@@ -2288,14 +2586,26 @@ build_int_wrapper (i)
   return t;
 }
 
-tree
+static tree
 build_srcloc (file, line)
      char *file;
      int line;
 {
-  tree t = make_node (SRCLOC);
+  tree t;
+
+  /* Make sure that we put these on the permanent obstack; up in
+     add_pending_template, we pass this return value into perm_tree_cons,
+     which also puts it on the permanent_obstack.  However, this wasn't
+     explicitly doing the same.  */
+  register struct obstack *ambient_obstack = current_obstack;
+  current_obstack = &permanent_obstack;
+
+  t = make_node (SRCLOC);
   SRCLOC_FILE (t) = file;
   SRCLOC_LINE (t) = line;
+
+  current_obstack = ambient_obstack;
+
   return t;
 }
 
@@ -2312,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
@@ -2321,8 +2642,7 @@ lvalue_type (arg)
   tree type = TREE_TYPE (arg);
   if (TREE_CODE (arg) == OVERLOAD)
     type = unknown_type_node;
-  return cp_build_type_variant
-    (type, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+  return type;
 }
 
 /* The type of ARG for printing error messages; denote lvalues with
@@ -2365,3 +2685,226 @@ member_p (decl)
   tree ctx = DECL_CONTEXT (decl);
   return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
 }
+
+/* Create a placeholder for member access where we don't actually have an
+   object that the access is against.  */
+
+tree
+build_dummy_object (type)
+     tree type;
+{
+  tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node);
+  return build_indirect_ref (decl, NULL_PTR);
+}
+
+/* We've gotten a reference to a member of TYPE.  Return *this if appropriate,
+   or a dummy object otherwise.  If BINFOP is non-0, it is filled with the
+   binfo path from current_class_type to TYPE, or 0.  */
+
+tree
+maybe_dummy_object (type, binfop)
+     tree type;
+     tree *binfop;
+{
+  tree decl, context;
+
+  if (current_class_type
+      && get_base_distance (type, current_class_type, 0, binfop) != -1)
+    context = current_class_type;
+  else
+    {
+      /* Reference from a nested class member function.  */
+      context = type;
+      if (binfop)
+       *binfop = TYPE_BINFO (type);
+    }
+
+  if (current_class_ref && context == current_class_type)
+    decl = current_class_ref;
+  else
+    decl = build_dummy_object (context);
+
+  return decl;
+}
+
+/* Returns 1 if OB is a placeholder object, or a pointer to one.  */
+
+int
+is_dummy_object (ob)
+     tree ob;
+{
+  if (TREE_CODE (ob) == INDIRECT_REF)
+    ob = TREE_OPERAND (ob, 0);
+  return (TREE_CODE (ob) == NOP_EXPR
+         && TREE_OPERAND (ob, 0) == void_zero_node);
+}
+
+/* Returns 1 iff type T is a POD type, as defined in [basic.types].  */
+
+int
+pod_type_p (t)
+     tree t;
+{
+  while (TREE_CODE (t) == ARRAY_TYPE)
+    t = TREE_TYPE (t);
+
+  if (INTEGRAL_TYPE_P (t))
+    return 1;  /* integral, character or enumeral type */
+  if (FLOAT_TYPE_P (t))
+    return 1;
+  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;
+}
+
+/* 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 (! flag_vtable_thunks)
+       {
+         error ("`com_interface' only supported with -fvtable-thunks");
+         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;
+
+      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;
+}
+