OSDN Git Service

91th Cygnus<->FSF merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl2.c
index d04cf51..1e8577a 100644 (file)
@@ -1,5 +1,5 @@
 /* Process declarations and variables for C compiler.
-   Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* Process declarations and symbol lookup for C front end.
@@ -34,11 +35,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "cp-tree.h"
 #include "decl.h"
 #include "lex.h"
+#include "output.h"
 
-extern tree grokdeclarator ();
 extern tree get_file_function_name ();
-extern tree cleanups_this_call;
-static void grok_function_init ();
+static void grok_function_init PROTO((tree, tree));
+void import_export_decl ();
+extern int current_class_depth;
 
 /* A list of virtual function tables we must make sure to write out.  */
 tree pending_vtables;
@@ -49,13 +51,13 @@ tree pending_vtables;
 tree pending_statics;
 
 /* A list of functions which were declared inline, but which we
-   may need to emit outline anyway. */
+   may need to emit outline anyway.  */
 static tree saved_inlines;
 
 /* Used to help generate temporary names which are unique within
    a function.  Reset to 0 by start_function.  */
 
-static int temp_name_counter;
+int temp_name_counter;
 
 /* Same, but not reset.  Local temp variables and global temp variables
    can have the same name.  */
@@ -64,6 +66,14 @@ static int global_temp_name_counter;
 /* Flag used when debugging spew.c */
 
 extern int spew_debug;
+
+/* Nonzero if we're done parsing and into end-of-file activities.  */
+
+int at_eof;
+
+/* Functions called along with real static constructors and destructors.  */
+
+tree static_ctors, static_dtors;
 \f
 /* C (and C++) language-specific option variables.  */
 
@@ -80,11 +90,21 @@ int flag_short_double;
 
 int flag_no_asm;
 
+/* Nonzero means don't recognize any extension keywords.  */
+
+int flag_no_gnu_keywords;
+
 /* Nonzero means don't recognize the non-ANSI builtin functions.  */
 
 int flag_no_builtin;
 
-/* Nonzero means do some things the same way PCC does.  */
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+   -ansi sets this.  */
+
+int flag_no_nonansi_builtin;
+
+/* Nonzero means do some things the same way PCC does.  Only provided so
+   the compiler will link.  */
 
 int flag_traditional;
 
@@ -94,11 +114,17 @@ int flag_signed_bitfields = 1;
 
 /* Nonzero means handle `#ident' directives.  0 means ignore them.  */
 
-int flag_no_ident = 0;
+int flag_no_ident;
 
-/* Nonzero means disable GNU extensions.  */
+/* Nonzero means enable obscure ANSI features and disable GNU extensions
+   that might cause ANSI-compliant code to be miscompiled.  */
 
-int flag_ansi = 0;
+int flag_ansi;
+
+/* Nonzero means do argument matching for overloading according to the
+   ANSI rules, rather than what g++ used to believe to be correct.  */
+
+int flag_ansi_overloading = 1;
 
 /* Nonzero means do emit exported implementations of functions even if
    they can be inlined.  */
@@ -106,15 +132,15 @@ int flag_ansi = 0;
 int flag_implement_inlines = 1;
 
 /* Nonzero means do emit exported implementations of templates, instead of
-   multiple static copies in each file that needs a definition. */
+   multiple static copies in each file that needs a definition.  */
 
-int flag_external_templates = 0;
+int flag_external_templates;
 
 /* Nonzero means that the decision to emit or not emit the implementation of a
    template depends on where the template is instantiated, rather than where
    it is defined.  */
 
-int flag_alt_external_templates = 0;
+int flag_alt_external_templates;
 
 /* Nonzero means that implicit instantiations will be emitted if needed.  */
 
@@ -129,12 +155,18 @@ int warn_implicit = 1;
 
 int warn_ctor_dtor_privacy = 1;
 
-/* True if we want to implement vtbvales using "thunks".
-   The default is off now, but will be on later.
+/* True if we want to implement vtables using "thunks".
+   The default is off.  */
+
+#if defined(NEW_OVER) && defined (__i386__)
+int flag_vtable_thunks = 1;
+#else
+int flag_vtable_thunks;
+#endif
+
+/* True if we want to deal with repository information.  */
 
-   Also causes output of vtables to be controlled by whether
-   we seen the class's first non-inline virtual function. */
-int flag_vtable_thunks = 0;
+int flag_use_repository;
 
 /* Nonzero means give string constants the type `const char *'
    to get extra warnings from them.  These warnings will be too numerous
@@ -152,19 +184,10 @@ int warn_cast_qual;
 
 int warn_template_debugging;
 
-/* Warn about traditional constructs whose meanings changed in ANSI C.  */
-
-int warn_traditional;
-
 /* Nonzero means warn about sizeof(function) or addition/subtraction
    of function pointers.  */
 
-int warn_pointer_arith;
-
-/* Nonzero means warn for non-prototype function decls
-   or non-prototyped defs without previous prototype.  */
-
-int warn_strict_prototypes;
+int warn_pointer_arith = 1;
 
 /* Nonzero means warn for any function def without prototype decl.  */
 
@@ -179,7 +202,11 @@ int warn_redundant_decls;
 
 int warn_missing_braces;
 
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Warn about comparison of signed and unsigned values.  */
+
+int warn_sign_compare;
+
+/* Warn about *printf or *scanf format/argument anomalies.  */
 
 int warn_format;
 
@@ -193,7 +220,7 @@ int warn_conversion;
 
 /* Warn if adding () is suggested.  */
 
-int warn_parentheses = 1;
+int warn_parentheses;
 
 /* Non-zero means warn in function declared in derived class has the
    same name as a virtual in the base class, but fails to match the
@@ -201,12 +228,22 @@ int warn_parentheses = 1;
 int warn_overloaded_virtual;
 
 /* Non-zero means warn when declaring a class that has a non virtual
-   destructor, when it really ought to have a virtual one. */
+   destructor, when it really ought to have a virtual one.  */
 int warn_nonvdtor;
 
 /* Non-zero means warn when a function is declared extern and later inline.  */
 int warn_extern_inline;
 
+/* Non-zero means warn when the compiler will reorder code.  */
+int warn_reorder;
+
+/* Non-zero means warn when synthesis behavior differs from Cfront's.  */
+int warn_synth;
+
+/* Non-zero means warn when we convert a pointer to member function
+   into a pointer to (void or function).  */
+int warn_pmf2ptr = 1;
+
 /* Nonzero means `$' can be in an identifier.
    See cccp.c for reasons why this breaks some obscure ANSI C programs.  */
 
@@ -218,6 +255,7 @@ int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
 /* Nonzero for -fno-strict-prototype switch: do not consider empty
    argument prototype to mean function takes no arguments.  */
 
+int flag_strict_prototype = 2;
 int strict_prototype = 1;
 int strict_prototypes_lang_c, strict_prototypes_lang_cplusplus = 1;
 
@@ -263,11 +301,6 @@ int write_virtuals;
 
 int flag_elide_constructors;
 
-/* Nonzero means recognize and handle exception handling constructs.
-   Use ansi syntax and semantics.  WORK IN PROGRESS!  */
-
-int flag_handle_exceptions;
-
 /* Nonzero means recognize and handle signature language constructs.  */
 
 int flag_handle_signatures;
@@ -282,17 +315,9 @@ int flag_default_inline = 1;
    0 means enums can convert to ints, but not vice-versa.  */
 int flag_int_enum_equivalence;
 
-/* Controls whether compiler is operating under LUCID's Cadillac
-   system.  1 means yes, 0 means no.  */
-int flag_cadillac;
-
-/* Controls whether compiler generates code to build objects
-   that can be collected when they become garbage.  */
-int flag_gc;
-
-/* Controls whether compiler generates 'dossiers' that give
+/* Controls whether compiler generates 'type descriptor' that give
    run-time type information.  */
-int flag_dossier;
+int flag_rtti = 1;
 
 /* Nonzero if we wish to output cross-referencing information
    for the GNU class browser.  */
@@ -308,18 +333,53 @@ extern int flag_gnu_xref;
    In general, it is `reasonable' to assume that for many programs,
    and better code can be generated in that case.  */
 
-int flag_assume_nonnull_objects;
+int flag_assume_nonnull_objects = 1;
 
 /* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
-   objects. */
+   objects.  */
+
 int flag_huge_objects;
 
 /* Nonzero if we want to conserve space in the .o files.  We do this
    by putting uninitialized data and runtime initialized data into
-   .common instead of .data at the expense of not flaging multiple
+   .common instead of .data at the expense of not flagging multiple
    definitions.  */
+
 int flag_conserve_space;
 
+/* Nonzero if we want to obey access control semantics.  */
+
+int flag_access_control = 1;
+
+/* Nonzero if we want to understand the operator names, i.e. 'bitand'.  */
+
+int flag_operator_names;
+
+/* Nonzero if we want to check the return value of new and avoid calling
+   constructors if it is a null pointer.  */
+
+int flag_check_new;
+
+/* Nonzero if we want the new ANSI rules for pushing a new scope for `for'
+   initialization variables.
+   0: Old rules, set by -fno-for-scope.
+   2: New ANSI rules, set by -ffor-scope.
+   1: Try to implement new ANSI rules, but with backup compatibility
+   (and warnings).  This is the default, for now.  */
+
+int flag_new_for_scope = 1;
+
+/* Nonzero if we want to emit defined symbols with common-like linkage as
+   weak symbols where possible, in order to conform to C++ semantics.
+   Otherwise, emit them as local symbols.  */
+
+int flag_weak = 1;
+
+/* Maximum template instantiation depth. Must be at least 17 for ANSI
+   compliance. */
+
+int max_tinst_depth = 17;
+
 /* Table of language-dependent -f options.
    STRING is the option name.  VARIABLE is the address of the variable.
    ON_VALUE is the value to store in VARIABLE
@@ -341,26 +401,32 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
   {"labels-ok", &flag_labels_ok, 1},
   {"stats", &flag_detailed_statistics, 1},
   {"this-is-variable", &flag_this_is_variable, 1},
-  {"strict-prototype", &strict_prototypes_lang_cplusplus, 1},
+  {"strict-prototype", &flag_strict_prototype, 1},
   {"all-virtual", &flag_all_virtual, 1},
   {"memoize-lookups", &flag_memoize_lookups, 1},
   {"elide-constructors", &flag_elide_constructors, 1},
-  {"handle-exceptions", &flag_handle_exceptions, 1},
   {"handle-signatures", &flag_handle_signatures, 1},
   {"default-inline", &flag_default_inline, 1},
   {"dollars-in-identifiers", &dollars_in_ident, 1},
   {"enum-int-equiv", &flag_int_enum_equivalence, 1},
-  {"gc", &flag_gc, 1},
-  {"dossier", &flag_dossier, 1},
+  {"rtti", &flag_rtti, 1},
   {"xref", &flag_gnu_xref, 1},
   {"nonnull-objects", &flag_assume_nonnull_objects, 1},
   {"implement-inlines", &flag_implement_inlines, 1},
   {"external-templates", &flag_external_templates, 1},
   {"implicit-templates", &flag_implicit_templates, 1},
+  {"ansi-overloading", &flag_ansi_overloading, 1},
   {"huge-objects", &flag_huge_objects, 1},
   {"conserve-space", &flag_conserve_space, 1},
   {"vtable-thunks", &flag_vtable_thunks, 1},
-  {"short-temps", &flag_short_temps, 1},
+  {"access-control", &flag_access_control, 1},
+  {"nonansi-builtins", &flag_no_nonansi_builtin, 0},
+  {"gnu-keywords", &flag_no_gnu_keywords, 0},
+  {"operator-names", &flag_operator_names, 1},
+  {"check-new", &flag_check_new, 1},
+  {"repo", &flag_use_repository, 1},
+  {"for-scope", &flag_new_for_scope, 2},
+  {"weak", &flag_weak, 1}
 };
 
 /* Decode the string P as a language-specific option.
@@ -372,8 +438,8 @@ lang_decode_option (p)
      char *p;
 {
   if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
-    flag_traditional = 1, dollars_in_ident = 1, flag_writable_strings = 1,
-    flag_this_is_variable = 1;
+    dollars_in_ident = 1, flag_writable_strings = 1,
+    flag_this_is_variable = 1, flag_new_for_scope = 0;
   /* The +e options are for cfront compatibility.  They come in as
      `-+eN', to kludge around gcc.c's argument handling.  */
   else if (p[0] == '-' && p[1] == '+' && p[2] == 'e')
@@ -412,30 +478,6 @@ lang_decode_option (p)
          flag_save_memoized_contexts = 0;
          found = 1;
        }
-      else if (! strncmp (p, "cadillac", 8))
-       {
-         flag_cadillac = atoi (p+9);
-         found = 1;
-       }
-      else if (! strncmp (p, "no-cadillac", 11))
-       {
-         flag_cadillac = 0;
-         found = 1;
-       }
-      else if (! strcmp (p, "gc"))
-       {
-         flag_gc = 1;
-         /* This must come along for the ride.  */
-         flag_dossier = 1;
-         found = 1;
-       }
-      else if (! strcmp (p, "no-gc"))
-       {
-         flag_gc = 0;
-         /* This must come along for the ride.  */
-         flag_dossier = 0;
-         found = 1;
-       }
       else if (! strcmp (p, "alt-external-templates"))
        {
          flag_external_templates = 1;
@@ -447,6 +489,28 @@ lang_decode_option (p)
          flag_alt_external_templates = 0;
          found = 1;
        }
+      else if (!strcmp (p, "repo"))
+       {
+         flag_use_repository = 1;
+         flag_implicit_templates = 0;
+         found = 1;
+       }
+      else if (!strncmp (p, "template-depth-", 15))
+       {
+         char *endp = p + 15;
+         while (*endp)
+           {
+             if (*endp >= '0' && *endp <= '9')
+               endp++;
+             else
+               {
+                 error ("Invalid option `%s'", p - 2);
+                 goto template_depth_lose;
+               }
+           }
+         max_tinst_depth = atoi (p + 15);
+       template_depth_lose: ;
+       }
       else for (j = 0;
                !found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]);
                j++)
@@ -487,20 +551,18 @@ lang_decode_option (p)
        warn_write_strings = setting;
       else if (!strcmp (p, "cast-qual"))
        warn_cast_qual = setting;
-      else if (!strcmp (p, "traditional"))
-       warn_traditional = setting;
       else if (!strcmp (p, "char-subscripts"))
        warn_char_subscripts = setting;
       else if (!strcmp (p, "pointer-arith"))
        warn_pointer_arith = setting;
-      else if (!strcmp (p, "strict-prototypes"))
-       warn_strict_prototypes = setting;
       else if (!strcmp (p, "missing-prototypes"))
        warn_missing_prototypes = setting;
       else if (!strcmp (p, "redundant-decls"))
        warn_redundant_decls = setting;
       else if (!strcmp (p, "missing-braces"))
        warn_missing_braces = setting;
+      else if (!strcmp (p, "sign-compare"))
+       warn_sign_compare = setting;
       else if (!strcmp (p, "format"))
        warn_format = setting;
       else if (!strcmp (p, "conversion"))
@@ -511,6 +573,12 @@ lang_decode_option (p)
        warn_nonvdtor = setting;
       else if (!strcmp (p, "extern-inline"))
        warn_extern_inline = setting;
+      else if (!strcmp (p, "reorder"))
+       warn_reorder = setting;
+      else if (!strcmp (p, "synth"))
+       warn_synth = setting;
+      else if (!strcmp (p, "pmf-conversions"))
+       warn_pmf2ptr = setting;
       else if (!strcmp (p, "comment"))
        ;                       /* cpp handles this one.  */
       else if (!strcmp (p, "comments"))
@@ -521,14 +589,15 @@ lang_decode_option (p)
        ;                       /* cpp handles this one.  */
       else if (!strcmp (p, "all"))
        {
-         extra_warnings = setting;
          warn_return_type = setting;
          warn_unused = setting;
          warn_implicit = setting;
          warn_ctor_dtor_privacy = setting;
          warn_switch = setting;
          warn_format = setting;
+         warn_parentheses = setting;
          warn_missing_braces = setting;
+         warn_sign_compare = setting;
          warn_extern_inline = setting;
          warn_nonvdtor = setting;
          /* We save the value of warn_uninitialized, since if they put
@@ -537,6 +606,7 @@ lang_decode_option (p)
          if (warn_uninitialized != 1)
            warn_uninitialized = (setting ? 2 : 0);
          warn_template_debugging = setting;
+         warn_reorder = setting;
        }
 
       else if (!strcmp (p, "overloaded-virtual"))
@@ -544,7 +614,8 @@ lang_decode_option (p)
       else return 0;
     }
   else if (!strcmp (p, "-ansi"))
-    flag_no_asm = 1, dollars_in_ident = 0, flag_ansi = 1;
+    dollars_in_ident = 0, flag_no_nonansi_builtin = 1, flag_ansi = 1,
+    flag_no_gnu_keywords = 1, flag_operator_names = 1;
 #ifdef SPEW_DEBUG
   /* Undocumented, only ever used when you're invoking cc1plus by hand, since
      it's probably safe to assume no sane person would ever want to use this
@@ -561,6 +632,7 @@ lang_decode_option (p)
 /* Incorporate `const' and `volatile' qualifiers for member functions.
    FUNCTION is a TYPE_DECL or a FUNCTION_DECL.
    QUALS is a list of qualifiers.  */
+
 tree
 grok_method_quals (ctype, function, quals)
      tree ctype, function, quals;
@@ -602,17 +674,18 @@ grok_method_quals (ctype, function, quals)
                                     ? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
                                     : TYPE_ARG_TYPES (fntype)));
   if (raises)
-    fntype = build_exception_variant (ctype, fntype, raises);
+    fntype = build_exception_variant (fntype, raises);
 
   TREE_TYPE (function) = fntype;
   return ctype;
 }
 
-#if 0                          /* Not used. */
+#if 0                          /* Not used.  */
 /* This routine replaces cryptic DECL_NAMEs with readable DECL_NAMEs.
    It leaves DECL_ASSEMBLER_NAMEs with the correct value.  */
 /* This does not yet work with user defined conversion operators
    It should.  */
+
 static void
 substitute_nice_name (decl)
      tree decl;
@@ -630,15 +703,38 @@ substitute_nice_name (decl)
 /* Warn when -fexternal-templates is used and #pragma
    interface/implementation is not used all the times it should be,
    inform the user.  */
+
 void
-warn_if_unknown_interface ()
+warn_if_unknown_interface (decl)
+     tree decl;
 {
   static int already_warned = 0;
-  if (++already_warned == 1)
-    warning ("templates that are built with -fexternal-templates should be in files that have #pragma interface/implementation");
+  if (already_warned++)
+    return;
+
+  if (flag_alt_external_templates)
+    {
+      struct tinst_level *til = tinst_for_decl ();
+      int sl = lineno;
+      char *sf = input_filename;
+
+      if (til)
+       {
+         lineno = til->line;
+         input_filename = til->file;
+       }
+      cp_warning ("template `%#D' instantiated in file without #pragma interface",
+                 decl);
+      lineno = sl;
+      input_filename = sf;
+    }
+  else
+    cp_warning_at ("template `%#D' defined in file without #pragma interface",
+                  decl);
 }
 
 /* A subroutine of the parser, to handle a component list.  */
+
 tree
 grok_x_components (specs, components)
      tree specs, components;
@@ -677,36 +773,34 @@ grok_x_components (specs, components)
          /* This code may be needed for UNION_TYPEs as
             well.  */
          tcode = record_type_node;
-         if (CLASSTYPE_DECLARED_CLASS(t))
+         if (CLASSTYPE_DECLARED_CLASS (t))
            tcode = class_type_node;
-         else if (IS_SIGNATURE(t))
+         else if (IS_SIGNATURE (t))
            tcode = signature_type_node;
-         else if (CLASSTYPE_DECLARED_EXCEPTION(t))
-           tcode = exception_type_node;
          
-         t = xref_defn_tag(tcode, TYPE_IDENTIFIER(t), NULL_TREE);
-         if (TYPE_CONTEXT(t))
-           CLASSTYPE_NO_GLOBALIZE(t) = 1;
-         if (TYPE_LANG_SPECIFIC (t)
-             && CLASSTYPE_DECLARED_EXCEPTION (t))
-           shadow_tag (specs);
+         t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
+         if (TYPE_CONTEXT (t))
+           CLASSTYPE_NO_GLOBALIZE (t) = 1;
          return NULL_TREE;
          break;
 
        case UNION_TYPE:
        case ENUMERAL_TYPE:
-         if (TREE_CODE(t) == UNION_TYPE)
+         if (TREE_CODE (t) == UNION_TYPE)
            tcode = union_type_node;
          else
            tcode = enum_type_node;
 
-         t = xref_defn_tag(tcode, TYPE_IDENTIFIER(t), NULL_TREE);
-         if (TREE_CODE(t) == UNION_TYPE && TYPE_CONTEXT(t))
-           CLASSTYPE_NO_GLOBALIZE(t) = 1;
+         t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
+         if (TREE_CODE (t) == UNION_TYPE && TYPE_CONTEXT (t))
+           CLASSTYPE_NO_GLOBALIZE (t) = 1;
          if (TREE_CODE (t) == UNION_TYPE
              && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
            {
+             /* See also shadow_tag.  */
+
              struct pending_inline **p;
+             tree *q;
              x = build_lang_field_decl (FIELD_DECL, NULL_TREE, t);
 
              /* Wipe out memory of synthesized methods */
@@ -718,6 +812,17 @@ grok_x_components (specs, components)
              TYPE_HAS_ASSIGNMENT (t) = 0;
              TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
 
+             q = &TYPE_METHODS (t);
+             while (*q)
+               {
+                 if (DECL_ARTIFICIAL (*q))
+                   *q = TREE_CHAIN (*q);
+                 else
+                   q = &TREE_CHAIN (*q);
+               }
+             if (TYPE_METHODS (t))
+               error ("an anonymous union cannot have function members");
+
              p = &pending_inlines;
              for (; *p; *p = (*p)->next)
                if (DECL_CONTEXT ((*p)->fndecl) != t)
@@ -776,6 +881,8 @@ grokclassfn (ctype, cname, function, flags, quals)
   tree arg_types;
   tree parm;
   tree qualtype;
+  tree fntype = TREE_TYPE (function);
+  tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
 
   if (fn_name == NULL_TREE)
     {
@@ -796,10 +903,11 @@ grokclassfn (ctype, cname, function, flags, quals)
       /* Right now we just make this a pointer.  But later
         we may wish to make it special.  */
       tree type = TREE_VALUE (arg_types);
+      int constp = 1;
 
       if ((flag_this_is_variable > 0)
          && (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)))
-       type = TYPE_MAIN_VARIANT (type);
+       constp = 0;
 
       if (DECL_CONSTRUCTOR_P (function))
        {
@@ -813,7 +921,7 @@ grokclassfn (ctype, cname, function, flags, quals)
              /* Mark the artificial `__in_chrg' parameter as "artificial".  */
              SET_DECL_ARTIFICIAL (parm);
              DECL_ARG_TYPE (parm) = integer_type_node;
-             DECL_REGISTER (parm) = 1;
+             TREE_READONLY (parm) = 1;
              TREE_CHAIN (parm) = last_function_parms;
              last_function_parms = parm;
            }
@@ -826,7 +934,7 @@ grokclassfn (ctype, cname, function, flags, quals)
       /* We can make this a register, so long as we don't
         accidentally complain if someone tries to take its address.  */
       DECL_REGISTER (parm) = 1;
-      if (TYPE_READONLY (type))
+      if (constp)
        TREE_READONLY (parm) = 1;
       TREE_CHAIN (parm) = last_function_parms;
       last_function_parms = parm;
@@ -855,23 +963,21 @@ grokclassfn (ctype, cname, function, flags, quals)
       buf[len] = '\0';
       strcat (buf, dbuf);
       DECL_ASSEMBLER_NAME (function) = get_identifier (buf);
-      parm = build_decl (PARM_DECL, in_charge_identifier, const_integer_type);
+      parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node);
       /* Mark the artificial `__in_chrg' parameter as "artificial".  */
       SET_DECL_ARTIFICIAL (parm);
-      TREE_USED (parm) = 1;
-#if 0
-      /* We don't need to mark the __in_chrg parameter itself as `const'
-        since its type is already `const int'.  In fact we MUST NOT mark
-        it as `const' cuz that will screw up the debug info (causing it
-        to say that the type of __in_chrg is `const const int').  */
       TREE_READONLY (parm) = 1;
-#endif
-      DECL_ARG_TYPE (parm) = const_integer_type;
+      DECL_ARG_TYPE (parm) = integer_type_node;
       /* This is the same chain as DECL_ARGUMENTS (...).  */
       TREE_CHAIN (last_function_parms) = parm;
 
-      TREE_TYPE (function) = build_cplus_method_type (qualtype, void_type_node,
-                                                     arg_types);
+      fntype = build_cplus_method_type (qualtype, void_type_node,
+                                       arg_types);
+      if (raises)
+       {
+         fntype = build_exception_variant (fntype, raises);
+       }
+      TREE_TYPE (function) = fntype;
       TYPE_HAS_DESTRUCTOR (ctype) = 1;
     }
   else
@@ -882,10 +988,14 @@ grokclassfn (ctype, cname, function, flags, quals)
        {
          arg_types = hash_tree_chain (integer_type_node,
                                       TREE_CHAIN (arg_types));
-         TREE_TYPE (function)
-           = build_cplus_method_type (qualtype,
-                                      TREE_TYPE (TREE_TYPE (function)),
-                                      arg_types);
+         fntype = build_cplus_method_type (qualtype,
+                                           TREE_TYPE (TREE_TYPE (function)),
+                                           arg_types);
+         if (raises)
+           {
+             fntype = build_exception_variant (fntype, raises);
+           }
+         TREE_TYPE (function) = fntype;
          arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
        }
 
@@ -893,7 +1003,7 @@ grokclassfn (ctype, cname, function, flags, quals)
 
       if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
        /* Only true for static member functions.  */
-       these_arg_types = hash_tree_chain (TYPE_POINTER_TO (qualtype),
+       these_arg_types = hash_tree_chain (build_pointer_type (qualtype),
                                           arg_types);
 
       DECL_ASSEMBLER_NAME (function)
@@ -902,7 +1012,7 @@ grokclassfn (ctype, cname, function, flags, quals)
 
 #if 0
       /* This code is going into the compiler, but currently, it makes
-        libg++/src/Interger.cc not compile.  The problem is that the nice name
+        libg++/src/Integer.cc not compile.  The problem is that the nice name
         winds up going into the symbol table, and conversion operations look
         for the manged name.  */
       substitute_nice_name (function);
@@ -916,6 +1026,7 @@ grokclassfn (ctype, cname, function, flags, quals)
 }
 
 /* Work on the expr used by alignof (this is only called by the parser).  */
+
 tree
 grok_alignof (expr)
      tree expr;
@@ -959,14 +1070,20 @@ grok_alignof (expr)
 
 /* Create an ARRAY_REF, checking for the user doing things backwards
    along the way.  */
+
 tree
 grok_array_decl (array_expr, index_exp)
      tree array_expr, index_exp;
 {
   tree type = TREE_TYPE (array_expr);
+  tree p1, p2, i1, i2;
 
   if (type == error_mark_node || index_exp == error_mark_node)
     return error_mark_node;
+  if (processing_template_decl)
+    return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE,
+                     array_expr, index_exp);
+
   if (type == NULL_TREE)
     {
       /* Something has gone very wrong.  Assume we are mistakenly reducing
@@ -981,36 +1098,43 @@ grok_array_decl (array_expr, index_exp)
 
   /* If they have an `operator[]', use that.  */
   if (TYPE_LANG_SPECIFIC (type)
-      && TYPE_OVERLOADS_ARRAY_REF (type))
+      && TYPE_OVERLOADS_ARRAY_REF (complete_type (type)))
     return build_opfncall (ARRAY_REF, LOOKUP_NORMAL,
-                        array_expr, index_exp, NULL_TREE);
+                          array_expr, index_exp, NULL_TREE);
 
   /* Otherwise, create an ARRAY_REF for a pointer or array type.  */
-  if (TREE_CODE (type) == POINTER_TYPE
-      || TREE_CODE (type) == ARRAY_TYPE)
-    return build_array_ref (array_expr, index_exp);
 
-  /* Woops, looks like they did something like `5[a]' instead of `a[5]'.
-     We don't emit a warning or error for this, since it's allowed
-     by ARM $8.2.4.  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    p1 = array_expr;
+  else
+    p1 = build_expr_type_conversion (WANT_POINTER, array_expr, 0);
 
-  type = TREE_TYPE (index_exp);
+  if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
+    p2 = index_exp;
+  else
+    p2 = build_expr_type_conversion (WANT_POINTER, index_exp, 0);
 
-  if (TREE_CODE (type) == OFFSET_TYPE
-      || TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, 0);
+  i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, 0);
 
-  if (TYPE_LANG_SPECIFIC (type)
-      && TYPE_OVERLOADS_ARRAY_REF (type))
-    error ("array expression backwards");
-  else if (TREE_CODE (type) == POINTER_TYPE
-          || TREE_CODE (type) == ARRAY_TYPE)
-    return build_array_ref (index_exp, array_expr);
+  if ((p1 && i2) && (i1 && p2))
+    error ("ambiguous conversion for array subscript");
+
+  if (p1 && i2)
+    array_expr = p1, index_exp = i2;
+  else if (i1 && p2)
+    array_expr = p2, index_exp = i1;
   else
-    error("`[]' applied to non-pointer type");
+    {
+      cp_error ("invalid types `%T[%T]' for array subscript",
+               type, TREE_TYPE (index_exp));
+      return error_mark_node;
+    }
+
+  if (array_expr == error_mark_node || index_exp == error_mark_node)
+    error ("ambiguous conversion for array subscript");
 
-  /* We gave an error, so give an error.  Huh?  */
-  return error_mark_node;
+  return build_array_ref (array_expr, index_exp);
 }
 
 /* Given the cast expression EXP, checking out its validity.   Either return
@@ -1020,29 +1144,41 @@ grok_array_decl (array_expr, index_exp)
    for doing an array delete.  If DOING_VEC is 2, they gave us the
    array size as an argument to delete.
    Implements ARM $5.3.4.  This is called from the parser.  */
+
 tree
 delete_sanity (exp, size, doing_vec, use_global_delete)
      tree exp, size;
      int doing_vec, use_global_delete;
 {
-  tree t = stabilize_reference (convert_from_reference (exp));
-  tree type = TREE_TYPE (t);
-  enum tree_code code = TREE_CODE (type);
+  tree t;
+  tree type;
+  enum tree_code code;
   /* For a regular vector delete (aka, no size argument) we will pass
      this down as a NULL_TREE into build_vec_delete.  */
   tree maxindex = NULL_TREE;
-  /* This is used for deleting arrays.  */
-  tree elt_size;
+
+  if (exp == error_mark_node)
+    return exp;
+
+  if (processing_template_decl)
+    {
+      t = build_min (DELETE_EXPR, void_type_node, exp, size);
+      DELETE_EXPR_USE_GLOBAL (t) = use_global_delete;
+      DELETE_EXPR_USE_VEC (t) = doing_vec;
+      return t;
+    }
+
+  t = stabilize_reference (convert_from_reference (exp));
+  type = TREE_TYPE (t);
+  code = TREE_CODE (type);
 
   switch (doing_vec)
     {
     case 2:
       maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
-      if (! flag_traditional)
-       pedwarn ("anachronistic use of array size in vector delete");
+      pedwarn ("anachronistic use of array size in vector delete");
       /* Fall through.  */
     case 1:
-      elt_size = c_sizeof (type);
       break;
     default:
       if (code != POINTER_TYPE)
@@ -1052,16 +1188,28 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
          return error_mark_node;
        }
 
-      /* Deleting a pointer with the value zero is legal and has no effect.  */
+      /* Deleting a pointer with the value zero is valid and has no effect.  */
       if (integer_zerop (t))
        return build1 (NOP_EXPR, void_type_node, t);
     }
 
-  /* You can't delete a pointer to constant.  */
-  if (code == POINTER_TYPE && TREE_READONLY (TREE_TYPE (type)))
+  if (code == POINTER_TYPE)
     {
-      error ("`const *' cannot be deleted");
-      return error_mark_node;
+#if 0
+      /* As of Valley Forge, you can delete a pointer to constant.  */
+      /* You can't delete a pointer to constant.  */
+      if (TREE_READONLY (TREE_TYPE (type)))
+       {
+         error ("`const *' cannot be deleted");
+         return error_mark_node;
+       }
+#endif
+      /* You also can't delete functions.  */
+      if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+       {
+         error ("cannot delete a function");
+         return error_mark_node;
+       }
     }
 
 #if 0
@@ -1079,25 +1227,37 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
 #endif
 
   if (doing_vec)
-    return build_vec_delete (t, maxindex, elt_size, integer_one_node,
+    return build_vec_delete (t, maxindex, integer_one_node,
                             integer_two_node, use_global_delete);
   else
-    return build_delete (type, t, integer_three_node,
-                        LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE,
-                        use_global_delete);
+    {
+      if (IS_AGGR_TYPE (TREE_TYPE (type))
+         && TYPE_GETS_REG_DELETE (TREE_TYPE (type)))
+       {
+         /* Only do access checking here; we'll be calling op delete
+            from the destructor.  */
+         tree tmp = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, t,
+                                    size_zero_node, NULL_TREE);
+         if (tmp == error_mark_node)
+           return error_mark_node;
+       }
+
+      return build_delete (type, t, integer_three_node,
+                          LOOKUP_NORMAL, use_global_delete);
+    }
 }
 
 /* Sanity check: report error if this function FUNCTION is not
    really a member of the class (CTYPE) it is supposed to belong to.
    CNAME is the same here as it is for grokclassfn above.  */
 
-void
-check_classfn (ctype, cname, function)
-     tree ctype, cname, function;
+tree
+check_classfn (ctype, function)
+     tree ctype, function;
 {
   tree fn_name = DECL_NAME (function);
   tree fndecl;
-  tree method_vec = CLASSTYPE_METHOD_VEC (ctype);
+  tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
   tree *methods = 0;
   tree *end = 0;
 
@@ -1107,7 +1267,11 @@ check_classfn (ctype, cname, function)
       end = TREE_VEC_END (method_vec);
 
       /* First suss out ctors and dtors.  */
-      if (*methods && fn_name == cname)
+      if (*methods && fn_name == DECL_NAME (*methods)
+         && DECL_CONSTRUCTOR_P (function))
+       goto got_it;
+      if (*++methods && fn_name == DECL_NAME (*methods)
+         && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
        goto got_it;
 
       while (++methods != end)
@@ -1119,7 +1283,32 @@ check_classfn (ctype, cname, function)
              while (fndecl)
                {
                  if (DECL_ASSEMBLER_NAME (function) == DECL_ASSEMBLER_NAME (fndecl))
-                   return;
+                   return fndecl;
+#if 0
+                 /* This doesn't work for static member functions that are
+                     pretending to be methods.  */
+                 /* We have to do more extensive argument checking here, as
+                    the name may have been changed by asm("new_name").  */
+                 if (decls_match (function, fndecl))
+                   return fndecl;
+#else
+                 if (DECL_NAME (function) == DECL_NAME (fndecl))
+                   {
+                     tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function));
+                     tree p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+
+                     /* Get rid of the this parameter on functions that become
+                        static.  */
+                     if (DECL_STATIC_FUNCTION_P (fndecl)
+                         && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
+                       p1 = TREE_CHAIN (p1);
+
+                     if (comptypes (TREE_TYPE (TREE_TYPE (function)),
+                                    TREE_TYPE (TREE_TYPE (fndecl)), 1)
+                         && compparms (p1, p2, 3))
+                       return fndecl;
+                   }
+#endif
                  fndecl = DECL_CHAIN (fndecl);
                }
              break;            /* loser */
@@ -1128,18 +1317,26 @@ check_classfn (ctype, cname, function)
     }
 
   if (methods != end)
-    cp_error ("argument list for `%D' does not match any in class `%T'",
-             fn_name, ctype);
+    {
+      tree fndecl = *methods;
+      cp_error ("prototype for `%#D' does not match any in class `%T'",
+               function, ctype);
+      cp_error_at ("candidate%s: %+#D", DECL_CHAIN (fndecl) ? "s are" : " is",
+                  fndecl);
+      while (fndecl = DECL_CHAIN (fndecl), fndecl)
+       cp_error_at ("                %#D", fndecl);
+    }
   else
     {
       methods = 0;
-      cp_error ("no `%D' member function declared in class `%T'",
-               fn_name, ctype);
+      cp_error ("no `%#D' member function declared in class `%T'",
+               function, ctype);
     }
 
-  /* If we did not find the method in the class, add it to
-     avoid spurious errors.  */
+  /* If we did not find the method in the class, add it to avoid
+     spurious errors.  */
   add_method (ctype, methods, function);
+  return NULL_TREE;
 }
 
 /* Process the specs, declarator (NULL if omitted) and width (NULL if omitted)
@@ -1163,11 +1360,12 @@ check_classfn (ctype, cname, function)
    CHANGES TO CODE IN `start_method'.  */
 
 tree
-grokfield (declarator, declspecs, raises, init, asmspec_tree)
-     tree declarator, declspecs, raises, init, asmspec_tree;
+grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
+     tree declarator, declspecs, init, asmspec_tree, attrlist;
 {
   register tree value;
   char *asmspec = 0;
+  int flags = LOOKUP_ONLYCONVERTING;
 
   /* Convert () initializers to = initializers.  */
   if (init == NULL_TREE && declarator != NULL_TREE
@@ -1179,15 +1377,28 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
     {
       init = TREE_OPERAND (declarator, 1);
       declarator = TREE_OPERAND (declarator, 0);
+      flags = 0;
+    }
+
+  if (declspecs == NULL_TREE
+      && TREE_CODE (declarator) == SCOPE_REF
+      && TREE_CODE (TREE_OPERAND (declarator, 1)) == IDENTIFIER_NODE)
+    {
+      /* Access declaration */
+      if (! IS_AGGR_TYPE_CODE (TREE_CODE (TREE_OPERAND (declarator, 0))))
+       ;
+      else if (TREE_COMPLEXITY (declarator) == current_class_depth)
+       pop_nested_class (1);
+      return do_class_using_decl (declarator);
     }
 
   if (init
       && TREE_CODE (init) == TREE_LIST
       && TREE_VALUE (init) == error_mark_node
       && TREE_CHAIN (init) == NULL_TREE)
-       init = NULL_TREE;
+    init = NULL_TREE;
 
-  value = grokdeclarator (declarator, declspecs, FIELD, init != 0, raises);
+  value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
   if (! value)
     return value; /* friend or constructor went bad.  */
 
@@ -1207,6 +1418,7 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
       DECL_CONTEXT (value) = current_class_type;
       DECL_CLASS_CONTEXT (value) = current_class_type;
       CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1;
+
       pushdecl_class_level (value);
       return value;
     }
@@ -1225,9 +1437,6 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
       return void_type_node;
     }
 
-  if (flag_cadillac)
-    cadillac_start_decl (value);
-
   if (asmspec_tree)
     asmspec = TREE_STRING_POINTER (asmspec_tree);
 
@@ -1244,7 +1453,7 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
          grok_function_init (value, init);
          init = NULL_TREE;
        }
-      else if (pedantic && ! TREE_STATIC (value))
+      else if (pedantic && TREE_CODE (value) != VAR_DECL)
        /* Already complained in grokdeclarator.  */
        init = NULL_TREE;
       else
@@ -1271,6 +1480,8 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
               because `decl_const_value' would mis-interpret it
               as only meaning that this VAR_DECL is defined.  */
            init = build1 (NOP_EXPR, TREE_TYPE (value), init);
+         else if (processing_template_decl)
+           ;
          else if (! TREE_CONSTANT (init))
            {
              /* We can allow references to things that are effectively
@@ -1287,35 +1498,35 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
        }
     }
 
-  /* The corresponding pop_obstacks is in finish_decl.  */
+  /* The corresponding pop_obstacks is in cp_finish_decl.  */
   push_obstacks_nochange ();
 
+  if (processing_template_decl && ! current_function_decl
+      && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == FUNCTION_DECL))
+    push_template_decl (value);
+
+  if (attrlist)
+    cplus_decl_attributes (value, TREE_PURPOSE (attrlist),
+                          TREE_VALUE (attrlist));
+
   if (TREE_CODE (value) == VAR_DECL)
     {
       /* We cannot call pushdecl here, because that would
         fill in the value of our TREE_CHAIN.  Instead, we
-        modify finish_decl to do the right thing, namely, to
+        modify cp_finish_decl to do the right thing, namely, to
         put this decl out straight away.  */
-      if (TREE_STATIC (value))
+      if (TREE_PUBLIC (value))
        {
          /* current_class_type can be NULL_TREE in case of error.  */
          if (asmspec == 0 && current_class_type)
            {
-             tree name;
-             char *buf, *buf2;
-
-             buf2 = build_overload_name (current_class_type, 1, 1);
-             buf = (char *)alloca (IDENTIFIER_LENGTH (DECL_NAME (value))
-                                   + sizeof (STATIC_NAME_FORMAT)
-                                   + strlen (buf2));
-             sprintf (buf, STATIC_NAME_FORMAT, buf2,
-                      IDENTIFIER_POINTER (DECL_NAME (value)));
-             name = get_identifier (buf);
              TREE_PUBLIC (value) = 1;
              DECL_INITIAL (value) = error_mark_node;
-             DECL_ASSEMBLER_NAME (value) = name;
+             DECL_ASSEMBLER_NAME (value)
+               = build_static_name (current_class_type, DECL_NAME (value));
            }
-         pending_statics = perm_tree_cons (NULL_TREE, value, pending_statics);
+         if (! processing_template_decl)
+           pending_statics = perm_tree_cons (NULL_TREE, value, pending_statics);
 
          /* Static consts need not be initialized in the class definition.  */
          if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (value)))
@@ -1334,24 +1545,32 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
        }
       DECL_INITIAL (value) = init;
       DECL_IN_AGGR_P (value) = 1;
+      DECL_CONTEXT (value) = current_class_type;
+      DECL_CLASS_CONTEXT (value) = current_class_type;
 
-      finish_decl (value, init, asmspec_tree, 1);
+      cp_finish_decl (value, init, asmspec_tree, 1, flags);
       pushdecl_class_level (value);
       return value;
     }
   if (TREE_CODE (value) == FIELD_DECL)
     {
       if (asmspec)
-       DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec);
+       {
+         /* This must override the asm specifier which was placed
+            by grokclassfn.  Lay this out fresh.  */
+         DECL_RTL (value) = NULL_RTX;
+         DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec);
+       }
       if (DECL_INITIAL (value) == error_mark_node)
        init = error_mark_node;
-      finish_decl (value, init, asmspec_tree, 1);
+      cp_finish_decl (value, init, asmspec_tree, 1, flags);
       DECL_INITIAL (value) = init;
       DECL_IN_AGGR_P (value) = 1;
       return value;
     }
   if (TREE_CODE (value) == FUNCTION_DECL)
     {
+      check_default_args (value);
       if (DECL_CHAIN (value) != NULL_TREE)
        {
          /* Need a fresh node here so that we don't get circularity
@@ -1360,15 +1579,24 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree)
          /* When does this happen?  */
          my_friendly_assert (init == NULL_TREE, 193);
        }
-      finish_decl (value, init, asmspec_tree, 1);
+      if (asmspec)
+       {
+         /* This must override the asm specifier which was placed
+            by grokclassfn.  Lay this out fresh.  */
+         DECL_RTL (value) = NULL_RTX;
+         DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec);
+       }
+      cp_finish_decl (value, init, asmspec_tree, 1, flags);
 
       /* Pass friends back this way.  */
       if (DECL_FRIEND_P (value))
        return void_type_node;
 
+#if 0 /* Just because a fn is declared doesn't mean we'll try to define it.  */
       if (current_function_decl && ! IS_SIGNATURE (current_class_type))
        cp_error ("method `%#D' of local class must be defined in class body",
                  value);
+#endif
 
       DECL_IN_AGGR_P (value) = 1;
       return value;
@@ -1385,7 +1613,8 @@ tree
 grokbitfield (declarator, declspecs, width)
      tree declarator, declspecs, width;
 {
-  register tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, NULL_TREE);
+  register tree value = grokdeclarator (declarator, declspecs, BITFIELD,
+                                       0, NULL_TREE);
 
   if (! value) return NULL_TREE; /* friends went bad.  */
 
@@ -1419,214 +1648,19 @@ grokbitfield (declarator, declspecs, width)
       cp_error ("static member `%D' cannot be a bitfield", value);
       return NULL_TREE;
     }
-  finish_decl (value, NULL_TREE, NULL_TREE, 0);
+  cp_finish_decl (value, NULL_TREE, NULL_TREE, 0, 0);
 
   if (width != error_mark_node)
     {
-      /* detect invalid field size.  */
-      if (TREE_CODE (width) == CONST_DECL)
-       width = DECL_INITIAL (width);
-      else if (TREE_READONLY_DECL_P (width))
-       width = decl_constant_value (width);
-      if (TREE_CODE (width) != INTEGER_CST)
-       {
-         cp_error ("structure field `%D' width not an integer constant",
-                     value);
-         DECL_INITIAL (value) = NULL_TREE;
-       }
-      else
-       {
-         constant_expression_warning (width);
-         DECL_INITIAL (value) = width;
-         DECL_BIT_FIELD (value) = 1;
-       }
+      constant_expression_warning (width);
+      DECL_INITIAL (value) = width;
+      DECL_BIT_FIELD (value) = 1;
     }
 
   DECL_IN_AGGR_P (value) = 1;
   return value;
 }
 
-#if 0
-/* Like GROKFIELD, except that the declarator has been
-   buried in DECLSPECS.  Find the declarator, and
-   return something that looks like it came from
-   GROKFIELD.  */
-tree
-groktypefield (declspecs, parmlist)
-     tree declspecs;
-     tree parmlist;
-{
-  tree spec = declspecs;
-  tree prev = NULL_TREE;
-
-  tree type_id = NULL_TREE;
-  tree quals = NULL_TREE;
-  tree lengths = NULL_TREE;
-  tree decl = NULL_TREE;
-
-  while (spec)
-    {
-      register tree id = TREE_VALUE (spec);
-
-      if (TREE_CODE (spec) != TREE_LIST)
-       /* Certain parse errors slip through.  For example,
-          `int class ();' is not caught by the parser. Try
-          weakly to recover here.  */
-       return NULL_TREE;
-
-      if (TREE_CODE (id) == TYPE_DECL
-         || (TREE_CODE (id) == IDENTIFIER_NODE && TREE_TYPE (id)))
-       {
-         /* We have a constructor/destructor or
-            conversion operator.  Use it.  */
-         if (prev)
-           TREE_CHAIN (prev) = TREE_CHAIN (spec);
-         else
-           declspecs = TREE_CHAIN (spec);
-
-         type_id = id;
-         goto found;
-       }
-      prev = spec;
-      spec = TREE_CHAIN (spec);
-    }
-
-  /* Nope, we have a conversion operator to a scalar type or something
-     else, that includes things like constructor declarations for
-     templates.  */
-  spec = declspecs;
-  while (spec)
-    {
-      tree id = TREE_VALUE (spec);
-
-      if (TREE_CODE (id) == IDENTIFIER_NODE)
-       {
-         if (id == ridpointers[(int)RID_INT]
-             || id == ridpointers[(int)RID_DOUBLE]
-             || id == ridpointers[(int)RID_FLOAT]
-             || id == ridpointers[(int)RID_WCHAR])
-           {
-             if (type_id)
-               error ("extra `%s' ignored",
-                      IDENTIFIER_POINTER (id));
-             else
-               type_id = id;
-           }
-         else if (id == ridpointers[(int)RID_LONG]
-                  || id == ridpointers[(int)RID_SHORT]
-                  || id == ridpointers[(int)RID_CHAR])
-           {
-             lengths = tree_cons (NULL_TREE, id, lengths);
-           }
-         else if (id == ridpointers[(int)RID_VOID])
-           {
-             if (type_id)
-               error ("spurious `void' type ignored");
-             else
-               error ("conversion to `void' type invalid");
-           }
-         else if (id == ridpointers[(int)RID_AUTO]
-                  || id == ridpointers[(int)RID_REGISTER]
-                  || id == ridpointers[(int)RID_TYPEDEF]
-                  || id == ridpointers[(int)RID_CONST]
-                  || id == ridpointers[(int)RID_VOLATILE])
-           {
-             error ("type specifier `%s' used invalidly",
-                    IDENTIFIER_POINTER (id));
-           }
-         else if (id == ridpointers[(int)RID_FRIEND]
-                  || id == ridpointers[(int)RID_VIRTUAL]
-                  || id == ridpointers[(int)RID_INLINE]
-                  || id == ridpointers[(int)RID_UNSIGNED]
-                  || id == ridpointers[(int)RID_SIGNED]
-                  || id == ridpointers[(int)RID_STATIC]
-                  || id == ridpointers[(int)RID_EXTERN])
-           {
-             quals = tree_cons (NULL_TREE, id, quals);
-           }
-         else
-           {
-             /* Happens when we have a global typedef
-                and a class-local member function with
-                the same name.  */
-             type_id = id;
-             goto found;
-           }
-       }
-      else if (TREE_CODE (id) == RECORD_TYPE)
-       {
-         type_id = TYPE_NAME (id);
-         if (TREE_CODE (type_id) == TYPE_DECL)
-           type_id = DECL_NAME (type_id);
-         if (type_id == NULL_TREE)
-           error ("identifier for aggregate type conversion omitted");
-       }
-      else if (TREE_CODE_CLASS (TREE_CODE (id)) == 't')
-       error ("`operator' missing on conversion operator or tag missing from type");
-      else
-       my_friendly_abort (194);
-      spec = TREE_CHAIN (spec);
-    }
-
-  if (type_id)
-    declspecs = chainon (lengths, quals);
-  else if (lengths)
-    {
-      if (TREE_CHAIN (lengths))
-       error ("multiple length specifiers");
-      type_id = ridpointers[(int)RID_INT];
-      declspecs = chainon (lengths, quals);
-    }
-  else if (quals)
-    {
-      error ("no type given, defaulting to `operator int ...'");
-      type_id = ridpointers[(int)RID_INT];
-      declspecs = quals;
-    }
-  else
-    return NULL_TREE;
-
- found:
-  decl = grokdeclarator (build_parse_node (CALL_EXPR, type_id, parmlist, NULL_TREE),
-                        declspecs, FIELD, 0, NULL_TREE);
-  if (decl == NULL_TREE)
-    return NULL_TREE;
-
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CHAIN (decl) != NULL_TREE)
-    {
-      /* Need a fresh node here so that we don't get circularity
-        when we link these together.  */
-      decl = copy_node (decl);
-    }
-
-  if (decl == void_type_node
-      || (TREE_CODE (decl) == FUNCTION_DECL
-         && TREE_CODE (TREE_TYPE (decl)) != METHOD_TYPE))
-    /* bunch of friends.  */
-    return decl;
-
-  if (DECL_IN_AGGR_P (decl))
-    {
-      cp_error ("`%D' already defined in the class ", decl);
-      return void_type_node;
-    }
-
-  finish_decl (decl, NULL_TREE, NULL_TREE, 0);
-
-  /* If this declaration is common to another declaration
-     complain about such redundancy, and return NULL_TREE
-     so that we don't build a circular list.  */
-  if (DECL_CHAIN (decl))
-    {
-      cp_error ("function `%D' declared twice in class %T", decl,
-                 DECL_CONTEXT (decl));
-      return NULL_TREE;
-    }
-  DECL_IN_AGGR_P (decl) = 1;
-  return decl;
-}
-#endif
-
 tree
 grokoptypename (declspecs, declarator)
      tree declspecs, declarator;
@@ -1675,11 +1709,18 @@ copy_assignment_arg_p (parmtype, virtualp)
      tree parmtype;
      int virtualp;
 {
+  if (current_class_type == NULL_TREE)
+    return 0;
+
   if (TREE_CODE (parmtype) == REFERENCE_TYPE)
     parmtype = TREE_TYPE (parmtype);
 
   if ((TYPE_MAIN_VARIANT (parmtype) == current_class_type)
-      || (virtualp && DERIVED_FROM_P (parmtype, current_class_type)))
+#if 0
+      /* Non-standard hack to support old Booch components.  */
+      || (! virtualp && DERIVED_FROM_P (parmtype, current_class_type))
+#endif
+      )
     return 1;
 
   return 0;
@@ -1696,14 +1737,17 @@ grok_function_init (decl, init)
 
   if (TREE_CODE (type) == FUNCTION_TYPE)
     cp_error ("initializer specified for non-member function `%D'", decl);
+#if 0
+  /* We'll check for this in finish_struct_1.  */
   else if (DECL_VINDEX (decl) == NULL_TREE)
     cp_error ("initializer specified for non-virtual method `%D'", decl);
+#endif
   else if (integer_zerop (init))
     {
 #if 0
       /* Mark this function as being "defined".  */
       DECL_INITIAL (decl) = error_mark_node;
-      /* pure virtual destructors must be defined. */
+      /* pure virtual destructors must be defined.  */
       /* pure virtual needs to be defined (as abort) only when put in 
         vtbl. For wellformed call, it should be itself. pr4737 */
       if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)))
@@ -1754,62 +1798,20 @@ grok_function_init (decl, init)
     cp_error ("invalid initializer for virtual method `%D'", decl);
 }
 \f
-/* When we get a declaration of the form
-
-   type cname::fname ...
-
-   the node for `cname::fname' gets built here in a special way.
-   Namely, we push into `cname's scope.  When this declaration is
-   processed, we pop back out.  */
-tree
-build_push_scope (cname, name)
-     tree cname;
-     tree name;
+void
+cplus_decl_attributes (decl, attributes, prefix_attributes)
+     tree decl, attributes, prefix_attributes;
 {
-  extern int current_class_depth;
-  tree ctype, rval;
-  int is_ttp = 0;
-
-  if (cname == error_mark_node)
-    return error_mark_node;
-
-  ctype = IDENTIFIER_TYPE_VALUE (cname);
-
-  if (TREE_CODE (ctype) == TEMPLATE_TYPE_PARM)
-    is_ttp = 1;
-  else if (ctype == NULL_TREE || ! IS_AGGR_TYPE (ctype))
-    {
-      cp_error ("`%T' not defined as aggregate type", cname);
-      return name;
-    }
-  else if (IS_SIGNATURE (ctype))
-    {
-      error ("cannot push into signature scope, scope resolution operator ignored");
-      return name;
-    }
-
-  rval = build_parse_node (SCOPE_REF, cname, name);
-
-  /* Don't need to push the scope if we're already in it.
-     We also don't need to push the scope for a ptr-to-member/method.  */
-
-  if (ctype == current_class_type || TREE_CODE (name) != IDENTIFIER_NODE
-      || is_ttp)
-    return rval;
+  if (decl == NULL_TREE || decl == void_type_node)
+    return;
 
-  /* We do need to push the scope in this case, since CTYPE helps
-     determine subsequent intializers (i.e., Foo::Bar x = foo_enum_1;).  */
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    decl = DECL_TEMPLATE_RESULT (decl);
 
-  push_nested_class (ctype, 3);
-  TREE_COMPLEXITY (rval) = current_class_depth;
-  return rval;
-}
+  decl_attributes (decl, attributes, prefix_attributes);
 
-void cplus_decl_attributes (decl, attributes)
-     tree decl, attributes;
-{
-  if (decl && decl != void_type_node)
-    decl_attributes (decl, attributes);
+  if (TREE_CODE (decl) == TYPE_DECL)
+    SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (decl), TREE_TYPE (decl));
 }
 \f
 /* CONSTRUCTOR_NAME:
@@ -1817,22 +1819,23 @@ void cplus_decl_attributes (decl, attributes)
    specified class.  Argument can be RECORD_TYPE, TYPE_DECL, or
    IDENTIFIER_NODE.  When given a template, this routine doesn't
    lose the specialization.  */
+
 tree
 constructor_name_full (thing)
      tree thing;
 {
-  if (TREE_CODE (thing) == UNINSTANTIATED_P_TYPE)
-    return DECL_NAME (UPT_TEMPLATE (thing));
-  if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
+  if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM)
+    thing = TYPE_NAME (thing);
+  else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
     {
       if (TYPE_WAS_ANONYMOUS (thing) && TYPE_HAS_CONSTRUCTOR (thing))
-       thing = DECL_NAME (TREE_VEC_ELT (TYPE_METHODS (thing), 0));
+       thing = DECL_NAME (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0));
       else
        thing = TYPE_NAME (thing);
     }
   if (TREE_CODE (thing) == TYPE_DECL
       || (TREE_CODE (thing) == TEMPLATE_DECL
-         && DECL_TEMPLATE_IS_CLASS (thing)))
+         && TREE_CODE (DECL_TEMPLATE_RESULT (thing)) == TYPE_DECL))
     thing = DECL_NAME (thing);
   my_friendly_assert (TREE_CODE (thing) == IDENTIFIER_NODE, 197);
   return thing;
@@ -1843,6 +1846,7 @@ constructor_name_full (thing)
    specified class.  Argument can be RECORD_TYPE, TYPE_DECL, or
    IDENTIFIER_NODE.  When given a template, return the plain
    unspecialized name.  */
+
 tree
 constructor_name (thing)
      tree thing;
@@ -1852,84 +1856,42 @@ constructor_name (thing)
   t = IDENTIFIER_TEMPLATE (thing);
   if (!t)
     return thing;
-  t = TREE_PURPOSE (t);
-  return DECL_NAME (t);
+  return t;
 }
 \f
 /* Cache the value of this class's main virtual function table pointer
    in a register variable.  This will save one indirection if a
    more than one virtual function call is made this function.  */
+
 void
 setup_vtbl_ptr ()
 {
-  extern rtx base_init_insns;
+  extern tree base_init_expr;
 
-  if (base_init_insns == 0
+  if (base_init_expr == 0
       && DECL_CONSTRUCTOR_P (current_function_decl))
-    emit_base_init (current_class_type, 0);
-
-#if 0
-  /* This has something a little wrong with it.
-
-     On a sun4, code like:
-
-        be L6
-        ld [%i0],%o1
-
-     is generated, when the below is used when -O4 is given.  The delay
-     slot it filled with an instruction that is safe, when this isn't
-     used, like in:
-
-        be L6
-        sethi %hi(LC1),%o0
-        ld [%i0],%o1
-
-     on code like:
-
-        struct A {
-          virtual void print() { printf("xxx"); }
-          void f();
-        };
-
-        void A::f() {
-          if (this) {
-            print();
-          } else {
-            printf("0");
-          }
-        }
-
-     And that is why this is disabled for now. (mrs)
-  */
-
-  if ((flag_this_is_variable & 1) == 0
-      && optimize
-      && current_class_type
-      && CLASSTYPE_VSIZE (current_class_type)
-      && ! DECL_STATIC_FUNCTION_P (current_function_decl))
-    {
-      tree vfield = build_vfield_ref (C_C_D, current_class_type);
-      current_vtable_decl = CLASSTYPE_VTBL_PTR (current_class_type);
-      DECL_RTL (current_vtable_decl) = 0;
-      DECL_INITIAL (current_vtable_decl) = error_mark_node;
-      /* Have to cast the initializer, since it may have come from a
-        more base class then we ascribe CURRENT_VTABLE_DECL to be.  */
-      finish_decl (current_vtable_decl, convert_force (TREE_TYPE (current_vtable_decl), vfield), 0, 0);
-      current_vtable_decl = build_indirect_ref (current_vtable_decl, NULL_PTR);
+    {
+      if (processing_template_decl)
+       add_tree (build_min_nt
+                 (CTOR_INITIALIZER,
+                  current_member_init_list, current_base_init_list));
+      else
+       emit_base_init (current_class_type, 0);
     }
-  else
-#endif
-    current_vtable_decl = NULL_TREE;
 }
 
 /* Record the existence of an addressable inline function.  */
+
 void
 mark_inline_for_output (decl)
      tree decl;
 {
+  decl = DECL_MAIN_VARIANT (decl);
   if (DECL_SAVED_INLINE (decl))
     return;
+  my_friendly_assert (TREE_PERMANENT (decl), 363);
   DECL_SAVED_INLINE (decl) = 1;
+#if 0
   if (DECL_PENDING_INLINE_INFO (decl) != 0
       && ! DECL_PENDING_INLINE_INFO (decl)->deja_vu)
     {
@@ -1949,6 +1911,7 @@ mark_inline_for_output (decl)
        }
       DECL_PENDING_INLINE_INFO (decl) = 0;
     }
+#endif
   saved_inlines = perm_tree_cons (NULL_TREE, decl, saved_inlines);
 }
 
@@ -1972,7 +1935,7 @@ get_temp_name (type, staticp)
 {
   char buf[sizeof (AUTO_TEMP_FORMAT) + 20];
   tree decl;
-  int toplev = global_bindings_p ();
+  int toplev = toplevel_bindings_p ();
 
   push_obstacks_nochange ();
   if (toplev || staticp)
@@ -1988,6 +1951,7 @@ get_temp_name (type, staticp)
     }
   TREE_USED (decl) = 1;
   TREE_STATIC (decl) = staticp;
+  DECL_ARTIFICIAL (decl) = 1;
 
   /* If this is a local variable, then lay out its rtl now.
      Otherwise, callers of this function are responsible for dealing
@@ -2006,6 +1970,7 @@ get_temp_name (type, staticp)
    It is not entered into current_binding_level, because
    that breaks things when it comes time to do final cleanups
    (which take place "outside" the binding contour of the function).  */
+
 tree
 get_temp_regvar (type, init)
      tree type, init;
@@ -2026,27 +1991,16 @@ get_temp_regvar (type, init)
   expand_decl (decl);
   expand_decl_init (decl);
 
-  if (type_needs_gc_entry (type))
-    DECL_GC_OFFSET (decl) = size_int (++current_function_obstack_index);
-
   return decl;
 }
 
-/* Make the macro TEMP_NAME_P available to units which do not
-   include c-tree.h.  */
-int
-temp_name_p (decl)
-     tree decl;
-{
-  return TEMP_NAME_P (decl);
-}
-
 /* Finish off the processing of a UNION_TYPE structure.
    If there are static members, then all members are
    static, and must be laid out together.  If the
    union is an anonymous union, we arrange for that
    as well.  PUBLIC_P is nonzero if this union is
    not declared static.  */
+
 void
 finish_anon_union (anon_union_decl)
      tree anon_union_decl;
@@ -2067,9 +2021,18 @@ finish_anon_union (anon_union_decl)
       return;
     }
 
-  while (field)
+  for (; field; field = TREE_CHAIN (field))
     {
-      tree decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
+      tree decl;
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
+
+      if (TREE_PRIVATE (field))
+       cp_pedwarn_at ("private member `%#D' in anonymous union", field);
+      else if (TREE_PROTECTED (field))
+       cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
+
+      decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
       /* tell `pushdecl' that this is not tentative.  */
       DECL_INITIAL (decl) = error_mark_node;
       TREE_PUBLIC (decl) = public_p;
@@ -2080,7 +2043,8 @@ finish_anon_union (anon_union_decl)
       /* Only write out one anon union element--choose the one that
         can hold them all.  */
       if (main_decl == NULL_TREE
-         && simple_cst_equal (DECL_SIZE (decl), DECL_SIZE (anon_union_decl)))
+         && 1 == simple_cst_equal (DECL_SIZE (decl),
+                                   DECL_SIZE (anon_union_decl)))
        {
          main_decl = decl;
        }
@@ -2096,20 +2060,24 @@ finish_anon_union (anon_union_decl)
         TREE_PURPOSE of the following TREE_LIST.  */
       elems = tree_cons (NULL_TREE, decl, elems);
       TREE_TYPE (elems) = type;
-      field = TREE_CHAIN (field);
     }
   if (static_p)
     {
-      make_decl_rtl (main_decl, 0, global_bindings_p ());
-      DECL_RTL (anon_union_decl) = DECL_RTL (main_decl);
+      if (main_decl)
+       {
+         make_decl_rtl (main_decl, 0, toplevel_bindings_p ());
+         DECL_RTL (anon_union_decl) = DECL_RTL (main_decl);
+       }
+      else
+       {
+         warning ("anonymous union with no members");
+         return;
+       }
     }
 
   /* The following call assumes that there are never any cleanups
      for anonymous unions--a reasonable assumption.  */
   expand_anon_union_decl (anon_union_decl, NULL_TREE, elems);
-
-  if (flag_cadillac)
-    cadillac_finish_anon_union (anon_union_decl);
 }
 
 /* Finish and output a table which is generated by the compiler.
@@ -2117,6 +2085,7 @@ finish_anon_union (anon_union_decl)
    TYPE is the type of the table entry.
    INIT is all the elements in the table.
    PUBLICP is non-zero if this table should be given external access.  */
+
 tree
 finish_table (name, type, init, publicp)
      tree name, type, init;
@@ -2134,7 +2103,9 @@ finish_table (name, type, init, publicp)
   if (TREE_VALUE (init) == integer_zero_node
       && TREE_CHAIN (init) == NULL_TREE)
     {
+#if 0
       if (empty_table == NULL_TREE)
+#endif
        {
          empty_table = get_temp_name (atype, 1);
          init = build (CONSTRUCTOR, atype, NULL_TREE, init);
@@ -2143,7 +2114,7 @@ finish_table (name, type, init, publicp)
          DECL_INITIAL (empty_table) = init;
          asmspec = build_string (IDENTIFIER_LENGTH (DECL_NAME (empty_table)),
                                  IDENTIFIER_POINTER (DECL_NAME (empty_table)));
-         finish_decl (empty_table, init, asmspec, 0);
+         cp_finish_decl (empty_table, NULL_TREE, asmspec, 0, 0);
        }
       is_empty = 1;
     }
@@ -2181,7 +2152,7 @@ finish_table (name, type, init, publicp)
                              IDENTIFIER_POINTER (DECL_NAME (empty_table)));
     }
 
-  finish_decl (decl, init, asmspec, 0);
+  cp_finish_decl (decl, NULL_TREE, asmspec, 0, 0);
   return decl;
 }
 
@@ -2191,6 +2162,7 @@ finish_table (name, type, init, publicp)
    used in FIELDS.
 
    It is given the same alignment as ALIGN_TYPE.  */
+
 void
 finish_builtin_type (type, name, fields, len, align_type)
      tree type;
@@ -2217,6 +2189,7 @@ finish_builtin_type (type, name, fields, len, align_type)
 #else
   TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type);
 #endif
+  TYPE_STUB_DECL (type) = TYPE_NAME (type);
   layout_decl (TYPE_NAME (type), 0);
 }
 \f
@@ -2263,8 +2236,10 @@ coerce_delete_type (type)
       type = build_function_type (TREE_TYPE (type), TREE_CHAIN (arg_types));
       arg_types = TREE_CHAIN (arg_types);
     }
+
   if (TREE_TYPE (type) != void_type_node)
     e1 = 1, error ("`operator delete' must return type `void'");
+
   if (arg_types == NULL_TREE
       || TREE_VALUE (arg_types) != ptr_type_node)
     e2 = 1, error ("`operator delete' takes type `void *' as first parameter");
@@ -2288,8 +2263,10 @@ coerce_delete_type (type)
            error ("`...' invalid in specification of `operator delete'");
        }
     }
+
   if (e3)
-    arg_types = tree_cons (NULL_TREE, ptr_type_node, build_tree_list (NULL_TREE, sizetype));
+    arg_types = tree_cons (NULL_TREE, ptr_type_node,
+                          build_tree_list (NULL_TREE, sizetype));
   else if (e3 |= e2)
     {
       if (arg_types == NULL_TREE)
@@ -2305,112 +2282,179 @@ coerce_delete_type (type)
   return type;
 }
 \f
+extern tree abort_fndecl;
+
 static void
 mark_vtable_entries (decl)
      tree decl;
 {
-  tree entries = TREE_CHAIN (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)));
+  tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl));
 
-  if (flag_dossier)
-    entries = TREE_CHAIN (entries);
+  if (flag_rtti)
+    {
+      tree fnaddr = (flag_vtable_thunks ? TREE_VALUE (TREE_CHAIN (entries))
+                    : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries)));
+      tree fn = TREE_OPERAND (fnaddr, 0);
+      TREE_ADDRESSABLE (fn) = 1;
+      mark_used (fn);
+    }
+  skip_rtti_stuff (&entries);
 
   for (; entries; entries = TREE_CHAIN (entries))
     {
-      tree fnaddr = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries));
+      tree fnaddr = (flag_vtable_thunks ? TREE_VALUE (entries) 
+                    : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries)));
       tree fn = TREE_OPERAND (fnaddr, 0);
       TREE_ADDRESSABLE (fn) = 1;
-      if (DECL_ABSTRACT_VIRTUAL_P (fn))
+      if (DECL_LANG_SPECIFIC (fn) && DECL_ABSTRACT_VIRTUAL_P (fn))
+       TREE_OPERAND (fnaddr, 0) = fn = abort_fndecl;
+      if (TREE_CODE (fn) == THUNK_DECL && DECL_EXTERNAL (fn))
        {
-         extern tree abort_fndecl;
-         TREE_OPERAND (fnaddr, 0) = abort_fndecl;
+         DECL_EXTERNAL (fn) = 0;
+         emit_thunk (fn);
        }
+      mark_used (fn);
     }
 }
 
-/* Set TREE_PUBLIC and/or TREE_EXTERN on the vtable DECL,
+/* Set DECL up to have the closest approximation of "initialized common"
+   linkage available.  */
+
+void
+comdat_linkage (decl)
+     tree decl;
+{
+  if (flag_weak)
+    make_decl_one_only (decl);
+  else
+    TREE_PUBLIC (decl) = 0;
+}
+
+/* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL,
    based on TYPE and other static flags.
 
    Note that anything public is tagged TREE_PUBLIC, whether
    it's public in this file or in another one.  */
 
-static void
-import_export_vtable (decl, type)
-  tree decl, type;
+void
+import_export_vtable (decl, type, final)
+     tree decl, type;
+     int final;
 {
-  if (write_virtuals >= 2
-      || CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+  if (DECL_INTERFACE_KNOWN (decl))
+    return;
+
+  /* +e0 or +e1 */
+  if (write_virtuals < 2 && write_virtuals != 0)
     {
-      if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
-         && ! flag_implicit_templates
-         && CLASSTYPE_INTERFACE_UNKNOWN (type))
+      TREE_PUBLIC (decl) = 1;
+      if (write_virtuals < 0)
+       DECL_EXTERNAL (decl) = 1;
+      DECL_INTERFACE_KNOWN (decl) = 1;
+    }
+  else if (CLASSTYPE_INTERFACE_KNOWN (type))
+    {
+      TREE_PUBLIC (decl) = 1;
+      DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
+      DECL_INTERFACE_KNOWN (decl) = 1;
+    }
+  else
+    {
+      /* We can only wait to decide if we have real non-inline virtual
+        functions in our class, or if we come from a template.  */
+
+      int found = CLASSTYPE_TEMPLATE_INSTANTIATION (type);
+
+      if (! found && ! final)
        {
-         SET_CLASSTYPE_INTERFACE_KNOWN (type);
-         CLASSTYPE_INTERFACE_ONLY (type) = 1;
-         CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 0;
+         tree method;
+         for (method = TYPE_METHODS (type); method != NULL_TREE;
+              method = TREE_CHAIN (method))
+           if (DECL_VINDEX (method) != NULL_TREE
+               && ! DECL_THIS_INLINE (method)
+               && ! DECL_ABSTRACT_VIRTUAL_P (method))
+             {
+               found = 1;
+               break;
+             }
        }
 
-      if (CLASSTYPE_INTERFACE_KNOWN (type))
+      if (final || ! found)
+       {
+         comdat_linkage (decl);
+         DECL_EXTERNAL (decl) = 0;
+       }
+      else
        {
          TREE_PUBLIC (decl) = 1;
-         DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
+         DECL_EXTERNAL (decl) = 1;
        }
     }
-  else if (write_virtuals != 0)
-    {
-      TREE_PUBLIC (decl) = 1;
-      if (write_virtuals < 0)
-       DECL_EXTERNAL (decl) = 1;
-    }
 }
 
 static void
-finish_vtable_vardecl (prev, vars)
+import_export_template (type)
+     tree type;
+{
+  if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
+      && ! flag_implicit_templates
+      && CLASSTYPE_INTERFACE_UNKNOWN (type))
+    {
+      SET_CLASSTYPE_INTERFACE_KNOWN (type);
+      CLASSTYPE_INTERFACE_ONLY (type) = 1;
+      CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 0;
+    }
+}
+    
+int
+finish_prevtable_vardecl (prev, vars)
      tree prev, vars;
 {
   tree ctype = DECL_CONTEXT (vars);
-  import_export_vtable (vars, ctype);
+  import_export_template (ctype);
 
-  if (flag_vtable_thunks && !CLASSTYPE_INTERFACE_KNOWN (ctype))
+#ifndef NO_LINKAGE_HEURISTICS
+  if (CLASSTYPE_INTERFACE_UNKNOWN (ctype) && TYPE_VIRTUAL_P (ctype)
+      && ! CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
     {
       tree method;
-      for (method = CLASSTYPE_METHODS (ctype); method != NULL_TREE;
-          method = DECL_NEXT_METHOD (method))
+      for (method = TYPE_METHODS (ctype); method != NULL_TREE;
+          method = TREE_CHAIN (method))
        {
-         if (DECL_VINDEX (method) != NULL_TREE && !DECL_SAVED_INSNS (method)
+         if (DECL_VINDEX (method) != NULL_TREE
+             && !DECL_THIS_INLINE (method)
              && !DECL_ABSTRACT_VIRTUAL_P (method))
            {
              SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
+             CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = ! DECL_EXTERNAL (method);
              CLASSTYPE_INTERFACE_ONLY (ctype) = DECL_EXTERNAL (method);
-             TREE_PUBLIC (vars) = 1;
-             DECL_EXTERNAL (vars) = DECL_EXTERNAL (method);
              break;
            }
        }
     }
+#endif
 
+  import_export_vtable (vars, ctype, 1);
+  return 1;
+}
+    
+static int
+finish_vtable_vardecl (prev, vars)
+     tree prev, vars;
+{
   if (write_virtuals >= 0
-      && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars)))
+      && ! DECL_EXTERNAL (vars)
+      && ((TREE_PUBLIC (vars) && ! DECL_WEAK (vars) && ! DECL_ONE_ONLY (vars))
+         || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars))
+         || (hack_decl_function_context (vars) && TREE_USED (vars)))
+      && ! TREE_ASM_WRITTEN (vars))
     {
-      extern tree the_null_vtable_entry;
-
-      /* Stuff this virtual function table's size into
-        `pfn' slot of `the_null_vtable_entry'.  */
-      tree nelts = array_type_nelts (TREE_TYPE (vars));
-      if (flag_vtable_thunks)
-       TREE_VALUE (CONSTRUCTOR_ELTS (DECL_INITIAL (vars))) = nelts;
-      else
-       SET_FNADDR_FROM_VTABLE_ENTRY (the_null_vtable_entry, nelts);
-      /* Kick out the dossier before writing out the vtable.  */
-      if (flag_dossier)
-       rest_of_decl_compilation (TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (DECL_INITIAL (vars))))), 0), 0, 1, 1);
-
       /* Write it out.  */
       mark_vtable_entries (vars);
       if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
-         store_init_value (vars, DECL_INITIAL (vars));
+       store_init_value (vars, DECL_INITIAL (vars));
 
-#ifdef DWARF_DEBUGGING_INFO
-      if (write_symbols == DWARF_DEBUG)
+      if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
        {
          /* Mark the VAR_DECL node representing the vtable itself as a
             "gratuitous" one, thereby forcing dwarfout.c to ignore it.
@@ -2435,19 +2479,79 @@ finish_vtable_vardecl (prev, vars)
 
          DECL_IGNORED_P (vars) = 1;
        }
-#endif /* DWARF_DEBUGGING_INFO */
 
-      rest_of_decl_compilation (vars, 0, 1, 1);
+      rest_of_decl_compilation (vars, NULL_PTR, 1, 1);
+      return 1;
     }
-  else if (TREE_USED (vars) && flag_vtable_thunks)
-    assemble_external (vars);
+  else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)))
+    /* We don't know what to do with this one yet.  */
+    return 0;
+
   /* We know that PREV must be non-zero here.  */
   TREE_CHAIN (prev) = TREE_CHAIN (vars);
+  return 0;
 }
 
-void
+static int
+prune_vtable_vardecl (prev, vars)
+     tree prev, vars;
+{
+  /* We know that PREV must be non-zero here.  */
+  TREE_CHAIN (prev) = TREE_CHAIN (vars);
+  return 1;
+}
+
+int
 walk_vtables (typedecl_fn, vardecl_fn)
      register void (*typedecl_fn)();
+     register int (*vardecl_fn)();
+{
+  tree prev, vars;
+  int flag = 0;
+
+  for (prev = 0, vars = getdecls (); vars; vars = TREE_CHAIN (vars))
+    {
+      register tree type = TREE_TYPE (vars);
+
+      if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars))
+       {
+         if (vardecl_fn)
+           flag |= (*vardecl_fn) (prev, vars);
+
+         if (prev && TREE_CHAIN (prev) != vars)
+           continue;
+       }
+      else if (TREE_CODE (vars) == TYPE_DECL
+              && type != error_mark_node
+              && TYPE_LANG_SPECIFIC (type)
+              && CLASSTYPE_VSIZE (type))
+       {
+         if (typedecl_fn) (*typedecl_fn) (prev, vars);
+       }
+
+      prev = vars;
+    }
+
+  return flag;
+}
+
+static void
+finish_sigtable_vardecl (prev, vars)
+     tree prev, vars;
+{
+  /* We don't need to mark sigtable entries as addressable here as is done
+     for vtables.  Since sigtables, unlike vtables, are always written out,
+     that was already done in build_signature_table_constructor.  */
+
+  rest_of_decl_compilation (vars, NULL_PTR, 1, 1);
+
+  /* We know that PREV must be non-zero here.  */
+  TREE_CHAIN (prev) = TREE_CHAIN (vars);
+}
+
+void
+walk_sigtables (typedecl_fn, vardecl_fn)
+     register void (*typedecl_fn)();
      register void (*vardecl_fn)();
 {
   tree prev, vars;
@@ -2458,12 +2562,13 @@ walk_vtables (typedecl_fn, vardecl_fn)
 
       if (TREE_CODE (vars) == TYPE_DECL
          && type != error_mark_node
-         && TYPE_LANG_SPECIFIC (type)
-         && CLASSTYPE_VSIZE (type))
+         && IS_SIGNATURE (type))
        {
          if (typedecl_fn) (*typedecl_fn) (prev, vars);
        }
-      else if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars))
+      else if (TREE_CODE (vars) == VAR_DECL
+              && TREE_TYPE (vars) != error_mark_node
+              && IS_SIGNATURE (TREE_TYPE (vars)))
        {
          if (vardecl_fn) (*vardecl_fn) (prev, vars);
        }
@@ -2472,10 +2577,129 @@ walk_vtables (typedecl_fn, vardecl_fn)
     }
 }
 
+/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
+   inline function or template instantiation at end-of-file.  */
+
+void
+import_export_decl (decl)
+     tree decl;
+{
+  if (DECL_INTERFACE_KNOWN (decl))
+    return;
+
+  if (DECL_TEMPLATE_INSTANTIATION (decl))
+    {
+      DECL_NOT_REALLY_EXTERN (decl) = 1;
+      if (DECL_IMPLICIT_INSTANTIATION (decl)
+         && (flag_implicit_templates || DECL_THIS_INLINE (decl)))
+       {
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           comdat_linkage (decl);
+         /* Dynamically initialized vars go into common.  */
+         else if (DECL_INITIAL (decl) == NULL_TREE
+                  || DECL_INITIAL (decl) == error_mark_node)
+           DECL_COMMON (decl) = 1;
+         else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
+           {
+             DECL_COMMON (decl) = 1;
+             DECL_INITIAL (decl) = error_mark_node;
+           }
+         else
+           {
+             /* Statically initialized vars are weak or comdat, if
+                 supported.  */
+             if (flag_weak)
+               make_decl_one_only (decl);
+             /* else leave vars public so multiple defs will break.  */
+           }
+       }
+      else
+       DECL_NOT_REALLY_EXTERN (decl) = 0;
+    }
+  else if (DECL_FUNCTION_MEMBER_P (decl))
+    {
+      tree ctype = DECL_CLASS_CONTEXT (decl);
+      if (CLASSTYPE_INTERFACE_KNOWN (ctype) && ! DECL_ARTIFICIAL (decl))
+       {
+         DECL_NOT_REALLY_EXTERN (decl)
+           = ! (CLASSTYPE_INTERFACE_ONLY (ctype)
+                || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+       }
+      else
+       comdat_linkage (decl);
+    }
+  /* tinfo function */
+  else if (DECL_ARTIFICIAL (decl) && DECL_MUTABLE_P (decl))
+    {
+      tree ctype = TREE_TYPE (DECL_NAME (decl));
+      if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype)
+         && TYPE_VIRTUAL_P (ctype))
+       {
+         DECL_NOT_REALLY_EXTERN (decl)
+           = ! (CLASSTYPE_INTERFACE_ONLY (ctype)
+                || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+       }
+      else if (TYPE_BUILT_IN (ctype) && ctype == TYPE_MAIN_VARIANT (ctype))
+       DECL_NOT_REALLY_EXTERN (decl) = 0;
+      else
+       comdat_linkage (decl);
+    } 
+  else if (DECL_C_STATIC (decl))
+    TREE_PUBLIC (decl) = 0;
+  else
+    comdat_linkage (decl);
+
+  DECL_INTERFACE_KNOWN (decl) = 1;
+}
+
+tree
+build_cleanup (decl)
+     tree decl;
+{
+  tree temp;
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    temp = decl;
+  else
+    {
+      mark_addressable (decl);
+      temp = build1 (ADDR_EXPR, build_pointer_type (type), decl);
+    }
+  temp = build_delete (TREE_TYPE (temp), temp,
+                      integer_two_node,
+                      LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+  return temp;
+}
+
 extern int parse_time, varconst_time;
+extern tree pending_templates;
+extern tree maybe_templates;
+
+extern struct obstack permanent_obstack;
+extern tree get_id_2 ();
 
-#define TIMEVAR(VAR, BODY)    \
-do { int otime = get_run_time (); BODY; VAR += get_run_time () - otime; } while (0)
+static tree
+get_sentry (base)
+     tree base;
+{
+  tree sname = get_id_2 ("__sn", base);
+  tree sentry = IDENTIFIER_GLOBAL_VALUE (sname);
+  if (! sentry)
+    {
+      push_obstacks (&permanent_obstack, &permanent_obstack);
+      sentry = build_decl (VAR_DECL, sname, integer_type_node);
+      TREE_PUBLIC (sentry) = 1;
+      DECL_ARTIFICIAL (sentry) = 1;
+      TREE_STATIC (sentry) = 1;
+      TREE_USED (sentry) = 1;
+      DECL_COMMON (sentry) = 1;
+      pushdecl_top_level (sentry);
+      cp_finish_decl (sentry, NULL_TREE, NULL_TREE, 0, 0);
+      pop_obstacks ();
+    }
+  return sentry;
+}
 
 /* This routine is called from the last rule in yyparse ().
    Its job is to create all the code needed to initialize and
@@ -2489,10 +2713,10 @@ finish_file ()
   int start_time, this_time;
 
   tree fnname;
-  tree vars = static_aggregates;
+  tree vars;
   int needs_cleaning = 0, needs_messing_up = 0;
 
-  build_exception_table ();
+  at_eof = 1;
 
   if (flag_detailed_statistics)
     dump_tree_statistics ();
@@ -2503,39 +2727,119 @@ finish_file ()
 
   start_time = get_run_time ();
 
+  /* Otherwise, GDB can get confused, because in only knows
+     about source for LINENO-1 lines.  */
+  lineno -= 1;
+
+  interface_unknown = 1;
+  interface_only = 0;
+
+  for (fnname = pending_templates; fnname; fnname = TREE_CHAIN (fnname))
+    {
+      tree decl = TREE_VALUE (fnname);
+      if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
+       {
+         instantiate_class_template (decl);
+         if (CLASSTYPE_TEMPLATE_INSTANTIATION (decl))
+           for (vars = TYPE_METHODS (decl); vars; vars = TREE_CHAIN (vars))
+             if (! DECL_ARTIFICIAL (vars))
+               instantiate_decl (vars);
+       }
+      else
+       instantiate_decl (decl);
+    }
+
+  for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
+    {
+      tree *args, fn, decl = TREE_VALUE (fnname);
+
+      if (DECL_INITIAL (decl))
+       continue;
+
+      fn = TREE_PURPOSE (fnname);
+      args = get_bindings (fn, decl);
+      fn = instantiate_template (fn, args);
+      free (args);
+      instantiate_decl (fn);
+    }
+
   /* Push into C language context, because that's all
      we'll need here.  */
   push_lang_context (lang_name_c);
 
-  /* Set up the name of the file-level functions we may need.  */
-  /* Use a global object (which is already required to be unique over
-     the program) rather than the file name (which imposes extra
-     constraints).  -- Raeburn@MIT.EDU, 10 Jan 1990.  */
+#if 1
+  /* The reason for pushing garbage onto the global_binding_level is to
+     ensure that we can slice out _DECLs which pertain to virtual function
+     tables.  If the last thing pushed onto the global_binding_level was a
+     virtual function table, then slicing it out would slice away all the
+     decls (i.e., we lose the head of the chain).
+
+     There are several ways of getting the same effect, from changing the
+     way that iterators over the chain treat the elements that pertain to
+     virtual function tables, moving the implementation of this code to
+     decl.c (where we can manipulate global_binding_level directly),
+     popping the garbage after pushing it and slicing away the vtable
+     stuff, or just leaving it alone.  */
+
+  /* Make last thing in global scope not be a virtual function table.  */
+#if 0 /* not yet, should get fixed properly later */
+  vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node);
+#else
+  vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node);
+#endif
+  DECL_IGNORED_P (vars) = 1;
+  SET_DECL_ARTIFICIAL (vars);
+  pushdecl (vars);
+#endif
+
+  /* Walk to mark the inline functions we need, then output them so
+     that we can pick up any other tdecls that those routines need.  */
+  walk_vtables ((void (*)())0, finish_prevtable_vardecl);
+
+  for (vars = pending_statics; vars; vars = TREE_CHAIN (vars))
+    {
+      tree decl = TREE_VALUE (vars);
+
+      if (DECL_TEMPLATE_INSTANTIATION (decl)
+         && ! DECL_IN_AGGR_P (decl))
+       {
+         import_export_decl (decl);
+         DECL_EXTERNAL (decl) = ! DECL_NOT_REALLY_EXTERN (decl);
+       }
+    }
+
+  for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars))
+    if (! TREE_ASM_WRITTEN (TREE_VALUE (vars)))
+      rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1);
+  vars = static_aggregates;
+
+  if (static_ctors || vars || exception_table_p ())
+    needs_messing_up = 1;
+  if (static_dtors)
+    needs_cleaning = 1;
 
   /* See if we really need the hassle.  */
   while (vars && needs_cleaning == 0)
     {
       tree decl = TREE_VALUE (vars);
       tree type = TREE_TYPE (decl);
-      if (TYPE_NEEDS_DESTRUCTOR (type))
+      if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars))
        {
          needs_cleaning = 1;
-         needs_messing_up = 1;
          break;
        }
-      else
-       needs_messing_up |= TYPE_NEEDS_CONSTRUCTING (type);
+
       vars = TREE_CHAIN (vars);
     }
+
   if (needs_cleaning == 0)
     goto mess_up;
 
-  /* Otherwise, GDB can get confused, because in only knows
-     about source for LINENO-1 lines.  */
-  lineno -= 1;
-
   fnname = get_file_function_name ('D');
-  start_function (void_list_node, build_parse_node (CALL_EXPR, fnname, void_list_node, NULL_TREE), 0, 0);
+  start_function (void_list_node,
+                 make_call_declarator (fnname, void_list_node, NULL_TREE,
+                                       NULL_TREE),
+                 NULL_TREE, 0);
   fnname = DECL_ASSEMBLER_NAME (current_function_decl);
   store_parm_decls ();
 
@@ -2546,38 +2850,45 @@ finish_file ()
 
   /* These must be done in backward order to destroy,
      in which they happen to be!  */
-  while (vars)
+  for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars))
     {
       tree decl = TREE_VALUE (vars);
       tree type = TREE_TYPE (decl);
       tree temp = TREE_PURPOSE (vars);
 
-      if (TYPE_NEEDS_DESTRUCTOR (type))
+      if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars)
+         && ! DECL_EXTERNAL (decl))
        {
-         if (TREE_STATIC (vars))
-           expand_start_cond (build_binary_op (NE_EXPR, temp, integer_zero_node, 1), 0);
-         if (TREE_CODE (type) == ARRAY_TYPE)
-           temp = decl;
-         else
+         int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+                                               || DECL_ONE_ONLY (decl)
+                                               || DECL_WEAK (decl)));
+
+         temp = build_cleanup (decl);
+
+         if (protect)
            {
-             mark_addressable (decl);
-             temp = build1 (ADDR_EXPR, TYPE_POINTER_TO (type), decl);
+             tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+             sentry = build_unary_op (PREDECREMENT_EXPR, sentry, 0);
+             sentry = build_binary_op (EQ_EXPR, sentry, integer_zero_node, 1);
+             expand_start_cond (sentry, 0);
            }
-         temp = build_delete (TREE_TYPE (temp), temp,
-                              integer_two_node, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+
          expand_expr_stmt (temp);
 
-         if (TREE_STATIC (vars))
+         if (protect)
            expand_end_cond ();
        }
-      vars = TREE_CHAIN (vars);
     }
 
-  expand_end_bindings (getdecls(), 1, 0);
+  for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors))
+    expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors),
+                                          NULL_TREE));
+      
+  expand_end_bindings (getdecls (), 1, 0);
   poplevel (1, 0, 0);
   pop_momentary ();
 
-  finish_function (lineno, 0);
+  finish_function (lineno, 0, 0);
 
   assemble_destructor (IDENTIFIER_POINTER (fnname));
 
@@ -2586,10 +2897,13 @@ finish_file ()
  mess_up:
   /* Must do this while we think we are at the top level.  */
   vars = nreverse (static_aggregates);
-  if (vars != NULL_TREE)
+  if (needs_messing_up)
     {
       fnname = get_file_function_name ('I');
-      start_function (void_list_node, build_parse_node (CALL_EXPR, fnname, void_list_node, NULL_TREE), 0, 0);
+      start_function (void_list_node,
+                     make_call_declarator (fnname, void_list_node, NULL_TREE,
+                                           NULL_TREE),
+                     NULL_TREE, 0);
       fnname = DECL_ASSEMBLER_NAME (current_function_decl);
       store_parm_decls ();
 
@@ -2598,25 +2912,29 @@ finish_file ()
       push_momentary ();
       expand_start_bindings (0);
 
+      if (exception_table_p ())
+       register_exception_table ();
+
       while (vars)
        {
          tree decl = TREE_VALUE (vars);
          tree init = TREE_PURPOSE (vars);
-         tree old_cleanups = cleanups_this_call;
 
          /* If this was a static attribute within some function's scope,
             then don't initialize it here.  Also, don't bother
             with initializers that contain errors.  */
          if (TREE_STATIC (vars)
+             || DECL_EXTERNAL (decl)
              || (init && TREE_CODE (init) == TREE_LIST
                  && value_member (error_mark_node, init)))
-           {
-             vars = TREE_CHAIN (vars);
-             continue;
-           }
+           goto next_mess;
 
          if (TREE_CODE (decl) == VAR_DECL)
            {
+             int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+                                                   || DECL_ONE_ONLY (decl)
+                                                   || DECL_WEAK (decl)));
+
              /* Set these global variables so that GDB at least puts
                 us near the declaration which required the initialization.  */
              input_filename = DECL_SOURCE_FILE (decl);
@@ -2624,86 +2942,67 @@ finish_file ()
              emit_note (input_filename, lineno);
 
              /* 9.5p5: The initializer of a static member of a class has
-                the same acess rights as a member function.  */
+                the same access rights as a member function.  */
              DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl);
+             DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
 
-             if (init)
+             if (protect)
                {
-                 if (TREE_CODE (init) == VAR_DECL)
-                   {
-                     /* This behavior results when there are
-                        multiple declarations of an aggregate,
-                        the last of which defines it.  */
-                     if (DECL_RTL (init) == DECL_RTL (decl))
-                       {
-                         my_friendly_assert (DECL_INITIAL (decl) == error_mark_node
-                                 || (TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR
-                                     && CONSTRUCTOR_ELTS (DECL_INITIAL (decl)) == NULL_TREE),
-                                             199);
-                         init = DECL_INITIAL (init);
-                         if (TREE_CODE (init) == CONSTRUCTOR
-                             && CONSTRUCTOR_ELTS (init) == NULL_TREE)
-                           init = NULL_TREE;
-                       }
-#if 0
-                     else if (TREE_TYPE (decl) == TREE_TYPE (init))
-                       {
-#if 1
-                         my_friendly_abort (200);
-#else
-                         /* point to real decl's rtl anyway.  */
-                         DECL_RTL (init) = DECL_RTL (decl);
-                         my_friendly_assert (DECL_INITIAL (decl) == error_mark_node,
-                                             201);
-                         init = DECL_INITIAL (init);
-#endif                         /* 1 */
-                       }
-#endif                         /* 0 */
-                   }
+                 tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+                 sentry = build_unary_op (PREINCREMENT_EXPR, sentry, 0);
+                 sentry = build_binary_op
+                   (EQ_EXPR, sentry, integer_one_node, 1);
+                 expand_start_cond (sentry, 0);
                }
+
+             expand_start_target_temps ();
+
              if (IS_AGGR_TYPE (TREE_TYPE (decl))
-                 || init == 0
                  || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
-               expand_aggr_init (decl, init, 0);
+               expand_aggr_init (decl, init, 0, 0);
              else if (TREE_CODE (init) == TREE_VEC)
                {
                  expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0),
                                                TREE_VEC_ELT (init, 1),
                                                TREE_VEC_ELT (init, 2), 0),
                               const0_rtx, VOIDmode, 0);
-                 free_temp_slots ();
                }
              else
                expand_assignment (decl, init, 0, 0);
 
+             /* Cleanup any temporaries needed for the initial value.  */
+             expand_end_target_temps ();
+
+             if (protect)
+               expand_end_cond ();
+
              DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
-           }
-         else if (TREE_CODE (decl) == SAVE_EXPR)
-           {
-             if (! PARM_DECL_EXPR (decl))
-               {
-                 /* a `new' expression at top level.  */
-                 expand_expr (decl, const0_rtx, VOIDmode, 0);
-                 free_temp_slots ();
-                 expand_aggr_init (build_indirect_ref (decl, NULL_PTR), init, 0);
-               }
+             DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
            }
          else if (decl == error_mark_node)
            ;
          else my_friendly_abort (22);
+
+       next_mess:
          vars = TREE_CHAIN (vars);
-         /* Cleanup any temporaries needed for the initial value.  */
-         expand_cleanups_to (old_cleanups);
        }
 
-      expand_end_bindings (getdecls(), 1, 0);
+      for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors))
+       expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors),
+                                              NULL_TREE));
+      
+      expand_end_bindings (getdecls (), 1, 0);
       poplevel (1, 0, 0);
       pop_momentary ();
 
-      finish_function (lineno, 0);
+      finish_function (lineno, 0, 0);
       assemble_constructor (IDENTIFIER_POINTER (fnname));
     }
 
+  expand_builtin_throw ();
+
+  permanent_allocation (1);
+
   /* Done with C language context needs.  */
   pop_lang_context ();
 
@@ -2712,10 +3011,21 @@ finish_file ()
   while (pending_statics)
     {
       tree decl = TREE_VALUE (pending_statics);
-      if (TREE_USED (decl) == 1
-         || TREE_READONLY (decl) == 0
-         || DECL_INITIAL (decl) == 0)
-       rest_of_decl_compilation (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 1, 1);
+
+      /* Output DWARF debug information.  */
+#ifdef DWARF_DEBUGGING_INFO
+      if (write_symbols == DWARF_DEBUG)
+       dwarfout_file_scope_decl (decl, 1);
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+      if (write_symbols == DWARF2_DEBUG)
+       dwarf2out_decl (decl);
+#endif
+
+      DECL_DEFER_OUTPUT (decl) = 0;
+      rest_of_decl_compilation
+       (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 1, 1);
+
       pending_statics = TREE_CHAIN (pending_statics);
     }
 
@@ -2725,118 +3035,99 @@ finish_file ()
 
   start_time = get_run_time ();
 
-  /* Now delete from the chain of variables all virtual function tables.
-     We output them all ourselves, because each will be treated specially.  */
+  if (flag_handle_signatures)
+    walk_sigtables ((void (*)())0, finish_sigtable_vardecl);
 
-#if 1
-  /* The reason for pushing garbage onto the global_binding_level is to
-     ensure that we can slice out _DECLs which pertain to virtual function
-     tables.  If the last thing pushed onto the global_binding_level was a
-     virtual function table, then slicing it out would slice away all the
-     decls (i.e., we lose the head of the chain).
-
-     There are several ways of getting the same effect, from changing the
-     way that iterators over the chain treat the elements that pertain to
-     virtual function tables, moving the implementation of this code to
-     decl.c (where we can manipulate global_binding_level directly),
-     popping the garbage after pushing it and slicing away the vtable
-     stuff, or just leaving it alone. */
-
-  /* Make last thing in global scope not be a virtual function table.  */
-#if 0 /* not yet, should get fixed properly later */
-  vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node);
-#else
-  vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node);
-#endif
-  DECL_IGNORED_P (vars) = 1;
-  SET_DECL_ARTIFICIAL (vars);
-  pushdecl (vars);
-#endif
-
-  walk_vtables ((void (*)())0, finish_vtable_vardecl);
-
-  for (vars = getdecls (); vars; vars = TREE_CHAIN (vars))
+  for (fnname = saved_inlines; fnname; fnname = TREE_CHAIN (fnname))
     {
-      if (TREE_CODE (vars) == THUNK_DECL)
-       emit_thunk (vars);
+      tree decl = TREE_VALUE (fnname);
+      import_export_decl (decl);
     }
 
+  /* Now write out inline functions which had their addresses taken and
+     which were not declared virtual and which were not declared `extern
+     inline'.  */
   {
-    int reconsider = 0;                /* More may be referenced; check again */
-    tree delayed = NULL_TREE;  /* These might be referenced later */
+    int reconsider = 1;                /* More may be referenced; check again */
 
-    /* Now write out inline functions which had their addresses taken and
-       which were not declared virtual and which were not declared `extern
-       inline'.  */
-    while (saved_inlines)
+    while (reconsider)
       {
-       tree decl = TREE_VALUE (saved_inlines);
-       saved_inlines = TREE_CHAIN (saved_inlines);
-       /* Redefinition of a member function can cause DECL_SAVED_INSNS to be
-          0; don't crash.  */
-       if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0)
-         continue;
-       if (DECL_FUNCTION_MEMBER_P (decl) && !TREE_PUBLIC (decl))
-         {
-           tree ctype = DECL_CLASS_CONTEXT (decl);
-           if (CLASSTYPE_INTERFACE_KNOWN (ctype))
-             {
-               TREE_PUBLIC (decl) = 1;
-               DECL_EXTERNAL (decl)
-                 = (CLASSTYPE_INTERFACE_ONLY (ctype)
-                    || (DECL_INLINE (decl) && ! flag_implement_inlines));
-             }
-         }
-       if (TREE_PUBLIC (decl)
-           || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
-           || flag_keep_inline_functions)
+       tree *p = &saved_inlines;
+       reconsider = 0;
+
+       /* We need to do this each time so that newly completed template
+           types don't wind up at the front of the list.  Sigh.  */
+       vars = build_decl (TYPE_DECL, make_anon_name (), integer_type_node);
+       DECL_IGNORED_P (vars) = 1;
+       SET_DECL_ARTIFICIAL (vars);
+       pushdecl (vars);
+
+       reconsider |= walk_vtables ((void (*)())0, finish_vtable_vardecl);
+
+       while (*p)
          {
-           if (DECL_EXTERNAL (decl)
-               || (DECL_IMPLICIT_INSTANTIATION (decl)
-                   && ! flag_implicit_templates))
-             assemble_external (decl);
-           else
+           tree decl = TREE_VALUE (*p);
+
+           if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
+               && TREE_USED (decl)
+               && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
              {
+               if (DECL_MUTABLE_P (decl))
+                 synthesize_tinfo_fn (decl);
+               else
+                 synthesize_method (decl);
                reconsider = 1;
-               temporary_allocation ();
-               output_inline_function (decl);
-               permanent_allocation (1);
              }
-         }
-       else if (TREE_USED (decl)
-                || TREE_USED (DECL_ASSEMBLER_NAME (decl)))
-         delayed = tree_cons (NULL_TREE, decl, delayed);
-      }
 
-    if (reconsider && delayed)
-      {
-       while (reconsider)
-         {
-           tree place;
-           reconsider = 0;
-           for (place = delayed; place; place = TREE_CHAIN (place))
+           /* Catch new template instantiations.  */
+           if (decl != TREE_VALUE (*p))
+             continue;
+
+           if (TREE_ASM_WRITTEN (decl)
+               || (DECL_SAVED_INSNS (decl) == 0 && ! DECL_ARTIFICIAL (decl)))
+             *p = TREE_CHAIN (*p);
+           else if (DECL_INITIAL (decl) == 0)
+             p = &TREE_CHAIN (*p);
+           else if ((TREE_PUBLIC (decl) && ! DECL_WEAK (decl)
+                     && ! DECL_ONE_ONLY (decl))
+                    || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+                    || flag_keep_inline_functions)
              {
-               tree decl = TREE_VALUE (place);
-               if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
-                   && ! TREE_ASM_WRITTEN (decl))
+               if (DECL_NOT_REALLY_EXTERN (decl))
                  {
-                   if (DECL_EXTERNAL (decl)
-                       || (DECL_IMPLICIT_INSTANTIATION (decl)
-                           && ! flag_implicit_templates))
-                     assemble_external (decl);
-                   else
-                     {
-                       reconsider = 1;
-                       temporary_allocation ();
-                       output_inline_function (decl);
-                       permanent_allocation (1);
-                     }
+                   DECL_EXTERNAL (decl) = 0;
+                   reconsider = 1;
+                   /* We can't inline this function after it's been
+                       emitted, so just disable inlining.  We want a
+                       variant of output_inline_function that doesn't
+                       prevent subsequent integration...  */
+                   flag_no_inline = 1;
+                   temporary_allocation ();
+                   output_inline_function (decl);
+                   permanent_allocation (1);
                  }
+
+               *p = TREE_CHAIN (*p);
              }
+           else
+             p = &TREE_CHAIN (*p);
          }
       }
   }
 
+  /* Now delete from the chain of variables all virtual function tables.
+     We output them all ourselves, because each will be treated specially.  */
+
+  walk_vtables ((void (*)())0, prune_vtable_vardecl);
+
+  for (vars = getdecls (); vars; vars = TREE_CHAIN (vars))
+    {
+      if (TREE_CODE (vars) == FUNCTION_DECL
+         && ! DECL_INTERFACE_KNOWN (vars)
+         && DECL_C_STATIC (vars))
+       TREE_PUBLIC (vars) = 0;
+    }
+
   if (write_virtuals == 2)
     {
       /* Now complain about an virtual function tables promised
@@ -2850,7 +3141,8 @@ finish_file ()
        }
     }
 
-  permanent_allocation (1);
+  finish_repo ();
+
   this_time = get_run_time ();
   parse_time -= this_time - start_time;
   varconst_time += this_time - start_time;
@@ -2867,6 +3159,7 @@ finish_file ()
 
    Maybe this shouldn't be recursive, but how often will it actually be
    used?  (jason) */
+
 tree
 reparse_absdcl_as_expr (type, decl)
      tree type, decl;
@@ -2878,7 +3171,7 @@ reparse_absdcl_as_expr (type, decl)
   /* recurse */
   decl = reparse_decl_as_expr (type, TREE_OPERAND (decl, 0));
 
-  decl = build_x_function_call (decl, NULL_TREE, current_class_decl);
+  decl = build_x_function_call (decl, NULL_TREE, current_class_ref);
 
   if (TREE_CODE (decl) == CALL_EXPR && TREE_TYPE (decl) != void_type_node)
     decl = require_complete_type (decl);
@@ -2893,13 +3186,15 @@ reparse_absdcl_as_expr (type, decl)
 
    In the above example, DECL is the `(int)(int)(int)', and EXPR is the
    `1'.  */
+
 tree
 reparse_absdcl_as_casts (decl, expr)
      tree decl, expr;
 {
   tree type;
   
-  if (TREE_CODE (expr) == CONSTRUCTOR)
+  if (TREE_CODE (expr) == CONSTRUCTOR
+      && TREE_TYPE (expr) == 0)
     {
       type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
       decl = TREE_OPERAND (decl, 0);
@@ -2929,53 +3224,267 @@ reparse_absdcl_as_casts (decl, expr)
   return expr;
 }
 
-/* Recursive helper function for reparse_decl_as_expr.  It may be a good
-   idea to reimplement this using an explicit stack, rather than recursion. */
-static tree
-reparse_decl_as_expr1 (decl)
-     tree decl;
+/* Given plain tree nodes for an expression, build up the full semantics.  */
+
+tree
+build_expr_from_tree (t)
+     tree t;
 {
-  switch (TREE_CODE (decl))
+  if (t == NULL_TREE || t == error_mark_node)
+    return t;
+
+  switch (TREE_CODE (t))
     {
     case IDENTIFIER_NODE:
-      return do_identifier (decl);
+      return do_identifier (t, 0);
+
+    case LOOKUP_EXPR:
+      if (LOOKUP_EXPR_GLOBAL (t))
+       return do_scoped_id (TREE_OPERAND (t, 0), 0);
+      else
+       return do_identifier (TREE_OPERAND (t, 0), 0);
+
     case INDIRECT_REF:
       return build_x_indirect_ref
-       (reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)), "unary *");
-    case ADDR_EXPR:
-      return build_x_unary_op (ADDR_EXPR,
-                              reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+       (build_expr_from_tree (TREE_OPERAND (t, 0)), "unary *");
+
+    case CAST_EXPR:
+      return build_functional_cast
+       (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case REINTERPRET_CAST_EXPR:
+      return build_reinterpret_cast
+       (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case CONST_CAST_EXPR:
+      return build_const_cast
+       (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case DYNAMIC_CAST_EXPR:
+      return build_dynamic_cast
+       (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case STATIC_CAST_EXPR:
+      return build_static_cast
+       (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case NEGATE_EXPR:
     case BIT_NOT_EXPR:
-      return build_x_unary_op (BIT_NOT_EXPR,
-                              reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+    case ABS_EXPR:
+    case TRUTH_NOT_EXPR:
+    case ADDR_EXPR:
+    case CONVERT_EXPR:      /* Unary + */
+      if (TREE_TYPE (t))
+       return t;
+      return build_x_unary_op (TREE_CODE (t),
+                              build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_ANDTC_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case TRUNC_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case RSHIFT_EXPR:
+    case LSHIFT_EXPR:
+    case RROTATE_EXPR:
+    case LROTATE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case MAX_EXPR:
+    case MIN_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case MEMBER_REF:
+      return build_x_binary_op
+       (TREE_CODE (t), 
+        build_expr_from_tree (TREE_OPERAND (t, 0)),
+        build_expr_from_tree (TREE_OPERAND (t, 1)));
+
+    case DOTSTAR_EXPR:
+      return build_m_component_ref
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        build_expr_from_tree (TREE_OPERAND (t, 1)));
+
     case SCOPE_REF:
-      return build_offset_ref (TREE_OPERAND (decl, 0), TREE_OPERAND (decl, 1));
+      return build_offset_ref (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
+
     case ARRAY_REF:
-      return grok_array_decl (reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)),
-                             TREE_OPERAND (decl, 1));
+      if (TREE_OPERAND (t, 0) == NULL_TREE)
+       /* new-type-id */
+       return build_parse_node (ARRAY_REF, NULL_TREE,
+                                build_expr_from_tree (TREE_OPERAND (t, 1)));
+      return grok_array_decl (build_expr_from_tree (TREE_OPERAND (t, 0)),
+                             build_expr_from_tree (TREE_OPERAND (t, 1)));
+
+    case SIZEOF_EXPR:
+      {
+       tree r = build_expr_from_tree (TREE_OPERAND (t, 0));
+       if (TREE_CODE_CLASS (TREE_CODE (r)) != 't')
+         r = TREE_TYPE (r);
+       return c_sizeof (r);
+      }
+
+    case MODOP_EXPR:
+      return build_x_modify_expr
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        TREE_CODE (TREE_OPERAND (t, 1)),
+        build_expr_from_tree (TREE_OPERAND (t, 2)));
+
+    case ARROW_EXPR:
+      return build_x_arrow
+       (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case NEW_EXPR:
+      return build_new
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        build_expr_from_tree (TREE_OPERAND (t, 1)),
+        build_expr_from_tree (TREE_OPERAND (t, 2)),
+        NEW_EXPR_USE_GLOBAL (t));
+
+    case DELETE_EXPR:
+      return delete_sanity
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        build_expr_from_tree (TREE_OPERAND (t, 1)),
+        DELETE_EXPR_USE_VEC (t), DELETE_EXPR_USE_GLOBAL (t));
+
+    case COMPOUND_EXPR:
+      if (TREE_OPERAND (t, 1) == NULL_TREE)
+       return build_x_compound_expr
+         (build_expr_from_tree (TREE_OPERAND (t, 0)));
+      else
+       my_friendly_abort (42);
+
+    case METHOD_CALL_EXPR:
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
+       {
+         tree ref = TREE_OPERAND (t, 0);
+         return build_scoped_method_call
+           (build_expr_from_tree (TREE_OPERAND (t, 1)),
+            build_expr_from_tree (TREE_OPERAND (ref, 0)),
+            TREE_OPERAND (ref, 1),
+            build_expr_from_tree (TREE_OPERAND (t, 2)));
+       }
+      return build_method_call
+       (build_expr_from_tree (TREE_OPERAND (t, 1)),
+        TREE_OPERAND (t, 0),
+        build_expr_from_tree (TREE_OPERAND (t, 2)),
+        NULL_TREE, LOOKUP_NORMAL);
+
+    case CALL_EXPR:
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
+       {
+         tree ref = TREE_OPERAND (t, 0);
+         return build_member_call
+           (build_expr_from_tree (TREE_OPERAND (ref, 0)),
+            TREE_OPERAND (ref, 1),
+            build_expr_from_tree (TREE_OPERAND (t, 1)));
+       }
+      else
+       {
+         tree name = TREE_OPERAND (t, 0);
+         if (! really_overloaded_fn (name))
+           name = build_expr_from_tree (name);
+         return build_x_function_call
+           (name, build_expr_from_tree (TREE_OPERAND (t, 1)),
+            current_class_ref);
+       }
+
+    case COND_EXPR:
+      return build_x_conditional_expr
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        build_expr_from_tree (TREE_OPERAND (t, 1)),
+        build_expr_from_tree (TREE_OPERAND (t, 2)));
+
+    case TREE_LIST:
+      {
+       tree purpose, value, chain;
+
+       if (t == void_list_node)
+         return t;
+
+       purpose = TREE_PURPOSE (t);
+       if (purpose)
+         purpose = build_expr_from_tree (purpose);
+       value = TREE_VALUE (t);
+       if (value)
+         value = build_expr_from_tree (value);
+       chain = TREE_CHAIN (t);
+       if (chain && chain != void_type_node)
+         chain = build_expr_from_tree (chain);
+       return tree_cons (purpose, value, chain);
+      }
+
+    case COMPONENT_REF:
+      return build_x_component_ref
+       (build_expr_from_tree (TREE_OPERAND (t, 0)),
+        TREE_OPERAND (t, 1), NULL_TREE, 1);
+
+    case THROW_EXPR:
+      return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case CONSTRUCTOR:
+      {
+       tree r = build_nt (CONSTRUCTOR, NULL_TREE,
+                          build_expr_from_tree (CONSTRUCTOR_ELTS (t)));
+
+       if (TREE_TYPE (t))
+         return digest_init (TREE_TYPE (t), r, 0);
+       return r;
+      }
+
+    case TYPEID_EXPR:
+      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 0))) == 't')
+       return get_typeid (TREE_OPERAND (t, 0));
+      return build_x_typeid (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+    case VAR_DECL:
+      return convert_from_reference (t);
+
     default:
-      my_friendly_abort (5);
-      return NULL_TREE;
+      return t;
     }
 }
 
 /* This is something of the form `int (*a)++' that has turned out to be an
    expr.  It was only converted into parse nodes, so we need to go through
    and build up the semantics.  Most of the work is done by
-   reparse_decl_as_expr1, above.
+   build_expr_from_tree, above.
 
    In the above example, TYPE is `int' and DECL is `*a'.  */
+
 tree
 reparse_decl_as_expr (type, decl)
      tree type, decl;
 {
-  decl = build_tree_list (NULL_TREE, reparse_decl_as_expr1 (decl));
-  return build_functional_cast (type, decl);
+  decl = build_expr_from_tree (decl);
+  if (type)
+    return build_functional_cast (type, build_tree_list (NULL_TREE, decl));
+  else
+    return decl;
 }
 
 /* This is something of the form `int (*a)' that has turned out to be a
    decl.  It was only converted into parse nodes, so we need to do the
-   checking that make_{pointer,reference}_declarator do. */
+   checking that make_{pointer,reference}_declarator do.  */
 
 tree
 finish_decl_parsing (decl)
@@ -3016,20 +3525,13 @@ check_cp_case_value (value)
   if (value == NULL_TREE)
     return value;
 
-  /* build_c_cast puts on a NOP_EXPR to make a non-lvalue.
-     Strip such NOP_EXPRs.  */
-  if (TREE_CODE (value) == NOP_EXPR
-      && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
-    value = TREE_OPERAND (value, 0);
+  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+  STRIP_TYPE_NOPS (value);
 
   if (TREE_READONLY_DECL_P (value))
     {
       value = decl_constant_value (value);
-      /* build_c_cast puts on a NOP_EXPR to make a non-lvalue.
-        Strip such NOP_EXPRs.  */
-      if (TREE_CODE (value) == NOP_EXPR
-         && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
-       value = TREE_OPERAND (value, 0);
+      STRIP_TYPE_NOPS (value);
     }
   value = fold (value);
 
@@ -3048,3 +3550,134 @@ check_cp_case_value (value)
 
   return value;
 }
+
+tree current_namespace;
+
+/* Get the inner part of a namespace id.  It doesn't have any prefix, nor
+   postfix.  Returns 0 if in global namespace.  */
+
+tree
+get_namespace_id ()
+{
+  tree x = current_namespace;
+  if (x)
+    x = TREE_PURPOSE (x);
+  return x;
+}
+
+/* Build up a DECL_ASSEMBLER_NAME for NAME in the current namespace.  */
+
+tree
+current_namespace_id (name)
+     tree name;
+{
+  tree old_id = get_namespace_id ();
+  char *buf;
+
+  /* Global names retain old encoding.  */
+  if (! old_id)
+    return name;
+
+  buf = (char *) alloca (8 + IDENTIFIER_LENGTH (old_id)
+                        + IDENTIFIER_LENGTH (name));
+  sprintf (buf, "__ns_%s_%s", IDENTIFIER_POINTER (old_id),
+          IDENTIFIER_POINTER (name));
+  return get_identifier (buf);
+}
+
+void
+do_namespace_alias (alias, namespace)
+     tree alias, namespace;
+{
+  sorry ("namespace alias");
+}
+
+void
+do_toplevel_using_decl (decl)
+     tree decl;
+{
+  if (decl == NULL_TREE || decl == error_mark_node)
+    return;
+
+  if (TREE_CODE (decl) == SCOPE_REF)
+    decl = resolve_scope_to_name (NULL_TREE, decl);
+
+  /* Is this the right way to do an id list? */
+  if (TREE_CODE (decl) != TREE_LIST)
+    {
+      pushdecl (decl);
+    }
+  else
+    while (decl)
+      {
+       pushdecl (TREE_VALUE (decl));
+       decl = TREE_CHAIN (decl);
+      }
+}
+
+tree
+do_class_using_decl (decl)
+     tree decl;
+{
+  tree name, value;
+
+  if (TREE_CODE (decl) != SCOPE_REF)
+    {
+      cp_error ("using-declaration for non-member at class scope");
+      return NULL_TREE;
+    }
+  name = TREE_OPERAND (decl, 1);
+  if (TREE_CODE (name) == BIT_NOT_EXPR)
+    {
+      cp_error ("using-declaration for destructor");
+      return NULL_TREE;
+    }
+
+  value = build_lang_field_decl (USING_DECL, name, void_type_node);
+  DECL_INITIAL (value) = TREE_OPERAND (decl, 0);
+  return value;
+}
+
+void
+do_using_directive (namespace)
+     tree namespace;
+{
+  sorry ("using directive");
+}
+
+void
+check_default_args (x)
+     tree x;
+{
+  tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
+  int saw_def = 0, i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE);
+  for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
+    {
+      if (TREE_PURPOSE (arg))
+       saw_def = 1;
+      else if (saw_def)
+       {
+         cp_error ("default argument missing for parameter %P of `%#D'",
+                   i, x);
+         break;
+       }
+    }
+}
+
+void
+mark_used (decl)
+     tree decl;
+{
+  TREE_USED (decl) = 1;
+  if (processing_template_decl)
+    return;
+  assemble_external (decl);
+  /* Is it a synthesized method that needs to be synthesized?  */
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CLASS_CONTEXT (decl)
+      && DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
+      /* Kludge: don't synthesize for default args.  */
+      && current_function_decl)
+    synthesize_method (decl);
+  if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
+    instantiate_decl (decl);
+}