OSDN Git Service

* cp/cp-tree.h (struct cp_language_function): Remove x_result_rtx.
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl.c
index f01d4de..82ebc36 100644 (file)
@@ -1,5 +1,6 @@
 /* Process declarations and variables for C compiler.
-   Copyright (C) 1988, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -31,49 +32,34 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "tree.h"
 #include "rtl.h"
+#include "expr.h"
 #include "flags.h"
 #include "cp-tree.h"
 #include "decl.h"
 #include "lex.h"
-#include <signal.h>
-#include "obstack.h"
 #include "defaults.h"
 #include "output.h"
 #include "except.h"
 #include "toplev.h"
 #include "../hash.h"
-#include "defaults.h"
 #include "ggc.h"
 
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-extern struct obstack permanent_obstack;
-extern struct obstack* saveable_obstack;
-
 extern int current_class_depth;
 
-extern tree static_ctors, static_dtors;
-
 extern tree global_namespace;
 
-extern int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree));
+extern int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree));
 
 /* Use garbage collection.  */
 
 int ggc_p = 1;
 
-#ifndef WCHAR_UNSIGNED
-#define WCHAR_UNSIGNED 0
-#endif
-
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
 #ifndef BOOL_TYPE_SIZE
 #ifdef SLOW_BYTE_ACCESS
-#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (POINTER_SIZE) : (CHAR_TYPE_SIZE))
+/* In the new ABI, `bool' has size and alignment `1', on all
+   platforms.  */
+#define BOOL_TYPE_SIZE \
+  ((SLOW_BYTE_ACCESS && !flag_new_abi) ? (POINTER_SIZE) : (CHAR_TYPE_SIZE))
 #else
 #define BOOL_TYPE_SIZE CHAR_TYPE_SIZE
 #endif
@@ -97,100 +83,112 @@ int ggc_p = 1;
 #define WCHAR_TYPE "int"
 #endif
 
-static tree grokparms                          PROTO((tree, int));
-static const char *redeclaration_error_message PROTO((tree, tree));
+static tree grokparms                          PARAMS ((tree, int));
+static const char *redeclaration_error_message PARAMS ((tree, tree));
 
-static void push_binding_level PROTO((struct binding_level *, int,
+static void push_binding_level PARAMS ((struct binding_level *, int,
                                      int));
-static void pop_binding_level PROTO((void));
-static void suspend_binding_level PROTO((void));
-static void resume_binding_level PROTO((struct binding_level *));
-static struct binding_level *make_binding_level PROTO((void));
-static void declare_namespace_level PROTO((void));
-static void signal_catch PROTO((int)) ATTRIBUTE_NORETURN;
-static void storedecls PROTO((tree));
-static void require_complete_types_for_parms PROTO((tree));
-static void push_overloaded_decl_1 PROTO((tree));
-static int ambi_op_p PROTO((tree));
-static int unary_op_p PROTO((tree));
-static tree store_bindings PROTO((tree, tree));
-static tree lookup_tag_reverse PROTO((tree, tree));
-static tree obscure_complex_init PROTO((tree, tree));
-static tree maybe_build_cleanup_1 PROTO((tree, tree));
-static tree lookup_name_real PROTO((tree, int, int, int));
-static void warn_extern_redeclared_static PROTO((tree, tree));
-static void grok_reference_init PROTO((tree, tree, tree));
-static tree grokfndecl PROTO((tree, tree, tree, tree, int,
+static void pop_binding_level PARAMS ((void));
+static void suspend_binding_level PARAMS ((void));
+static void resume_binding_level PARAMS ((struct binding_level *));
+static struct binding_level *make_binding_level PARAMS ((void));
+static void declare_namespace_level PARAMS ((void));
+static int decl_jump_unsafe PARAMS ((tree));
+static void storedecls PARAMS ((tree));
+static void require_complete_types_for_parms PARAMS ((tree));
+static int ambi_op_p PARAMS ((enum tree_code));
+static int unary_op_p PARAMS ((enum tree_code));
+static tree store_bindings PARAMS ((tree, tree));
+static tree lookup_tag_reverse PARAMS ((tree, tree));
+static tree obscure_complex_init PARAMS ((tree, tree));
+static tree lookup_name_real PARAMS ((tree, int, int, int));
+static void warn_extern_redeclared_static PARAMS ((tree, tree));
+static void grok_reference_init PARAMS ((tree, tree, tree));
+static tree grokfndecl PARAMS ((tree, tree, tree, tree, int,
                              enum overload_flags, tree,
                              tree, int, int, int, int, int, int, tree));
-static tree grokvardecl PROTO((tree, tree, RID_BIT_TYPE *, int, int, tree));
-static tree lookup_tag PROTO((enum tree_code, tree,
+static tree grokvardecl PARAMS ((tree, tree, RID_BIT_TYPE *, int, int, tree));
+static tree lookup_tag PARAMS ((enum tree_code, tree,
                              struct binding_level *, int));
 static void set_identifier_type_value_with_scope
-       PROTO((tree, tree, struct binding_level *));
-static void record_builtin_type PROTO((enum rid, const char *, tree));
-static void record_unknown_type PROTO((tree, const char *));
-static int member_function_or_else PROTO((tree, tree, const char *));
-static void bad_specifiers PROTO((tree, const char *, int, int, int, int,
+       PARAMS ((tree, tree, struct binding_level *));
+static void record_builtin_type PARAMS ((enum rid, const char *, tree));
+static void record_unknown_type PARAMS ((tree, const char *));
+static tree build_library_fn_1 PARAMS ((tree, enum tree_code, tree));
+static int member_function_or_else PARAMS ((tree, tree, enum overload_flags));
+static void bad_specifiers PARAMS ((tree, const char *, int, int, int, int,
                                  int));
-static void lang_print_error_function PROTO((const char *));
-static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
-static void check_for_uninitialized_const_var PROTO((tree));
-static unsigned long typename_hash PROTO((hash_table_key));
-static boolean typename_compare PROTO((hash_table_key, hash_table_key));
-static void push_binding PROTO((tree, tree, struct binding_level*));
-static int add_binding PROTO((tree, tree));
-static void pop_binding PROTO((tree, tree));
-static tree local_variable_p PROTO((tree *, int *, void *));
-static tree find_binding PROTO((tree, tree));
-static tree select_decl PROTO((tree, int));
-static int lookup_flags PROTO((int, int));
-static tree qualify_lookup PROTO((tree, int));
-static tree record_builtin_java_type PROTO((const char *, int));
-static const char *tag_name PROTO((enum tag_types code));
-static void find_class_binding_level PROTO((void));
-static struct binding_level *innermost_nonclass_level PROTO((void));
-static void warn_about_implicit_typename_lookup PROTO((tree, tree));
-static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *));
-static int walk_globals_r PROTO((tree, void *));
-static void add_decl_to_level PROTO((tree, struct binding_level *));
-static tree make_label_decl PROTO((tree, int));
-static void pop_label PROTO((tree));
-static void pop_labels PROTO((tree));
-static void maybe_deduce_size_from_array_init PROTO((tree, tree));
-static void layout_var_decl PROTO((tree));
-static void maybe_commonize_var PROTO((tree));
-static tree check_initializer PROTO((tree, tree));
-static void make_rtl_for_nonlocal_decl PROTO((tree, tree, const char *));
-static void push_cp_function_context PROTO((struct function *));
-static void pop_cp_function_context PROTO((struct function *));
-static void mark_binding_level PROTO((void *));
-static void mark_cp_function_context PROTO((struct function *));
-static void mark_saved_scope PROTO((void *));
-static void mark_lang_function PROTO((struct language_function *));
-static void mark_stmt_tree PROTO((struct stmt_tree *));
-static void save_function_data PROTO((tree));
-static void check_function_type PROTO((tree));
-static void destroy_local_static PROTO((tree));
-static void destroy_local_var PROTO((tree));
-static void finish_constructor_body PROTO((void));
-static void finish_destructor_body PROTO((void));
-static tree compute_array_index_type PROTO((tree, tree));
-static tree create_array_type_for_decl PROTO((tree, tree, tree));
+static tree maybe_process_template_type_declaration PARAMS ((tree, int, struct binding_level*));
+static void check_for_uninitialized_const_var PARAMS ((tree));
+static unsigned long typename_hash PARAMS ((hash_table_key));
+static boolean typename_compare PARAMS ((hash_table_key, hash_table_key));
+static void push_binding PARAMS ((tree, tree, struct binding_level*));
+static int add_binding PARAMS ((tree, tree));
+static void pop_binding PARAMS ((tree, tree));
+static tree local_variable_p_walkfn PARAMS ((tree *, int *, void *));
+static tree find_binding PARAMS ((tree, tree));
+static tree select_decl PARAMS ((tree, int));
+static int lookup_flags PARAMS ((int, int));
+static tree qualify_lookup PARAMS ((tree, int));
+static tree record_builtin_java_type PARAMS ((const char *, int));
+static const char *tag_name PARAMS ((enum tag_types code));
+static void find_class_binding_level PARAMS ((void));
+static struct binding_level *innermost_nonclass_level PARAMS ((void));
+static void warn_about_implicit_typename_lookup PARAMS ((tree, tree));
+static int walk_namespaces_r PARAMS ((tree, walk_namespaces_fn, void *));
+static int walk_globals_r PARAMS ((tree, void *));
+static void add_decl_to_level PARAMS ((tree, struct binding_level *));
+static tree make_label_decl PARAMS ((tree, int));
+static void use_label PARAMS ((tree));
+static void check_previous_goto_1 PARAMS ((tree, struct binding_level *, tree,
+                                          const char *, int));
+static void check_previous_goto PARAMS ((struct named_label_use_list *));
+static void check_switch_goto PARAMS ((struct binding_level *));
+static void check_previous_gotos PARAMS ((tree));
+static void pop_label PARAMS ((tree, tree));
+static void pop_labels PARAMS ((tree));
+static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
+static void layout_var_decl PARAMS ((tree));
+static void maybe_commonize_var PARAMS ((tree));
+static tree check_initializer PARAMS ((tree, tree));
+static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
+static void push_cp_function_context PARAMS ((struct function *));
+static void pop_cp_function_context PARAMS ((struct function *));
+static void mark_binding_level PARAMS ((void *));
+static void mark_named_label_lists PARAMS ((void *, void *));
+static void mark_cp_function_context PARAMS ((struct function *));
+static void mark_saved_scope PARAMS ((void *));
+static void mark_lang_function PARAMS ((struct cp_language_function *));
+static void save_function_data PARAMS ((tree));
+static void check_function_type PARAMS ((tree, tree));
+static void destroy_local_var PARAMS ((tree));
+static void finish_constructor_body PARAMS ((void));
+static void finish_destructor_body PARAMS ((void));
+static tree create_array_type_for_decl PARAMS ((tree, tree, tree));
+static tree get_atexit_node PARAMS ((void));
+static tree get_dso_handle_node PARAMS ((void));
+static tree start_cleanup_fn PARAMS ((void));
+static void end_cleanup_fn PARAMS ((void));
+static tree cp_make_fname_decl PARAMS ((tree, const char *, int));
+static void initialize_predefined_identifiers PARAMS ((void));
+static tree check_special_function_return_type 
+  PARAMS ((special_function_kind, tree, tree, tree));
+static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
+static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
+static void store_parm_decls PARAMS ((tree));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
-static void indent PROTO((void));
+static void indent PARAMS ((void));
 #endif
 
 /* Erroneous argument lists can use this *IFF* they do not modify it.  */
 tree error_mark_list;
 
 /* The following symbols are subsumed in the cp_global_trees array, and
-   listed here individually for documentation purposes. 
+   listed here individually for documentation purposes.
 
    C++ extensions
        tree wchar_decl_node;
-       tree void_zero_node;
 
        tree vtable_entry_type;
        tree delta_type_node;
@@ -204,10 +202,12 @@ tree error_mark_list;
 #if 0
        tree __tp_desc_type_node;
 #endif
-       tree __access_mode_type_node;
-       tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node;
-       tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node;
-       tree __ptmf_desc_type_node, __ptmd_desc_type_node;
+        tree ti_desc_type_node;
+       tree bltn_desc_type_node, ptr_desc_type_node;
+       tree ary_desc_type_node, func_desc_type_node, enum_desc_type_node;
+       tree class_desc_type_node, si_class_desc_type_node, vmi_class_desc_type_node;
+       tree ptm_desc_type_node;
+       tree base_desc_type_node;
 #if 0
    Not needed yet?  May be needed one day?
        tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type;
@@ -215,7 +215,6 @@ tree error_mark_list;
        tree __ptmf_desc_array_type, __ptmd_desc_array_type;
 #endif
 
-       tree class_star_type_node;
        tree class_type_node, record_type_node, union_type_node, enum_type_node;
        tree unknown_type_node;
 
@@ -224,9 +223,10 @@ tree error_mark_list;
        tree vtbl_type_node;
        tree vtbl_ptr_type_node;
 
-   Nnamespace std
+   Namespaces,
 
        tree std_node;
+       tree abi_node;
 
    A FUNCTION_DECL which can call `abort'.  Not necessarily the
    one that the user will declare, but sufficient to be called
@@ -239,7 +239,8 @@ tree error_mark_list;
        tree global_delete_fndecl;
 
    Used by RTTI
-       tree type_info_type_node, tinfo_fn_id, tinfo_fn_type;
+       tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
+       tree tinfo_var_id;
 
 */
 
@@ -256,26 +257,19 @@ int in_std;
 /* Expect only namespace names now. */
 static int only_namespace_names;
 
-/* If original DECL_RESULT of current function was a register,
-   but due to being an addressable named return value, would up
-   on the stack, this variable holds the named return value's
-   original location.  */
-
-#define original_result_rtx cp_function_chain->x_result_rtx
+/* Used only for jumps to as-yet undefined labels, since jumps to
+   defined labels can have their validity checked immediately.  */
 
-struct named_label_list
+struct named_label_use_list
 {
   struct binding_level *binding_level;
   tree names_in_scope;
   tree label_decl;
   const char *filename_o_goto;
   int lineno_o_goto;
-  struct named_label_list *next;
+  struct named_label_use_list *next;
 };
 
-/* Used only for jumps to as-yet undefined labels, since jumps to
-   defined labels can have their validity checked by stmt.c.  */
-
 #define named_label_uses cp_function_chain->x_named_label_uses
 
 /* A list of objects which have constructors or destructors
@@ -290,15 +284,6 @@ tree static_aggregates;
 
 tree integer_two_node, integer_three_node;
 
-/* While defining an enum type, this is 1 plus the last enumerator
-   constant value.  */
-
-static tree enum_next_value;
-
-/* Nonzero means that there was overflow computing enum_next_value.  */
-
-static int enum_overflow;
-
 /* Parsing a function declarator leaves here a chain of structure
    and enum types declared in the parmlist.  */
 
@@ -308,16 +293,22 @@ static tree last_function_parm_tags;
 tree last_function_parms;
 static tree current_function_parm_tags;
 
-/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
-   that have names.  Here so we can clear out their names' definitions
-   at the end of the function.  The TREE_VALUE is a LABEL_DECL; the
-   TREE_PURPOSE is the previous binding of the label.  */
+/* A list of all LABEL_DECLs in the function that have names.  Here so
+   we can clear out their names' definitions at the end of the
+   function, and so we can check the validity of jumps to these labels.  */
 
-#define named_labels cp_function_chain->x_named_labels
+struct named_label_list
+{
+  struct binding_level *binding_level;
+  tree names_in_scope;
+  tree old_value;
+  tree label_decl;
+  tree bad_decls;
+  int eh_region;
+  struct named_label_list *next;
+};
 
-/* The FUNCTION_DECL for the function currently being compiled,
-   or 0 if between functions.  */
-tree current_function_decl;
+#define named_labels cp_function_chain->x_named_labels
 
 /* Set to 0 at beginning of a function definition, and whenever
    a label (case or named) is defined.  Set to value of expression
@@ -326,6 +317,23 @@ tree current_function_decl;
 
 tree current_function_return_value;
 
+/* Nonzero means use the ISO C94 dialect of C.  */
+
+int flag_isoc94;
+
+/* Nonzero means use the ISO C99 dialect of C.  */
+
+int flag_isoc99;
+
+/* Nonzero means we are a hosted implementation for code shared with C.  */
+
+int flag_hosted = 1;
+
+/* Nonzero means add default format_arg attributes for functions not
+   in ISO C.  */
+
+int flag_noniso_default_format_attributes = 1;
+
 /* Nonzero means give `double' the same size as `float'.  */
 
 extern int flag_short_double;
@@ -339,10 +347,6 @@ extern int flag_no_builtin;
 
 extern int flag_no_nonansi_builtin;
 
-/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
-   objects.  */
-extern 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 flagging multiple
@@ -363,6 +367,10 @@ tree signed_size_zero_node;
    unit.  */
 tree anonymous_namespace_name;
 
+/* The number of function bodies which we are currently processing.
+   (Zero if we are at namespace scope, one inside the body of a
+   function, two inside the body of a function in a local class, etc.)  */
+int function_depth;
 \f
 /* For each binding contour we allocate a binding_level structure
    which records the names defined in that contour.
@@ -436,9 +444,8 @@ struct binding_level
        that were entered and exited one level down.  */
     tree blocks;
 
-    /* The BLOCK node for this level, if one has been preallocated.
-       If 0, the BLOCK is allocated (if needed) when the level is popped.  */
-    tree this_block;
+    /* The _TYPE node for this level, if parm_flag == 2.  */
+    tree this_class;
 
     /* The binding level which this one is contained in (inherits from).  */
     struct binding_level *level_chain;
@@ -448,19 +455,18 @@ struct binding_level
     tree incomplete;
 
     /* List of VAR_DECLS saved from a previous for statement.
-       These would be dead in ANSI-conforming code, but might
+       These would be dead in ISO-conforming code, but might
        be referenced in ARM-era code.  These are stored in a
        TREE_LIST; the TREE_VALUE is the actual declaration.  */
     tree dead_vars_from_for;
 
     /* 1 for the level that holds the parameters of a function.
-       2 for the level that holds a class declaration.
-       3 for levels that hold parameter declarations.  */
-    unsigned parm_flag : 4;
+       2 for the level that holds a class declaration.  */
+    unsigned parm_flag : 2;
 
     /* 1 means make a BLOCK for this level regardless of all else.
        2 for temporary binding contours created by the compiler.  */
-    unsigned keep : 3;
+    unsigned keep : 2;
 
     /* Nonzero if this level "doesn't exist" for tags.  */
     unsigned tag_transparent : 1;
@@ -470,22 +476,29 @@ struct binding_level
     unsigned more_cleanups_ok : 1;
     unsigned have_cleanups : 1;
 
-    /* Nonzero if this level is for storing the decls for template
+    /* Nonzero if this scope is for storing the decls for template
        parameters and generic decls; these decls will be discarded and
        replaced with a TEMPLATE_DECL.  */
-    unsigned pseudo_global : 1;
+    unsigned template_parms_p : 1;
+
+    /* Nonzero if this scope corresponds to the `<>' in a 
+       `template <>' clause.  Whenever this flag is set,
+       TEMPLATE_PARMS_P will be set as well.  */
+    unsigned template_spec_p : 1;
 
     /* This is set for a namespace binding level.  */
     unsigned namespace_p : 1;
 
     /* True if this level is that of a for-statement where we need to
-       worry about ambiguous (ARM or ANSI) scope rules.  */
+       worry about ambiguous (ARM or ISO) scope rules.  */
     unsigned is_for_scope : 1;
 
-    /* True if this level corresponds to an EH region, as for a try block.  */
+    /* True if this level corresponds to an EH region, as for a try block.
+       Currently this information is only available while building the
+       tree structure.  */
     unsigned eh_region : 1;
 
-    /* One bit left for this word.  */
+    /* Four bits left for this word.  */
 
 #if defined(DEBUG_CP_BINDING_LEVELS)
     /* Binding depth at which this level began.  */
@@ -494,11 +507,11 @@ struct binding_level
   };
 
 #define NULL_BINDING_LEVEL ((struct binding_level *) NULL)
-  
+
 /* The binding level currently in effect.  */
 
 #define current_binding_level                  \
-  (current_function                            \
+  (cfun                                                \
    ? cp_function_chain->bindings               \
    : scope_chain->bindings)
 
@@ -534,7 +547,7 @@ indent ()
 }
 #endif /* defined(DEBUG_CP_BINDING_LEVELS) */
 
-static tree pushdecl_with_scope        PROTO((tree, struct binding_level *));
+static tree pushdecl_with_scope        PARAMS ((tree, struct binding_level *));
 
 static void
 push_binding_level (newlevel, tag_transparent, keep)
@@ -549,11 +562,6 @@ push_binding_level (newlevel, tag_transparent, keep)
   newlevel->tag_transparent = tag_transparent;
   newlevel->more_cleanups_ok = 1;
 
-  /* We are called before expand_start_bindings, but after
-     expand_eh_region_start for a try block; so we check this now,
-     before the EH block is covered up.  */
-  newlevel->eh_region = is_eh_region ();
-
   newlevel->keep = keep;
 #if defined(DEBUG_CP_BINDING_LEVELS)
   newlevel->binding_depth = binding_depth;
@@ -702,15 +710,15 @@ innermost_nonclass_level ()
 /* Nonzero if we are currently in a toplevel binding level.  This
    means either the global binding level or a namespace in a toplevel
    binding level.  Since there are no non-toplevel namespace levels,
-   this really means any namespace or pseudo-global level.  We also
-   include a class whose context is toplevel.  */
+   this really means any namespace or template parameter level.  We
+   also include a class whose context is toplevel.  */
 
 int
 toplevel_bindings_p ()
 {
   struct binding_level *b = innermost_nonclass_level ();
 
-  return b->namespace_p || b->pseudo_global;
+  return b->namespace_p || b->template_parms_p;
 }
 
 /* Nonzero if this is a namespace scope, or if we are defining a class
@@ -748,22 +756,108 @@ kept_level_p ()
              && !current_binding_level->tag_transparent));
 }
 
-void
-declare_pseudo_global_level ()
-{
-  current_binding_level->pseudo_global = 1;
-}
-
 static void
 declare_namespace_level ()
 {
   current_binding_level->namespace_p = 1;
 }
 
+/* Returns non-zero if this scope was created to store template
+   parameters.  */
+
 int
-pseudo_global_level_p ()
+template_parm_scope_p ()
+{
+  return current_binding_level->template_parms_p;
+}
+
+/* Returns the kind of template specialization we are currently
+   processing, given that it's declaration contained N_CLASS_SCOPES
+   explicit scope qualifications.  */
+
+tmpl_spec_kind
+current_tmpl_spec_kind (n_class_scopes)
+     int n_class_scopes;
 {
-  return current_binding_level->pseudo_global;
+  int n_template_parm_scopes = 0;
+  int seen_specialization_p = 0;
+  int innermost_specialization_p = 0;
+  struct binding_level *b;
+
+  /* Scan through the template parameter scopes.  */
+  for (b = current_binding_level; b->template_parms_p; b = b->level_chain)
+    {
+      /* If we see a specialization scope inside a parameter scope,
+        then something is wrong.  That corresponds to a declaration
+        like:
+
+           template <class T> template <> ...
+
+        which is always illegal since [temp.expl.spec] forbids the
+        specialization of a class member template if the enclosing
+        class templates are not explicitly specialized as well.  */
+      if (b->template_spec_p)
+       {
+         if (n_template_parm_scopes == 0)
+           innermost_specialization_p = 1;
+         else
+           seen_specialization_p = 1;
+       }
+      else if (seen_specialization_p == 1)
+       return tsk_invalid_member_spec;
+
+      ++n_template_parm_scopes;
+    }
+
+  /* Handle explicit instantiations.  */
+  if (processing_explicit_instantiation)
+    {
+      if (n_template_parm_scopes != 0)
+       /* We've seen a template parameter list during an explicit
+          instantiation.  For example:
+
+            template <class T> template void f(int);
+
+          This is erroneous.  */
+       return tsk_invalid_expl_inst;
+      else
+       return tsk_expl_inst;
+    }
+
+  if (n_template_parm_scopes < n_class_scopes)
+    /* We've not seen enough template headers to match all the
+       specialized classes present.  For example:
+
+         template <class T> void R<T>::S<T>::f(int);
+
+       This is illegal; there needs to be one set of template
+       parameters for each class.  */
+    return tsk_insufficient_parms;
+  else if (n_template_parm_scopes == n_class_scopes)
+    /* We're processing a non-template declaration (even though it may
+       be a member of a template class.)  For example:
+
+         template <class T> void S<T>::f(int);
+
+       The `class T' maches the `S<T>', leaving no template headers
+       corresponding to the `f'.  */
+    return tsk_none;
+  else if (n_template_parm_scopes > n_class_scopes + 1)
+    /* We've got too many template headers.  For example:
+
+         template <> template <class T> void f (T);
+
+       There need to be more enclosing classes.  */
+    return tsk_excessive_parms;
+  else
+    /* This must be a template.  It's of the form:
+
+         template <class T> template <class U> void S<T>::f(U);
+
+       This is a specialization if the innermost level was a
+       specialization; otherwise it's just a definition of the
+       template.  */
+    return innermost_specialization_p ? tsk_expl_spec : tsk_template;
 }
 
 void
@@ -783,7 +877,7 @@ pushlevel (tag_transparent)
 {
   struct binding_level *newlevel;
 
-  if (current_function && !doing_semantic_analysis_p ())
+  if (cfun && !doing_semantic_analysis_p ())
     return;
 
   /* Reuse or create a struct for this binding level.  */
@@ -804,12 +898,52 @@ pushlevel (tag_transparent)
   keep_next_level_flag = 0;
 }
 
+/* Enter a new scope.  The KIND indicates what kind of scope is being
+   created.  */
+
+void
+begin_scope (sk)
+     scope_kind sk;
+{
+  pushlevel (0);
+
+  switch (sk)
+    {
+    case sk_template_spec:
+      current_binding_level->template_spec_p = 1;
+      /* Fall through.  */
+
+    case sk_template_parms:
+      current_binding_level->template_parms_p = 1;
+      break;
+
+    default:
+      my_friendly_abort (20000309);
+    }
+}
+
+/* Exit the current scope.  */
+
+void
+finish_scope ()
+{
+  poplevel (0, 0, 0);
+}
+
 void
 note_level_for_for ()
 {
   current_binding_level->is_for_scope = 1;
 }
 
+/* Record that the current binding level represents a try block.  */
+
+void
+note_level_for_eh ()
+{
+  current_binding_level->eh_region = 1;
+}
+
 /* For a binding between a name and an entity at a block scope,
    this is the `struct binding_level' for the block.  */
 #define BINDING_LEVEL(NODE) \
@@ -889,6 +1023,16 @@ add_binding (id, decl)
         the name of any type declared in that scope to refer to the
         type to which it already refers.  */
     ok = 0;
+  /* There can be two block-scope declarations of the same variable,
+     so long as they are `extern' declarations.  */
+  else if (TREE_CODE (decl) == VAR_DECL
+          && TREE_CODE (BINDING_VALUE (binding)) == VAR_DECL
+          && DECL_EXTERNAL (decl)
+          && DECL_EXTERNAL (BINDING_VALUE (binding)))
+    {
+      duplicate_decls (decl, BINDING_VALUE (binding));
+      ok = 0;
+    }
   else
     {
       cp_error ("declaration of `%#D'", decl);
@@ -1000,12 +1144,11 @@ push_class_binding (id, decl)
       else
        {
          if (TREE_CODE (decl) == OVERLOAD)
-           context = DECL_REAL_CONTEXT (OVL_CURRENT (decl));
+           context = CP_DECL_CONTEXT (OVL_CURRENT (decl));
          else
            {
-             my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd',
-                                 0);
-             context = DECL_REAL_CONTEXT (decl);
+             my_friendly_assert (DECL_P (decl), 0);
+             context = CP_DECL_CONTEXT (decl);
            }
 
          if (is_properly_derived_from (current_class_type, context))
@@ -1026,13 +1169,13 @@ push_class_binding (id, decl)
 /* Remove the binding for DECL which should be the innermost binding
    for ID.  */
 
-static void 
-pop_binding (id, decl) 
+static void
+pop_binding (id, decl)
      tree id;
      tree decl;
 {
   tree binding;
-    
+
   if (id == NULL_TREE)
     /* It's easiest to write the loops that call this function without
        checking whether or not the entities involved have names.  We
@@ -1064,11 +1207,10 @@ pop_binding (id, decl)
    in a valid manner, and issue any appropriate warnings or errors.  */
 
 static void
-pop_label (link)
-     tree link;
+pop_label (label, old_value)
+     tree label;
+     tree old_value;
 {
-  tree label = TREE_VALUE (link);
-
   if (!processing_template_decl && doing_semantic_analysis_p ())
     {
       if (DECL_INITIAL (label) == NULL_TREE)
@@ -1077,35 +1219,35 @@ pop_label (link)
          /* Avoid crashing later.  */
          define_label (input_filename, 1, DECL_NAME (label));
        }
-      else if (warn_unused && !TREE_USED (label))
+      else if (warn_unused_label && !TREE_USED (label))
        cp_warning_at ("label `%D' defined but not used", label);
     }
 
-  SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
+  SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
 }
 
-/* At the end of a function, all labels declared within the fucntion
-   go out of scope.  BLOCK is the top-level block for the 
+/* At the end of a function, all labels declared within the function
+   go out of scope.  BLOCK is the top-level block for the
    function.  */
 
 static void
 pop_labels (block)
      tree block;
 {
-  tree link;
+  struct named_label_list *link;
 
   /* Clear out the definitions of all label names, since their scopes
      end here.  */
-  for (link = named_labels; link; link = TREE_CHAIN (link))
+  for (link = named_labels; link; link = link->next)
     {
-      pop_label (link);
+      pop_label (link->label_decl, link->old_value);
       /* Put the labels into the "variables" of the top-level block,
         so debugger can see them.  */
-      TREE_CHAIN (TREE_VALUE (link)) = BLOCK_VARS (block);
-      BLOCK_VARS (block) = TREE_VALUE (link);
+      TREE_CHAIN (link->label_decl) = BLOCK_VARS (block);
+      BLOCK_VARS (block) = link->label_decl;
     }
 
-  named_labels = NULL_TREE;
+  named_labels = NULL;
 }
 
 /* Exit a binding level.
@@ -1139,10 +1281,9 @@ poplevel (keep, reverse, functionbody)
   tree subblocks;
   tree block = NULL_TREE;
   tree decl;
-  int block_previously_created;
   int leaving_for_scope;
 
-  if (current_function && !doing_semantic_analysis_p ())
+  if (cfun && !doing_semantic_analysis_p ())
     return NULL_TREE;
 
   my_friendly_assert (current_binding_level->parm_flag != 2,
@@ -1169,6 +1310,40 @@ poplevel (keep, reverse, functionbody)
   if (current_binding_level->keep == 1)
     keep = 1;
 
+  /* Any uses of undefined labels, and any defined labels, now operate
+     under constraints of next binding contour.  */
+  if (cfun && !functionbody)
+    {
+      struct binding_level *level_chain;
+      level_chain = current_binding_level->level_chain;
+      if (level_chain)
+       {
+         struct named_label_use_list *uses;
+         struct named_label_list *labels;
+         for (labels = named_labels; labels; labels = labels->next)
+           if (labels->binding_level == current_binding_level)
+             {
+               tree decl;
+               if (current_binding_level->eh_region)
+                 labels->eh_region = 1;
+               for (decl = labels->names_in_scope; decl;
+                    decl = TREE_CHAIN (decl))
+                 if (decl_jump_unsafe (decl))
+                   labels->bad_decls = tree_cons (NULL_TREE, decl,
+                                                  labels->bad_decls);
+               labels->binding_level = level_chain;
+               labels->names_in_scope = level_chain->names;
+             }
+
+         for (uses = named_label_uses; uses; uses = uses->next)
+           if (uses->binding_level == current_binding_level)
+             {
+               uses->binding_level = level_chain;
+               uses->names_in_scope = level_chain->names;
+             }
+       }
+    }
+
   /* Get the decls in the order they were written.
      Usually current_binding_level->names is in reverse order.
      But parameter decls were previously put in forward order.  */
@@ -1181,7 +1356,6 @@ poplevel (keep, reverse, functionbody)
 
   /* Output any nested inline functions within this block
      if they weren't already output.  */
-
   for (decl = decls; decl; decl = TREE_CHAIN (decl))
     if (TREE_CODE (decl) == FUNCTION_DECL
        && ! TREE_ASM_WRITTEN (decl)
@@ -1202,43 +1376,27 @@ poplevel (keep, reverse, functionbody)
          }
       }
 
+  /* When not in function-at-a-time mode, expand_end_bindings will
+     warn about unused variables.  But, in function-at-a-time mode
+     expand_end_bindings is not passed the list of variables in the
+     current scope, and therefore no warning is emitted.  So, we
+     explicitly warn here.  */
+  if (!processing_template_decl)
+    warn_about_unused_variables (getdecls ());
+
   /* If there were any declarations or structure tags in that level,
      or if this level is a function body,
      create a BLOCK to record them for the life of this function.  */
-
   block = NULL_TREE;
-  block_previously_created = (current_binding_level->this_block != NULL_TREE);
-  if (block_previously_created)
-    block = current_binding_level->this_block;
-  else if (keep == 1 || functionbody)
+  if (keep == 1 || functionbody)
     block = make_node (BLOCK);
   if (block != NULL_TREE)
     {
-      if (block_previously_created)
-       {
-         if (decls || tags || subblocks)
-           {
-             if (BLOCK_VARS (block))
-               warning ("internal compiler error: debugging info corrupted");
-
-             BLOCK_VARS (block) = decls;
-
-             /* We can have previous subblocks and new subblocks when
-                doing fixup_gotos with complex cleanups.  We chain the new
-                subblocks onto the end of any pre-existing subblocks.  */
-             BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block),
-                                                subblocks);
-           }
-       }
-      else
-       {
-         BLOCK_VARS (block) = decls;
-         BLOCK_SUBBLOCKS (block) = subblocks;
-       }
+      BLOCK_VARS (block) = decls;
+      BLOCK_SUBBLOCKS (block) = subblocks;
     }
 
   /* In each subblock, record that this is its superior.  */
-
   if (keep >= 0)
     for (link = subblocks; link; link = TREE_CHAIN (link))
       BLOCK_SUPERCONTEXT (link) = block;
@@ -1247,15 +1405,16 @@ poplevel (keep, reverse, functionbody)
      in a for-init statement were in scope after the for-statement
      ended.  We only use the new rules in flag_new_for_scope is
      nonzero.  */
-  leaving_for_scope 
+  leaving_for_scope
     = current_binding_level->is_for_scope && flag_new_for_scope == 1;
 
   /* Remove declarations for all the DECLs in this level.  */
   for (link = decls; link; link = TREE_CHAIN (link))
     {
-      if (leaving_for_scope && TREE_CODE (link) == VAR_DECL)
+      if (leaving_for_scope && TREE_CODE (link) == VAR_DECL
+          && DECL_NAME (link))
        {
-         tree outer_binding 
+         tree outer_binding
            = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (link)));
          tree ns_binding;
 
@@ -1264,21 +1423,21 @@ poplevel (keep, reverse, functionbody)
          else
            ns_binding = NULL_TREE;
 
-         if (outer_binding 
-             && (BINDING_LEVEL (outer_binding) 
+         if (outer_binding
+             && (BINDING_LEVEL (outer_binding)
                  == current_binding_level->level_chain))
            /* We have something like:
-              
+
                 int i;
                 for (int i; ;);
-                
+
               and we are leaving the `for' scope.  There's no reason to
               keep the binding of the inner `i' in this case.  */
            pop_binding (DECL_NAME (link), link);
-         else if ((outer_binding 
-                   && (TREE_CODE (BINDING_VALUE (outer_binding)) 
+         else if ((outer_binding
+                   && (TREE_CODE (BINDING_VALUE (outer_binding))
                        == TYPE_DECL))
-                  || (ns_binding 
+                  || (ns_binding
                       && TREE_CODE (ns_binding) == TYPE_DECL))
            /* Here, we have something like:
 
@@ -1296,11 +1455,11 @@ poplevel (keep, reverse, functionbody)
              /* Mark this VAR_DECL as dead so that we can tell we left it
                 there only for backward compatibility.  */
              DECL_DEAD_FOR_LOCAL (link) = 1;
-             
+
              /* Keep track of what should of have happenned when we
                 popped the binding.  */
              if (outer_binding && BINDING_VALUE (outer_binding))
-               DECL_SHADOWED_FOR_VAR (link) 
+               DECL_SHADOWED_FOR_VAR (link)
                  = BINDING_VALUE (outer_binding);
 
              /* Add it to the list of dead variables in the next
@@ -1317,17 +1476,17 @@ poplevel (keep, reverse, functionbody)
                = 0;
            }
        }
-      else 
+      else
        {
          /* Remove the binding.  */
          decl = link;
          if (TREE_CODE (decl) == TREE_LIST)
            decl = TREE_VALUE (decl);
-         if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
+         if (DECL_P (decl))
            pop_binding (DECL_NAME (decl), decl);
          else if (TREE_CODE (decl) == OVERLOAD)
            pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl);
-         else 
+         else
            my_friendly_abort (0);
        }
     }
@@ -1345,9 +1504,9 @@ poplevel (keep, reverse, functionbody)
 
   /* Restore the IDENTIFIER_LABEL_VALUEs for local labels.  */
   for (link = current_binding_level->shadowed_labels;
-       link; 
+       link;
        link = TREE_CHAIN (link))
-    pop_label (link);
+    pop_label (TREE_VALUE (link), TREE_PURPOSE (link));
 
   /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
      list if a `using' declaration put them there.  The debugging
@@ -1379,35 +1538,15 @@ poplevel (keep, reverse, functionbody)
       pop_labels (block);
     }
 
-  /* Any uses of undefined labels now operate under constraints
-     of next binding contour.  */
-  if (current_function)
-    {
-      struct binding_level *level_chain;
-      level_chain = current_binding_level->level_chain;
-      if (level_chain)
-       {
-         struct named_label_list *labels;
-         for (labels = named_label_uses; labels; labels = labels->next)
-           if (labels->binding_level == current_binding_level)
-             {
-               labels->binding_level = level_chain;
-               labels->names_in_scope = level_chain->names;
-             }
-       }
-    }
-
   tmp = current_binding_level->keep;
 
   pop_binding_level ();
   if (functionbody)
     DECL_INITIAL (current_function_decl) = block;
   else if (block)
-    {
-      if (!block_previously_created)
-        current_binding_level->blocks
-          = chainon (current_binding_level->blocks, block);
-    }
+    current_binding_level->blocks
+      = chainon (current_binding_level->blocks, block);
+
   /* If we did not make a block for the level just exited,
      any blocks made for inner levels
      (since they cannot be recorded as subblocks in that level)
@@ -1417,23 +1556,28 @@ poplevel (keep, reverse, functionbody)
     current_binding_level->blocks
       = chainon (current_binding_level->blocks, subblocks);
 
+  /* Each and every BLOCK node created here in `poplevel' is important
+     (e.g. for proper debugging information) so if we created one
+     earlier, mark it as "used".  */
+  if (block)
+    TREE_USED (block) = 1;
+
   /* Take care of compiler's internal binding structures.  */
   if (tmp == 2)
     {
-      add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
-      /* Each and every BLOCK node created here in `poplevel' is important
-        (e.g. for proper debugging information) so if we created one
-        earlier, mark it as "used".  */
+      tree scope_stmts;
+
+      scope_stmts
+       = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
       if (block)
-       TREE_USED (block) = 1;
+       {
+         SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+         SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+       }
+
       block = poplevel (keep, reverse, functionbody);
     }
 
-  /* Each and every BLOCK node created here in `poplevel' is important
-     (e.g. for proper debugging information) so if we created one
-     earlier, mark it as "used".  */
-  if (block)
-    TREE_USED (block) = 1;
   return block;
 }
 
@@ -1479,9 +1623,11 @@ insert_block (block)
 
 void
 set_block (block)
-    register tree block;
+    tree block ATTRIBUTE_UNUSED;
 {
-  current_binding_level->this_block = block;
+  /* The RTL expansion machinery requires us to provide this callback,
+     but it is not applicable in function-at-a-time mode.  */
+  my_friendly_assert (cfun && !doing_semantic_analysis_p (), 20000911);
 }
 
 /* Do a pushlevel for class declarations.  */
@@ -1512,6 +1658,7 @@ pushlevel_class ()
 
   class_binding_level = current_binding_level;
   class_binding_level->parm_flag = 2;
+  class_binding_level->this_class = current_class_type;
 }
 
 /* ...and a poplevel for class declarations.  */
@@ -1523,7 +1670,7 @@ poplevel_class ()
   tree shadowed;
 
   my_friendly_assert (level != 0, 354);
-  
+
   /* If we're leaving a toplevel class, don't bother to do the setting
      of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
      shouldn't even be used when current_class_type isn't set, and second,
@@ -1538,7 +1685,7 @@ poplevel_class ()
           shadowed;
           shadowed = TREE_CHAIN (shadowed))
        IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = NULL_TREE;
-       
+
       /* Find the next enclosing class, and recreate
         IDENTIFIER_CLASS_VALUEs appropriate for that class.  */
       b = level->level_chain;
@@ -1546,8 +1693,8 @@ poplevel_class ()
        b = b->level_chain;
 
       if (b)
-       for (shadowed = b->class_shadowed; 
-            shadowed; 
+       for (shadowed = b->class_shadowed;
+            shadowed;
             shadowed = TREE_CHAIN (shadowed))
          {
            tree t;
@@ -1555,9 +1702,9 @@ poplevel_class ()
            t = IDENTIFIER_BINDING (TREE_PURPOSE (shadowed));
            while (t && BINDING_LEVEL (t) != b)
              t = TREE_CHAIN (t);
-      
+
            if (t)
-             IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) 
+             IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed))
                = BINDING_VALUE (t);
          }
     }
@@ -1574,8 +1721,8 @@ poplevel_class ()
     SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
 
   /* Remove the bindings for all of the class-level declarations.  */
-  for (shadowed = level->class_shadowed; 
-       shadowed; 
+  for (shadowed = level->class_shadowed;
+       shadowed;
        shadowed = TREE_CHAIN (shadowed))
     pop_binding (TREE_PURPOSE (shadowed), TREE_TYPE (shadowed));
 
@@ -1629,9 +1776,8 @@ vtype_decl_p (t, data)
      void *data ATTRIBUTE_UNUSED;
 {
   return (TREE_CODE (t) == TYPE_DECL
-         && TREE_TYPE (t) != error_mark_node
-         && TYPE_LANG_SPECIFIC (TREE_TYPE (t))
-         && CLASSTYPE_VSIZE (TREE_TYPE (t)));
+         && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
+         && TYPE_POLYMORPHIC_P (TREE_TYPE (t)));
 }
 
 /* Return the declarations that are members of the namespace NS.  */
@@ -1699,7 +1845,7 @@ struct walk_globals_data {
    for which P returns non-zero, call F with its address.  If any call
    to F returns a non-zero value, return a non-zero value.  */
 
-static int 
+static int
 walk_globals_r (namespace, data)
      tree namespace;
      void *data;
@@ -1770,10 +1916,21 @@ wrapup_globals_for_namespace (namespace, data)
 
   /* Process the decls in reverse order--earliest first.
      Put them into VEC from back to front, then take out from front.  */
-  
+
   for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
-    vec[len - i - 1] = decl;
-  
+    {
+      /* Pretend we've output an unused static variable.  This ensures
+         that the toplevel __FUNCTION__ etc won't be emitted, unless
+         needed. */
+      if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl)
+         && !TREE_PUBLIC (decl) && !TREE_USED (decl))
+       {
+         TREE_ASM_WRITTEN (decl) = 1;
+         DECL_IGNORED_P (decl) = 1;
+       }
+      vec[len - i - 1] = decl;
+    }
+
   if (last_time)
     {
       check_global_declarations (vec, len);
@@ -1814,7 +1971,7 @@ mark_binding_level (arg)
 {
   struct binding_level *lvl = *(struct binding_level **)arg;
 
-  while (lvl)
+  for (; lvl; lvl = lvl->level_chain)
     {
       ggc_mark_tree (lvl->names);
       ggc_mark_tree (lvl->tags);
@@ -1824,12 +1981,31 @@ mark_binding_level (arg)
       ggc_mark_tree (lvl->type_shadowed);
       ggc_mark_tree (lvl->shadowed_labels);
       ggc_mark_tree (lvl->blocks);
-      ggc_mark_tree (lvl->this_block);
+      ggc_mark_tree (lvl->this_class);
       ggc_mark_tree (lvl->incomplete);
       ggc_mark_tree (lvl->dead_vars_from_for);
+    }
+}
+
+static void
+mark_named_label_lists (labs, uses)
+     void *labs;
+     void *uses;
+{
+  struct named_label_list *l = *(struct named_label_list **)labs;
+  struct named_label_use_list *u = *(struct named_label_use_list **)uses;
 
-      lvl = lvl->level_chain;
+  for (; l; l = l->next)
+    {
+      ggc_mark (l);
+      mark_binding_level (l->binding_level);
+      ggc_mark_tree (l->old_value);
+      ggc_mark_tree (l->label_decl);
+      ggc_mark_tree (l->bad_decls);
     }
+
+  for (; u; u = u->next)
+    ggc_mark (u);
 }
 \f
 /* For debugging.  */
@@ -1859,7 +2035,7 @@ print_binding_level (lvl)
       /* We can probably fit 3 names to a line?  */
       for (t = lvl->names; t; t = TREE_CHAIN (t))
        {
-         if (no_print_functions && (TREE_CODE (t) == FUNCTION_DECL)) 
+         if (no_print_functions && (TREE_CODE (t) == FUNCTION_DECL))
            continue;
          if (no_print_builtins
              && (TREE_CODE (t) == TYPE_DECL)
@@ -1998,7 +2174,7 @@ find_binding (name, scope)
   tree iter, prev = NULL_TREE;
 
   scope = ORIGINAL_NAMESPACE (scope);
-  
+
   for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter;
        iter = TREE_CHAIN (iter))
     {
@@ -2033,7 +2209,7 @@ binding_for_name (name, scope)
   tree result;
 
   scope = ORIGINAL_NAMESPACE (scope);
-  
+
   if (b && TREE_CODE (b) != CPLUS_BINDING)
     {
       /* Get rid of optimization for global scope. */
@@ -2043,15 +2219,13 @@ binding_for_name (name, scope)
     }
   if (b && (result = find_binding (name, scope)))
     return result;
-  /* Not found, make a new permanent one. */
-  push_obstacks (&permanent_obstack, &permanent_obstack);
+  /* Not found, make a new one. */
   result = make_node (CPLUS_BINDING);
   TREE_CHAIN (result) = b;
   IDENTIFIER_NAMESPACE_BINDINGS (name) = result;
   BINDING_SCOPE (result) = scope;
   BINDING_TYPE (result) = NULL_TREE;
   BINDING_VALUE (result) = NULL_TREE;
-  pop_obstacks ();
   return result;
 }
 
@@ -2089,7 +2263,7 @@ set_namespace_binding (name, scope, val)
 
   if (scope == NULL_TREE)
     scope = global_namespace;
-  
+
   if (scope == global_namespace)
     {
       b = IDENTIFIER_NAMESPACE_BINDINGS (name);
@@ -2154,7 +2328,7 @@ push_namespace (name)
             }
         }
     }
-  
+
   if (need_new)
     {
       /* Make a new namespace, binding the name to it. */
@@ -2163,6 +2337,7 @@ push_namespace (name)
         level is set elsewhere.  */
       if (!global)
        {
+         DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
          d = pushdecl (d);
          pushlevel (0);
          declare_namespace_level ();
@@ -2212,7 +2387,7 @@ push_nested_namespace (ns)
 
 /* Pop back from the scope of the namespace NS, which was previously
    entered with push_nested_namespace.  */
-     
+
 void
 pop_nested_namespace (ns)
      tree ns;
@@ -2234,16 +2409,6 @@ pop_nested_namespace (ns)
    scope isn't enough, because more binding levels may be pushed.  */
 struct saved_scope *scope_chain;
 
-/* Mark ST for GC.  */
-
-static void
-mark_stmt_tree (st)
-     struct stmt_tree *st;
-{
-  ggc_mark_tree (st->x_last_stmt);
-  ggc_mark_tree (st->x_last_expr_type);
-}
-
 /* Mark ARG (which is really a struct saved_scope **) for GC.  */
 
 static void
@@ -2263,11 +2428,12 @@ mark_saved_scope (arg)
       if (t->lang_base)
        ggc_mark_tree_varray (t->lang_base);
       ggc_mark_tree (t->lang_name);
-      ggc_mark_tree (t->x_function_parms);
       ggc_mark_tree (t->template_parms);
       ggc_mark_tree (t->x_previous_class_type);
       ggc_mark_tree (t->x_previous_class_values);
       ggc_mark_tree (t->x_saved_tree);
+      ggc_mark_tree (t->incomplete);
+      ggc_mark_tree (t->lookups);
 
       mark_stmt_tree (&t->x_stmt_tree);
       mark_binding_level (&t->bindings);
@@ -2289,7 +2455,7 @@ store_bindings (names, old_bindings)
       else
        id = DECL_NAME (t);
 
-      if (!id 
+      if (!id
          /* Note that we may have an IDENTIFIER_CLASS_VALUE even when
             we have no IDENTIFIER_BINDING if we have left the class
             scope, but cached the class-level declarations.  */
@@ -2334,7 +2500,7 @@ maybe_push_to_top_level (pseudo)
   b = scope_chain ? current_binding_level : 0;
 
   /* If we're in the middle of some function, save our state.  */
-  if (current_function)
+  if (cfun)
     {
       need_pop = 1;
       push_function_context_to (NULL_TREE);
@@ -2356,7 +2522,7 @@ maybe_push_to_top_level (pseudo)
         inserted into namespace level, finish_file wouldn't find them
         when doing pending instantiations. Therefore, don't stop at
         namespace level, but continue until :: .  */
-      if (b == global_binding_level || (pseudo && b->pseudo_global))
+      if (b == global_binding_level || (pseudo && b->template_parms_p))
        break;
 
       old_bindings = store_bindings (b->names, old_bindings);
@@ -2380,10 +2546,7 @@ maybe_push_to_top_level (pseudo)
   VARRAY_TREE_INIT (current_lang_base, 10, "current_lang_base");
   current_lang_stack = &VARRAY_TREE (current_lang_base, 0);
   current_lang_name = lang_name_cplusplus;
-  strict_prototype = strict_prototypes_lang_cplusplus;
   current_namespace = global_namespace;
-
-  push_obstacks (&permanent_obstack, &permanent_obstack);
 }
 
 void
@@ -2402,8 +2565,6 @@ pop_from_top_level ()
   if (previous_class_type)
     invalidate_class_lookup_cache ();
 
-  pop_obstacks ();
-
   VARRAY_FREE (current_lang_base);
 
   scope_chain = s->prev;
@@ -2418,11 +2579,6 @@ pop_from_top_level ()
        }
     }
 
-  if (current_lang_name == lang_name_cplusplus)
-    strict_prototype = strict_prototypes_lang_cplusplus;
-  else if (current_lang_name == lang_name_c)
-    strict_prototype = strict_prototypes_lang_c;
-
   /* If we were in the middle of compiling a function, restore our
      state.  */
   if (s->need_pop_function_context)
@@ -2433,7 +2589,7 @@ pop_from_top_level ()
 }
 \f
 /* Push a definition of struct, union or enum tag "name".
-   into binding_level "b".   "type" should be the type node, 
+   into binding_level "b".   "type" should be the type node,
    We assume that the tag "name" is not already defined.
 
    Note that the definition may really be just a forward reference.
@@ -2530,30 +2686,30 @@ pop_everything ()
    Returns the TYPE_DECL for TYPE, which may have been altered by this
    processing.  */
 
-static tree 
+static tree
 maybe_process_template_type_declaration (type, globalize, b)
      tree type;
      int globalize;
      struct binding_level* b;
 {
   tree decl = TYPE_NAME (type);
+
   if (processing_template_parmlist)
     /* You can't declare a new template type in a template parameter
        list.  But, you can declare a non-template type:
-       
+
          template <class A*> struct S;
-       
+
        is a forward-declaration of `A'.  */
     ;
-  else 
+  else
     {
       maybe_check_template_type (type);
 
-      my_friendly_assert (IS_AGGR_TYPE (type) 
+      my_friendly_assert (IS_AGGR_TYPE (type)
                          || TREE_CODE (type) == ENUMERAL_TYPE, 0);
-                         
-                         
+
+
       if (processing_template_decl)
        {
          /* This may change after the call to
@@ -2569,16 +2725,16 @@ maybe_process_template_type_declaration (type, globalize, b)
             friend case, push_template_decl will already have put the
             friend into global scope, if appropriate.  */
          if (TREE_CODE (type) != ENUMERAL_TYPE
-             && !globalize && b->pseudo_global
+             && !globalize && b->template_parms_p
              && b->level_chain->parm_flag == 2)
            {
              finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
              /* Put this tag on the list of tags for the class, since
                 that won't happen below because B is not the class
                 binding level, but is instead the pseudo-global level.  */
-             b->level_chain->tags = 
+             b->level_chain->tags =
                tree_cons (name, type, b->level_chain->tags);
-             if (TYPE_SIZE (current_class_type) == NULL_TREE)
+             if (!COMPLETE_TYPE_P (current_class_type))
                CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
            }
        }
@@ -2600,7 +2756,7 @@ create_implicit_typedef (name, type)
   tree decl;
 
   decl = build_decl (TYPE_DECL, name, type);
-  SET_DECL_ARTIFICIAL (decl);
+  DECL_ARTIFICIAL (decl) = 1;
   /* There are other implicit type declarations, like the one *within*
      a class that allows you to write `S::S'.  We must distinguish
      amongst these.  */
@@ -2644,17 +2800,16 @@ pushtag (name, type, globalize)
 
              if (! globalize)
                context = cs;
-             else if (cs != NULL_TREE 
-                      && TREE_CODE_CLASS (TREE_CODE (cs)) == 't')
+             else if (cs != NULL_TREE && TYPE_P (cs))
                /* When declaring a friend class of a local class, we want
                   to inject the newly named class into the scope
                   containing the local class, not the namespace scope.  */
-               context = hack_decl_function_context (get_type_decl (cs));
+               context = decl_function_context (get_type_decl (cs));
            }
          if (!context)
            context = current_namespace;
 
-         if ((b->pseudo_global && b->level_chain->parm_flag == 2)
+         if ((b->template_parms_p && b->level_chain->parm_flag == 2)
              || b->parm_flag == 2)
            in_class = 1;
 
@@ -2688,13 +2843,29 @@ pushtag (name, type, globalize)
 
          TYPE_CONTEXT (type) = DECL_CONTEXT (d);
          DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
-         if (!uses_template_parms (type))
-           DECL_ASSEMBLER_NAME (d)
-             = get_identifier (build_overload_name (type, 1, 1));
+
+         /* If this is a local class, keep track of it.  We need this
+            information for name-mangling, and so that it is possible to find
+            all function definitions in a translation unit in a convenient
+            way.  (It's otherwise tricky to find a member function definition
+            it's only pointed to from within a local class.)  */
+         if (TYPE_CONTEXT (type) 
+             && TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL
+             && !processing_template_decl)
+           VARRAY_PUSH_TREE (local_classes, type);
+
+         if (!uses_template_parms (type)) 
+           {
+             if (flag_new_abi)
+               DECL_ASSEMBLER_NAME (d) = mangle_type (type);
+             else
+               DECL_ASSEMBLER_NAME (d)
+                 = get_identifier (build_overload_name (type, 1, 1));
+           }
         }
       if (b->parm_flag == 2)
        {
-         if (TYPE_SIZE (current_class_type) == NULL_TREE)
+         if (!COMPLETE_TYPE_P (current_class_type))
            CLASSTYPE_TAGS (current_class_type) = b->tags;
        }
     }
@@ -2792,49 +2963,41 @@ decls_match (newdecl, olddecl)
       tree p1 = TYPE_ARG_TYPES (f1);
       tree p2 = TYPE_ARG_TYPES (f2);
 
-      if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl)
-         && ! (DECL_LANGUAGE (newdecl) == lang_c
-               && DECL_LANGUAGE (olddecl) == lang_c))
+      if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
+         && ! (DECL_EXTERN_C_P (newdecl)
+               && DECL_EXTERN_C_P (olddecl)))
        return 0;
 
-      /* When we parse a static member function definition,
-        we put together a FUNCTION_DECL which thinks its type
-        is METHOD_TYPE.  Change that to FUNCTION_TYPE, and
-        proceed.  */
-      if (TREE_CODE (f1) == METHOD_TYPE && DECL_STATIC_FUNCTION_P (olddecl))
-       revert_static_member_fn (&newdecl, &f1, &p1);
-      else if (TREE_CODE (f2) == METHOD_TYPE
-              && DECL_STATIC_FUNCTION_P (newdecl))
-       revert_static_member_fn (&olddecl, &f2, &p2);
-
-      /* Here we must take care of the case where new default
-        parameters are specified.  Also, warn if an old
-        declaration becomes ambiguous because default
-        parameters may cause the two to be ambiguous.  */
       if (TREE_CODE (f1) != TREE_CODE (f2))
-       {
-         if (TREE_CODE (f1) == OFFSET_TYPE)
-           cp_compiler_error ("`%D' redeclared as member function", newdecl);
-         else
-           cp_compiler_error ("`%D' redeclared as non-member function", newdecl);
-         return 0;
-       }
+        return 0;
 
       if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
        {
-         if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c
-             && p2 == NULL_TREE)
+         if (p2 == NULL_TREE && DECL_EXTERN_C_P (olddecl)
+             && (DECL_BUILT_IN (olddecl)
+#ifndef NO_IMPLICIT_EXTERN_C
+                 || (DECL_IN_SYSTEM_HEADER (newdecl) && !DECL_CLASS_SCOPE_P (newdecl))
+                 || (DECL_IN_SYSTEM_HEADER (olddecl) && !DECL_CLASS_SCOPE_P (olddecl))
+#endif
+             ))
            {
              types_match = self_promoting_args_p (p1);
              if (p1 == void_list_node)
                TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
            }
-         else if (!strict_prototypes_lang_c && DECL_LANGUAGE (olddecl)==lang_c
-                  && DECL_LANGUAGE (newdecl) == lang_c && p1 == NULL_TREE)
+#ifndef NO_IMPLICIT_EXTERN_C
+         else if (p1 == NULL_TREE
+                  && (DECL_EXTERN_C_P (olddecl)
+                      && DECL_IN_SYSTEM_HEADER (olddecl)
+                      && !DECL_CLASS_SCOPE_P (olddecl))
+                  && (DECL_EXTERN_C_P (newdecl)
+                      && DECL_IN_SYSTEM_HEADER (newdecl)
+                      && !DECL_CLASS_SCOPE_P (newdecl)))
            {
              types_match = self_promoting_args_p (p2);
              TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
            }
+#endif
          else
            types_match = compparms (p1, p2);
        }
@@ -2846,7 +3009,11 @@ decls_match (newdecl, olddecl)
       if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
                                DECL_TEMPLATE_PARMS (olddecl)))
        return 0;
-      
+
+      if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl))
+         != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)))
+       return 0;
+
       if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
        types_match = 1;
       else
@@ -2890,10 +3057,11 @@ warn_extern_redeclared_static (newdecl, olddecl)
 
   tree name;
 
-  if (TREE_CODE (newdecl) == TYPE_DECL 
-      || TREE_CODE (newdecl) == TEMPLATE_DECL)
+  if (TREE_CODE (newdecl) == TYPE_DECL
+      || TREE_CODE (newdecl) == TEMPLATE_DECL
+      || TREE_CODE (newdecl) == CONST_DECL)
     return;
-  
+
   /* Don't get confused by static member functions; that's a different
      use of `static'.  */
   if (TREE_CODE (newdecl) == FUNCTION_DECL
@@ -2945,7 +3113,7 @@ duplicate_decls (newdecl, olddecl)
   if (TREE_TYPE (newdecl) == error_mark_node
       || TREE_TYPE (olddecl) == error_mark_node)
     types_match = 1;
+
   /* Check for redeclaration and other discrepancies. */
   if (TREE_CODE (olddecl) == FUNCTION_DECL
       && DECL_ARTIFICIAL (olddecl))
@@ -2979,8 +3147,8 @@ duplicate_decls (newdecl, olddecl)
        }
       else if (!types_match)
        {
-         if ((DECL_LANGUAGE (newdecl) == lang_c
-              && DECL_LANGUAGE (olddecl) == lang_c)
+         if ((DECL_EXTERN_C_P (newdecl)
+              && DECL_EXTERN_C_P (olddecl))
              || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
                            TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
            {
@@ -3001,7 +3169,7 @@ duplicate_decls (newdecl, olddecl)
            /* Discard the old built-in function.  */
            return 0;
        }
-      
+
       if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
        {
          /* If a builtin function is redeclared as `static', merge
@@ -3009,9 +3177,9 @@ duplicate_decls (newdecl, olddecl)
          DECL_THIS_STATIC (olddecl) = 1;
          TREE_PUBLIC (olddecl) = 0;
 
-         /* Make the olddeclaration consistent with the new one so that
-            all remnants of the builtin-ness of this function will be
-            banished.  */
+         /* Make the old declaration consistent with the new one so
+            that all remnants of the builtin-ness of this function
+            will be banished.  */
          DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
          DECL_RTL (olddecl) = DECL_RTL (newdecl);
          DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
@@ -3057,7 +3225,7 @@ duplicate_decls (newdecl, olddecl)
     }
   else if (!types_match)
     {
-      if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl))
+      if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl))
        /* These are certainly not duplicate declarations; they're
           from different scopes.  */
        return 0;
@@ -3088,8 +3256,7 @@ duplicate_decls (newdecl, olddecl)
        }
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
        {
-         if (DECL_LANGUAGE (newdecl) == lang_c
-             && DECL_LANGUAGE (olddecl) == lang_c)
+         if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))
            {
              cp_error ("declaration of C function `%#D' conflicts with",
                        newdecl);
@@ -3113,14 +3280,14 @@ duplicate_decls (newdecl, olddecl)
          cp_error_at ("previous declaration as `%#D'", olddecl);
        }
     }
-  else if (TREE_CODE (newdecl) == FUNCTION_DECL 
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL
            && ((DECL_TEMPLATE_SPECIALIZATION (olddecl)
                 && (!DECL_TEMPLATE_INFO (newdecl)
-                    || (DECL_TI_TEMPLATE (newdecl) 
+                    || (DECL_TI_TEMPLATE (newdecl)
                         != DECL_TI_TEMPLATE (olddecl))))
                || (DECL_TEMPLATE_SPECIALIZATION (newdecl)
                    && (!DECL_TEMPLATE_INFO (olddecl)
-                       || (DECL_TI_TEMPLATE (olddecl) 
+                       || (DECL_TI_TEMPLATE (olddecl)
                            != DECL_TI_TEMPLATE (newdecl))))))
     /* It's OK to have a template specialization and a non-template
        with the same type, or to have specializations of two
@@ -3131,8 +3298,8 @@ duplicate_decls (newdecl, olddecl)
        specialize one of its methods.  This situation is legal, but
        the declarations must be merged in the usual way.  */
     return 0;
-  else if (TREE_CODE (newdecl) == FUNCTION_DECL 
-          && ((DECL_TEMPLATE_INSTANTIATION (olddecl) 
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL
+          && ((DECL_TEMPLATE_INSTANTIATION (olddecl)
                && !DECL_USE_TEMPLATE (newdecl))
               || (DECL_TEMPLATE_INSTANTIATION (newdecl)
                   && !DECL_USE_TEMPLATE (olddecl))))
@@ -3193,7 +3360,7 @@ duplicate_decls (newdecl, olddecl)
 
          if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE)
            t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2);
-       
+
          for (; t1 && t1 != void_list_node;
               t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++)
            if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
@@ -3242,20 +3409,21 @@ duplicate_decls (newdecl, olddecl)
         definition.  */
       if (DECL_VINDEX (olddecl))
        DECL_VINDEX (newdecl) = DECL_VINDEX (olddecl);
+      if (DECL_VIRTUAL_CONTEXT (olddecl))
+       DECL_VIRTUAL_CONTEXT (newdecl) = DECL_VIRTUAL_CONTEXT (olddecl);
       if (DECL_CONTEXT (olddecl))
        DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
-      if (DECL_CLASS_CONTEXT (olddecl))
-       DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
-      if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
+      if (DECL_PENDING_INLINE_INFO (newdecl) == 0)
        DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
       DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
       DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
-      DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
+      DECL_PURE_VIRTUAL_P (newdecl) |= DECL_PURE_VIRTUAL_P (olddecl);
       DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
       DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl);
       DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl);
+      DECL_LANG_SPECIFIC (newdecl)->u2 = DECL_LANG_SPECIFIC (olddecl)->u2;
       new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
-      
+
       /* Optionally warn about more than one declaration for the same
          name, but don't warn about a function declaration followed by a
          definition.  */
@@ -3284,41 +3452,39 @@ duplicate_decls (newdecl, olddecl)
          CLASSTYPE_FRIEND_CLASSES (newtype)
            = CLASSTYPE_FRIEND_CLASSES (oldtype);
        }
+
+      DECL_ORIGINAL_TYPE (newdecl) = DECL_ORIGINAL_TYPE (olddecl);
     }
 
   /* Copy all the DECL_... slots specified in the new decl
      except for any that we copy here from the old type.  */
-  DECL_MACHINE_ATTRIBUTES (newdecl) 
+  DECL_MACHINE_ATTRIBUTES (newdecl)
     = merge_machine_decl_attributes (olddecl, newdecl);
 
   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
-      if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl),
-                            DECL_TEMPLATE_RESULT (olddecl)))
-       cp_error ("invalid redeclaration of %D", newdecl);
       TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
-      DECL_TEMPLATE_SPECIALIZATIONS (olddecl) 
+      DECL_TEMPLATE_SPECIALIZATIONS (olddecl)
        = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
                   DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
+
       return 1;
     }
-    
+
   if (types_match)
     {
       /* Automatically handles default parameters.  */
       tree oldtype = TREE_TYPE (olddecl);
       tree newtype;
 
-      /* Make sure we put the new type in the same obstack as the old one.  */
-      if (oldtype)
-       push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
-      else
-       push_permanent_obstack ();
-
       /* Merge the data types specified in the two decls.  */
       newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
 
+      /* If common_type produces a non-typedef type, just use the old type.  */
+      if (TREE_CODE (newdecl) == TYPE_DECL
+         && newtype == DECL_ORIGINAL_TYPE (newdecl))
+       newtype = oldtype;
+
       if (TREE_CODE (newdecl) == VAR_DECL)
        DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl);
       /* Do this after calling `common_type' so that default
@@ -3340,7 +3506,7 @@ duplicate_decls (newdecl, olddecl)
            {
              cp_error ("declaration of `%F' throws different exceptions",
                        newdecl);
-             cp_error_at ("to previous declaration `%F'", olddecl);
+             cp_error_at ("than previous declaration `%F'", olddecl);
            }
        }
       TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
@@ -3388,7 +3554,15 @@ duplicate_decls (newdecl, olddecl)
       /* Keep the old rtl since we can safely use it.  */
       DECL_RTL (newdecl) = DECL_RTL (olddecl);
 
-      pop_obstacks ();
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+       {
+         DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+           |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+         DECL_NO_CHECK_MEMORY_USAGE (newdecl)
+           |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
+         DECL_NO_LIMIT_STACK (newdecl)
+           |= DECL_NO_LIMIT_STACK (olddecl);
+       }
     }
   /* If cannot merge, then use the new type and qualifiers,
      and don't preserve the old rtl.  */
@@ -3413,13 +3587,13 @@ duplicate_decls (newdecl, olddecl)
   TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
   if (! DECL_EXTERNAL (olddecl))
     DECL_EXTERNAL (newdecl) = 0;
-  
+
   if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
     {
       DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
       DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
       DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
-      DECL_TEMPLATE_INSTANTIATED (newdecl) 
+      DECL_TEMPLATE_INSTANTIATED (newdecl)
        |= DECL_TEMPLATE_INSTANTIATED (olddecl);
       /* Don't really know how much of the language-specific
         values we should copy from old to new.  */
@@ -3439,8 +3613,8 @@ duplicate_decls (newdecl, olddecl)
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      if (DECL_TEMPLATE_INSTANTIATION (olddecl) 
-         && !DECL_TEMPLATE_INSTANTIATION (newdecl)) 
+      if (DECL_TEMPLATE_INSTANTIATION (olddecl)
+         && !DECL_TEMPLATE_INSTANTIATION (newdecl))
        {
          /* If newdecl is not a specialization, then it is not a
             template-related function at all.  And that means that we
@@ -3448,16 +3622,16 @@ duplicate_decls (newdecl, olddecl)
          my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl),
                              0);
 
-         if (TREE_USED (olddecl)) 
+         if (TREE_USED (olddecl))
            /* From [temp.expl.spec]:
-              
+
               If a template, a member template or the member of a class
               template is explicitly specialized then that
               specialization shall be declared before the first use of
               that specialization that would cause an implicit
               instantiation to take place, in every translation unit in
               which such a use occurs.  */
-           cp_error ("explicit specialization of %D after first use", 
+           cp_error ("explicit specialization of %D after first use",
                      olddecl);
 
          SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
@@ -3512,8 +3686,6 @@ duplicate_decls (newdecl, olddecl)
          if (DECL_ARGUMENTS (olddecl))
            DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
        }
-      if (DECL_LANG_SPECIFIC (olddecl))
-       DECL_MAIN_VARIANT (newdecl) = DECL_MAIN_VARIANT (olddecl);
     }
 
   if (TREE_CODE (newdecl) == NAMESPACE_DECL)
@@ -3543,16 +3715,16 @@ duplicate_decls (newdecl, olddecl)
             the following sequence of events has occurred:
 
             o A friend function was declared in a class template.  The
-            class template was instantiated.  
+            class template was instantiated.
 
-            o The instantiation of the friend declaration was 
-            recorded on the instantiation list, and is newdecl.  
+            o The instantiation of the friend declaration was
+            recorded on the instantiation list, and is newdecl.
 
             o Later, however, instantiate_class_template called pushdecl
             on the newdecl to perform name injection.  But, pushdecl in
             turn called duplicate_decls when it discovered that another
             declaration of a global function with the same name already
-            existed. 
+            existed.
 
             o Here, in duplicate_decls, we decided to clobber newdecl.
 
@@ -3561,8 +3733,8 @@ duplicate_decls (newdecl, olddecl)
             instantiations so that if we try to do the instantiation
             again we won't get the clobbered declaration.  */
 
-         tree tmpl = DECL_TI_TEMPLATE (newdecl); 
-         tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); 
+         tree tmpl = DECL_TI_TEMPLATE (newdecl);
+         tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
 
          for (; decls; decls = TREE_CHAIN (decls))
            if (TREE_VALUE (decls) == newdecl)
@@ -3606,10 +3778,9 @@ pushdecl (x)
 
   /* We shouldn't be calling pushdecl when we're generating RTL for a
      function that we already did semantic analysis on previously.  */
-  my_friendly_assert (!current_function || doing_semantic_analysis_p (),
+  my_friendly_assert (!cfun || doing_semantic_analysis_p (),
                      19990913);
 
-  name = DECL_ASSEMBLER_NAME (x);
   need_new_binding = 1;
 
   if (DECL_TEMPLATE_PARM_P (x))
@@ -3623,54 +3794,103 @@ pushdecl (x)
              nesting.  */
          && !(TREE_CODE (x) == FUNCTION_DECL && !DECL_INITIAL (x))
          /* A local declaration for an `extern' variable is in the
-            scoped of the current namespace, not the current
+            scope of the current namespace, not the current
             function.  */
          && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
-         /* Don't change DECL_CONTEXT of virtual methods.  */
-         && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
          && !DECL_CONTEXT (x))
        DECL_CONTEXT (x) = current_function_decl;
-      if (!DECL_CONTEXT (x))
-       DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
-    }
 
-  /* Type are looked up using the DECL_NAME, as that is what the rest of the
-     compiler wants to use.  */
-  if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
-      || TREE_CODE (x) == NAMESPACE_DECL)
-    name = DECL_NAME (x);
+      /* If this is the declaration for a namespace-scope function,
+        but the declaration itself is in a local scope, mark the
+        declaration.  */
+      if (TREE_CODE (x) == FUNCTION_DECL
+         && DECL_NAMESPACE_SCOPE_P (x)
+         && current_function_decl
+         && x != current_function_decl)
+       DECL_LOCAL_FUNCTION_P (x) = 1;
+    }
 
+  name = DECL_NAME (x);
   if (name)
     {
-#if 0
-      /* Not needed...see below.  */
-      char *file;
-      int line;
-#endif
+      int different_binding_level = 0;
+
       if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
        name = TREE_OPERAND (name, 0);
-      
-      /* Namespace-scoped variables are not found in the current level. */
-      if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x))
+
+      /* In case this decl was explicitly namespace-qualified, look it
+        up in its namespace context.  */
+      if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x)
+         && namespace_bindings_p ())
        t = namespace_binding (name, DECL_CONTEXT (x));
       else
        t = lookup_name_current_level (name);
+
+      /* [basic.link] If there is a visible declaration of an entity
+        with linkage having the same name and type, ignoring entities
+        declared outside the innermost enclosing namespace scope, the
+        block scope declaration declares that same entity and
+        receives the linkage of the previous declaration.  */
+      if (! t && current_function_decl && x != current_function_decl
+         && (TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
+         && DECL_EXTERNAL (x))
+       {
+         /* Look in block scope.  */
+         t = IDENTIFIER_VALUE (name);
+         /* Or in the innermost namespace.  */
+         if (! t)
+           t = namespace_binding (name, DECL_CONTEXT (x));
+         /* Does it have linkage?  */
+         if (t && ! (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+           t = NULL_TREE;
+         if (t)
+           different_binding_level = 1;
+       }
+
+      /* If we are declaring a function, and the result of name-lookup
+        was an OVERLOAD, look for an overloaded instance that is
+        actually the same as the function we are declaring.  (If
+        there is one, we have to merge our declaration with the
+        previous declaration.)  */
+      if (t && TREE_CODE (t) == OVERLOAD)
+       {
+         tree match;
+
+         if (TREE_CODE (x) == FUNCTION_DECL)
+           for (match = t; match; match = OVL_NEXT (match))
+             {
+               if (DECL_ASSEMBLER_NAME (OVL_CURRENT (t))
+                   == DECL_ASSEMBLER_NAME (x))
+                 break;
+             }
+         else
+           /* Just choose one.  */
+           match = t;
+
+         if (match)
+           t = OVL_CURRENT (match);
+         else
+           t = NULL_TREE;
+       }
+
       if (t == error_mark_node)
        {
          /* error_mark_node is 0 for a while during initialization!  */
          t = NULL_TREE;
          cp_error_at ("`%#D' used prior to declaration", x);
        }
-
       else if (t != NULL_TREE)
        {
-#if 0
-         /* This is turned off until I have time to do it right (bpk).  */
-         /* With the code below that uses it...  */
-         file = DECL_SOURCE_FILE (t);
-         line = DECL_SOURCE_LINE (t);
-#endif
-         if (TREE_CODE (t) == PARM_DECL)
+         if (different_binding_level)
+           {
+             if (decls_match (x, t))
+               /* The standard only says that the local extern
+                  inherits linkage from the previous decl; in
+                  particular, default args are not shared.  It would
+                  be nice to propagate inlining info, though.  FIXME.  */
+               TREE_PUBLIC (x) = TREE_PUBLIC (t);
+           }
+         else if (TREE_CODE (t) == PARM_DECL)
            {
              if (DECL_CONTEXT (t) == NULL_TREE)
                fatal ("parse errors have confused me too much");
@@ -3679,7 +3899,7 @@ pushdecl (x)
              if (duplicate_decls (x, t))
                return t;
            }
-         else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
+         else if ((DECL_EXTERN_C_FUNCTION_P (x)
                    || DECL_FUNCTION_TEMPLATE_P (x))
                   && is_overloaded_fn (t))
            /* Don't do anything just yet. */;
@@ -3698,36 +3918,6 @@ pushdecl (x)
            }
          else if (duplicate_decls (x, t))
            {
-#if 0
-             /* This is turned off until I have time to do it right (bpk).  */
-
-             /* Also warn if they did a prototype with `static' on it, but
-                then later left the `static' off.  */
-             if (! TREE_PUBLIC (name) && TREE_PUBLIC (x))
-               {
-                 if (DECL_LANG_SPECIFIC (t) && DECL_FRIEND_P (t))
-                   return t;
-
-                 if (extra_warnings)
-                   {
-                     cp_warning ("`static' missing from declaration of `%D'",
-                                 t);
-                     warning_with_file_and_line (file, line,
-                                                 "previous declaration of `%s'",
-                                                 decl_as_string (t, 0));
-                   }
-
-                 /* Now fix things so it'll do what they expect.  */
-                 if (current_function_decl)
-                   TREE_PUBLIC (current_function_decl) = 0;
-               }
-             /* Due to interference in memory reclamation (X may be
-                obstack-deallocated at this point), we must guard against
-                one really special case.  [jason: This should be handled
-                by start_function]  */
-             if (current_function_decl == x)
-               current_function_decl = t;
-#endif
              if (TREE_CODE (t) == TYPE_DECL)
                SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
              else if (TREE_CODE (t) == FUNCTION_DECL)
@@ -3738,7 +3928,7 @@ pushdecl (x)
          else if (DECL_MAIN_P (x))
            {
              /* A redeclaration of main, but not a duplicate of the
-                previous one. 
+                previous one.
 
                 [basic.start.main]
 
@@ -3755,14 +3945,13 @@ pushdecl (x)
 
       /* If this is a function conjured up by the backend, massage it
         so it looks friendly.  */
-      if (TREE_CODE (x) == FUNCTION_DECL
-         && ! DECL_LANG_SPECIFIC (x))
+      if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_LANG_SPECIFIC (x))
        {
          retrofit_lang_decl (x);
          DECL_LANGUAGE (x) = lang_c;
        }
 
-      if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
+      if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_FUNCTION_MEMBER_P (x))
        {
          t = push_overloaded_decl (x, PUSH_LOCAL);
          if (t != x)
@@ -3787,7 +3976,7 @@ pushdecl (x)
       if (TREE_CODE (x) == TYPE_DECL)
        {
          tree type = TREE_TYPE (x);
-          if (DECL_SOURCE_LINE (x) == 0)
+         if (DECL_SOURCE_LINE (x) == 0)
             {
              if (TYPE_NAME (type) == 0)
                TYPE_NAME (type) = x;
@@ -3796,24 +3985,20 @@ pushdecl (x)
                   /* We don't want to copy the type when all we're
                      doing is making a TYPE_DECL for the purposes of
                      inlining.  */
-                  && (!TYPE_NAME (type) 
+                  && (!TYPE_NAME (type)
                       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
             {
-             push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-
              DECL_ORIGINAL_TYPE (x) = type;
               type = build_type_copy (type);
              TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
               TYPE_NAME (type) = x;
               TREE_TYPE (x) = type;
-
-             pop_obstacks ();
             }
 
          if (type != error_mark_node
              && TYPE_NAME (type)
              && TYPE_IDENTIFIER (type))
-            set_identifier_type_value_with_scope (DECL_NAME (x), type, 
+            set_identifier_type_value_with_scope (DECL_NAME (x), type,
                                                  current_binding_level);
 
        }
@@ -3822,20 +4007,18 @@ pushdecl (x)
 
         We get warnings about inline functions where they are defined.
         We get warnings about other functions from push_overloaded_decl.
-        
+
         Avoid duplicate warnings where they are used.  */
       if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL)
        {
          tree decl;
 
-         if (IDENTIFIER_NAMESPACE_VALUE (name) != NULL_TREE
-             && (DECL_EXTERNAL (IDENTIFIER_NAMESPACE_VALUE (name))
-                 || TREE_PUBLIC (IDENTIFIER_NAMESPACE_VALUE (name))))
-           decl = IDENTIFIER_NAMESPACE_VALUE (name);
-         else
-           decl = NULL_TREE;
+         decl = IDENTIFIER_NAMESPACE_VALUE (name);
+         if (decl && TREE_CODE (decl) == OVERLOAD)
+           decl = OVL_FUNCTION (decl);
 
-         if (decl
+         if (decl && decl != error_mark_node
+             && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
              /* If different sort of thing, we already gave an error.  */
              && TREE_CODE (decl) == TREE_CODE (x)
              && !same_type_p (TREE_TYPE (x), TREE_TYPE (decl)))
@@ -3855,21 +4038,32 @@ pushdecl (x)
             warn if we later see static one.  */
          if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))
            TREE_PUBLIC (name) = 1;
-
+         
+         /* Bind the mangled name for the entity.  In the future, we
+            should not need to do this; mangled names are an
+            implementation detail of which the front-end should not
+            need to be aware.  */
          if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
                && t != NULL_TREE)
              /* For an ordinary function, we create a binding from
                 the mangled name (i.e., NAME) to the DECL.  But, for
                 an `extern "C"' function, the mangled name and the
                 ordinary name are the same so we need not do this.  */
-             && !(TREE_CODE (x) == FUNCTION_DECL && 
-                  DECL_LANGUAGE (x) == lang_c))
+             && !DECL_EXTERN_C_FUNCTION_P (x))
            {
+             tree mangled_name;
+
+             if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
+                 || TREE_CODE (x) == NAMESPACE_DECL)
+               mangled_name = name;
+             else
+               mangled_name = DECL_ASSEMBLER_NAME (x);
+
              if (TREE_CODE (x) == FUNCTION_DECL)
-               my_friendly_assert 
-                 ((IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE)
-                 || (IDENTIFIER_GLOBAL_VALUE (name) == x), 378);
-             SET_IDENTIFIER_NAMESPACE_VALUE (name, x);
+               my_friendly_assert
+                 ((IDENTIFIER_GLOBAL_VALUE (mangled_name) == NULL_TREE)
+                 || (IDENTIFIER_GLOBAL_VALUE (mangled_name) == x), 378);
+             SET_IDENTIFIER_NAMESPACE_VALUE (mangled_name, x);
            }
 
          /* Don't forget if the function was used via an implicit decl.  */
@@ -3912,16 +4106,29 @@ pushdecl (x)
 
          /* If this is a TYPE_DECL, push it into the type value slot.  */
          if (TREE_CODE (x) == TYPE_DECL)
-           set_identifier_type_value_with_scope (name, TREE_TYPE (x), 
+           set_identifier_type_value_with_scope (name, TREE_TYPE (x),
                                                  current_binding_level);
 
          /* Clear out any TYPE_DECL shadowed by a namespace so that
             we won't think this is a type.  The C struct hack doesn't
             go through namespaces.  */
          if (TREE_CODE (x) == NAMESPACE_DECL)
-           set_identifier_type_value_with_scope (name, NULL_TREE, 
+           set_identifier_type_value_with_scope (name, NULL_TREE,
                                                  current_binding_level);
 
+         if (oldlocal)
+           {
+             tree d = oldlocal;
+
+             while (oldlocal
+                    && TREE_CODE (oldlocal) == VAR_DECL
+                    && DECL_DEAD_FOR_LOCAL (oldlocal))
+               oldlocal = DECL_SHADOWED_FOR_VAR (oldlocal);
+
+             if (oldlocal == NULL_TREE)
+               oldlocal = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (d));
+           }
+
          /* If this is an extern function declaration, see if we
             have a global definition or declaration for the function.  */
          if (oldlocal == NULL_TREE
@@ -3948,15 +4155,14 @@ pushdecl (x)
              && TREE_PUBLIC (x))
            TREE_PUBLIC (name) = 1;
 
-         if (DECL_FROM_INLINE (x))
-           /* Inline decls shadow nothing.  */;
-
          /* Warn if shadowing an argument at the top level of the body.  */
-         else if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x)
-                  && TREE_CODE (oldlocal) == PARM_DECL
-                  /* Don't complain if it's from an enclosing function.  */
-                  && DECL_CONTEXT (oldlocal) == current_function_decl
-                  && TREE_CODE (x) != PARM_DECL)
+         if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x)
+             /* Inline decls shadow nothing.  */
+             && !DECL_FROM_INLINE (x)
+             && TREE_CODE (oldlocal) == PARM_DECL
+             /* Don't complain if it's from an enclosing function.  */
+             && DECL_CONTEXT (oldlocal) == current_function_decl
+             && TREE_CODE (x) != PARM_DECL)
            {
              /* Go to where the parms should be and see if we
                 find them there.  */
@@ -3969,37 +4175,31 @@ pushdecl (x)
              if (b->parm_flag == 1)
                cp_error ("declaration of `%#D' shadows a parameter", name);
            }
-         else if (warn_shadow && oldlocal != NULL_TREE
-                  && current_binding_level->is_for_scope
-                  && !DECL_DEAD_FOR_LOCAL (oldlocal))
-           {
-             warning ("variable `%s' shadows local",
-                      IDENTIFIER_POINTER (name));
-             cp_warning_at ("  this is the shadowed declaration", oldlocal);
-           }              
+
          /* Maybe warn if shadowing something else.  */
-         else if (warn_shadow && !DECL_EXTERNAL (x)
-                  /* No shadow warnings for internally generated vars.  */
-                  && ! DECL_ARTIFICIAL (x)
-                  /* No shadow warnings for vars made for inlining.  */
-                  && ! DECL_FROM_INLINE (x))
+         if (warn_shadow && !DECL_EXTERNAL (x)
+             /* Inline decls shadow nothing.  */
+             && !DECL_FROM_INLINE (x)
+             /* No shadow warnings for internally generated vars.  */
+             && ! DECL_ARTIFICIAL (x)
+             /* No shadow warnings for vars made for inlining.  */
+             && ! DECL_FROM_INLINE (x))
            {
-             const char *warnstring = NULL;
-
              if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL)
-               warnstring = "declaration of `%s' shadows a parameter";
+               warning ("declaration of `%s' shadows a parameter",
+                       IDENTIFIER_POINTER (name));
              else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE
                       && current_class_ptr
                       && !TREE_STATIC (name))
-               warnstring = "declaration of `%s' shadows a member of `this'";
+               warning ("declaration of `%s' shadows a member of `this'",
+                       IDENTIFIER_POINTER (name));
              else if (oldlocal != NULL_TREE)
-               warnstring = "declaration of `%s' shadows previous local";
+               warning ("declaration of `%s' shadows previous local",
+                       IDENTIFIER_POINTER (name));
              else if (oldglobal != NULL_TREE)
                /* XXX shadow warnings in outer-more namespaces */
-               warnstring = "declaration of `%s' shadows global declaration";
-
-             if (warnstring)
-               warning (warnstring, IDENTIFIER_POINTER (name));
+               warning ("declaration of `%s' shadows global declaration",
+                       IDENTIFIER_POINTER (name));
            }
        }
 
@@ -4009,17 +4209,23 @@ pushdecl (x)
       /* Keep count of variables in this level with incomplete type.  */
       if (TREE_CODE (x) == VAR_DECL
          && TREE_TYPE (x) != error_mark_node
-         && ((TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+         && ((!COMPLETE_TYPE_P (TREE_TYPE (x))
               && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
              /* RTTI TD entries are created while defining the type_info.  */
              || (TYPE_LANG_SPECIFIC (TREE_TYPE (x))
                  && TYPE_BEING_DEFINED (TREE_TYPE (x)))))
-       current_binding_level->incomplete 
-         = tree_cons (NULL_TREE, x, current_binding_level->incomplete);
+       {
+         if (namespace_bindings_p ())
+           namespace_scope_incomplete
+             = tree_cons (NULL_TREE, x, namespace_scope_incomplete);
+         else
+           current_binding_level->incomplete
+             = tree_cons (NULL_TREE, x, current_binding_level->incomplete);
+       }
     }
 
   if (need_new_binding)
-    add_decl_to_level (x, 
+    add_decl_to_level (x,
                       DECL_NAMESPACE_SCOPE_P (x)
                       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
                       : current_binding_level);
@@ -4159,11 +4365,12 @@ maybe_push_decl (decl)
   /* Add this decl to the current binding level, but not if it comes
      from another scope, e.g. a static member variable.  TEM may equal
      DECL or it may be a previous decl of the same name.  */
-  if ((TREE_CODE (decl) != PARM_DECL 
-       && DECL_CONTEXT (decl) != NULL_TREE 
-       /* Definitions of namespace members outside their namespace are
-         possible. */
-       && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
+  if (decl == error_mark_node
+      || (TREE_CODE (decl) != PARM_DECL
+         && DECL_CONTEXT (decl) != NULL_TREE
+         /* Definitions of namespace members outside their namespace are
+            possible. */
+         && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
       || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
       || TREE_CODE (type) == UNKNOWN_TYPE
       /* The declaration of a template specialization does not affect
@@ -4176,29 +4383,6 @@ maybe_push_decl (decl)
     return pushdecl (decl);
 }
 
-#if 0
-/* This function is used to push the mangled decls for nested types into
-   the appropriate scope.  Previously pushdecl_top_level was used, but that
-   is incorrect for members of local classes.  */
-
-void
-pushdecl_nonclass_level (x)
-     tree x;
-{
-  struct binding_level *b = current_binding_level;
-
-  my_friendly_assert (b->parm_flag != 2, 180);
-
-#if 0
-  /* Get out of template binding levels */
-  while (b->pseudo_global)
-    b = b->level_chain;
-#endif
-
-  pushdecl_with_scope (x, b);
-}
-#endif
-
 /* Make the declaration(s) of X appear in CLASS scope
    under the name NAME.  */
 
@@ -4208,7 +4392,7 @@ push_class_level_binding (name, x)
      tree x;
 {
   tree binding;
-  /* The class_binding_level will be NULL if x is a template 
+  /* The class_binding_level will be NULL if x is a template
      parameter name in a member template.  */
   if (!class_binding_level)
     return;
@@ -4222,7 +4406,7 @@ push_class_level_binding (name, x)
      class, then we will need to restore IDENTIFIER_CLASS_VALUE when
      we leave this class.  Record the shadowed declaration here.  */
   binding = IDENTIFIER_BINDING (name);
-  if (binding 
+  if (binding
       && ((TREE_CODE (x) == OVERLOAD
           && BINDING_VALUE (binding)
           && is_overloaded_fn (BINDING_VALUE (binding)))
@@ -4279,9 +4463,10 @@ push_class_level_binding (name, x)
     }
 }
 
-/* Insert another USING_DECL into the current binding level,
-   returning this declaration. If this is a redeclaration,
-   do nothing and return NULL_TREE.  */
+/* Insert another USING_DECL into the current binding level, returning
+   this declaration. If this is a redeclaration, do nothing, and
+   return NULL_TREE if this not in namespace scope (in namespace
+   scope, a using decl might extend any previous bindings).  */
 
 tree
 push_using_decl (scope, name)
@@ -4289,14 +4474,14 @@ push_using_decl (scope, name)
      tree name;
 {
   tree decl;
-  
+
   my_friendly_assert (TREE_CODE (scope) == NAMESPACE_DECL, 383);
   my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 384);
   for (decl = current_binding_level->usings; decl; decl = TREE_CHAIN (decl))
     if (DECL_INITIAL (decl) == scope && DECL_NAME (decl) == name)
       break;
   if (decl)
-    return NULL_TREE;
+    return namespace_bindings_p () ? decl : NULL_TREE;
   decl = build_lang_decl (USING_DECL, name, void_type_node);
   DECL_INITIAL (decl) = scope;
   TREE_CHAIN (decl) = current_binding_level->usings;
@@ -4314,7 +4499,7 @@ push_using_directive (used)
 {
   tree ud = current_binding_level->using_directives;
   tree iter, ancestor;
-  
+
   /* Check if we already have this. */
   if (purpose_member (used, ud) != NULL_TREE)
     return NULL_TREE;
@@ -4336,14 +4521,14 @@ push_using_directive (used)
    want to be referenced by that name.  It is then up to the users of
    that name to decide what to do with that list.
 
-   DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
-   slot.  It is dealt with the same way.
+   DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its
+   DECL_TEMPLATE_RESULT.  It is dealt with the same way.
 
    FLAGS is a bitwise-or of the following values:
      PUSH_LOCAL: Bind DECL in the current scope, rather than at
                  namespace scope.
      PUSH_USING: DECL is being pushed as the result of a using
-                 declaration. 
+                 declaration.
 
    The value returned may be a previous declaration if we guessed wrong
    about what language DECL should belong to (C or C++).  Otherwise,
@@ -4378,7 +4563,7 @@ push_overloaded_decl (decl, flags)
       else if (is_overloaded_fn (old))
         {
           tree tmp;
-         
+
          for (tmp = old; tmp; tmp = OVL_NEXT (tmp))
            {
              tree fn = OVL_CURRENT (tmp);
@@ -4389,11 +4574,14 @@ push_overloaded_decl (decl, flags)
                                TYPE_ARG_TYPES (TREE_TYPE (decl))))
                cp_error ("`%#D' conflicts with previous using declaration `%#D'",
                          decl, fn);
-             
+
              if (duplicate_decls (decl, fn))
                return fn;
            }
        }
+      else if (old == error_mark_node)
+       /* Ignore the undefined symbol marker.  */
+       old = NULL_TREE;
       else
        {
          cp_error_at ("previous non-function declaration `%#D'", old);
@@ -4428,7 +4616,7 @@ push_overloaded_decl (decl, flags)
       if (TREE_CODE (new_binding) == OVERLOAD && old)
        {
          tree *d;
-         
+
          for (d = &BINDING_LEVEL (IDENTIFIER_BINDING (name))->names;
               *d;
               d = &TREE_CHAIN (*d))
@@ -4441,7 +4629,7 @@ push_overloaded_decl (decl, flags)
                  TREE_VALUE (*d) = new_binding;
                else
                  /* Build a TREE_LIST to wrap the OVERLOAD.  */
-                 *d = tree_cons (NULL_TREE, new_binding, 
+                 *d = tree_cons (NULL_TREE, new_binding,
                                  TREE_CHAIN (*d));
 
                /* And update the CPLUS_BINDING node.  */
@@ -4469,15 +4657,6 @@ implicitly_declare (functionid)
      tree functionid;
 {
   register tree decl;
-  int temp = allocation_temporary_p ();
-
-  push_obstacks_nochange ();
-
-  /* Save the decl permanently so we can warn if definition follows.
-     In ANSI C, warn_implicit is usually false, so the saves little space.
-     But in C++, it's usually true, hence the extra code.  */
-  if (temp && (! warn_implicit || toplevel_bindings_p ()))
-    end_temporary_allocation ();
 
   /* We used to reuse an old implicit decl here,
      but this loses with inline functions because it can clobber
@@ -4487,7 +4666,7 @@ implicitly_declare (functionid)
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
 
-  /* ANSI standard says implicit declarations are in the innermost block.
+  /* ISO standard says implicit declarations are in the innermost block.
      So we record the decl in the standard fashion.  */
   pushdecl (decl);
   rest_of_decl_compilation (decl, NULL_PTR, 0, 0);
@@ -4501,8 +4680,6 @@ implicitly_declare (functionid)
 
   SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl);
 
-  pop_obstacks ();
-
   return decl;
 }
 
@@ -4531,7 +4708,7 @@ redeclaration_error_message (newdecl, olddecl)
       /* If this is a pure function, its olddecl will actually be
         the original initialization to `0' (which we force to call
         abort()).  Don't complain about redefinition in this case.  */
-      if (DECL_LANG_SPECIFIC (olddecl) && DECL_ABSTRACT_VIRTUAL_P (olddecl))
+      if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_VIRTUAL_P (olddecl))
        return 0;
 
       /* If both functions come from different namespaces, this is not
@@ -4557,15 +4734,17 @@ redeclaration_error_message (newdecl, olddecl)
   else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
       if ((TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
+          && (DECL_TEMPLATE_RESULT (newdecl) 
+              != DECL_TEMPLATE_RESULT (olddecl))
           && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl))
           && DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)))
          || (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL
-             && TYPE_SIZE (TREE_TYPE (newdecl))
-             && TYPE_SIZE (TREE_TYPE (olddecl))))
+             && COMPLETE_TYPE_P (TREE_TYPE (newdecl))
+             && COMPLETE_TYPE_P (TREE_TYPE (olddecl))))
        return "redefinition of `%#D'";
       return 0;
     }
-  else if (toplevel_bindings_p ())
+  else if (toplevel_bindings_p () || DECL_NAMESPACE_SCOPE_P (newdecl))
     {
       /* Objects declared at top level:  */
       /* If at least one is a reference, it's ok.  */
@@ -4611,17 +4790,25 @@ make_label_decl (id, local_p)
   /* Record the fact that this identifier is bound to this label.  */
   SET_IDENTIFIER_LABEL_VALUE (id, decl);
 
-  /* Record this label on the list of used labels so that we can check
-     at the end of the function to see whether or not the label was
-     actually defined.  */
-  if ((named_label_uses == NULL || named_label_uses->label_decl != decl)
-      && (named_label_uses == NULL
-         || named_label_uses->names_in_scope != current_binding_level->names
-         || named_label_uses->label_decl != decl))
-    {
-      struct named_label_list *new_ent;
-      new_ent
-       = (struct named_label_list*)oballoc (sizeof (struct named_label_list));
+  return decl;
+}
+
+/* Record this label on the list of used labels so that we can check
+   at the end of the function to see whether or not the label was
+   actually defined, and so we can check when the label is defined whether
+   this use is valid.  */
+
+static void
+use_label (decl)
+     tree decl;
+{
+  if (named_label_uses == NULL
+      || named_label_uses->names_in_scope != current_binding_level->names
+      || named_label_uses->label_decl != decl)
+    {
+      struct named_label_use_list *new_ent;
+      new_ent = ((struct named_label_use_list *)
+                ggc_alloc (sizeof (struct named_label_use_list)));
       new_ent->label_decl = decl;
       new_ent->names_in_scope = current_binding_level->names;
       new_ent->binding_level = current_binding_level;
@@ -4630,19 +4817,18 @@ make_label_decl (id, local_p)
       new_ent->next = named_label_uses;
       named_label_uses = new_ent;
     }
-
-  return decl;
 }
 
 /* Look for a label named ID in the current function.  If one cannot
    be found, create one.  (We keep track of used, but undefined,
    labels, and complain about them at the end of a function.)  */
 
-tree 
+tree
 lookup_label (id)
      tree id;
 {
   tree decl;
+  struct named_label_list *ent;
 
   /* You can't use labels at global scope.  */
   if (current_function_decl == NULL_TREE)
@@ -4651,7 +4837,7 @@ lookup_label (id)
             IDENTIFIER_POINTER (id));
       return NULL_TREE;
     }
-  
+
   /* See if we've already got this label.  */
   decl = IDENTIFIER_LABEL_VALUE (id);
   if (decl != NULL_TREE && DECL_CONTEXT (decl) == current_function_decl)
@@ -4660,12 +4846,17 @@ lookup_label (id)
   /* Record this label on the list of labels used in this function.
      We do this before calling make_label_decl so that we get the
      IDENTIFIER_LABEL_VALUE before the new label is declared.  */
-  named_labels = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
-                           named_labels);
+  ent = ((struct named_label_list *)
+        ggc_alloc_cleared (sizeof (struct named_label_list)));
+  ent->old_value = IDENTIFIER_LABEL_VALUE (id);
+  ent->next = named_labels;
+  named_labels = ent;
+
   /* We need a new label.  */
   decl = make_label_decl (id, /*local_p=*/0);
+
   /* Now fill in the information we didn't have before.  */
-  TREE_VALUE (named_labels) = decl;
+  ent->label_decl = decl;
 
   return decl;
 }
@@ -4681,28 +4872,225 @@ declare_local_label (id)
   /* Add a new entry to the SHADOWED_LABELS list so that when we leave
      this scope we can restore the old value of
      IDENTIFIER_TYPE_VALUE.  */
-  current_binding_level->shadowed_labels 
+  current_binding_level->shadowed_labels
     = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
                 current_binding_level->shadowed_labels);
   /* Look for the label.  */
   decl = make_label_decl (id, /*local_p=*/1);
   /* Now fill in the information we didn't have before.  */
   TREE_VALUE (current_binding_level->shadowed_labels) = decl;
-  
+
   return decl;
 }
 
+/* Returns nonzero if it is ill-formed to jump past the declaration of
+   DECL.  Returns 2 if it's also a real problem.  */
+
+static int
+decl_jump_unsafe (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
+    return 0;
+
+  if (DECL_INITIAL (decl) == NULL_TREE
+      && pod_type_p (TREE_TYPE (decl)))
+    return 0;
+
+  /* This is really only important if we're crossing an initialization.
+     The POD stuff is just pedantry; why should it matter if the class
+     contains a field of pointer to member type?  */
+  if (DECL_INITIAL (decl)
+      || (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
+    return 2;
+  return 1;
+}
+
+/* Check that a single previously seen jump to a newly defined label
+   is OK.  DECL is the LABEL_DECL or 0; LEVEL is the binding_level for
+   the jump context; NAMES are the names in scope in LEVEL at the jump
+   context; FILE and LINE are the source position of the jump or 0.  */
+
+static void
+check_previous_goto_1 (decl, level, names, file, line)
+     tree decl;
+     struct binding_level *level;
+     tree names;
+     const char *file;
+     int line;
+{
+  int identified = 0;
+  int saw_eh = 0;
+  struct binding_level *b = current_binding_level;
+  for (; b; b = b->level_chain)
+    {
+      tree new_decls = b->names;
+      tree old_decls = (b == level ? names : NULL_TREE);
+      for (; new_decls != old_decls;
+          new_decls = TREE_CHAIN (new_decls))
+       {
+         int problem = decl_jump_unsafe (new_decls);
+         if (! problem)
+           continue;
+
+         if (! identified)
+           {
+             if (decl)
+               cp_pedwarn ("jump to label `%D'", decl);
+             else
+               pedwarn ("jump to case label");
+
+             if (file)
+               pedwarn_with_file_and_line (file, line, "  from here");
+             identified = 1;
+           }
+
+         if (problem > 1 && DECL_ARTIFICIAL (new_decls))
+           /* Can't skip init of __exception_info.  */
+           cp_error_at ("  enters catch block", new_decls);
+         else if (problem > 1)
+           cp_error_at ("  crosses initialization of `%#D'",
+                        new_decls);
+         else
+           cp_pedwarn_at ("  enters scope of non-POD `%#D'",
+                          new_decls);
+       }
+
+      if (b == level)
+       break;
+      if (b->eh_region && ! saw_eh)
+       {
+         if (! identified)
+           {
+             if (decl)
+               cp_pedwarn ("jump to label `%D'", decl);
+             else
+               pedwarn ("jump to case label");
+
+             if (file)
+               pedwarn_with_file_and_line (file, line, "  from here");
+             identified = 1;
+           }
+         error ("  enters try block");
+         saw_eh = 1;
+       }
+    }
+}
+
+static void
+check_previous_goto (use)
+     struct named_label_use_list *use;
+{
+  check_previous_goto_1 (use->label_decl, use->binding_level,
+                        use->names_in_scope, use->filename_o_goto,
+                        use->lineno_o_goto);
+}
+
+static void
+check_switch_goto (level)
+     struct binding_level *level;
+{
+  check_previous_goto_1 (NULL_TREE, level, level->names, NULL, 0);
+}
+
+/* Check that any previously seen jumps to a newly defined label DECL
+   are OK.  Called by define_label.  */
+
+static void
+check_previous_gotos (decl)
+     tree decl;
+{
+  struct named_label_use_list **usep;
+
+  if (! TREE_USED (decl))
+    return;
+
+  for (usep = &named_label_uses; *usep; )
+    {
+      struct named_label_use_list *use = *usep;
+      if (use->label_decl == decl)
+       {
+         check_previous_goto (use);
+         *usep = use->next;
+       }
+      else
+       usep = &(use->next);
+    }
+}
+
+/* Check that a new jump to a label DECL is OK.  Called by
+   finish_goto_stmt.  */
+
+void
+check_goto (decl)
+     tree decl;
+{
+  int identified = 0;
+  tree bad;
+  struct named_label_list *lab;
+
+  /* We can't know where a computed goto is jumping.  So we assume
+     that it's OK.  */
+  if (! DECL_P (decl))
+    return;
+
+  /* If the label hasn't been defined yet, defer checking.  */
+  if (! DECL_INITIAL (decl))
+    {
+      use_label (decl);
+      return;
+    }
+
+  for (lab = named_labels; lab; lab = lab->next)
+    if (decl == lab->label_decl)
+      break;
+
+  /* If the label is not on named_labels it's a gcc local label, so
+     it must be in an outer scope, so jumping to it is always OK.  */
+  if (lab == 0)
+    return;
+
+  if ((lab->eh_region || lab->bad_decls) && !identified)
+    {
+      cp_pedwarn_at ("jump to label `%D'", decl);
+      pedwarn ("  from here");
+      identified = 1;
+    }
+
+  for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad))
+    {
+      tree b = TREE_VALUE (bad);
+      int u = decl_jump_unsafe (b);
+
+      if (u > 1 && DECL_ARTIFICIAL (b))
+       /* Can't skip init of __exception_info.  */
+       cp_error_at ("  enters catch block", b);
+      else if (u > 1)
+       cp_error_at ("  skips initialization of `%#D'", b);
+      else
+       cp_pedwarn_at ("  enters scope of non-POD `%#D'", b);
+    }
+
+  if (lab->eh_region)
+    error ("  enters try block");
+}
+
 /* Define a label, specifying the location in the source file.
    Return the LABEL_DECL node for the label, if the definition is valid.
    Otherwise return 0.  */
 
 tree
 define_label (filename, line, name)
-     char *filename;
+     const char *filename;
      int line;
      tree name;
 {
   tree decl = lookup_label (name);
+  struct named_label_list *ent;
+
+  for (ent = named_labels; ent; ent = ent->next)
+    if (ent->label_decl == decl)
+      break;
 
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
@@ -4718,104 +5106,17 @@ define_label (filename, line, name)
     }
   else
     {
-      struct named_label_list *uses, *prev;
-      int identified = 0;
-      int saw_eh = 0;
-
       /* Mark label as having been defined.  */
       DECL_INITIAL (decl) = error_mark_node;
       /* Say where in the source.  */
       DECL_SOURCE_FILE (decl) = filename;
       DECL_SOURCE_LINE (decl) = line;
-
-      prev = NULL;
-      uses = named_label_uses;
-      while (uses != NULL)
-       if (uses->label_decl == decl)
-         {
-           struct binding_level *b = current_binding_level;
-           while (b)
-             {
-               tree new_decls = b->names;
-               tree old_decls = (b == uses->binding_level)
-                                 ? uses->names_in_scope : NULL_TREE;
-               while (new_decls != old_decls)
-                 {
-                   if (TREE_CODE (new_decls) == VAR_DECL
-                       /* Don't complain about crossing initialization
-                          of internal entities.  They can't be accessed,
-                          and they should be cleaned up
-                          by the time we get to the label.  */
-                       && ! DECL_ARTIFICIAL (new_decls)
-                       && !(DECL_INITIAL (new_decls) == NULL_TREE
-                            && pod_type_p (TREE_TYPE (new_decls))))
-                     {
-                       /* This is really only important if we're crossing
-                          an initialization.  The POD stuff is just
-                          pedantry; why should it matter if the class
-                          contains a field of pointer to member type?  */
-                       int problem = (DECL_INITIAL (new_decls)
-                                      || (TYPE_NEEDS_CONSTRUCTING
-                                          (TREE_TYPE (new_decls))));
-
-                       if (! identified)
-                         {
-                           if (problem)
-                             {
-                               cp_error ("jump to label `%D'", decl);
-                               error_with_file_and_line
-                                 (uses->filename_o_goto,
-                                  uses->lineno_o_goto, "  from here");
-                             }
-                           else
-                             {
-                               cp_pedwarn ("jump to label `%D'", decl);
-                               pedwarn_with_file_and_line
-                                 (uses->filename_o_goto,
-                                  uses->lineno_o_goto, "  from here");
-                             }
-                           identified = 1;
-                         }
-
-                       if (problem)
-                         cp_error_at ("  crosses initialization of `%#D'",
-                                      new_decls);
-                       else
-                         cp_pedwarn_at ("  enters scope of non-POD `%#D'",
-                                        new_decls);
-                     }
-                   new_decls = TREE_CHAIN (new_decls);
-                 }
-               if (b == uses->binding_level)
-                 break;
-               if (b->eh_region && ! saw_eh)
-                 {
-                   if (! identified)
-                     {
-                       cp_error ("jump to label `%D'", decl);
-                       error_with_file_and_line
-                         (uses->filename_o_goto,
-                          uses->lineno_o_goto, "  from here");
-                       identified = 1;
-                     }
-                   error ("  enters exception handling block");
-                   saw_eh = 1;
-                 }
-               b = b->level_chain;
-             }
-
-           if (prev != NULL)
-             prev->next = uses->next;
-           else
-             named_label_uses = uses->next;
-
-           uses = uses->next;
-         }
-       else
-         {
-           prev = uses;
-           uses = uses->next;
-         }
+      if (ent)
+       {
+         ent->names_in_scope = current_binding_level->names;
+         ent->binding_level = current_binding_level;
+       }
+      check_previous_gotos (decl);
       current_function_return_value = NULL_TREE;
       return decl;
     }
@@ -4825,80 +5126,95 @@ struct cp_switch
 {
   struct binding_level *level;
   struct cp_switch *next;
+  /* The SWITCH_STMT being built.  */
+  tree switch_stmt;
+  /* A splay-tree mapping the low element of a case range to the high
+     element, or NULL_TREE if there is no high element.  Used to
+     determine whether or not a new case label duplicates an old case
+     label.  We need a tree, rather than simply a hash table, because
+     of the GNU case range extension.  */
+  splay_tree cases;
 };
 
+/* A stack of the currently active switch statements.  The innermost
+   switch statement is on the top of the stack.  There is no need to
+   mark the stack for garbage collection because it is only active
+   during the processing of the body of a function, and we never
+   collect at that point.  */
+   
 static struct cp_switch *switch_stack;
 
+/* Called right after a switch-statement condition is parsed.
+   SWITCH_STMT is the switch statement being parsed.  */
+
 void
-push_switch ()
+push_switch (switch_stmt)
+     tree switch_stmt;
 {
   struct cp_switch *p
-    = (struct cp_switch *) oballoc (sizeof (struct cp_switch));
+    = (struct cp_switch *) xmalloc (sizeof (struct cp_switch));
   p->level = current_binding_level;
   p->next = switch_stack;
+  p->switch_stmt = switch_stmt;
+  p->cases = splay_tree_new (case_compare, NULL, NULL);
   switch_stack = p;
 }
 
 void
 pop_switch ()
 {
+  struct cp_switch *cs;
+  
+  cs = switch_stack;
+  splay_tree_delete (cs->cases);
   switch_stack = switch_stack->next;
+  free (cs);
 }
 
 /* Note that we've seen a definition of a case label, and complain if this
    is a bad place for one.  */
 
 void
-define_case_label ()
+finish_case_label (low_value, high_value)
+     tree low_value;
+     tree high_value;
 {
-  tree cleanup = last_cleanup_this_contour ();
-  struct binding_level *b = current_binding_level;
-  int identified = 0;
+  tree cond;
 
   if (! switch_stack)
-    /* Don't crash; we'll complain in do_case.  */
-    return;
-  
-  if (cleanup)
     {
-      static int explained = 0;
-      cp_warning_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup));
-      warning ("where case label appears here");
-      if (!explained)
-       {
-         warning ("(enclose actions of previous case statements requiring");
-         warning ("destructors in their own binding contours.)");
-         explained = 1;
-       }
+      if (high_value)
+       error ("case label not within a switch statement");
+      else if (low_value)
+       cp_error ("case label `%E' not within a switch statement", 
+                 low_value);
+      else
+       error ("`default' label not within a switch statement");
+      return;
     }
 
-  for (; b && b != switch_stack->level; b = b->level_chain)
+  if (processing_template_decl)
     {
-      tree new_decls = b->names;
-      for (; new_decls; new_decls = TREE_CHAIN (new_decls))
-       {
-         if (TREE_CODE (new_decls) == VAR_DECL
-             /* Don't complain about crossing initialization
-                of internal entities.  They can't be accessed,
-                and they should be cleaned up
-                by the time we get to the label.  */
-             && ! DECL_ARTIFICIAL (new_decls)
-             && ((DECL_INITIAL (new_decls) != NULL_TREE
-                  && DECL_INITIAL (new_decls) != error_mark_node)
-                 || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
-           {
-             if (! identified)
-               error ("jump to case label");
-             identified = 1;
-             cp_error_at ("  crosses initialization of `%#D'",
-                          new_decls);
-           }
-       }
+      tree label;
+
+      /* For templates, just add the case label; we'll do semantic
+        analysis at instantiation-time.  */
+      label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+      add_stmt (build_case_label (low_value, high_value, label));
+      return;
     }
 
+  /* Find the condition on which this switch statement depends.  */
+  cond = SWITCH_COND (switch_stack->switch_stmt);
+  if (cond && TREE_CODE (cond) == TREE_LIST)
+    cond = TREE_VALUE (cond);
+
+  c_add_case_label (switch_stack->cases, cond, low_value, high_value);
+
+  check_switch_goto (switch_stack->level);
+
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
-
   current_binding_level->more_cleanups_ok = 0;
   current_function_return_value = NULL_TREE;
 }
@@ -4961,9 +5277,9 @@ lookup_tag (form, name, binding_level, thislevel_only)
      int thislevel_only;
 {
   register struct binding_level *level;
-  /* Non-zero if, we should look past a pseudo-global level, even if
-     THISLEVEL_ONLY.  */
-  int allow_pseudo_global = 1;
+  /* Non-zero if, we should look past a template parameter level, even
+     if THISLEVEL_ONLY.  */
+  int allow_template_parms_p = 1;
 
   for (level = binding_level; level; level = level->level_chain)
     {
@@ -4982,15 +5298,15 @@ lookup_tag (form, name, binding_level, thislevel_only)
          {
            tree old = binding_for_name (name, tail);
 
-           /* If we just skipped past a pseudo global level, even
-              though THISLEVEL_ONLY, and we find a template class
-              declaration, then we use the _TYPE node for the
+           /* If we just skipped past a template parameter level,
+              even though THISLEVEL_ONLY, and we find a template
+              class declaration, then we use the _TYPE node for the
               template.  See the example below.  */
-           if (thislevel_only && !allow_pseudo_global
-               && old && BINDING_VALUE (old) 
+           if (thislevel_only && !allow_template_parms_p
+               && old && BINDING_VALUE (old)
                && DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
              old = TREE_TYPE (BINDING_VALUE (old));
-           else 
+           else
              old = BINDING_TYPE (old);
 
            /* If it has an original type, it is a typedef, and we
@@ -5029,20 +5345,20 @@ lookup_tag (form, name, binding_level, thislevel_only)
          }
       if (thislevel_only && ! level->tag_transparent)
        {
-         if (level->pseudo_global && allow_pseudo_global)
+         if (level->template_parms_p && allow_template_parms_p)
            {
              /* We must deal with cases like this:
-                
+
                   template <class T> struct S;
                   template <class T> struct S {};
-                  
+
                 When looking up `S', for the second declaration, we
                 would like to find the first declaration.  But, we
                 are in the pseudo-global level created for the
                 template parameters, rather than the (surrounding)
                 namespace level.  Thus, we keep going one more level,
                 even though THISLEVEL_ONLY is non-zero.  */
-             allow_pseudo_global = 0;
+             allow_template_parms_p = 0;
              continue;
            }
          else
@@ -5121,12 +5437,12 @@ lookup_namespace_name (namespace, name)
       name = TREE_OPERAND (name, 0);
       if (TREE_CODE (name) == OVERLOAD)
        name = DECL_NAME (OVL_CURRENT (name));
-      else if (TREE_CODE_CLASS (TREE_CODE (name)) == 'd')
+      else if (DECL_P (name))
        name = DECL_NAME (name);
     }
 
   my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373);
-  
+
   val = make_node (CPLUS_BINDING);
   if (!qualified_lookup_using_namespace (name, namespace, val, 0))
     return error_mark_node;
@@ -5138,14 +5454,14 @@ lookup_namespace_name (namespace, name)
       if (template_id)
        {
          if (DECL_CLASS_TEMPLATE_P (val))
-           val = lookup_template_class (val, 
+           val = lookup_template_class (val,
                                         TREE_OPERAND (template_id, 1),
                                         /*in_decl=*/NULL_TREE,
                                         /*context=*/NULL_TREE,
                                         /*entering_scope=*/0);
          else if (DECL_FUNCTION_TEMPLATE_P (val)
                   || TREE_CODE (val) == OVERLOAD)
-           val = lookup_template_function (val, 
+           val = lookup_template_function (val,
                                            TREE_OPERAND (template_id, 1));
          else
            {
@@ -5197,10 +5513,10 @@ typename_compare (k1, k2)
   t2 = (tree) k2;
   d1 = TYPE_NAME (t1);
   d2 = TYPE_NAME (t2);
-  
+
   return (DECL_NAME (d1) == DECL_NAME (d2)
          && same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2))
-         && ((TREE_TYPE (t1) != NULL_TREE) 
+         && ((TREE_TYPE (t1) != NULL_TREE)
              == (TREE_TYPE (t2) != NULL_TREE))
          && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
          && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2));
@@ -5210,7 +5526,7 @@ typename_compare (k1, k2)
    the type of `T', NAME is the IDENTIFIER_NODE for `t'.  If BASE_TYPE
    is non-NULL, this type is being created by the implicit typename
    extension, and BASE_TYPE is a type named `t' in some base class of
-   `T' which depends on template parameters.  
+   `T' which depends on template parameters.
 
    Returns the new TYPENAME_TYPE.  */
 
@@ -5227,19 +5543,17 @@ build_typename_type (context, name, fullname, base_type)
 
   static struct hash_table ht;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
   if (!ht.table)
     {
       static struct hash_table *h = &ht;
-      if (!hash_table_init (&ht, &hash_newfunc, &typename_hash, 
+      if (!hash_table_init (&ht, &hash_newfunc, &typename_hash,
                            &typename_compare))
        fatal ("virtual memory exhausted");
       ggc_add_tree_hash_table_root (&h, 1);
     }
 
   /* Build the TYPENAME_TYPE.  */
-  t = make_lang_type (TYPENAME_TYPE);
+  t = make_aggr_type (TYPENAME_TYPE);
   TYPE_CONTEXT (t) = FROB_CONTEXT (context);
   TYPENAME_TYPE_FULLNAME (t) = fullname;
   TREE_TYPE (t) = base_type;
@@ -5259,8 +5573,6 @@ build_typename_type (context, name, fullname, base_type)
     /* Insert the type into the table.  */
     hash_lookup (&ht, t, /*create=*/true, /*copy=*/0);
 
-  pop_obstacks ();
-
   return t;
 }
 
@@ -5275,10 +5587,10 @@ make_typename_type (context, name, complain)
 {
   tree fullname;
 
-  if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+  if (TYPE_P (name))
     {
-      if (!(TYPE_LANG_SPECIFIC (name) 
-           && (CLASSTYPE_IS_TEMPLATE (name) 
+      if (!(TYPE_LANG_SPECIFIC (name)
+           && (CLASSTYPE_IS_TEMPLATE (name)
                || CLASSTYPE_USE_TEMPLATE (name))))
        name = TYPE_IDENTIFIER (name);
       else
@@ -5327,15 +5639,15 @@ make_typename_type (context, name, complain)
              return error_mark_node;
            }
 
-         return lookup_template_class (tmpl, 
+         return lookup_template_class (tmpl,
                                        TREE_OPERAND (fullname, 1),
-                                       NULL_TREE, context, 
+                                       NULL_TREE, context,
                                        /*entering_scope=*/0);
        }
       else
        {
           tree t;
-          
+
          if (!IS_AGGR_TYPE (context))
            {
              if (complain)
@@ -5357,8 +5669,8 @@ make_typename_type (context, name, complain)
        cp_error ("no type named `%#T' in `%#T'", name, context);
       return error_mark_node;
     }
-    
-  
+
+
   return build_typename_type (context, name, fullname,  NULL_TREE);
 }
 
@@ -5378,7 +5690,7 @@ select_decl (binding, flags)
         return val;
       return NULL_TREE;
     }
-  
+
   /* If we could have a type and
      we have nothing or we need a type and have none.  */
   if (BINDING_TYPE (binding)
@@ -5425,7 +5737,7 @@ unqualified_namespace_lookup (name, flags, spacesp)
       BINDING_TYPE (b) = BINDING_TYPE (val);
 
       /* Add all _DECLs seen through local using-directives. */
-      for (level = current_binding_level; 
+      for (level = current_binding_level;
           !level->namespace_p;
           level = level->level_chain)
        if (!lookup_using_namespace (name, b, level->using_directives,
@@ -5438,7 +5750,7 @@ unqualified_namespace_lookup (name, flags, spacesp)
       siter = initial;
       while (1)
        {
-         if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter), 
+         if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter),
                                       scope, flags, spacesp))
            /* Give up because of error. */
            return error_mark_node;
@@ -5507,7 +5819,7 @@ warn_about_implicit_typename_lookup (typename, binding)
       && ! (TREE_CODE (binding) == TYPE_DECL
            && same_type_p (TREE_TYPE (binding), subtype)))
     {
-      cp_warning ("lookup of `%D' finds `%#D'", 
+      cp_warning ("lookup of `%D' finds `%#D'",
                  name, binding);
       cp_warning ("  instead of `%D' from dependent base class",
                  typename);
@@ -5525,7 +5837,7 @@ warn_about_implicit_typename_lookup (typename, binding)
    If PREFER_TYPE is > 0, we prefer TYPE_DECLs or namespaces.
    If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces).
    If PREFER_TYPE is -2, we're being called from yylex(). (UGLY)
-   Otherwise we prefer non-TYPE_DECLs.  
+   Otherwise we prefer non-TYPE_DECLs.
 
    If NONCLASS is non-zero, we don't look for the NAME in class scope,
    using IDENTIFIER_CLASS_VALUE.  */
@@ -5567,7 +5879,7 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
        type = got_scope;
       else if (got_object != error_mark_node)
        type = got_object;
-      
+
       if (type)
        {
          if (type == error_mark_node)
@@ -5590,14 +5902,24 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
            }
          else if (! IS_AGGR_TYPE (type)
                   || TREE_CODE (type) == TEMPLATE_TYPE_PARM
-                  || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
+                  || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
                   || TREE_CODE (type) == TYPENAME_TYPE)
            /* Someone else will give an error about this if needed.  */
            val = NULL_TREE;
          else if (type == current_class_type)
            val = IDENTIFIER_CLASS_VALUE (name);
          else
-           val = lookup_member (type, name, 0, prefer_type);
+           {
+             val = lookup_member (type, name, 0, prefer_type);
+             type_access_control (type, val);
+
+             /* Restore the containing TYPENAME_TYPE if we looked
+                through it before.  */
+             if (got_scope && got_scope != type
+                 && val && TREE_CODE (val) == TYPE_DECL
+                 && TREE_CODE (TREE_TYPE (val)) == TYPENAME_TYPE)
+               TYPE_CONTEXT (TREE_TYPE (val)) = got_scope;
+           }
        }
       else
        val = NULL_TREE;
@@ -5626,23 +5948,28 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
       if (!LOCAL_BINDING_P (t) && nonclass)
        /* We're not looking for class-scoped bindings, so keep going.  */
        continue;
-      
+
       /* If this is the kind of thing we're looking for, we're done.  */
       if (qualify_lookup (BINDING_VALUE (t), flags))
        binding = BINDING_VALUE (t);
-      else if ((flags & LOOKUP_PREFER_TYPES) 
+      else if ((flags & LOOKUP_PREFER_TYPES)
               && qualify_lookup (BINDING_TYPE (t), flags))
        binding = BINDING_TYPE (t);
       else
        binding = NULL_TREE;
 
+      /* Handle access control on types from enclosing or base classes.  */
+      if (binding && ! yylex
+         && BINDING_LEVEL (t) && BINDING_LEVEL (t)->parm_flag == 2)
+       type_access_control (BINDING_LEVEL (t)->this_class, binding);
+
       if (binding
          && (!val || !IMPLICIT_TYPENAME_TYPE_DECL_P (binding)))
        {
          if (val_is_implicit_typename && !yylex)
            warn_about_implicit_typename_lookup (val, binding);
          val = binding;
-         val_is_implicit_typename 
+         val_is_implicit_typename
            = IMPLICIT_TYPENAME_TYPE_DECL_P (val);
          if (!val_is_implicit_typename)
            break;
@@ -5747,14 +6074,14 @@ lookup_name_current_level (name)
       if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
        t = TREE_VALUE (t);
     }
-  else if (IDENTIFIER_BINDING (name) 
+  else if (IDENTIFIER_BINDING (name)
           && LOCAL_BINDING_P (IDENTIFIER_BINDING (name)))
     {
       while (1)
        {
          if (BINDING_LEVEL (IDENTIFIER_BINDING (name)) == b)
            return IDENTIFIER_VALUE (name);
-         
+
          if (b->keep == 2)
            b = b->level_chain;
          else
@@ -5805,35 +6132,8 @@ end_only_namespace_names ()
   only_namespace_names = 0;
 }
 \f
-/* Arrange for the user to get a source line number, even when the
-   compiler is going down in flames, so that she at least has a
-   chance of working around problems in the compiler.  We used to
-   call error(), but that let the segmentation fault continue
-   through; now, it's much more passive by asking them to send the
-   maintainers mail about the problem.  */
-
-static void
-signal_catch (sig)
-     int sig ATTRIBUTE_UNUSED;
-{
-  signal (SIGSEGV, SIG_DFL);
-#ifdef SIGIOT
-  signal (SIGIOT, SIG_DFL);
-#endif
-#ifdef SIGILL
-  signal (SIGILL, SIG_DFL);
-#endif
-#ifdef SIGABRT
-  signal (SIGABRT, SIG_DFL);
-#endif
-#ifdef SIGBUS
-  signal (SIGBUS, SIG_DFL);
-#endif
-  my_friendly_abort (0);
-}
-
 /* Push the declarations of builtin types into the namespace.
-   RID_INDEX, if < RID_MAX is the index of the builtin type
+   RID_INDEX is the index of the builtin type
    in the array RID_POINTERS.  NAME is the name used when looking
    up the builtin type.  TYPE is the _TYPE node for the builtin type.  */
 
@@ -5852,7 +6152,7 @@ record_builtin_type (rid_index, name, type)
     tname = get_identifier (name);
 
   TYPE_BUILT_IN (type) = 1;
-  
+
   if (tname)
     {
       tdecl = pushdecl (build_decl (TYPE_DECL, tname, type));
@@ -5925,27 +6225,63 @@ record_unknown_type (type, name)
   TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
   TYPE_SIZE (type) = TYPE_SIZE (void_type_node);
   TYPE_ALIGN (type) = 1;
+  TYPE_USER_ALIGN (type) = 0;
   TYPE_MODE (type) = TYPE_MODE (void_type_node);
-} 
+}
 
-/* Push overloaded decl, in global scope, with one argument so it
-   can be used as a callback from define_function.  */
+/* An string for which we should create an IDENTIFIER_NODE at
+   startup.  */
 
-static void
-push_overloaded_decl_1 (x)
-     tree x;
+typedef struct predefined_identifier
 {
-  pushdecl (x);
-}
+  /* The name of the identifier.  */
+  const char *name;
+  /* The place where the IDENTIFIER_NODE should be stored.  */
+  tree *node;
+  /* Non-zero if this is the name of a constructor or destructor.  */
+  int ctor_or_dtor_p;
+} predefined_identifier;
 
-inline tree
-auto_function (name, type)
-     tree name, type;
-{
-  return define_function
-    (IDENTIFIER_POINTER (name), type, push_overloaded_decl_1,
-     IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type),
-                                             0)));
+/* Create all the predefined identifiers.  */
+
+static void
+initialize_predefined_identifiers () 
+{
+  struct predefined_identifier *pid;
+
+  /* A table of identifiers to create at startup.  */
+  static predefined_identifier predefined_identifiers[] = {
+    { "C++", &lang_name_cplusplus, 0 },
+    { "C", &lang_name_c, 0 },
+    { "Java", &lang_name_java, 0 },
+    { CTOR_NAME, &ctor_identifier, 1 },
+    { "__base_ctor", &base_ctor_identifier, 1 },
+    { "__comp_ctor", &complete_ctor_identifier, 1 },
+    { DTOR_NAME, &dtor_identifier, 1 },
+    { "__comp_dtor", &complete_dtor_identifier, 1 },
+    { "__base_dtor", &base_dtor_identifier, 1 },
+    { "__deleting_dtor", &deleting_dtor_identifier, 1 },
+    { VTABLE_DELTA2_NAME, &delta2_identifier, 0 },
+    { VTABLE_DELTA_NAME, &delta_identifier, 0 },
+    { IN_CHARGE_NAME, &in_charge_identifier, 0 },
+    { VTABLE_INDEX_NAME, &index_identifier, 0 },
+    { "nelts", &nelts_identifier, 0 },
+    { THIS_NAME, &this_identifier, 0 },
+    { VTABLE_PFN_NAME, &pfn_identifier, 0 },
+    { "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
+    { "_vptr", &vptr_identifier, 0 },
+    { "__cp_push_exception", &cp_push_exception_identifier, 0 },
+    { "__vtt_parm", &vtt_parm_identifier, 0 },
+    { "std", &std_identifier, 0 },
+    { NULL, NULL, 0 }
+  };
+
+  for (pid = predefined_identifiers; pid->name; ++pid)
+    {
+      *pid->node = get_identifier (pid->name);
+      if (pid->ctor_or_dtor_p)
+       IDENTIFIER_CTOR_OR_DTOR_P (*pid->node) = 1;
+    }
 }
 
 /* Create the predefined scalar types of C,
@@ -5960,16 +6296,19 @@ init_decl_processing ()
   int wchar_type_size;
   tree array_domain_type;
 
-  /* Have to make these distinct before we try using them.  */
-  lang_name_cplusplus = get_identifier ("C++");
-  lang_name_c = get_identifier ("C");
-  lang_name_java = get_identifier ("Java");
+  /* Check to see that the user did not specify an invalid combination
+     of command-line options.  */
+  if (flag_new_abi && !flag_vtable_thunks)
+    fatal ("the new ABI requires vtable thunks");
 
-  /* Let the back-end now how to save and restore language-specific
-     per-function globals.  */
+  /* Create all the identifiers we need.  */
+  initialize_predefined_identifiers ();
+
+  /* Fill in back-end hooks.  */
   init_lang_status = &push_cp_function_context;
   free_lang_status = &pop_cp_function_context;
   mark_lang_status = &mark_cp_function_context;
+  lang_safe_from_p = &c_safe_from_p;
 
   cp_parse_init ();
   init_decl2 ();
@@ -5984,12 +6323,11 @@ init_decl_processing ()
   global_namespace = current_namespace;
   current_lang_name = NULL_TREE;
 
-  if (flag_strict_prototype == 2)
-    flag_strict_prototype = pedantic;
+  /* Adjust various flags based on command-line settings.  */
   if (! flag_permissive && ! pedantic)
     flag_pedantic_errors = 1;
-
-  strict_prototypes_lang_c = flag_strict_prototype;
+  if (!flag_no_inline)
+    flag_inline_trees = 1;
 
   /* Initially, C.  */
   current_lang_name = lang_name_c;
@@ -5998,28 +6336,6 @@ init_decl_processing ()
   current_binding_level = NULL_BINDING_LEVEL;
   free_binding_level = NULL_BINDING_LEVEL;
 
-  /* Because most segmentation signals can be traced back into user
-     code, catch them and at least give the user a chance of working
-     around compiler bugs.  */
-  signal (SIGSEGV, signal_catch);
-
-  /* We will also catch aborts in the back-end through signal_catch and
-     give the user a chance to see where the error might be, and to defeat
-     aborts in the back-end when there have been errors previously in their
-     code.  */
-#ifdef SIGIOT
-  signal (SIGIOT, signal_catch);
-#endif
-#ifdef SIGILL
-  signal (SIGILL, signal_catch);
-#endif
-#ifdef SIGABRT
-  signal (SIGABRT, signal_catch);
-#endif
-#ifdef SIGBUS
-  signal (SIGBUS, signal_catch);
-#endif
-
   build_common_tree_nodes (flag_signed_char);
 
   error_mark_list = build_tree_list (error_mark_node, error_mark_node);
@@ -6032,16 +6348,6 @@ init_decl_processing ()
   NAMESPACE_LEVEL (global_namespace) = global_binding_level;
   declare_namespace_level ();
 
-  this_identifier = get_identifier (THIS_NAME);
-  in_charge_identifier = get_identifier (IN_CHARGE_NAME);
-  ctor_identifier = get_identifier (CTOR_NAME);
-  dtor_identifier = get_identifier (DTOR_NAME);
-  pfn_identifier = get_identifier (VTABLE_PFN_NAME);
-  index_identifier = get_identifier (VTABLE_INDEX_NAME);
-  delta_identifier = get_identifier (VTABLE_DELTA_NAME);
-  delta2_identifier = get_identifier (VTABLE_DELTA2_NAME);
-  pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2");
-
   /* Define `int' and `char' first so that dbx will output them first.  */
   record_builtin_type (RID_INT, NULL_PTR, integer_type_node);
   record_builtin_type (RID_CHAR, "char", char_type_node);
@@ -6050,16 +6356,20 @@ init_decl_processing ()
   record_builtin_type (RID_SIGNED, NULL_PTR, integer_type_node);
   record_builtin_type (RID_LONG, "long int", long_integer_type_node);
   record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node);
-  record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node);
+  record_builtin_type (RID_MAX, "long unsigned int",
+                      long_unsigned_type_node);
   record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node);
-  record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node);
+  record_builtin_type (RID_MAX, "long long int",
+                      long_long_integer_type_node);
   record_builtin_type (RID_MAX, "long long unsigned int",
                       long_long_unsigned_type_node);
   record_builtin_type (RID_MAX, "long long unsigned",
                       long_long_unsigned_type_node);
   record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
-  record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node);
-  record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node);
+  record_builtin_type (RID_MAX, "short unsigned int",
+                      short_unsigned_type_node); 
+  record_builtin_type (RID_MAX, "unsigned short",
+                      short_unsigned_type_node);
 
   ptrdiff_type_node
     = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
@@ -6076,11 +6386,11 @@ init_decl_processing ()
 
   /* Create the widest literal types. */
   widest_integer_literal_type_node = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, 
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
                        widest_integer_literal_type_node));
 
   widest_unsigned_literal_type_node = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, 
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
                        widest_unsigned_literal_type_node));
 
   /* These are types that type_for_size and type_for_mode use.  */
@@ -6126,7 +6436,8 @@ init_decl_processing ()
   boolean_true_node = build_int_2 (1, 0);
   TREE_TYPE (boolean_true_node) = boolean_type_node;
 
-  signed_size_zero_node = build_int_2 (0, 0);  record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
+  signed_size_zero_node = build_int_2 (0, 0);
+  record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
   record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
   record_builtin_type (RID_MAX, "long double", long_double_type_node);
 
@@ -6145,13 +6456,9 @@ init_decl_processing ()
   void_list_node = build_tree_list (NULL_TREE, void_type_node);
   TREE_PARMLIST (void_list_node) = 1;
 
-  /* Used for expressions that do nothing, but are not errors.  */
-  void_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (void_zero_node) = void_type_node;
-
   string_type_node = build_pointer_type (char_type_node);
   const_string_type_node
-    = build_pointer_type (build_qualified_type (char_type_node, 
+    = build_pointer_type (build_qualified_type (char_type_node,
                                                TYPE_QUAL_CONST));
   empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE);
 #if 0
@@ -6160,9 +6467,7 @@ init_decl_processing ()
 
   /* Make a type to be the domain of a few array types
      whose domains don't really matter.
-     200 is small enough that it always fits in size_t
-     and large enough that it can hold most function names for the
-     initializations of __FUNCTION__ and __PRETTY_FUNCTION__.  */
+     200 is small enough that it always fits in size_t.  */
   array_domain_type = build_index_type (build_int_2 (200, 0));
 
   /* Make a type for arrays of characters.
@@ -6170,19 +6475,23 @@ init_decl_processing ()
      array type.  */
   char_array_type_node
     = build_array_type (char_type_node, array_domain_type);
+
   /* Likewise for arrays of ints.  */
   int_array_type_node
     = build_array_type (integer_type_node, array_domain_type);
 
-  /* This is just some anonymous class type.  Nobody should ever
-     need to look inside this envelope.  */
-  class_star_type_node = build_pointer_type (make_lang_type (RECORD_TYPE));
-
-  if (flag_huge_objects)
+  if (flag_new_abi)
+    delta_type_node = ptrdiff_type_node;
+  else if (flag_huge_objects)
     delta_type_node = long_integer_type_node;
   else
     delta_type_node = short_integer_type_node;
 
+  if (flag_new_abi)
+    vtable_index_type = ptrdiff_type_node;
+  else
+    vtable_index_type = delta_type_node;
+
   default_function_type
     = build_function_type (integer_type_node, NULL_TREE);
 
@@ -6190,6 +6499,7 @@ init_decl_processing ()
   const_ptr_type_node
     = build_pointer_type (build_qualified_type (void_type_node,
                                                TYPE_QUAL_CONST));
+  vtt_parm_type = build_pointer_type (const_ptr_type_node);
   c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
   lang_type_promotes_to = convert_type_from_ellipsis;
 
@@ -6217,12 +6527,10 @@ init_decl_processing ()
                                    : WCHAR_TYPE);
   wchar_type_node = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (wchar_type_node));
   wchar_type_size = TYPE_PRECISION (wchar_type_node);
-  signed_wchar_type_node = make_signed_type (wchar_type_size);
-  unsigned_wchar_type_node = make_unsigned_type (wchar_type_size);
-  wchar_type_node
-    = TREE_UNSIGNED (wchar_type_node)
-      ? unsigned_wchar_type_node
-      : signed_wchar_type_node;
+  if (TREE_UNSIGNED (wchar_type_node))
+    wchar_type_node = make_signed_type (wchar_type_size);
+  else
+    wchar_type_node = make_unsigned_type (wchar_type_size);
   record_builtin_type (RID_WCHAR, "__wchar_t", wchar_type_node);
 
   /* Artificial declaration of wchar_t -- can be bashed */
@@ -6247,13 +6555,13 @@ init_decl_processing ()
     }
   else
     {
-      vtable_entry_type = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
-                                  delta_type_node);
-      fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
-                                  delta_type_node);
-      fields[2] = build_lang_decl (FIELD_DECL, pfn_identifier,
-                                  ptr_type_node);
+      vtable_entry_type = make_aggr_type (RECORD_TYPE);
+      fields[0] = build_decl (FIELD_DECL, delta_identifier,
+                             delta_type_node);
+      fields[1] = build_decl (FIELD_DECL, index_identifier,
+                             delta_type_node);
+      fields[2] = build_decl (FIELD_DECL, pfn_identifier,
+                             ptr_type_node);
       finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2,
                           double_type_node);
 
@@ -6263,6 +6571,7 @@ init_decl_processing ()
       DECL_NAME (fields[3]) = delta2_identifier;
       DECL_MODE (fields[3]) = TYPE_MODE (delta_type_node);
       DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node);
+      DECL_SIZE_UNIT (fields[3]) = TYPE_SIZE_UNIT (delta_type_node);
       TREE_UNSIGNED (fields[3]) = 0;
       TREE_CHAIN (fields[2]) = fields[3];
       vtable_entry_type = build_qualified_type (vtable_entry_type,
@@ -6279,10 +6588,18 @@ init_decl_processing ()
   layout_type (vtbl_ptr_type_node);
   record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node);
 
-  std_node = build_decl (NAMESPACE_DECL, 
-                        get_identifier (flag_honor_std ? "fake std":"std"),
+  std_node = build_decl (NAMESPACE_DECL,
+                        flag_honor_std 
+                        ? get_identifier ("fake std") : std_identifier,
                         void_type_node);
   pushdecl (std_node);
+  
+  if (flag_new_abi)
+    {
+      push_namespace (get_identifier ("__cxxabiv1"));
+      abi_node = current_namespace;
+      pop_namespace ();
+    }
 
   global_type_node = make_node (LANG_TYPE);
   record_unknown_type (global_type_node, "global type");
@@ -6301,15 +6618,14 @@ init_decl_processing ()
     newtype = build_exception_variant
       (ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
     deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
-    auto_function (ansi_opname[(int) NEW_EXPR], newtype);
-    auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype);
-    global_delete_fndecl = auto_function (ansi_opname[(int) DELETE_EXPR],
-                                         deltype);
-    auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype);
+    push_cp_library_fn (NEW_EXPR, newtype);
+    push_cp_library_fn (VEC_NEW_EXPR, newtype);
+    global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype);
+    push_cp_library_fn (VEC_DELETE_EXPR, deltype);
   }
 
   abort_fndecl
-    = define_function ("__pure_virtual", void_ftype, 0, 0);
+    = build_library_fn_ptr ("__pure_virtual", void_ftype);
 
   /* Perform other language dependent initializations.  */
   init_class_processing ();
@@ -6328,6 +6644,11 @@ init_decl_processing ()
     flag_weak = 0;
 
   /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
+  function_id_node = get_identifier ("__FUNCTION__");
+  pretty_function_id_node = get_identifier ("__PRETTY_FUNCTION__");
+  func_id_node = get_identifier ("__func__");
+
+  make_fname_decl = cp_make_fname_decl;
   declare_function_name ();
 
   /* Prepare to check format strings against argument lists.  */
@@ -6336,8 +6657,6 @@ init_decl_processing ()
   /* Show we use EH for cleanups.  */
   using_eh_for_cleanups ();
 
-  print_error_function = lang_print_error_function;
-  lang_get_alias_set = &c_get_alias_set;
   valid_lang_attribute = cp_valid_lang_attribute;
 
   /* Maintain consistency.  Perhaps we should just complain if they
@@ -6360,10 +6679,8 @@ init_decl_processing ()
   ggc_add_tree_root (&static_dtors, 1);
   ggc_add_tree_root (&lastiddecl, 1);
 
-  ggc_add_tree_root (&enum_next_value, 1);
   ggc_add_tree_root (&last_function_parm_tags, 1);
   ggc_add_tree_root (&current_function_return_value, 1);
-  ggc_add_tree_root (&current_function_parms, 1);
   ggc_add_tree_root (&current_function_parm_tags, 1);
   ggc_add_tree_root (&last_function_parms, 1);
   ggc_add_tree_root (&error_mark_list, 1);
@@ -6379,66 +6696,219 @@ init_decl_processing ()
   ggc_add_tree_root (&static_aggregates, 1);
 }
 
-/* Function to print any language-specific context for an error message.  */
+/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
+   decl, NAME is the initialization string and TYPE_DEP indicates whether
+   NAME depended on the type of the function. We make use of that to detect
+   __PRETTY_FUNCTION__ inside a template fn.  Because we build a tree for
+   the function before emitting any of it, we don't need to treat the
+   VAR_DECL specially. We can decide whether to emit it later, if it was
+   used.  */
 
-static void
-lang_print_error_function (file)
-     const char *file;
+static tree
+cp_make_fname_decl (id, name, type_dep)
+     tree id;
+     const char *name;
+     int type_dep;
 {
-  default_print_error_function (file);
-  maybe_print_template_context ();
+  tree decl, type, init;
+  size_t length = strlen (name);
+  tree domain = NULL_TREE;
+  
+  if (!processing_template_decl)
+    type_dep = 0;
+  if (!type_dep)
+    domain = build_index_type (build_int_2 (length, 0));
+
+  type =  build_cplus_array_type
+          (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+          domain);
+
+  decl = build_decl (VAR_DECL, id, type);
+  TREE_STATIC (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  DECL_SOURCE_LINE (decl) = 0;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IN_SYSTEM_HEADER (decl) = 1;
+  pushdecl (decl);
+  if (processing_template_decl)
+    decl = push_template_decl (decl);
+  if (type_dep)
+    {
+      init = build (FUNCTION_NAME, type);
+      DECL_PRETTY_FUNCTION_P (decl) = 1;
+    }
+  else
+    {
+      init = build_string (length + 1, name);
+      TREE_TYPE (init) = type;
+    }
+  DECL_INITIAL (decl) = init;
+  cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+  
+  /* We will have to make sure we only emit this, if it is actually used. */
+  return decl;
 }
 
-/* Make a definition for a builtin function named NAME and whose data type
+/* Entry point for the benefit of c_common_nodes_and_builtins.
+
+   Make a definition for a builtin function named NAME and whose data type
    is TYPE.  TYPE should be a function type with argument types.
 
-   If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
+   CLASS and CODE tell later passes how to compile calls to this function.
+   See tree.h for possible values.
+
+   If LIBNAME is nonzero, use that for DECL_ASSEMBLER_NAME,
    the name to be called if we can't opencode the function.  */
 
 tree
-define_function (name, type, pfn, library_name)
+builtin_function (name, type, code, class, libname)
      const char *name;
      tree type;
-     void (*pfn) PROTO((tree));
-     const char *library_name;
+     int code;
+     enum built_in_class class;
+     const char *libname;
 {
-  tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type);
-  DECL_EXTERNAL (decl) = 1;
-  TREE_PUBLIC (decl) = 1;
-  DECL_ARTIFICIAL (decl) = 1;
+  tree decl = build_library_fn_1 (get_identifier (name), ERROR_MARK, type);
+  DECL_BUILT_IN_CLASS (decl) = class;
+  DECL_FUNCTION_CODE (decl) = code;
 
   my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 392);
-  DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
 
   /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
      we cannot change DECL_ASSEMBLER_NAME until we have installed this
      function in the namespace.  */
-  if (pfn) (*pfn) (decl);
-  if (library_name)
-    DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
+  pushdecl (decl);
+  if (libname)
+    DECL_ASSEMBLER_NAME (decl) = get_identifier (libname);
   make_function_rtl (decl);
+
+  /* Warn if a function in the namespace for users
+     is used without an occasion to consider it declared.  */
+  if (name[0] != '_' || name[1] != '_')
+    DECL_ANTICIPATED (decl) = 1;
+
   return decl;
 }
 
+/* Generate a FUNCTION_DECL with the typical flags for a runtime library
+   function.  Not called directly.  */
+
+static tree
+build_library_fn_1 (name, operator_code, type)
+     tree name;
+     enum tree_code operator_code;
+     tree type;
+{
+  tree fn = build_lang_decl (FUNCTION_DECL, name, type);
+  DECL_EXTERNAL (fn) = 1;
+  TREE_PUBLIC (fn) = 1;
+  DECL_ARTIFICIAL (fn) = 1;
+  TREE_NOTHROW (fn) = 1;
+  SET_OVERLOADED_OPERATOR_CODE (fn, operator_code);
+  return fn;
+}
+
+/* Returns the _DECL for a library function with C linkage.
+   We assume that such functions never throw; if this is incorrect,
+   callers should unset TREE_NOTHROW.  */
+
+tree
+build_library_fn (name, type)
+     tree name;
+     tree type;
+{
+  tree fn = build_library_fn_1 (name, ERROR_MARK, type);
+  make_function_rtl (fn);
+  return fn;
+}
+
+/* Returns the _DECL for a library function with C++ linkage.  */
 
-/* Wrapper around define_function, for the benefit of 
-   c_common_nodes_and_builtins.
-   FUNCTION_CODE tells later passes how to compile calls to this function.
-   See tree.h for its possible values.  */
+static tree
+build_cp_library_fn (name, operator_code, type)
+     tree name;
+     enum tree_code operator_code;
+     tree type;
+{
+  tree fn = build_library_fn_1 (name, operator_code, type);
+  TREE_NOTHROW (fn) = TYPE_NOTHROW_P (type);
+  DECL_CONTEXT (fn) = FROB_CONTEXT (current_namespace);
+  set_mangled_name_for_decl (fn);
+  make_function_rtl (fn);
+  return fn;
+}
+
+/* Like build_library_fn, but takes a C string instead of an
+   IDENTIFIER_NODE.  */
 
 tree
-builtin_function (name, type, code, class, libname)
+build_library_fn_ptr (name, type)
      const char *name;
      tree type;
-     int code;
-     enum built_in_class class;
-     const char *libname;
 {
-  tree decl = define_function (name, type, (void (*) PROTO((tree)))pushdecl,
-                              libname);
-  DECL_BUILT_IN_CLASS (decl) = class;
-  DECL_FUNCTION_CODE (decl) = code;
-  return decl;
+  return build_library_fn (get_identifier (name), type);
+}
+
+/* Like build_cp_library_fn, but takes a C string instead of an
+   IDENTIFIER_NODE.  */
+
+tree
+build_cp_library_fn_ptr (name, type)
+     const char *name;
+     tree type;
+{
+  return build_cp_library_fn (get_identifier (name), ERROR_MARK, type);
+}
+
+/* Like build_library_fn, but also pushes the function so that we will
+   be able to find it via IDENTIFIER_GLOBAL_VALUE.  */
+
+tree
+push_library_fn (name, type)
+     tree name, type;
+{
+  tree fn = build_library_fn (name, type);
+  pushdecl_top_level (fn);
+  return fn;
+}
+
+/* Like build_cp_library_fn, but also pushes the function so that it
+   will be found by normal lookup.  */
+
+static tree
+push_cp_library_fn (operator_code, type)
+     enum tree_code operator_code;
+     tree type;
+{
+  tree fn = build_cp_library_fn (ansi_opname (operator_code), 
+                                operator_code,
+                                type);
+  pushdecl (fn);
+  return fn;
+}
+
+/* Like push_library_fn, but takes a TREE_LIST of parm types rather than
+   a FUNCTION_TYPE.  */
+
+tree
+push_void_library_fn (name, parmtypes)
+     tree name, parmtypes;
+{
+  tree type = build_function_type (void_type_node, parmtypes);
+  return push_library_fn (name, type);
+}
+
+/* Like push_library_fn, but also note that this function throws
+   and does not return.  Used for __throw_foo and the like.  */
+
+tree
+push_throw_library_fn (name, type)
+     tree name, type;
+{
+  tree fn = push_library_fn (name, type);
+  TREE_THIS_VOLATILE (fn) = 1;
+  TREE_NOTHROW (fn) = 0;
+  return fn;
 }
 \f
 /* When we call finish_struct for an anonymous union, we create
@@ -6476,8 +6946,7 @@ fixup_anonymous_aggr (t)
        q = &TREE_CHAIN (*q);
     }
 
-  /* ANSI C++ June 5 1992 WP 9.5.3.  Anonymous unions may not have
-     function members.  */
+  /* ISO C++ 9.5.3.  Anonymous unions may not have function members.  */
   if (TYPE_METHODS (t))
     error ("an anonymous union cannot have function members");
 }
@@ -6492,6 +6961,7 @@ check_tag_decl (declspecs)
      tree declspecs;
 {
   int found_type = 0;
+  int saw_friend = 0;
   tree ob_modifier = NULL_TREE;
   register tree link;
   register tree t = NULL_TREE;
@@ -6500,11 +6970,15 @@ check_tag_decl (declspecs)
     {
       register tree value = TREE_VALUE (link);
 
-      if (TYPE_P (value))
+      if (TYPE_P (value)
+         || (TREE_CODE (value) == IDENTIFIER_NODE
+             && IDENTIFIER_GLOBAL_VALUE (value)
+             && TYPE_P (IDENTIFIER_GLOBAL_VALUE (value))))
        {
          ++found_type;
 
-         if (IS_AGGR_TYPE (value) || TREE_CODE (value) == ENUMERAL_TYPE)
+         if ((TREE_CODE (value) != TYPENAME_TYPE && IS_AGGR_TYPE (value))
+             || TREE_CODE (value) == ENUMERAL_TYPE)
            {
              my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
              t = value;
@@ -6515,6 +6989,8 @@ check_tag_decl (declspecs)
          if (current_class_type == NULL_TREE
              || current_scope () != current_class_type)
            ob_modifier = value;
+         else
+           saw_friend = 1;
        }
       else if (value == ridpointers[(int) RID_STATIC]
               || value == ridpointers[(int) RID_EXTERN]
@@ -6531,9 +7007,7 @@ check_tag_decl (declspecs)
   if (found_type > 1)
     error ("multiple types in one declaration");
 
-  /* Inside a class, we might be in a friend or access declaration.
-     Until we have a good way of detecting the latter, don't warn.  */
-  if (t == NULL_TREE && ! current_class_type)
+  if (t == NULL_TREE && ! saw_friend)
     pedwarn ("declaration does not declare anything");
 
   /* Check for an anonymous union.  We're careful
@@ -6634,10 +7108,6 @@ groktypename (typename)
    do go through here.  Structure field declarations are done by
    grokfield and not through here.  */
 
-/* Set this to zero to debug not using the temporary obstack
-   to parse initializers.  */
-int debug_temp_inits = 1;
-
 tree
 start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
      tree declarator, declspecs;
@@ -6665,13 +7135,13 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
     }
 
   if (attributes || prefix_attributes)
-    attrlist = build_scratch_list (attributes, prefix_attributes);
+    attrlist = build_tree_list (attributes, prefix_attributes);
   else
     attrlist = NULL_TREE;
 
   decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
                         attrlist);
-                        
+
   if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE)
     return NULL_TREE;
 
@@ -6680,10 +7150,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   if (type == error_mark_node)
     return NULL_TREE;
 
-  context
-    = (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
-      ? DECL_CLASS_CONTEXT (decl)
-      : DECL_CONTEXT (decl);
+  context = DECL_CONTEXT (decl);
 
   if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL
       && context != current_namespace && TREE_CODE (decl) == VAR_DECL)
@@ -6742,11 +7209,11 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
 #ifdef SET_DEFAULT_DECL_ATTRIBUTES
   SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
 #endif
-  
+
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   cplus_decl_attributes (decl, attributes, prefix_attributes);
 
-  if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE)
+  if (context && COMPLETE_TYPE_P (complete_type (context)))
     {
       push_nested_class (context, 2);
 
@@ -6759,7 +7226,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
            {
              if (DECL_CONTEXT (field) != context)
                {
-                 cp_pedwarn ("ANSI C++ does not permit `%T::%D' to be defined as `%T::%D'",
+                 cp_pedwarn ("ISO C++ does not permit `%T::%D' to be defined as `%T::%D'",
                              DECL_CONTEXT (field), DECL_NAME (decl),
                              context, DECL_NAME (decl));
                  DECL_CONTEXT (decl) = DECL_CONTEXT (field);
@@ -6784,8 +7251,8 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
 
       /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set.  */
       DECL_IN_AGGR_P (decl) = 0;
-      if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) 
-         || CLASSTYPE_USE_TEMPLATE (context))
+      if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
+         || CLASSTYPE_TEMPLATE_INSTANTIATION (context))
        {
          SET_DECL_TEMPLATE_SPECIALIZATION (decl);
          /* [temp.expl.spec] An explicit specialization of a static data
@@ -6807,14 +7274,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   tem = maybe_push_decl (decl);
 
   if (processing_template_decl)
-    {
-      if (at_function_scope_p ())
-       push_permanent_obstack ();
-      tem = push_template_decl (tem);
-      if (at_function_scope_p ())
-       pop_obstacks ();
-    }
-
+    tem = push_template_decl (tem);
 
 #if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
   /* Tell the back-end to use or not use .common as appropriate.  If we say
@@ -6824,13 +7284,10 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
      data segment.  */
   DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
 #endif
-  
+
   if (! processing_template_decl)
     start_decl_1 (tem);
 
-  /* Corresponding pop_obstacks is done in `cp_finish_decl'.  */
-  push_obstacks_nochange ();
-
   return tem;
 }
 
@@ -6847,7 +7304,7 @@ start_decl_1 (decl)
   /* If this type of object needs a cleanup, but we're not allowed to
      add any more objects with cleanups to the current scope, create a
      new binding level.  */
-  if (TYPE_NEEDS_DESTRUCTOR (type)
+  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
       && current_binding_level->more_cleanups_ok == 0)
     {
       keep_next_level (2);
@@ -6863,7 +7320,7 @@ start_decl_1 (decl)
     {
       /* Don't allow initializations for incomplete types except for
         arrays which might be completed by the initialization.  */
-      if (TYPE_SIZE (complete_type (type)) != NULL_TREE)
+      if (COMPLETE_TYPE_P (complete_type (type)))
        ;                       /* A complete type is ok.  */
       else if (TREE_CODE (type) != ARRAY_TYPE)
        {
@@ -6872,7 +7329,7 @@ start_decl_1 (decl)
          initialized = 0;
          type = TREE_TYPE (decl) = error_mark_node;
        }
-      else if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)
+      else if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type))))
        {
          if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
            cp_error ("elements of array `%#D' have incomplete type", decl);
@@ -6884,10 +7341,12 @@ start_decl_1 (decl)
   if (!initialized
       && TREE_CODE (decl) != TYPE_DECL
       && TREE_CODE (decl) != TEMPLATE_DECL
-      && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl))
+      && type != error_mark_node
+      && IS_AGGR_TYPE (type) 
+      && ! DECL_EXTERNAL (decl))
     {
       if ((! processing_template_decl || ! uses_template_parms (type))
-         && TYPE_SIZE (complete_type (type)) == NULL_TREE)
+         && !COMPLETE_TYPE_P (complete_type (type)))
        {
          cp_error ("aggregate `%#D' has incomplete type and cannot be initialized",
                 decl);
@@ -6937,7 +7396,7 @@ grok_reference_init (decl, type, init)
 
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
-      cp_error ("ANSI C++ forbids use of initializer list to initialize reference `%D'", decl);
+      cp_error ("ISO C++ forbids use of initializer list to initialize reference `%D'", decl);
       return;
     }
 
@@ -6953,7 +7412,7 @@ grok_reference_init (decl, type, init)
       /* Note: default conversion is only called in very special cases.  */
       init = default_conversion (init);
     }
-  
+
   /* Convert INIT to the reference type TYPE.  This may involve the
      creation of a temporary, whose lifetime must be the same as that
      of the reference.  If so, a DECL_STMT for the temporary will be
@@ -6963,7 +7422,8 @@ grok_reference_init (decl, type, init)
      first.  */
   tmp = convert_to_reference
     (type, init, CONV_IMPLICIT,
-     LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl);
+     LOOKUP_ONLYCONVERTING|LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND,
+     decl);
 
   if (tmp == error_mark_node)
     return;
@@ -7036,12 +7496,9 @@ maybe_deduce_size_from_array_init (decl, init)
       && TYPE_DOMAIN (type) == NULL_TREE
       && TREE_CODE (decl) != TYPE_DECL)
     {
-      int do_default
-       = (TREE_STATIC (decl)
-          /* Even if pedantic, an external linkage array
-             may have incomplete type at first.  */
-          ? pedantic && ! DECL_EXTERNAL (decl)
-          : !DECL_EXTERNAL (decl));
+      /* do_default is really a C-ism to deal with tentative definitions.
+        But let's leave it here to ease the eventual merge.  */
+      int do_default = !DECL_EXTERNAL (decl);
       tree initializer = init ? init : DECL_INITIAL (decl);
       int failure = complete_array_type (type, initializer, do_default);
 
@@ -7077,16 +7534,18 @@ layout_var_decl (decl)
      tree decl;
 {
   tree type = TREE_TYPE (decl);
+#if 0
   tree ttype = target_type (type);
+#endif
 
   /* If we haven't already layed out this declaration, do so now.
      Note that we must not call complete type for an external object
      because it's type might involve templates that we are not
-     supposed to isntantiate yet.  (And it's perfectly legal to say 
+     supposed to isntantiate yet.  (And it's perfectly legal to say
      `extern X x' for some incomplete type `X'.)  */
   if (!DECL_EXTERNAL (decl))
     complete_type (type);
-  if (!DECL_SIZE (decl)&& TYPE_SIZE (type))
+  if (!DECL_SIZE (decl) && COMPLETE_TYPE_P (type))
     layout_decl (decl, 0);
 
   if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
@@ -7097,12 +7556,17 @@ layout_var_decl (decl)
       cp_error ("storage size of `%D' isn't known", decl);
       TREE_TYPE (decl) = error_mark_node;
     }
+#if 0
+  /* Keep this code around in case we later want to control debug info
+     based on whether a type is "used".  (jason 1999-11-11) */
+
   else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
     /* Let debugger know it should output info for this type.  */
     note_debug_info_needed (ttype);
 
   if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
     note_debug_info_needed (DECL_CONTEXT (decl));
+#endif
 
   if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
       && DECL_SIZE (decl) != NULL_TREE
@@ -7127,7 +7591,7 @@ maybe_commonize_var (decl)
      linkage.  */
   if (TREE_STATIC (decl)
       /* Don't mess with __FUNCTION__.  */
-      && ! TREE_ASM_WRITTEN (decl)
+      && ! DECL_ARTIFICIAL (decl)
       && current_function_decl
       && DECL_CONTEXT (decl) == current_function_decl
       && (DECL_THIS_INLINE (current_function_decl)
@@ -7162,7 +7626,7 @@ maybe_commonize_var (decl)
          if (TREE_PUBLIC (decl))
            DECL_ASSEMBLER_NAME (decl)
              = build_static_name (current_function_decl, DECL_NAME (decl));
-         else if (! DECL_ARTIFICIAL (decl))
+         else
            {
              cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
              cp_warning_at ("  you can work around this by removing the initializer", decl);
@@ -7224,18 +7688,18 @@ check_initializer (decl, init)
       if (type == error_mark_node)
        /* We will have already complained.  */
        init = NULL_TREE;
-      else if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
+      else if (COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
        {
          cp_error ("variable-sized object `%D' may not be initialized", decl);
          init = NULL_TREE;
        }
       else if (TREE_CODE (type) == ARRAY_TYPE
-              && !TYPE_SIZE (TREE_TYPE (type)))
+              && !COMPLETE_TYPE_P (TREE_TYPE (type)))
        {
          cp_error ("elements of array `%#D' have incomplete type", decl);
          init = NULL_TREE;
        }
-      else if (!TYPE_SIZE (type))
+      else if (!COMPLETE_TYPE_P (type))
        {
          cp_error ("`%D' has incomplete type", decl);
          TREE_TYPE (decl) = error_mark_node;
@@ -7293,7 +7757,7 @@ check_initializer (decl, init)
     }
   else if (DECL_EXTERNAL (decl))
     ;
-  else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't'
+  else if (TYPE_P (type)
           && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
     {
       tree core_type = strip_array_types (type);
@@ -7309,14 +7773,13 @@ check_initializer (decl, init)
 
       check_for_uninitialized_const_var (decl);
 
-      if (TYPE_SIZE (type) != NULL_TREE
-         && TYPE_NEEDS_CONSTRUCTING (type))
+      if (COMPLETE_TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type))
        init = obscure_complex_init (decl, NULL_TREE);
 
     }
   else
     check_for_uninitialized_const_var (decl);
-  
+
   return init;
 }
 
@@ -7328,11 +7791,8 @@ make_rtl_for_nonlocal_decl (decl, init, asmspec)
      tree init;
      const char *asmspec;
 {
-  int toplev;
-  tree type;
-
-  type = TREE_TYPE (decl);
-  toplev = toplevel_bindings_p ();
+  int toplev = toplevel_bindings_p ();
+  int defer_p;
 
   /* Handle non-variables up front.  */
   if (TREE_CODE (decl) != VAR_DECL)
@@ -7341,97 +7801,56 @@ make_rtl_for_nonlocal_decl (decl, init, asmspec)
       return;
     }
 
-  /* Set the DECL_ASSEMBLER_NAME for the variable.  */
-  if (asmspec)
-    DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
-
-  if (DECL_VIRTUAL_P (decl))
-    make_decl_rtl (decl, NULL_PTR, toplev);
-  else if (TREE_READONLY (decl)
-          && DECL_INITIAL (decl) != NULL_TREE
-          && DECL_INITIAL (decl) != error_mark_node
-          && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
-    {
-      DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
-
-      if (toplev && ! TREE_PUBLIC (decl))
-       {
-         /* If this is a static const, change its apparent linkage
-            if it belongs to a #pragma interface.  */
-         if (!interface_unknown)
-           {
-             TREE_PUBLIC (decl) = 1;
-             DECL_EXTERNAL (decl) = interface_only;
-           }
-         make_decl_rtl (decl, asmspec, toplev);
-       }
-      else if (toplev)
-       rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
-    }
-  else if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl))
+  /* If we see a class member here, it should be a static data
+     member.  */
+  if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl))
     {
       my_friendly_assert (TREE_STATIC (decl), 19990828);
-
-      if (init == NULL_TREE
-#ifdef DEFAULT_STATIC_DEFS
-         /* If this code is dead, then users must
-            explicitly declare static member variables
-            outside the class def'n as well.  */
-         && TYPE_NEEDS_CONSTRUCTING (type)
-#endif
-         )
-       {
-         DECL_EXTERNAL (decl) = 1;
-         make_decl_rtl (decl, asmspec, 1);
-       }
-      else
-       rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+      /* An in-class declaration of a static data member should be
+        external; it is only a declaration, and not a definition.  */
+      if (init == NULL_TREE)
+       my_friendly_assert (DECL_EXTERNAL (decl), 20000723);
     }
-  else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL
-          || (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)))
-    rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
-}
 
-/* Create RTL for the local static variable DECL.  */
+  /* Set the DECL_ASSEMBLER_NAME for the variable.  */
+  if (asmspec)
+    DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+
+  /* We don't create any RTL for local variables.  */
+  if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl))
+    return;
 
-void
-make_rtl_for_local_static (decl)
-     tree decl;
-{
-  tree type = TREE_TYPE (decl);
-  const char *asmspec = NULL;
+  /* We defer emission of local statics until the corresponding
+     DECL_STMT is expanded.  */
+  defer_p = DECL_FUNCTION_SCOPE_P (decl) || DECL_VIRTUAL_P (decl);
 
-  if (TREE_READONLY (decl)
+  /* We try to defer namespace-scope static constants so that they are
+     not emitted into the object file unncessarily.  */
+  if (!DECL_VIRTUAL_P (decl)
+      && TREE_READONLY (decl)
       && DECL_INITIAL (decl) != NULL_TREE
       && DECL_INITIAL (decl) != error_mark_node
       && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))
-      && ! TREE_SIDE_EFFECTS (decl)
-      && ! TREE_PUBLIC (decl)
-      && ! DECL_EXTERNAL (decl)
-      && ! TYPE_NEEDS_DESTRUCTOR (type)
-      && ! TREE_ADDRESSABLE (decl)
-      && DECL_MODE (decl) != BLKmode)
-    {
-      /* As an optimization, we try to put register-sized static
-        constants in a register, rather than writing them out.  If we
-        take the address of the constant later, we'll make RTL for it
-        at that point.  */
-      DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
-      store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
-      TREE_ASM_WRITTEN (decl) = 1;
-      return;
-    }
-
-  if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+      && toplev
+      && !TREE_PUBLIC (decl))
     {
-      /* The only way this situaton can occur is if the
-        user specified a name for this DECL using the
-        `attribute' syntax.  */
-      asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-      DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl);
+      /* Fool with the linkage according to #pragma interface.  */
+      if (!interface_unknown)
+       {
+         TREE_PUBLIC (decl) = 1;
+         DECL_EXTERNAL (decl) = interface_only;
+       }
+
+      defer_p = 1;
     }
 
-  rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0);
+  /* If we're deferring the variable, just make RTL.  Do not actually
+     emit the variable.  */
+  if (defer_p)
+    make_decl_rtl (decl, asmspec, toplev);
+  /* If we're not deferring, go ahead and assemble the variable.  */
+  else
+    rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
 }
 
 /* The old ARM scoping rules injected variables declared in the
@@ -7444,9 +7863,12 @@ void
 maybe_inject_for_scope_var (decl)
      tree decl;
 {
+  if (!DECL_NAME (decl))
+    return;
+  
   if (current_binding_level->is_for_scope)
     {
-      struct binding_level *outer 
+      struct binding_level *outer
        = current_binding_level->level_chain;
 
       /* Check to see if the same name is already bound at the outer
@@ -7458,11 +7880,11 @@ maybe_inject_for_scope_var (decl)
         Otherwise, we need to preserve the temp slot for decl to last
         into the outer binding level.  */
 
-      tree outer_binding 
+      tree outer_binding
        = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
-             
+
       if (outer_binding && BINDING_LEVEL (outer_binding) == outer
-         && (TREE_CODE (BINDING_VALUE (outer_binding)) 
+         && (TREE_CODE (BINDING_VALUE (outer_binding))
              == VAR_DECL)
          && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
        {
@@ -7501,7 +7923,7 @@ initialize_local_var (decl, init, flags)
   if (TREE_STATIC (decl))
     {
       if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
-         || TYPE_NEEDS_DESTRUCTOR (type))
+         || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
        expand_static_init (decl, init);
       return;
     }
@@ -7509,7 +7931,7 @@ initialize_local_var (decl, init, flags)
   if (DECL_SIZE (decl) && type != error_mark_node)
     {
       int already_used;
-  
+
       /* Compute and store the initial value.  */
       already_used = TREE_USED (decl) || TREE_USED (type);
 
@@ -7517,12 +7939,12 @@ initialize_local_var (decl, init, flags)
        {
          int saved_stmts_are_full_exprs_p;
 
-         emit_line_note (DECL_SOURCE_FILE (decl),
-                         DECL_SOURCE_LINE (decl));
-         saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
-         stmts_are_full_exprs_p = 1;
+         my_friendly_assert (building_stmt_tree (), 20000906);
+         saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
+         current_stmt_tree ()->stmts_are_full_exprs_p = 1;
          finish_expr_stmt (build_aggr_init (decl, init, flags));
-         stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
+         current_stmt_tree ()->stmts_are_full_exprs_p = 
+           saved_stmts_are_full_exprs_p;
        }
 
       /* Set this to 0 so we can tell whether an aggregate which was
@@ -7533,7 +7955,7 @@ initialize_local_var (decl, init, flags)
         marked used. (see TREE_USED, above.)  */
       if (TYPE_NEEDS_CONSTRUCTING (type)
          && ! already_used
-         && !TYPE_NEEDS_DESTRUCTOR (type) 
+         && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
          && DECL_NAME (decl))
        TREE_USED (decl) = 0;
       else if (already_used)
@@ -7543,7 +7965,7 @@ initialize_local_var (decl, init, flags)
 
 /* Generate code to destroy DECL (a local variable).  */
 
-void 
+static void
 destroy_local_var (decl)
      tree decl;
 {
@@ -7553,9 +7975,10 @@ destroy_local_var (decl)
   /* Only variables get cleaned up.  */
   if (TREE_CODE (decl) != VAR_DECL)
     return;
-  
+
   /* And only things with destructors need cleaning up.  */
-  if (!TYPE_NEEDS_DESTRUCTOR (type))
+  if (type == error_mark_node
+      || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     return;
 
   if (TREE_CODE (decl) == VAR_DECL &&
@@ -7564,7 +7987,7 @@ destroy_local_var (decl)
        translation unit, or that need a static cleanup.  The latter
        are handled by finish_file.  */
     return;
-  
+
   /* Compute the cleanup.  */
   cleanup = maybe_build_cleanup (decl);
 
@@ -7574,73 +7997,28 @@ destroy_local_var (decl)
     finish_decl_cleanup (decl, cleanup);
 }
 
-/* Let the back-end know about DECL.  */
-
-void
-emit_local_var (decl)
-     tree decl;
-{
-  /* Create RTL for this variable.  */
-  if (DECL_RTL (decl))
-    /* Only a RESULT_DECL should have non-NULL RTL when
-                    arriving here.  All other local variables are
-                    assigned RTL in this function.  */
-    my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 
-                       19990828);
-  else
-    {
-      if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-       /* The user must have specified an assembler name for this
-          variable.  Set that up now.  */
-       rest_of_decl_compilation 
-         (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
-          /*top_level=*/0, /*at_end=*/0);
-      else
-       expand_decl (decl);
-    }
-
-  /* Actually do the initialization.  */
-  expand_start_target_temps ();
-  expand_decl_init (decl);
-  expand_end_target_temps ();
-}
-
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
    it must be determined now, from the initial value, or it is an error.
 
-   Call `pop_obstacks' iff NEED_POP is nonzero.
-
-   For C++, `cp_finish_decl' must be fairly evasive:  it must keep initializers
-   for aggregates that have constructors alive on the permanent obstack,
-   so that the global initializing functions can be written at the end.
-
-   INIT0 holds the value of an initializer that should be allowed to escape
+   INIT holds the value of an initializer that should be allowed to escape
    the normal rules.
 
-   FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0
-   if the (init) syntax was used.
-
-   For functions that take default parameters, DECL points to its
-   "maximal" instantiation.  `cp_finish_decl' must then also declared its
-   subsequently lower and lower forms of instantiation, checking for
-   ambiguity as it goes.  This can be sped up later.  */
+   FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0
+   if the (init) syntax was used.  */
 
 void
-cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
+cp_finish_decl (decl, init, asmspec_tree, flags)
      tree decl, init;
      tree asmspec_tree;
-     int need_pop;
      int flags;
 {
   register tree type;
   tree ttype = NULL_TREE;
-  int temporary = allocation_temporary_p ();
   const char *asmspec = NULL;
   int was_readonly = 0;
 
-  /* If this is 0, then we did not change obstacks.  */
   if (! decl)
     {
       if (init)
@@ -7654,18 +8032,18 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
   if (init && TREE_CODE (init) == NAMESPACE_DECL)
     {
-      cp_error ("Cannot initialize `%D' to namespace `%D'",
+      cp_error ("cannot initialize `%D' to namespace `%D'",
                decl, init);
       init = NULL_TREE;
     }
 
   if (current_class_type
-      && DECL_REAL_CONTEXT (decl) == current_class_type
+      && CP_DECL_CONTEXT (decl) == current_class_type
       && TYPE_BEING_DEFINED (current_class_type)
       && (DECL_INITIAL (decl) || init))
     DECL_DEFINED_IN_CLASS_P (decl) = 1;
 
-  if (TREE_CODE (decl) == VAR_DECL 
+  if (TREE_CODE (decl) == VAR_DECL
       && DECL_CONTEXT (decl)
       && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
       && DECL_CONTEXT (decl) != current_namespace
@@ -7678,16 +8056,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
   type = TREE_TYPE (decl);
 
   if (type == error_mark_node)
-    {
-      if (toplevel_bindings_p () && temporary)
-       end_temporary_allocation ();
-
-      return;
-    }
-
+    return;
+  
   /* Add this declaration to the statement-tree.  */
   if (building_stmt_tree () 
-      && TREE_CODE (current_scope ()) == FUNCTION_DECL)
+      && at_function_scope_p ()
+      && TREE_CODE (decl) != RESULT_DECL)
     add_decl_stmt (decl);
 
   if (TYPE_HAS_MUTABLE_P (type))
@@ -7726,7 +8100,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
         type, and that type has not been defined yet, delay emitting
         the debug information for it, as we will emit it later.  */
       if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl
-         && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE)
+         && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
        TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
 
       rest_of_decl_compilation (decl, NULL_PTR,
@@ -7763,14 +8137,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
   GNU_xref_decl (current_function_decl, decl);
 
-  /* For top-level declaration, the initial value was read in
-     the temporary obstack.  MAXINDEX, rtl, etc. to be made below
-     must go in the permanent obstack; but don't discard the
-     temporary data yet.  */
-
-  if (toplevel_bindings_p () && temporary)
-    end_temporary_allocation ();
-
   if (TREE_CODE (decl) == VAR_DECL)
     layout_var_decl (decl);
 
@@ -7785,11 +8151,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
       make_rtl_for_nonlocal_decl (decl, init, asmspec);
 
-      if (TREE_CODE (type) == FUNCTION_TYPE 
+      if (TREE_CODE (type) == FUNCTION_TYPE
          || TREE_CODE (type) == METHOD_TYPE)
-       abstract_virtuals_error (decl, 
+       abstract_virtuals_error (decl,
                                 strip_array_types (TREE_TYPE (type)));
-      else 
+      else
        abstract_virtuals_error (decl, strip_array_types (type));
 
       if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -7818,8 +8184,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
            {
              /* If we're not building RTL, then we need to do so
                 now.  */
-             if (!building_stmt_tree ())
-               emit_local_var (decl);
+             my_friendly_assert (building_stmt_tree (), 20000906);
              /* Initialize the variable.  */
              initialize_local_var (decl, init, flags);
              /* Clean up the variable.  */
@@ -7830,7 +8195,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
        {
          /* Cleanups for static variables are handled by `finish_file'.  */
          if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
-             || TYPE_NEEDS_DESTRUCTOR (type))
+             || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
            expand_static_init (decl, init);
        }
     finish_end0:
@@ -7839,9 +8204,9 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
         due to initialization of qualified member variable.
         I.e., Foo::x = 10;  */
       {
-       tree context = DECL_REAL_CONTEXT (decl);
+       tree context = CP_DECL_CONTEXT (decl);
        if (context
-           && TREE_CODE_CLASS (TREE_CODE (context)) == 't'
+           && TYPE_P (context)
            && (TREE_CODE (decl) == VAR_DECL
                /* We also have a pushclass done that we need to undo here
                   if we're at top level and declare a method.  */
@@ -7849,7 +8214,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
            /* If size hasn't been set, we're still defining it,
               and therefore inside the class body; don't pop
               the binding level..  */
-           && TYPE_SIZE (context) != NULL_TREE
+           && COMPLETE_TYPE_P (context)
            && context == current_class_type)
          pop_nested_class ();
       }
@@ -7857,30 +8222,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
  finish_end:
 
-  /* If requested, warn about definitions of large data objects.  */
-
-  if (warn_larger_than
-      && ! processing_template_decl
-      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
-      && !DECL_EXTERNAL (decl))
-    {
-      register tree decl_size = DECL_SIZE (decl);
-
-      if (decl_size && TREE_CODE (decl_size) == INTEGER_CST)
-       {
-         unsigned units = TREE_INT_CST_LOW (decl_size) / BITS_PER_UNIT;
-
-         if (units > larger_than_size)
-           warning_with_decl (decl, "size of `%s' is %u bytes", units);
-       }
-    }
-
-  if (need_pop)
-    /* Resume permanent allocation, if not within a function.  The
-       corresponding push_obstacks_nochange is in start_decl,
-       start_method, groktypename, and in grokfield.  */
-    pop_obstacks ();
-
   if (was_readonly)
     TREE_READONLY (decl) = 1;
 }
@@ -7892,52 +8233,217 @@ finish_decl (decl, init, asmspec_tree)
      tree decl, init;
      tree asmspec_tree;
 {
-  cp_finish_decl (decl, init, asmspec_tree, 1, 0);
+  cp_finish_decl (decl, init, asmspec_tree, 0);
 }
 
-/* Generate code to handle the destruction of the function-scoped
-   static variable DECL.  */
+/* Returns a declaration for a VAR_DECL as if:
 
-static void
-destroy_local_static (decl)
-     tree decl;
-{
-  tree cleanup, fcall;
+     extern "C" TYPE NAME;
+
+   had been seen.  Used to create compiler-generated global
+   variables.  */
+
+tree
+declare_global_var (name, type)
+     tree name;
+     tree type;
+{
+  tree decl;
+
+  push_to_top_level ();
+  decl = build_decl (VAR_DECL, name, type);
+  TREE_PUBLIC (decl) = 1;
+  DECL_EXTERNAL (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  pushdecl (decl);
+  cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+  pop_from_top_level ();
+
+  return decl;
+}
+
+/* Returns a pointer to the `atexit' function.  Note that if
+   FLAG_USE_CXA_ATEXIT is non-zero, then this will actually be the new
+   `__cxa_atexit' function specified in the IA64 C++ ABI.  */
+
+static tree
+get_atexit_node ()
+{
+  tree atexit_fndecl;
+  tree arg_types;
+  tree fn_type;
+  tree fn_ptr_type;
+  const char *name;
+
+  if (atexit_node)
+    return atexit_node;
+
+  if (flag_use_cxa_atexit)
+    {
+      /* The declaration for `__cxa_atexit' is:
+
+          int __cxa_atexit (void (*)(void *), void *, void *)
+
+        We build up the argument types and then then function type
+        itself.  */
+
+      /* First, build the pointer-to-function type for the first
+        argument.  */
+      arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+      fn_type = build_function_type (void_type_node, arg_types);
+      fn_ptr_type = build_pointer_type (fn_type);
+      /* Then, build the rest of the argument types.  */
+      arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+      arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
+      arg_types = tree_cons (NULL_TREE, fn_ptr_type, arg_types);
+      /* And the final __cxa_atexit type.  */
+      fn_type = build_function_type (integer_type_node, arg_types);
+      fn_ptr_type = build_pointer_type (fn_type);
+      name = "__cxa_atexit";
+    }
+  else
+    {
+      /* The declaration for `atexit' is:
+
+           int atexit (void (*)());
+
+        We build up the argument types and then then function type
+        itself.  */
+      fn_type = build_function_type (void_type_node, void_list_node);
+      fn_ptr_type = build_pointer_type (fn_type);
+      arg_types = tree_cons (NULL_TREE, fn_ptr_type, void_list_node);
+      /* Build the final atexit type.  */
+      fn_type = build_function_type (integer_type_node, arg_types);
+      name = "atexit";
+    }
+
+  /* Now, build the function declaration.  */
+  push_lang_context (lang_name_c);
+  atexit_fndecl = build_library_fn_ptr (name, fn_type);
+  mark_used (atexit_fndecl);
+  pop_lang_context ();
+  atexit_node = default_conversion (atexit_fndecl);
+
+  return atexit_node;
+}
+
+/* Returns the __dso_handle VAR_DECL.  */
+
+static tree
+get_dso_handle_node ()
+{
+  if (dso_handle_node)
+    return dso_handle_node;
+
+  /* Declare the variable.  */
+  dso_handle_node = declare_global_var (get_identifier ("__dso_handle"),
+                                       ptr_type_node);
+
+  return dso_handle_node;
+}
+
+/* Begin a new function with internal linkage whose job will be simply
+   to destroy some particular variable.  */
+
+static tree
+start_cleanup_fn ()
+{
+  static int counter = 0;
+  int old_interface_unknown = interface_unknown;
+  char name[32];
+  tree parmtypes;
+  tree fntype;
+  tree fndecl;
+
+  push_to_top_level ();
+
+  /* No need to mangle this.  */
+  push_lang_context (lang_name_c);
+
+  interface_unknown = 1;
+
+  /* Build the parameter-types.  */
+  parmtypes = void_list_node;
+  /* Functions passed to __cxa_atexit take an additional parameter.
+     We'll just ignore it.  After we implement the new calling
+     convention for destructors, we can eliminate the use of
+     additional cleanup functions entirely in the -fnew-abi case.  */
+  if (flag_use_cxa_atexit)
+    parmtypes = tree_cons (NULL_TREE, ptr_type_node, parmtypes);
+  /* Build the function type itself.  */
+  fntype = build_function_type (void_type_node, parmtypes);
+  /* Build the name of the function.  */
+  sprintf (name, "__tcf_%d", counter++);
+  /* Build the function declaration.  */
+  fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
+  /* It's a function with internal linkage, generated by the
+     compiler.  */
+  TREE_PUBLIC (fndecl) = 0;
+  DECL_ARTIFICIAL (fndecl) = 1;
+  /* Make the function `inline' so that it is only emitted if it is
+     actually needed.  It is unlikely that it will be inlined, since
+     it is only called via a function pointer, but we avoid unncessary
+     emissions this way.  */
+  DECL_INLINE (fndecl) = 1;
+  /* Build the parameter.  */
+  if (flag_use_cxa_atexit)
+    {
+      tree parmdecl;
+
+      parmdecl = build_decl (PARM_DECL, NULL_TREE, ptr_type_node);
+      DECL_CONTEXT (parmdecl) = fndecl;
+      DECL_ARG_TYPE (parmdecl) = ptr_type_node;
+      TREE_USED (parmdecl) = 1;
+      DECL_ARGUMENTS (fndecl) = parmdecl;
+    }
+
+  pushdecl (fndecl);
+  start_function (/*specs=*/NULL_TREE, fndecl, NULL_TREE, SF_PRE_PARSED);
+  do_pushlevel ();
+
+  interface_unknown = old_interface_unknown;
+
+  pop_lang_context ();
+
+  return current_function_decl;
+}
+
+/* Finish the cleanup function begun by start_cleanup_fn.  */
+
+static void
+end_cleanup_fn ()
+{
+  do_poplevel ();
+
+  expand_body (finish_function (0));
+
+  pop_from_top_level ();
+}
+
+/* Generate code to handle the destruction of DECL, an object with
+   static storage duration.  */
+
+void
+register_dtor_fn (decl)
+     tree decl;
+{
+  tree cleanup;
   tree compound_stmt;
+  tree args;
+  tree fcall;
+
   int saved_flag_access_control;
 
-  if (atexit_node == 0)
-    {
-      tree atexit_fndecl, PFV, pfvlist;
-      /* Remember this information until end of file.  */
-      push_obstacks (&permanent_obstack, &permanent_obstack);
-      PFV = build_pointer_type (build_function_type
-                               (void_type_node, void_list_node));
-
-      pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
-
-      push_lang_context (lang_name_c);
-      /* Note that we do not call pushdecl for this function;
-        there's no reason that this declaration should be
-        accessible to anyone.  */
-      atexit_fndecl
-       = define_function ("atexit",
-                          build_function_type (void_type_node,
-                                               pfvlist),
-                          /*pfn=*/0, NULL_PTR);
-      mark_used (atexit_fndecl);
-      atexit_node = default_conversion (atexit_fndecl);
-      pop_lang_context ();
-      pop_obstacks ();
-    }
-             
+  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
+    return;
+
   /* Call build_cleanup before we enter the anonymous function so that
      any access checks will be done relative to the current scope,
      rather than the scope of the anonymous function.  */
   build_cleanup (decl);
 
   /* Now start the function.  */
-  cleanup = start_anon_func ();
+  cleanup = start_cleanup_fn ();
 
   /* Now, recompute the cleanup.  It may contain SAVE_EXPRs that refer
      to the original function, rather than the anonymous one.  That
@@ -7952,16 +8458,20 @@ destroy_local_static (decl)
   compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
   finish_expr_stmt (fcall);
   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
-  end_anon_func ();
+  end_cleanup_fn ();
 
   /* Call atexit with the cleanup function.  */
   mark_addressable (cleanup);
   cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
-  fcall = build_function_call (atexit_node,
-                              tree_cons (NULL_TREE, 
-                                         cleanup, 
-                                         NULL_TREE));
-  finish_expr_stmt (fcall);
+  if (flag_use_cxa_atexit)
+    {
+      args = tree_cons (NULL_TREE, get_dso_handle_node (), NULL_TREE);
+      args = tree_cons (NULL_TREE, null_pointer_node, args);
+      args = tree_cons (NULL_TREE, cleanup, args);
+    }
+  else
+    args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
+  finish_expr_stmt (build_function_call (get_atexit_node (), args));
 }
 
 void
@@ -7979,22 +8489,19 @@ expand_static_init (decl, init)
   else if (! toplevel_bindings_p ())
     {
       /* Emit code to perform this initialization but once.  */
-      tree temp;
       tree if_stmt;
       tree then_clause;
       tree assignment;
-      tree temp_init;
-
-      /* Remember this information until end of file.  */
-      push_obstacks (&permanent_obstack, &permanent_obstack);
+      tree guard;
+      tree guard_init;
 
       /* Emit code to perform this initialization but once.  This code
         looks like:
 
-           static int temp = 0;
-           if (!temp) {
+           static int guard = 0;
+           if (!guard) {
              // Do initialization.
-            temp = 1;
+            guard = 1;
             // Register variable for destruction at end of program.
           }
 
@@ -8002,7 +8509,7 @@ expand_static_init (decl, init)
         initialization is complete.  This ensures that an exception,
         thrown during the construction, will cause the variable to
         reinitialized when we pass through this code again, as per:
-        
+
           [stmt.dcl]
 
           If the initialization exits by throwing an exception, the
@@ -8012,14 +8519,13 @@ expand_static_init (decl, init)
          In theory, this process should be thread-safe, too; multiple
         threads should not be able to initialize the variable more
         than once.  We don't yet attempt to ensure thread-safety.  */
-      temp = get_temp_name (integer_type_node, 1);
-      rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
+
+      /* Create the guard variable.  */
+      guard = get_guard (decl);
 
       /* Begin the conditional initialization.  */
       if_stmt = begin_if_stmt ();
-      finish_if_stmt_cond (build_binary_op (EQ_EXPR, temp,
-                                           integer_zero_node), 
-                          if_stmt);
+      finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
       then_clause = begin_compound_stmt (/*has_no_scope=*/0);
 
       /* Do the initialization itself.  */
@@ -8041,40 +8547,28 @@ expand_static_init (decl, init)
         the assignment to TEMP into a single expression, ensuring
         that when we call finish_expr_stmt the cleanups will not be
         run until after TEMP is set to 1.  */
-      temp_init = build_modify_expr (temp, NOP_EXPR, integer_one_node);
+      guard_init = set_guard (guard);
       if (assignment)
        {
          assignment = tree_cons (NULL_TREE, assignment,
-                                 build_tree_list (NULL_TREE, 
-                                                  temp_init));
+                                 build_tree_list (NULL_TREE,
+                                                  guard_init));
          assignment = build_compound_expr (assignment);
        }
       else
-       assignment = temp_init;
+       assignment = guard_init;
       finish_expr_stmt (assignment);
 
       /* Use atexit to register a function for destroying this static
         variable.  */
-      if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
-       destroy_local_static (decl);
+      register_dtor_fn (decl);
 
       finish_compound_stmt (/*has_no_scope=*/0, then_clause);
       finish_then_clause (if_stmt);
       finish_if_stmt ();
-
-      /* Resume old (possibly temporary) allocation.  */
-      pop_obstacks ();
     }
   else
-    {
-      /* This code takes into account memory allocation policy of
-        `start_decl'.  Namely, if TYPE_NEEDS_CONSTRUCTING does not
-        hold for this object, then we must make permanent the storage
-        currently in the temporary obstack.  */
-      if (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
-       preserve_initializer ();
-      static_aggregates = tree_cons (init, decl, static_aggregates);
-    }
+    static_aggregates = tree_cons (init, decl, static_aggregates);
 }
 
 /* Finish the declaration of a catch-parameter.  */
@@ -8110,14 +8604,21 @@ complete_array_type (type, initial_value, do_default)
 {
   register tree maxindex = NULL_TREE;
   int value = 0;
-  
-  /* Allocate on the same obstack as TYPE.  */
-  push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-  
+
   if (initial_value)
     {
-      /* Note MAXINDEX  is really the maximum index,
-        one less than the size.  */
+      /* An array of character type can be initialized from a
+        brace-enclosed string constant.  */
+      if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+         && TREE_CODE (initial_value) == CONSTRUCTOR
+         && CONSTRUCTOR_ELTS (initial_value)
+         && (TREE_CODE (TREE_VALUE (CONSTRUCTOR_ELTS (initial_value)))
+             == STRING_CST)
+         && TREE_CHAIN (CONSTRUCTOR_ELTS (initial_value)) == NULL_TREE)
+       initial_value = TREE_VALUE (CONSTRUCTOR_ELTS (initial_value));
+
+      /* Note MAXINDEX is really the maximum index, one less than the
+        size.  */
       if (TREE_CODE (initial_value) == STRING_CST)
        {
          int eltsize
@@ -8128,13 +8629,14 @@ complete_array_type (type, initial_value, do_default)
       else if (TREE_CODE (initial_value) == CONSTRUCTOR)
        {
          tree elts = CONSTRUCTOR_ELTS (initial_value);
-         maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node);
+
+         maxindex = ssize_int (-1);
          for (; elts; elts = TREE_CHAIN (elts))
            {
              if (TREE_PURPOSE (elts))
                maxindex = TREE_PURPOSE (elts);
              else
-               maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node);
+               maxindex = size_binop (PLUS_EXPR, maxindex, ssize_int (1));
            }
          maxindex = copy_node (maxindex);
        }
@@ -8181,8 +8683,6 @@ complete_array_type (type, initial_value, do_default)
        TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = domain;
     }
 
-  pop_obstacks();
-  
   /* Lay out the type now that we can get the real answer.  */
 
   layout_type (type);
@@ -8195,13 +8695,18 @@ complete_array_type (type, initial_value, do_default)
    message to print in that case.  Otherwise, quietly return 1.  */
 
 static int
-member_function_or_else (ctype, cur_type, string)
+member_function_or_else (ctype, cur_type, flags)
      tree ctype, cur_type;
-     const char *string;
+     enum overload_flags flags;
 {
   if (ctype && ctype != cur_type)
     {
-      error (string, TYPE_NAME_STRING (ctype));
+      if (flags == DTOR_FLAG)
+       cp_error ("destructor for alien class `%T' cannot be a member",
+                 ctype);
+      else
+       cp_error ("constructor for alien class `%T' cannot be a member",
+                 ctype);
       return 0;
     }
   return 1;
@@ -8241,7 +8746,7 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
    or `volatile'.
    RAISES is a list of exceptions that this function can raise.
    CHECK is 1 if we must find this method in CTYPE, 0 if we should
-   not look, and -1 if we should not call `grokclassfn' at all.  
+   not look, and -1 if we should not call `grokclassfn' at all.
 
    Returns `NULL_TREE' if something goes wrong, after issuing
    applicable error messages.  */
@@ -8283,7 +8788,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
-  else if (publicp && ! ctype)
+  else if (!ctype)
     DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
 
   /* `main' and builtins have implicit 'C' linkage.  */
@@ -8306,16 +8811,19 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
     }
 
   if (ctype)
-    DECL_CLASS_CONTEXT (decl) = ctype;
+    DECL_CONTEXT (decl) = ctype;
 
   if (ctype == NULL_TREE && DECL_MAIN_P (decl))
     {
       if (processing_template_decl)
-       error ("cannot declare `main' to be a template");
+       error ("cannot declare `::main' to be a template");
       if (inlinep)
-       error ("cannot declare `main' to be inline");
-      else if (! publicp)
-       error ("cannot declare `main' to be static");
+       error ("cannot declare `::main' to be inline");
+      if (!publicp)
+       error ("cannot declare `::main' to be static");
+      if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),
+                       integer_type_node))
+       error ("`main' must return `int'");
       inlinep = 0;
       publicp = 1;
     }
@@ -8323,7 +8831,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   /* Members of anonymous types and local classes have no linkage; make
      them internal.  */
   if (ctype && (ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype))
-               || hack_decl_function_context (TYPE_MAIN_DECL (ctype))))
+               || decl_function_context (TYPE_MAIN_DECL (ctype))))
     publicp = 0;
 
   if (publicp)
@@ -8338,7 +8846,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        {
          if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
            {
-             if (DECL_LANGUAGE (decl) == lang_c)
+             if (DECL_EXTERN_C_P (decl))
                /* Allow this; it's pretty common in C.  */;
              else
                cp_pedwarn ("non-local function `%#D' uses anonymous type",
@@ -8371,7 +8879,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
     grok_op_properties (decl, virtualp, check < 0);
 
-  if (ctype && hack_decl_function_context (decl))
+  if (ctype && decl_function_context (decl))
     DECL_NO_STATIC_CHAIN (decl) = 1;
 
   for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
@@ -8394,7 +8902,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
          if (PROCESSING_REAL_TEMPLATE_DECL_P ())
            {
              /* Something like `template <class T> friend void f<T>()'.  */
-             cp_error ("template-id `%D' in declaration of primary template", 
+             cp_error ("invalid use of template-id `%D' in declaration of primary template",
                        orig_declarator);
              return NULL_TREE;
            }
@@ -8417,7 +8925,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
          if (inlinep)
            {
-             cp_error ("`inline' is not allowed in declaration of friend template specialization `%D'", 
+             cp_error ("`inline' is not allowed in declaration of friend template specialization `%D'",
                        decl);
              return NULL_TREE;
            }
@@ -8429,7 +8937,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
   /* Plain overloading: will not be grok'd by grokclassfn.  */
   if (! ctype && ! processing_template_decl
-      && DECL_LANGUAGE (decl) != lang_c
+      && !DECL_EXTERN_C_P (decl)
       && (! DECL_USE_TEMPLATE (decl) || name_mangling_version < 1))
     set_mangled_name_for_decl (decl);
 
@@ -8438,103 +8946,85 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        tentative.  error_mark_node is replaced later with the BLOCK.  */
     DECL_INITIAL (decl) = error_mark_node;
 
+  if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
+    TREE_NOTHROW (decl) = 1;
+
   /* Caller will do the rest of this.  */
   if (check < 0)
     return decl;
 
   if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
+    DECL_CONSTRUCTOR_P (decl) = 1;
+
+  /* Function gets the ugly name, field gets the nice one.  This call
+     may change the type of the function (because of default
+     parameters)!  */
+  if (ctype != NULL_TREE)
+    grokclassfn (ctype, decl, flags, quals);
+
+  decl = check_explicit_specialization (orig_declarator, decl,
+                                       template_count,
+                                       2 * (funcdef_flag != 0) +
+                                       4 * (friendp != 0));
+  if (decl == error_mark_node)
+    return NULL_TREE;
+
+  if (ctype != NULL_TREE
+      && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
+      && check)
     {
-      tree tmp;
-      /* Just handle constructors here.  We could do this
-        inside the following if stmt, but I think
-        that the code is more legible by breaking this
-        case out.  See comments below for what each of
-        the following calls is supposed to do.  */
-      DECL_CONSTRUCTOR_P (decl) = 1;
-
-      grokclassfn (ctype, decl, flags, quals);
-
-      decl = check_explicit_specialization (orig_declarator, decl,
-                                           template_count, 
-                                           2 * (funcdef_flag != 0) + 
-                                           4 * (friendp != 0));
-      if (decl == error_mark_node)
-       return NULL_TREE;
+      tree old_decl;
 
-      if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
-         && check)
-       {
-         tmp = check_classfn (ctype, decl);
+      old_decl = check_classfn (ctype, decl);
 
-         if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
-           tmp = DECL_TEMPLATE_RESULT(tmp);
+      if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
+       /* Because grokfndecl is always supposed to return a
+          FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
+          here.  We depend on our callers to figure out that its
+          really a template that's being returned.  */
+       old_decl = DECL_TEMPLATE_RESULT (old_decl);
 
-         if (tmp && DECL_ARTIFICIAL (tmp))
-           cp_error ("definition of implicitly-declared `%D'", tmp);
-         if (tmp && duplicate_decls (decl, tmp))
-           return tmp;
+      if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
+         && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+       {
+         /* Remove the `this' parm added by grokclassfn.
+            XXX Isn't this done in start_function, too?  */
+         revert_static_member_fn (decl);
+         last_function_parms = TREE_CHAIN (last_function_parms);
        }
-      if (! grok_ctor_properties (ctype, decl))
-       return NULL_TREE;
-    }
-  else
-    {
-      tree tmp;
-
-      /* Function gets the ugly name, field gets the nice one.
-        This call may change the type of the function (because
-        of default parameters)!  */
-      if (ctype != NULL_TREE)
-       grokclassfn (ctype, decl, flags, quals);
-
-      decl = check_explicit_specialization (orig_declarator, decl,
-                                           template_count, 
-                                           2 * (funcdef_flag != 0) + 
-                                           4 * (friendp != 0));
-      if (decl == error_mark_node)
-       return NULL_TREE;
+      if (old_decl && DECL_ARTIFICIAL (old_decl))
+       cp_error ("definition of implicitly-declared `%D'", old_decl);
 
-      if (ctype != NULL_TREE
-         && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
-         && check)
+      if (old_decl)
        {
-         tmp = check_classfn (ctype, decl);
+         /* Since we've smashed OLD_DECL to its
+            DECL_TEMPLATE_RESULT, we must do the same to DECL.  */
+         if (TREE_CODE (decl) == TEMPLATE_DECL)
+           decl = DECL_TEMPLATE_RESULT (decl);
 
-         if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
-           tmp = DECL_TEMPLATE_RESULT (tmp);
-             
-         if (tmp && DECL_STATIC_FUNCTION_P (tmp)
-             && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-           {
-             /* Remove the `this' parm added by grokclassfn.
-                XXX Isn't this done in start_function, too?  */
-             revert_static_member_fn (&decl, NULL, NULL);
-             last_function_parms = TREE_CHAIN (last_function_parms);
-           }
-         if (tmp && DECL_ARTIFICIAL (tmp))
-           cp_error ("definition of implicitly-declared `%D'", tmp);
-         if (tmp)
-           {
-             /* Attempt to merge the declarations.  This can fail, in
-                the case of some illegal specialization declarations.  */
-             if (!duplicate_decls (decl, tmp))
-               cp_error ("no `%#D' member function declared in class `%T'",
-                         decl, ctype);
-             return tmp;
-           }
+         /* Attempt to merge the declarations.  This can fail, in
+            the case of some illegal specialization declarations.  */
+         if (!duplicate_decls (decl, old_decl))
+           cp_error ("no `%#D' member function declared in class `%T'",
+                     decl, ctype);
+         return old_decl;
        }
+    }
 
-      if (ctype == NULL_TREE || check)
-       return decl;
+  if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
+    return NULL_TREE;
 
-      if (virtualp)
-       {
-         DECL_VIRTUAL_P (decl) = 1;
-         if (DECL_VINDEX (decl) == NULL_TREE)
-           DECL_VINDEX (decl) = error_mark_node;
-         IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
-       }
+  if (ctype == NULL_TREE || check)
+    return decl;
+
+  if (virtualp)
+    {
+      DECL_VIRTUAL_P (decl) = 1;
+      if (DECL_VINDEX (decl) == NULL_TREE)
+       DECL_VINDEX (decl) = error_mark_node;
+      IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
     }
+
   return decl;
 }
 
@@ -8560,8 +9050,16 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
       type = TREE_TYPE (type);
       decl = build_lang_decl (VAR_DECL, declarator, type);
       DECL_CONTEXT (decl) = basetype;
-      DECL_CLASS_CONTEXT (decl) = basetype;
-      DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator);
+      /* DECL_ASSEMBLER_NAME is needed only for full-instantiated
+        templates.  */
+      if (!uses_template_parms (decl))
+       {
+         if (flag_new_abi)
+           DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
+         else
+           DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype,
+                                                           declarator);
+       }
     }
   else
     {
@@ -8574,14 +9072,10 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
       else
        context = NULL_TREE;
 
-      if (processing_template_decl) 
-       {
-         /* If we're in a template, we need DECL_LANG_SPECIFIC so that
-            we can call push_template_decl.  */
-         push_permanent_obstack ();
-         decl = build_lang_decl (VAR_DECL, declarator, type);
-         pop_obstacks ();
-       }
+      if (processing_template_decl && context)
+       /* For global variables, declared in a template, we need the
+          full lang_decl.  */
+       decl = build_lang_decl (VAR_DECL, declarator, type);
       else
        decl = build_decl (VAR_DECL, declarator, type);
 
@@ -8589,8 +9083,14 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
        set_decl_namespace (decl, context, 0);
 
       context = DECL_CONTEXT (decl);
-      if (declarator && context && current_lang_name != lang_name_c)
-       DECL_ASSEMBLER_NAME (decl) = build_static_name (context, declarator);
+      if (declarator && context && current_lang_name != lang_name_c) 
+       {
+         if (flag_new_abi)
+           DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
+         else
+           DECL_ASSEMBLER_NAME (decl) 
+             = build_static_name (context, declarator);
+       }
     }
 
   if (in_namespace)
@@ -8668,34 +9168,39 @@ build_ptrmemfunc_type (type)
   /* Make sure that we always have the unqualified pointer-to-member
      type first.  */
   if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
-    unqualified_variant 
+    unqualified_variant
       = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
 
-  push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-
-  u = make_lang_type (UNION_TYPE);
-  SET_IS_AGGR_TYPE (u, 0);
-  fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
-  fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
-                              delta_type_node);
-  finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
-  TYPE_NAME (u) = NULL_TREE;
-
-  t = make_lang_type (RECORD_TYPE);
-
+  t = make_aggr_type (RECORD_TYPE);
   /* Let the front-end know this is a pointer to member function...  */
   TYPE_PTRMEMFUNC_FLAG (t) = 1;
   /* ... and not really an aggregate.  */
   SET_IS_AGGR_TYPE (t, 0);
 
-  fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
-                              delta_type_node);
-  fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
-                              delta_type_node);
-  fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
-  finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
+  if (!flag_new_abi)
+    {
+      u = make_aggr_type (UNION_TYPE);
+      SET_IS_AGGR_TYPE (u, 0);
+      fields[0] = build_decl (FIELD_DECL, pfn_identifier, type);
+      fields[1] = build_decl (FIELD_DECL, delta2_identifier,
+                             delta_type_node);
+      finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
+      TYPE_NAME (u) = NULL_TREE;
 
-  pop_obstacks ();
+      fields[0] = build_decl (FIELD_DECL, delta_identifier,
+                             delta_type_node);
+      fields[1] = build_decl (FIELD_DECL, index_identifier,
+                             delta_type_node);
+      fields[2] = build_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
+      finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
+    }
+  else
+    {
+      fields[0] = build_decl (FIELD_DECL, pfn_identifier, type);
+      fields[1] = build_decl (FIELD_DECL, delta_identifier,
+                             delta_type_node);
+      finish_builtin_type (t, "__ptrmemfunc_type", fields, 1, ptr_type_node);
+    }
 
   /* Zap out the name so that the back-end will give us the debugging
      information for this anonymous RECORD_TYPE.  */
@@ -8741,7 +9246,7 @@ check_static_variable_definition (decl, type)
      required.  */
   if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
     {
-      cp_error ("in-class initialization of static data member of non-integral type `%T'", 
+      cp_error ("invalid in-class initialization of static data member of non-integral type `%T'",
                type);
       /* If we just return the declaration, crashes will sometimes
         occur.  We therefore return void_type_node, as if this was a
@@ -8750,10 +9255,10 @@ check_static_variable_definition (decl, type)
       return 1;
     }
   else if (!CP_TYPE_CONST_P (type))
-    cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+    cp_error ("ISO C++ forbids in-class initialization of non-const static member `%D'",
              decl);
   else if (pedantic && !INTEGRAL_TYPE_P (type))
-    cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
+    cp_pedwarn ("ISO C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
 
   return 0;
 }
@@ -8762,7 +9267,7 @@ check_static_variable_definition (decl, type)
    appropriate index type for the array.  If non-NULL, NAME is the
    name of the thing being declared.  */
 
-static tree
+tree
 compute_array_index_type (name, size)
      tree name;
      tree size;
@@ -8773,8 +9278,7 @@ compute_array_index_type (name, size)
   STRIP_TYPE_NOPS (size);
 
   /* It might be a const variable or enumeration constant.  */
-  if (TREE_READONLY_DECL_P (size))
-    size = decl_constant_value (size);
+  size = decl_constant_value (size);
 
   /* If this involves a template parameter, it will be a constant at
      instantiation time, but we don't know what the value is yet.
@@ -8803,12 +9307,15 @@ compute_array_index_type (name, size)
       && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE
       && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE)
     {
-      cp_error ("size of array `%D' has non-integer type", name);
+      if (name)
+       cp_error ("size of array `%D' has non-integer type", name);
+      else
+       cp_error ("size of array has non-integer type");
       size = integer_one_node;
     }
 
   /* Normally, the array-bound will be a constant.  */
-  if (TREE_CONSTANT (size))
+  if (TREE_CODE (size) == INTEGER_CST)
     {
       /* Check to see if the array bound overflowed.  Make that an
         error, no matter how generous we're being.  */
@@ -8822,24 +9329,41 @@ compute_array_index_type (name, size)
       /* An array must have a positive number of elements.  */
       if (INT_CST_LT (size, integer_zero_node))
        {
-         cp_error ("size of array `%D' is negative", name);
+         if (name)
+           cp_error ("size of array `%D' is negative", name);
+         else
+           cp_error ("size of array is negative");
          size = integer_one_node;
        }
       /* Except that an extension we allow zero-sized arrays.  We
-        always allow them in system headers because glibc uses 
+        always allow them in system headers because glibc uses
         them.  */
       else if (integer_zerop (size) && pedantic && !in_system_header)
-       cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", name);
+       {
+         if (name)
+           cp_pedwarn ("ISO C++ forbids zero-size array `%D'", name);
+         else
+           cp_pedwarn ("ISO C++ forbids zero-size array");
+       }
+    }
+  else if (TREE_CONSTANT (size))
+    {
+      /* `(int) &fn' is not a valid array bound.  */
+      if (name)
+       cp_error ("size of array `%D' is not an integral constant-expression",
+                 name);
+      else
+       cp_error ("size of array is not an integral constant-expression");
     }
 
   /* Compute the index of the largest element in the array.  It is
      one less than the number of elements in the array.  */
   itype
-    = fold (build_binary_op (MINUS_EXPR,
-                            cp_convert (ssizetype, size),
-                            cp_convert (ssizetype,
-                                        integer_one_node)));
-  
+    = fold (cp_build_binary_op (MINUS_EXPR,
+                               cp_convert (ssizetype, size),
+                               cp_convert (ssizetype,
+                                           integer_one_node)));
+
   /* Check for variable-sized arrays.  We allow such things as an
      extension, even though they are not allowed in ANSI/ISO C++.  */
   if (!TREE_CONSTANT (itype))
@@ -8847,10 +9371,10 @@ compute_array_index_type (name, size)
       if (pedantic)
        {
          if (name)
-           cp_pedwarn ("ANSI C++ forbids variable-size array `%D'",
+           cp_pedwarn ("ISO C++ forbids variable-size array `%D'",
                        name);
          else
-           cp_pedwarn ("ANSI C++ forbids variable-size array");
+           cp_pedwarn ("ISO C++ forbids variable-size array");
        }
 
       /* Create a variable-sized array index type.  */
@@ -8864,7 +9388,7 @@ compute_array_index_type (name, size)
       error ("overflow in array dimension");
       TREE_OVERFLOW (itype) = 0;
     }
-  
+
   /* Create and return the appropriate index type.  */
   return build_index_type (itype);
 }
@@ -8928,14 +9452,13 @@ create_array_type_for_decl (name, type, size)
     }
 
   /* [dcl.array]
-     
+
      The constant expressions that specify the bounds of the arrays
      can be omitted only for the first member of the sequence.  */
   if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
     {
-      cp_error ("declaration of `%D' as multidimensional array",
+      cp_error ("declaration of `%D' as multidimensional array must have bounds for all dimensions except the first",
                name);
-      cp_error ("must have bounds for all dimensions except the first");
 
       return error_mark_node;
     }
@@ -8947,6 +9470,54 @@ create_array_type_for_decl (name, type, size)
   return build_cplus_array_type (type, itype);
 }
 
+/* Check that it's OK to declare a function with the indicated TYPE.
+   SFK indicates the kind of special function (if any) that this
+   function is.  CTYPE is the class of which this function is a
+   member.  OPTYPE is the type given in a conversion operator
+   declaration.  Returns the actual return type of the function; that
+   may be different than TYPE if an error occurs, or for certain
+   special functions.  */
+
+static tree
+check_special_function_return_type (sfk, type, ctype, optype)
+     special_function_kind sfk;
+     tree type;
+     tree ctype;
+     tree optype;
+{
+  switch (sfk)
+    {
+    case sfk_constructor:
+      if (type)
+       cp_error ("return type specification for constructor invalid");
+       
+      /* In the old ABI, we return `this'; in the new ABI we don't
+        bother.  */
+      type = flag_new_abi ? void_type_node : build_pointer_type        (ctype);
+      break;
+
+    case sfk_destructor:
+      if (type)
+       cp_error ("return type specification for destructor invalid");
+      type = void_type_node;
+      break;
+
+    case sfk_conversion:
+      if (type && !same_type_p (type, optype))
+       cp_error ("operator `%T' declared to return `%T'", optype, type);
+      else if (type)
+       cp_pedwarn ("return type specified for `operator %T'",  optype);
+      type = optype;
+      break;
+
+    default:
+      my_friendly_abort (20000408);
+      break;
+    }
+
+  return type;
+}
+
 /* Given declspecs and a declarator,
    determine the name and type of the object declared
    and construct a ..._DECL node for it.
@@ -8977,7 +9548,7 @@ create_array_type_for_decl (name, type, size)
    ATTRLIST is a TREE_LIST node with prefix attributes in TREE_VALUE and
    normal attributes in TREE_PURPOSE, or NULL_TREE.
 
-   In the TYPENAME case, DECLARATOR is really an absolute declarator.
+   In the TYPENAME case, DECLARATOR is really an abstract declarator.
    It may also be so in the PARM case, for a prototype where the
    argument type is specified but not the name.
 
@@ -9001,13 +9572,12 @@ create_array_type_for_decl (name, type, size)
    is erroneous, NULL_TREE is returned.
 
    QUALS is used only for FUNCDEF and MEMFUNCDEF cases.  For a member
-   function, these are the qualifiers to give to the `this' pointer.
+   function, these are the qualifiers to give to the `this' pointer. We
+   apply TYPE_QUAL_RESTRICT to the this ptr, not the object.
 
    May return void_type_node if the declarator turned out to be a friend.
    See grokfield for details.  */
 
-enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
-
 tree
 grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      tree declspecs;
@@ -9046,7 +9616,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   /* Keep track of what sort of function is being processed
      so that we can warn about default return values, or explicit
      return values which do not match prescribed defaults.  */
-  enum return_types return_type = return_normal;
+  special_function_kind sfk = sfk_none;
 
   tree dname = NULL_TREE;
   tree ctype = current_class_type;
@@ -9096,7 +9666,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
              my_friendly_assert (flags == NO_SPECIAL, 152);
              flags = DTOR_FLAG;
-             return_type = return_dtor;
+             sfk = sfk_destructor;
              if (TREE_CODE (name) == TYPE_DECL)
                TREE_OPERAND (decl, 0) = name = constructor_name (name);
              my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
@@ -9166,6 +9736,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
                decl = start_decl (declarator, declspecs, 1,
                                   attributes, prefix_attributes);
+               decl_type_access_control (decl);
                if (decl)
                  {
                    /* Look for __unused__ attribute */
@@ -9194,12 +9765,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                && decl != NULL_TREE && flags != DTOR_FLAG
                && decl == constructor_name (ctype))
              {
-               return_type = return_ctor;
+               sfk = sfk_constructor;
                ctor_return_type = ctype;
              }
            ctype = NULL_TREE;
            break;
-           
+
          case TEMPLATE_ID_EXPR:
              {
                tree fns = TREE_OPERAND (decl, 0);
@@ -9225,26 +9796,26 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            next = 0;
 
-           if (is_rid (dname))
+           if (C_IS_RESERVED_WORD (dname))
              {
                cp_error ("declarator-id missing; using reserved word `%D'",
                          dname);
                name = IDENTIFIER_POINTER (dname);
              }
-           if (! IDENTIFIER_OPNAME_P (dname)
-               /* GNU/Linux headers use '__op'.  Arrgh.  */
-               || (IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname)))
+           else if (!IDENTIFIER_TYPENAME_P (dname))
              name = IDENTIFIER_POINTER (dname);
            else
              {
-               if (IDENTIFIER_TYPENAME_P (dname))
-                 {
-                   my_friendly_assert (flags == NO_SPECIAL, 154);
-                   flags = TYPENAME_FLAG;
-                   ctor_return_type = TREE_TYPE (dname);
-                   return_type = return_conversion;
-                 }
-               name = operator_name_string (dname);
+               my_friendly_assert (flags == NO_SPECIAL, 154);
+               flags = TYPENAME_FLAG;
+               ctor_return_type = TREE_TYPE (dname);
+               sfk = sfk_conversion;
+               if (IDENTIFIER_GLOBAL_VALUE (dname)
+                   && (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (dname)) 
+                       == TYPE_DECL))
+                 name = IDENTIFIER_POINTER (dname);
+               else
+                 name = "<invalid operator>";
              }
            break;
 
@@ -9269,7 +9840,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                       && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
                ctype = cname;
              else if (TREE_CODE (cname) == TEMPLATE_TYPE_PARM
-                      || TREE_CODE (cname) == TEMPLATE_TEMPLATE_PARM)
+                      || TREE_CODE (cname) == BOUND_TEMPLATE_TEMPLATE_PARM)
                {
                  cp_error ("`%T::%D' is not a valid declarator", cname,
                            TREE_OPERAND (decl, 1));
@@ -9306,7 +9877,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  if (TREE_CODE (decl) == IDENTIFIER_NODE
                      && constructor_name (ctype) == decl)
                    {
-                     return_type = return_ctor;
+                     sfk = sfk_constructor;
                      ctor_return_type = ctype;
                    }
                  else if (TREE_CODE (decl) == BIT_NOT_EXPR
@@ -9314,7 +9885,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                           && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
                               || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
                    {
-                     return_type = return_dtor;
+                     sfk = sfk_destructor;
                      ctor_return_type = ctype;
                      flags = DTOR_FLAG;
                      TREE_OPERAND (decl, 0) = constructor_name (ctype);
@@ -9341,8 +9912,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            /* Avoid giving two errors for this.  */
            IDENTIFIER_CLASS_VALUE (dname) = NULL_TREE;
 
-           declspecs = temp_tree_cons (NULL_TREE, integer_type_node,
-                                       declspecs);
+           declspecs = tree_cons (NULL_TREE, integer_type_node, declspecs);
            *next = dname;
            next = 0;
            break;
@@ -9393,7 +9963,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
-  
+
   /* Look through the decl specs and record which ones appear.
      Some typespecs are defined as built-in typenames.
      Others, the ones that are modifiers of other types,
@@ -9464,7 +10034,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits))
                    {
                      if (pedantic && ! in_system_header && warn_long_long)
-                       pedwarn ("ANSI C++ does not support `long long'");
+                       pedwarn ("ISO C++ does not support `long long'");
                      if (longlong)
                        error ("`long long long' is too long for GCC");
                      else
@@ -9478,7 +10048,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            }
        }
       /* C++ aggregate types.  */
-      else if (TREE_CODE (id) == TYPE_DECL || TREE_CODE (id) == TEMPLATE_DECL)
+      else if (TREE_CODE (id) == TYPE_DECL)
        {
          if (type)
            cp_error ("multiple declarations `%T' and `%T'", type,
@@ -9531,58 +10101,35 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       defaulted_int = 1;
     }
 
-  if (type == NULL_TREE)
+  if (sfk != sfk_none)
+    type = check_special_function_return_type (sfk, type,
+                                              ctor_return_type,
+                                              ctor_return_type);
+  else if (type == NULL_TREE)
     {
+      int is_main;
+
       explicit_int = -1;
-      if (return_type == return_dtor)
-       type = void_type_node;
-      else if (return_type == return_ctor)
-       type = build_pointer_type (ctor_return_type);
-      else if (return_type == return_conversion)
-       type = ctor_return_type;
-      else
-       {
+
          /* We handle `main' specially here, because 'main () { }' is so
             common.  With no options, it is allowed.  With -Wreturn-type,
             it is a warning.  It is only an error with -pedantic-errors.  */
-         int is_main = (funcdef_flag
-                        && MAIN_NAME_P (dname)
-                        && ctype == NULL_TREE
-                        && in_namespace == NULL_TREE
-                        && current_namespace == global_namespace);
-
-         if (in_system_header || flag_ms_extensions)
-           /* Allow it, sigh.  */;
-         else if (pedantic || ! is_main)
-           cp_pedwarn ("ANSI C++ forbids declaration of `%s' with no type",
-                       name);
-         else if (warn_return_type)
-           cp_warning ("ANSI C++ forbids declaration of `%s' with no type",
-                       name);
-
-         type = integer_type_node;
-       }
-    }
-  else if (return_type == return_dtor)
-    {
-      error ("return type specification for destructor invalid");
-      type = void_type_node;
-    }
-  else if (return_type == return_ctor)
-    {
-      error ("return type specification for constructor invalid");
-      type = build_pointer_type (ctor_return_type);
-    }
-  else if (return_type == return_conversion)
-    {
-      if (!same_type_p (type, ctor_return_type))
-       cp_error ("operator `%T' declared to return `%T'",
-                 ctor_return_type, type);
-      else
-       cp_pedwarn ("return type specified for `operator %T'",
-                   ctor_return_type);
+      is_main = (funcdef_flag
+                && MAIN_NAME_P (dname)
+                && ctype == NULL_TREE
+                && in_namespace == NULL_TREE
+                && current_namespace == global_namespace);
+
+      if (in_system_header || flag_ms_extensions)
+       /* Allow it, sigh.  */;
+      else if (pedantic || ! is_main)
+       cp_pedwarn ("ISO C++ forbids declaration of `%s' with no type",
+                   name);
+      else if (warn_return_type)
+       cp_warning ("ISO C++ forbids declaration of `%s' with no type",
+                   name);
 
-      type = ctor_return_type;
+      type = integer_type_node;
     }
 
   ctype = NULL_TREE;
@@ -9596,7 +10143,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       && TYPE_MAIN_VARIANT (type) == double_type_node)
     {
       RIDBIT_RESET (RID_LONG, specbits);
-      type = build_qualified_type (long_double_type_node, 
+      type = build_qualified_type (long_double_type_node,
                                   CP_TYPE_QUALS (type));
     }
 
@@ -9665,7 +10212,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
         It is implementation-defined whether a plain (neither
         explicitly signed or unsigned) char, short, int, or long
         bit-field is signed or unsigned.
-            
+
         Naturally, we extend this to long long as well.  Note that
         this does not include wchar_t.  */
       || (bitfield && !flag_signed_bitfields
@@ -9673,7 +10220,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          /* A typedef for plain `int' without `signed' can be
             controlled just like plain `int', but a typedef for
             `signed int' cannot be so controlled.  */
-         && !(typedef_decl 
+         && !(typedef_decl
               && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))
          && (TREE_CODE (type) == INTEGER_TYPE
              || TREE_CODE (type) == CHAR_TYPE)
@@ -9727,7 +10274,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        type = build_complex_type (type);
     }
 
-  if (return_type == return_conversion 
+  if (sfk == sfk_conversion
       && (RIDBIT_SETP (RID_CONST, specbits)
          || RIDBIT_SETP (RID_VOLATILE, specbits)
          || RIDBIT_SETP (RID_RESTRICT, specbits)))
@@ -9739,9 +10286,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      Likewise for VOLATILEP.  */
 
   constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type);
-  restrictp = 
+  restrictp =
     !! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type);
-  volatilep = 
+  volatilep =
     !! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type);
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
                | (restrictp ? TYPE_QUAL_RESTRICT : 0)
@@ -9826,21 +10373,33 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
              if (declarator)
                {
-                 /* Avoid trying to get an operand off an identifier node.  */ 
+                 /* Avoid trying to get an operand off an identifier node.  */
                  if (TREE_CODE (declarator) == IDENTIFIER_NODE)
                    tmp = declarator;
                  else
                    tmp = TREE_OPERAND (declarator, 0);
                  op = IDENTIFIER_OPNAME_P (tmp);
+                 if (IDENTIFIER_TYPENAME_P (tmp))
+                   {
+                     if (IDENTIFIER_GLOBAL_VALUE (tmp)
+                         && (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (tmp)) 
+                             == TYPE_DECL))
+                       name = IDENTIFIER_POINTER (tmp);
+                     else
+                       name = "<invalid operator>";
+                   }
                }
              error ("storage class specified for %s `%s'",
                     op ? "member operator" : "field",
-                    op ? operator_name_string (tmp) : name);
+                    name);
            }
          else
-           error (((decl_context == PARM || decl_context == CATCHPARM)
-                   ? "storage class specified for parameter `%s'"
-                   : "storage class specified for typename"), name);
+           {
+             if (decl_context == PARM || decl_context == CATCHPARM)
+               error ("storage class specified for parameter `%s'", name);
+             else
+               error ("storage class specified for typename");
+           }
          RIDBIT_RESET (RID_REGISTER, specbits);
          RIDBIT_RESET (RID_AUTO, specbits);
          RIDBIT_RESET (RID_EXTERN, specbits);
@@ -9875,7 +10434,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      the declared identifier (or NULL_TREE, in an absolute declarator).  */
 
   inner_attrs = NULL_TREE;
-  ignore_attrs = 0;  
+  ignore_attrs = 0;
 
   while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
         && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
@@ -9918,8 +10477,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          if (ctype != NULL_TREE)
            {
              tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
-             ctype = grok_method_quals (ctype, dummy, quals);
+             grok_method_quals (ctype, dummy, quals);
              type = TREE_TYPE (dummy);
+             ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
              quals = NULL_TREE;
            }
        }
@@ -9963,6 +10523,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            declarator = TREE_OPERAND (declarator, 0);
 
            type = create_array_type_for_decl (dname, type, size);
+
+           /* VLAs never work as fields. */
+           if (decl_context == FIELD && !processing_template_decl 
+               && TREE_CODE (type) == ARRAY_TYPE
+               && TYPE_DOMAIN (type) != NULL_TREE
+               && !TREE_CONSTANT (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+             {
+               cp_error ("size of member `%D' is not constant", dname);
+               /* Proceed with arbitrary constant size, so that offset
+                  computations don't get confused. */
+               type = create_array_type_for_decl (dname, TREE_TYPE (type),
+                                                  integer_one_node);
+             }
+
            ctype = NULL_TREE;
          }
          break;
@@ -9997,7 +10571,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
              inner_decl = TREE_OPERAND (inner_decl, 1);
 
-           if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR) 
+           if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR)
              inner_decl = dname;
 
            /* Pick up type qualifiers which should be applied to `this'.  */
@@ -10009,18 +10583,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            /* Say it's a definition only for the CALL_EXPR
               closest to the identifier.  */
            funcdecl_p
-             = inner_decl 
+             = inner_decl
              && (TREE_CODE (inner_decl) == IDENTIFIER_NODE
-                 || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR 
+                 || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR
                  || TREE_CODE (inner_decl) == BIT_NOT_EXPR);
-           
+
            if (ctype == NULL_TREE
                && decl_context == FIELD
                && funcdecl_p
                && (friendp == 0 || dname == current_class_name))
              ctype = current_class_type;
 
-           if (ctype && return_type == return_conversion)
+           if (ctype && sfk == sfk_conversion)
              TYPE_HAS_CONVERSION (ctype) = 1;
            if (ctype && constructor_name (ctype) == dname)
              {
@@ -10031,9 +10605,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
                if (flags == DTOR_FLAG)
                  {
-                   /* ANSI C++ June 5 1992 WP 12.4.1.  A destructor may
-                      not be declared const or volatile.  A destructor
-                      may not be static.  */
+                   /* ISO C++ 12.4/2.  A destructor may not be
+                      declared const or volatile.  A destructor may
+                      not be static.  */
                    if (staticp == 2)
                      error ("destructor cannot be static member function");
                    if (quals)
@@ -10044,8 +10618,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      }
                    if (decl_context == FIELD)
                      {
-                       if (! member_function_or_else (ctype, current_class_type,
-                                                      "destructor for alien class `%s' cannot be a member"))
+                       if (! member_function_or_else (ctype,
+                                                      current_class_type,
+                                                      flags))
                          return void_type_node;
                      }
                  }
@@ -10053,9 +10628,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  {
                    if (explicitp == 1)
                      explicitp = 2;
-                   /* ANSI C++ June 5 1992 WP 12.1.2.  A constructor may
-                      not be declared const or volatile.  A constructor may
-                      not be virtual.  A constructor may not be static.  */
+                   /* ISO C++ 12.1.  A constructor may not be
+                      declared const or volatile.  A constructor may
+                      not be virtual.  A constructor may not be
+                      static.  */
                    if (staticp == 2)
                      error ("constructor cannot be static member function");
                    if (virtualp)
@@ -10077,14 +10653,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      if (RIDBIT_ANY_SET (tmp_bits))
                        error ("return value type specifier for constructor ignored");
                    }
-                   type = build_pointer_type (ctype);
                    if (decl_context == FIELD)
                      {
-                       if (! member_function_or_else (ctype, current_class_type,
-                                                      "constructor for alien class `%s' cannot be member"))
+                       if (! member_function_or_else (ctype,
+                                                      current_class_type,
+                                                      flags))
                          return void_type_node;
                        TYPE_HAS_CONSTRUCTOR (ctype) = 1;
-                       if (return_type != return_ctor)
+                       if (sfk != sfk_constructor)
                          return NULL_TREE;
                      }
                  }
@@ -10126,11 +10702,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                   want the underlying IDENTIFIER.  */
                if (TREE_CODE (declarator) == BIT_NOT_EXPR)
                  declarator = TREE_OPERAND (declarator, 0);
-               
-               if (strict_prototype == 0 && arg_types == NULL_TREE)
-                 arg_types = void_list_node;
-               else if (arg_types == NULL_TREE
-                        || arg_types != void_list_node)
+
+                if (arg_types != void_list_node)
                  {
                    cp_error ("destructors may not have parameters");
                    arg_types = void_list_node;
@@ -10313,14 +10886,26 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            ctype = TREE_OPERAND (declarator, 0);
 
            t = ctype;
-           while (t != NULL_TREE && CLASS_TYPE_P (t)) 
+           while (t != NULL_TREE && CLASS_TYPE_P (t))
              {
-               if (CLASSTYPE_TEMPLATE_INFO (t) &&
-                   !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
+               /* You're supposed to have one `template <...>' 
+                  for every template class, but you don't need one
+                  for a full specialization.  For example:
+
+                    template <class T> struct S{};
+                    template <> struct S<int> { void f(); };
+                    void S<int>::f () {}
+
+                  is correct; there shouldn't be a `template <>' for
+                  the definition of `S<int>::f'.  */
+               if (CLASSTYPE_TEMPLATE_INFO (t)
+                   && (CLASSTYPE_TEMPLATE_INSTANTIATION (t)
+                       || uses_template_parms (CLASSTYPE_TI_ARGS (t))))
                  template_count += 1;
+
                t = TYPE_MAIN_DECL (t);
                if (DECL_LANG_SPECIFIC (t))
-                 t = DECL_CLASS_CONTEXT (t);
+                 t = DECL_CONTEXT (t);
                else
                  t = NULL_TREE;
              }
@@ -10359,7 +10944,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      }
                  }
                else if (RIDBIT_SETP (RID_TYPEDEF, specbits)
-                        || TYPE_SIZE (complete_type (ctype)) != NULL_TREE)
+                        || COMPLETE_TYPE_P (complete_type (ctype)))
                  {
                    /* Have to move this code elsewhere in this function.
                       this code is used for i.e., typedef int A::M; M *pm;
@@ -10509,29 +11094,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       if (decl_context == FIELD)
        {
          if (declarator == constructor_name (current_class_type))
-           cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class",
+           cp_pedwarn ("ISO C++ forbids nested type `%D' with same name as enclosing class",
                        declarator);
          decl = build_lang_decl (TYPE_DECL, declarator, type);
        }
       else
-       {
-         /* Make sure this typedef lives as long as its type,
-            since it might be used as a template parameter. */
-         if (type != error_mark_node)
-           push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-         if (processing_template_decl)
-           decl = build_lang_decl (TYPE_DECL, declarator, type);
-         else
-           decl = build_decl (TYPE_DECL, declarator, type);
-         if (type != error_mark_node)
-           pop_obstacks ();
-       }
+       decl = build_decl (TYPE_DECL, declarator, type);
 
       /* If the user declares "typedef struct {...} foo" then the
         struct will have an anonymous name.  Fill that name in now.
         Nothing can refer to it, so nothing needs know about the name
         change.  */
       if (type != error_mark_node
+         && declarator
          && TYPE_NAME (type)
          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
          && ANON_AGGRNAME_P (TYPE_IDENTIFIER (type))
@@ -10553,22 +11128,27 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
             type is a (non-primary) template.  The name for the
             template needs updating as well.  */
          if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type))
-           DECL_NAME (CLASSTYPE_TI_TEMPLATE (type)) 
+           DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))
              = TYPE_IDENTIFIER (type);
 
-         /* XXX Temporarily set the scope. 
-            When returning, start_decl expects it as NULL_TREE,
-            and will then then set it using pushdecl. */
-         my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 980404);
-         if (current_class_type)
-           DECL_CONTEXT (decl) = current_class_type;
+         if (flag_new_abi) 
+           DECL_ASSEMBLER_NAME (decl) = mangle_type (type);
          else
-           DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
-
-         DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl);
-         DECL_ASSEMBLER_NAME (decl)
-           = get_identifier (build_overload_name (type, 1, 1));
-         DECL_CONTEXT (decl) = NULL_TREE;
+           {
+             /* XXX Temporarily set the scope.
+                When returning, start_decl expects it as NULL_TREE,
+                and will then then set it using pushdecl. */
+             my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 980404);
+             if (current_class_type)
+               DECL_CONTEXT (decl) = current_class_type;
+             else
+               DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+             
+             DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl);
+             DECL_ASSEMBLER_NAME (decl)
+               = get_identifier (build_overload_name (type, 1, 1));
+             DECL_CONTEXT (decl) = NULL_TREE;
+           }
 
          /* FIXME remangle member functions; member functions of a
             type with external linkage have external linkage.  */
@@ -10584,7 +11164,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          if (ctype == NULL_TREE)
            {
              if (TREE_CODE (type) != METHOD_TYPE)
-               cp_error_at ("invalid type qualifier for non-method type", decl);
+               cp_error_at ("invalid type qualifier for non-member function type", decl);
              else
                ctype = TYPE_METHOD_BASETYPE (type);
            }
@@ -10641,6 +11221,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              inlinep = 0;
            }
 
+         /* Until core issue 180 is resolved, allow 'friend typename A::B'.
+            But don't allow implicit typenames.  */
+         if (!current_aggr && (TREE_CODE (type) != TYPENAME_TYPE
+                               || IMPLICIT_TYPENAME_P (type)))
+           {
+             if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+               cp_pedwarn ("template parameters cannot be friends");
+             else if (TREE_CODE (type) == TYPENAME_TYPE)
+               cp_pedwarn ("\
+friend declaration requires class-key, i.e. `friend class %T::%T'",
+                           constructor_name (current_class_type),
+                           TYPE_IDENTIFIER (type));
+             else
+               cp_pedwarn ("\
+friend declaration requires class-key, i.e. `friend %#T'",
+                           type);
+           }
+
          /* Only try to do this stuff if we didn't already give up.  */
          if (type != integer_type_node)
            {
@@ -10648,21 +11246,26 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              if (current_class_type)
                make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type));
              else
-               error ("trying to make class `%s' a friend of global scope",
-                      TYPE_NAME_STRING (type));
+               cp_error ("trying to make class `%T' a friend of global scope",
+                         type);
              type = void_type_node;
            }
        }
       else if (quals)
        {
-         tree dummy = build_decl (TYPE_DECL, declarator, type);
          if (ctype == NULL_TREE)
            {
-             my_friendly_assert (TREE_CODE (type) == METHOD_TYPE, 159);
-             ctype = TYPE_METHOD_BASETYPE (type);
+             if (TREE_CODE (type) != METHOD_TYPE)
+               cp_error ("invalid qualifiers on non-member function type");
+             else
+               ctype = TYPE_METHOD_BASETYPE (type);
+           }
+         if (ctype)
+           {
+             tree dummy = build_decl (TYPE_DECL, declarator, type);
+             grok_method_quals (ctype, dummy, quals);
+             type = TREE_TYPE (dummy);
            }
-         grok_method_quals (ctype, dummy, quals);
-         type = TREE_TYPE (dummy);
        }
 
       return type;
@@ -10725,7 +11328,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          return NULL_TREE;
        }
     }
-  
+
   {
     register tree decl;
 
@@ -10792,10 +11395,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    return void_type_node;
                  }
 
-               if (declarator == ansi_opname[(int) NEW_EXPR]
-                   || declarator == ansi_opname[(int) VEC_NEW_EXPR]
-                   || declarator == ansi_opname[(int) DELETE_EXPR]
-                   || declarator == ansi_opname[(int) VEC_DELETE_EXPR])
+               if (declarator == ansi_opname (NEW_EXPR)
+                   || declarator == ansi_opname (VEC_NEW_EXPR)
+                   || declarator == ansi_opname (DELETE_EXPR)
+                   || declarator == ansi_opname (VEC_DELETE_EXPR))
                  {
                    if (virtualp)
                      {
@@ -10810,11 +11413,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              }
 
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
-           function_context = (ctype != NULL_TREE) ? 
-             hack_decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
+           function_context = (ctype != NULL_TREE) ?
+             decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
            publicp = (! friendp || ! staticp)
              && function_context == NULL_TREE;
-           decl = grokfndecl (ctype, type, 
+           decl = grokfndecl (ctype, type,
                               TREE_CODE (declarator) != TEMPLATE_ID_EXPR
                               ? declarator : dname,
                               declarator,
@@ -10846,16 +11449,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                   We don't look at the first parameter, which is
                   really just the `this' parameter for the new
                   object.  */
-               tree arg_types = 
+               tree arg_types =
                  TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)));
 
                /* Skip the `in_chrg' argument too, if present.  */
-               if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl)))
+               if (DECL_HAS_IN_CHARGE_PARM_P (decl))
                  arg_types = TREE_CHAIN (arg_types);
 
                if (arg_types == void_list_node
-                   || (arg_types 
-                       && TREE_CHAIN (arg_types) 
+                   || (arg_types
+                       && TREE_CHAIN (arg_types)
                        && TREE_CHAIN (arg_types) != void_list_node
                        && !TREE_PURPOSE (TREE_CHAIN (arg_types))))
                  DECL_NONCONVERTING_P (decl) = 1;
@@ -10875,7 +11478,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              return NULL_TREE;
          }
        else if (!staticp && ! processing_template_decl
-                && TYPE_SIZE (complete_type (type)) == NULL_TREE
+                && !COMPLETE_TYPE_P (complete_type (type))
                 && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
          {
            if (declarator)
@@ -10900,7 +11503,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          {
            if (friendp)
              {
-               error ("`%s' is neither function nor method; cannot be declared friend",
+               error ("`%s' is neither function nor member function; cannot be declared friend",
                       IDENTIFIER_POINTER (declarator));
                friendp = 0;
              }
@@ -10919,8 +11522,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  {
                    if (template_class_depth (current_class_type) == 0)
                      {
-                       decl 
-                         = check_explicit_specialization 
+                       decl
+                         = check_explicit_specialization
                          (declarator, decl,
                           template_count, 2 * (funcdef_flag != 0) + 4);
                        if (decl == error_mark_node)
@@ -10933,7 +11536,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  }
                if (t && funcdef_flag)
                  return t;
-               
+
                return void_type_node;
              }
          }
@@ -10948,17 +11551,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  {
                    /* An attempt is being made to initialize a non-static
                       member.  But, from [class.mem]:
-                      
+
                       4 A member-declarator can contain a
                       constant-initializer only if it declares a static
                       member (_class.static_) of integral or enumeration
-                      type, see _class.static.data_.  
+                      type, see _class.static.data_.
 
                       This used to be relatively common practice, but
                       the rest of the compiler does not correctly
                       handle the initialization unless the member is
                       static so we make it static below.  */
-                   cp_pedwarn ("ANSI C++ forbids initialization of member `%D'",
+                   cp_pedwarn ("ISO C++ forbids initialization of member `%D'",
                                declarator);
                    cp_pedwarn ("making `%D' static", declarator);
                    staticp = 1;
@@ -10979,11 +11582,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            /* 9.2p13 [class.mem] */
            if (declarator == constructor_name (current_class_type)
-               /* Divergence from the standard:  In extern "C", we
-                  allow non-static data members here, because C does
-                  and /usr/include/netinet/in.h uses that.  */
-               && (staticp || ! in_system_header))
-             cp_pedwarn ("ANSI C++ forbids data member `%D' with same name as enclosing class",
+               /* The standard does not allow non-static data members
+                  here either, but we agreed at the 10/99 meeting
+                  to change that in TC 1 so that they are allowed in
+                  classes with no user-defined constructors.  */
+               && staticp)
+             cp_pedwarn ("ISO C++ forbids static data member `%D' with same name as enclosing class",
                          declarator);
 
            if (staticp)
@@ -10997,7 +11601,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              }
            else
              {
-               decl = build_lang_decl (FIELD_DECL, declarator, type);
+               decl = build_decl (FIELD_DECL, declarator, type);
+               DECL_NONADDRESSABLE_P (decl) = bitfield;
                if (RIDBIT_SETP (RID_MUTABLE, specbits))
                  {
                    DECL_MUTABLE_P (decl) = 1;
@@ -11040,7 +11645,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            else
              pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name);
          }
-       
+
        if (ctype == NULL_TREE)
          {
            if (virtualp)
@@ -11061,7 +11666,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        decl = grokfndecl (ctype, type, original_name, declarator,
                           virtualp, flags, quals, raises,
                           1, friendp,
-                          publicp, inlinep, funcdef_flag, 
+                          publicp, inlinep, funcdef_flag,
                           template_count, in_namespace);
        if (decl == NULL_TREE)
          return NULL_TREE;
@@ -11096,9 +11701,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        /* It's a variable.  */
 
        /* An uninitialized decl with `extern' is a reference.  */
-       decl = grokvardecl (type, declarator, &specbits, 
-                           initialized, 
-                           (type_quals & TYPE_QUAL_CONST) != 0, 
+       decl = grokvardecl (type, declarator, &specbits,
+                           initialized,
+                           (type_quals & TYPE_QUAL_CONST) != 0,
                            in_namespace);
        bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
                        inlinep, friendp, raises != NULL_TREE);
@@ -11185,10 +11790,17 @@ static void
 require_complete_types_for_parms (parms)
      tree parms;
 {
-  while (parms)
+  for (; parms; parms = TREE_CHAIN (parms))
     {
       tree type = TREE_TYPE (parms);
-      if (TYPE_SIZE (complete_type (type)) == NULL_TREE)
+
+      /* Try to complete the TYPE.  */
+      type = complete_type (type);
+
+      if (type == error_mark_node)
+       continue;
+
+      if (!COMPLETE_TYPE_P (type))
        {
          if (DECL_NAME (parms))
            error ("parameter `%s' has incomplete type",
@@ -11199,32 +11811,51 @@ require_complete_types_for_parms (parms)
        }
       else
        layout_decl (parms, 0);
-
-      parms = TREE_CHAIN (parms);
     }
 }
 
-/* Returns *TP if *TP is a local variable (or parameter).  Returns
-   NULL_TREE otherwise.  */
+/* Returns non-zero if T is a local variable.  */
 
-static tree
-local_variable_p (tp, walk_subtrees, data)
-     tree *tp;
-     int *walk_subtrees ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
+int
+local_variable_p (t)
+     tree t;
 {
-  tree t = *tp;
-
-  if ((TREE_CODE (t) == VAR_DECL 
+  if ((TREE_CODE (t) == VAR_DECL
        /* A VAR_DECL with a context that is a _TYPE is a static data
          member.  */
        && !TYPE_P (CP_DECL_CONTEXT (t))
        /* Any other non-local variable must be at namespace scope.  */
-       && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL)
+       && !DECL_NAMESPACE_SCOPE_P (t))
       || (TREE_CODE (t) == PARM_DECL))
-    return t;
+    return 1;
 
-  return NULL_TREE;
+  return 0;
+}
+
+/* Returns non-zero if T is an automatic local variable or a label.
+   (These are the declarations that need to be remapped when the code
+   containing them is duplicated.)  */
+
+int
+nonstatic_local_decl_p (t)
+     tree t;
+{
+  return ((local_variable_p (t) && !TREE_STATIC (t))
+         || TREE_CODE (t) == LABEL_DECL
+         || TREE_CODE (t) == RESULT_DECL);
+}
+
+/* Like local_variable_p, but suitable for use as a tree-walking
+   function.  */
+
+static tree
+local_variable_p_walkfn (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
+         ? *tp : NULL_TREE);
 }
 
 /* Check that ARG, which is a default-argument expression for a
@@ -11261,7 +11892,7 @@ check_default_argument (decl, arg)
   else
     decl_type = TREE_TYPE (decl);
 
-  if (arg == error_mark_node 
+  if (arg == error_mark_node
       || decl == error_mark_node
       || TREE_TYPE (arg) == error_mark_node
       || decl_type == error_mark_node)
@@ -11270,14 +11901,14 @@ check_default_argument (decl, arg)
     return error_mark_node;
 
   /* [dcl.fct.default]
-     
+
      A default argument expression is implicitly converted to the
      parameter type.  */
   if (!TREE_TYPE (arg)
       || !can_convert_arg (decl_type, TREE_TYPE (arg), arg))
     {
       if (decl)
-       cp_error ("default argument for `%#D' has type `%T'", 
+       cp_error ("default argument for `%#D' has type `%T'",
                  decl, TREE_TYPE (arg));
       else
        cp_error ("default argument for parameter of type `%T' has type `%T'",
@@ -11289,11 +11920,12 @@ check_default_argument (decl, arg)
   /* [dcl.fct.default]
 
      Local variables shall not be used in default argument
-     expressions. 
+     expressions.
 
      The keyword `this' shall not be used in a default argument of a
      member function.  */
-  var = walk_tree (&arg, local_variable_p, NULL);
+  var = walk_tree_without_duplicates (&arg, local_variable_p_walkfn, 
+                                     NULL);
   if (var)
     {
       cp_error ("default argument `%E' uses local variable `%D'",
@@ -11380,7 +12012,7 @@ grokparms (first_parm, funcdef_flag)
 
              chain = TREE_CHAIN (parm);
              /* @@ weak defense against parse errors.  */
-             if (TREE_CODE (decl) != VOID_TYPE 
+             if (TREE_CODE (decl) != VOID_TYPE
                  && TREE_CODE (decl) != TREE_LIST)
                {
                  /* Give various messages as the need arises.  */
@@ -11528,17 +12160,25 @@ replace_defarg (arg, init)
   TREE_PURPOSE (arg) = init;
 }
 \f
+/* D is a constructor or overloaded `operator='.  Returns non-zero if
+   D's arguments allow it to be a copy constructor, or copy assignment
+   operator.  */
+
 int
 copy_args_p (d)
      tree d;
 {
-  tree t = FUNCTION_ARG_CHAIN (d);
-  if (DECL_CONSTRUCTOR_P (d)
-      && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d)))
+  tree t;
+
+  if (!DECL_FUNCTION_MEMBER_P (d))
+    return 0;
+
+  t = FUNCTION_ARG_CHAIN (d);
+  if (DECL_CONSTRUCTOR_P (d) && DECL_HAS_IN_CHARGE_PARM_P (d))
     t = TREE_CHAIN (t);
   if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
       && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
-         == DECL_CLASS_CONTEXT (d))
+         == DECL_CONTEXT (d))
       && (TREE_CHAIN (t) == NULL_TREE
          || TREE_CHAIN (t) == void_list_node
          || TREE_PURPOSE (TREE_CHAIN (t))))
@@ -11565,7 +12205,7 @@ grok_ctor_properties (ctype, decl)
      added to any ctor so we can tell if the class has been initialized
      yet.  This could screw things up in this function, so we deliberately
      ignore the leading int if we're in that situation.  */
-  if (TYPE_USES_VIRTUAL_BASECLASSES (ctype))
+  if (DECL_HAS_IN_CHARGE_PARM_P (decl))
     {
       my_friendly_assert (parmtypes
                          && TREE_VALUE (parmtypes) == integer_type_node,
@@ -11597,7 +12237,7 @@ grok_ctor_properties (ctype, decl)
      A declaration of a constructor for a class X is ill-formed if its
      first parameter is of type (optionally cv-qualified) X and either
      there are no other parameters or else all other parameters have
-     default arguments.  
+     default arguments.
 
      We *don't* complain about member template instantiations that
      have this form, though; they can occur as we try to decide what
@@ -11626,30 +12266,30 @@ grok_ctor_properties (ctype, decl)
   return 1;
 }
 
-/* An operator with this name can be either unary or binary.  */
+/* An operator with this code is unary, but can also be binary.  */
 
 static int
-ambi_op_p (name)
-     tree name;
+ambi_op_p (code)
+     enum tree_code code;
 {
-  return (name == ansi_opname [(int) INDIRECT_REF]
-         || name == ansi_opname [(int) ADDR_EXPR]
-         || name == ansi_opname [(int) NEGATE_EXPR]
-         || name == ansi_opname[(int) POSTINCREMENT_EXPR]
-         || name == ansi_opname[(int) POSTDECREMENT_EXPR]
-         || name == ansi_opname [(int) CONVERT_EXPR]);
+  return (code == INDIRECT_REF
+         || code == ADDR_EXPR
+         || code == CONVERT_EXPR
+         || code == NEGATE_EXPR
+         || code == PREINCREMENT_EXPR
+         || code == PREDECREMENT_EXPR);
 }
 
 /* An operator with this name can only be unary.  */
 
 static int
-unary_op_p (name)
-     tree name;
+unary_op_p (code)
+     enum tree_code code;
 {
-  return (name == ansi_opname [(int) TRUTH_NOT_EXPR]
-         || name == ansi_opname [(int) BIT_NOT_EXPR]
-         || name == ansi_opname [(int) COMPONENT_REF]
-         || IDENTIFIER_TYPENAME_P (name));
+  return (code == TRUTH_NOT_EXPR
+         || code == BIT_NOT_EXPR
+         || code == COMPONENT_REF
+         || code == TYPE_EXPR);
 }
 
 /* Do a little sanity-checking on how they declared their operator.  */
@@ -11660,49 +12300,93 @@ grok_op_properties (decl, virtualp, friendp)
      int virtualp, friendp;
 {
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  tree argtype;
   int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
   tree name = DECL_NAME (decl);
+  enum tree_code operator_code;
+  int arity;
+
+  /* Count the number of arguments.  */
+  for (argtype = argtypes, arity = 0;
+       argtype && argtype != void_list_node;
+       argtype = TREE_CHAIN (argtype))
+    ++arity;
 
   if (current_class_type == NULL_TREE)
     friendp = 1;
 
+  if (DECL_CONV_FN_P (decl))
+    operator_code = TYPE_EXPR;
+  else
+    do
+      {
+#define DEF_OPERATOR(NAME, CODE, NEW_MANGLING, OLD_MANGING, ARITY, ASSN_P)  \
+       if (ansi_opname (CODE) == name)                                     \
+         {                                                                 \
+           operator_code = CODE;                                           \
+           break;                                                          \
+         }                                                                 \
+       else if (ansi_assopname (CODE) == name)                             \
+         {                                                                 \
+           operator_code = CODE;                                           \
+           DECL_ASSIGNMENT_OPERATOR_P (decl) = 1;                          \
+           break;                                                          \
+         }
+
+#include "operators.def"
+#undef DEF_OPERATOR
+
+       my_friendly_abort (20000527);
+      }
+    while (0);
+  my_friendly_assert (operator_code != LAST_CPLUS_TREE_CODE, 20000526);
+  SET_OVERLOADED_OPERATOR_CODE (decl, operator_code);
+
   if (! friendp)
     {
-      /* [class.copy]
+      switch (operator_code)
+       {
+       case CALL_EXPR:
+         TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
+         break;
+         
+       case ARRAY_REF:
+         TYPE_OVERLOADS_ARRAY_REF (current_class_type) = 1;
+         break;
 
-        A user-declared copy assignment operator X::operator= is a
-        non-static non-template member function of class X with
-        exactly one parameter of type X, X&, const X&, volatile X& or
-        const volatile X&.  */
-      if (name == ansi_opname[(int) MODIFY_EXPR]
-         && !(DECL_TEMPLATE_INSTANTIATION (decl)
-              && is_member_template (DECL_TI_TEMPLATE (decl))))
-       ;
-      else if (name == ansi_opname[(int) CALL_EXPR])
-       TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
-      else if (name == ansi_opname[(int) ARRAY_REF])
-       TYPE_OVERLOADS_ARRAY_REF (current_class_type) = 1;
-      else if (name == ansi_opname[(int) COMPONENT_REF]
-              || name == ansi_opname[(int) MEMBER_REF])
-       TYPE_OVERLOADS_ARROW (current_class_type) = 1;
-      else if (name == ansi_opname[(int) NEW_EXPR])
-       TYPE_GETS_NEW (current_class_type) |= 1;
-      else if (name == ansi_opname[(int) DELETE_EXPR])
-       TYPE_GETS_DELETE (current_class_type) |= 1;
-      else if (name == ansi_opname[(int) VEC_NEW_EXPR])
-       TYPE_GETS_NEW (current_class_type) |= 2;
-      else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
-       TYPE_GETS_DELETE (current_class_type) |= 2;
-    }
-
-  if (name == ansi_opname[(int) NEW_EXPR]
-      || name == ansi_opname[(int) VEC_NEW_EXPR])
+       case COMPONENT_REF:
+       case MEMBER_REF:
+         TYPE_OVERLOADS_ARROW (current_class_type) = 1;
+         break;
+         
+       case NEW_EXPR:
+         TYPE_HAS_NEW_OPERATOR (current_class_type) = 1;
+         break;
+         
+       case DELETE_EXPR:
+         TYPE_GETS_DELETE (current_class_type) |= 1;
+         break;
+         
+       case VEC_NEW_EXPR:
+         TYPE_HAS_ARRAY_NEW_OPERATOR (current_class_type) = 1;
+         break;
+         
+       case VEC_DELETE_EXPR:
+         TYPE_GETS_DELETE (current_class_type) |= 2;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR)
     {
       /* When the compiler encounters the definition of A::operator new, it
         doesn't look at the class declaration to find out if it's static.  */
       if (methodp)
-       revert_static_member_fn (&decl, NULL, NULL);
-     
+       revert_static_member_fn (decl);
+
       /* Take care of function decl if we had syntax errors.  */
       if (argtypes == NULL_TREE)
        TREE_TYPE (decl)
@@ -11712,26 +12396,18 @@ grok_op_properties (decl, virtualp, friendp)
       else
        TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
     }
-  else if (name == ansi_opname[(int) DELETE_EXPR]
-          || name == ansi_opname[(int) VEC_DELETE_EXPR])
+  else if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
     {
       if (methodp)
-       revert_static_member_fn (&decl, NULL, NULL);
-     
+       revert_static_member_fn (decl);
+
       if (argtypes == NULL_TREE)
        TREE_TYPE (decl)
          = build_function_type (void_type_node,
                                 hash_tree_chain (ptr_type_node,
                                                  void_list_node));
       else
-       {
-         TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
-
-         if (! friendp && name == ansi_opname[(int) VEC_DELETE_EXPR]
-             && (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)))
-                 != void_list_node))
-           TYPE_VEC_DELETE_TAKES_SIZE (current_class_type) = 1;
-       }
+       TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
     }
   else
     {
@@ -11740,11 +12416,11 @@ grok_op_properties (decl, virtualp, friendp)
         an enumeration, or a reference to an enumeration.  13.4.0.6 */
       if (! methodp || DECL_STATIC_FUNCTION_P (decl))
        {
-         if (IDENTIFIER_TYPENAME_P (name)
-             || name == ansi_opname[(int) CALL_EXPR]
-             || name == ansi_opname[(int) MODIFY_EXPR]
-             || name == ansi_opname[(int) COMPONENT_REF]
-             || name == ansi_opname[(int) ARRAY_REF])
+         if (operator_code == TYPE_EXPR
+             || operator_code == CALL_EXPR
+             || operator_code == COMPONENT_REF
+             || operator_code == ARRAY_REF
+             || operator_code == NOP_EXPR)
            cp_error ("`%D' must be a nonstatic member function", decl);
          else
            {
@@ -11764,7 +12440,7 @@ grok_op_properties (decl, virtualp, friendp)
                    if (IS_AGGR_TYPE (arg)
                        || TREE_CODE (arg) == ENUMERAL_TYPE
                        || TREE_CODE (arg) == TEMPLATE_TYPE_PARM
-                       || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+                       || TREE_CODE (arg) == BOUND_TEMPLATE_TEMPLATE_PARM)
                      goto foundaggr;
                  }
              cp_error
@@ -11774,27 +12450,28 @@ grok_op_properties (decl, virtualp, friendp)
              ;
            }
        }
-      
-      if (name == ansi_opname[(int) CALL_EXPR])
+
+      if (operator_code == CALL_EXPR)
        return;                 /* No restrictions on args. */
 
       if (IDENTIFIER_TYPENAME_P (name) && ! DECL_TEMPLATE_INFO (decl))
        {
          tree t = TREE_TYPE (name);
-         if (TREE_CODE (t) == VOID_TYPE)
-           pedwarn ("void is not a valid type conversion operator");
-         else if (! friendp)
+         if (! friendp)
            {
              int ref = (TREE_CODE (t) == REFERENCE_TYPE);
              const char *what = 0;
+             
              if (ref)
                t = TYPE_MAIN_VARIANT (TREE_TYPE (t));
 
-             if (t == current_class_type)
+             if (TREE_CODE (t) == VOID_TYPE)
+               what = "void";
+             else if (t == current_class_type)
                what = "the same type";
              /* Don't force t to be complete here.  */
              else if (IS_AGGR_TYPE (t)
-                      && TYPE_SIZE (t)
+                      && COMPLETE_TYPE_P (t)
                       && DERIVED_FROM_P (t, current_class_type))
                what = "a base class";
 
@@ -11804,18 +12481,27 @@ grok_op_properties (decl, virtualp, friendp)
            }
        }
 
-      if (name == ansi_opname[(int) MODIFY_EXPR])
+      if (DECL_ASSIGNMENT_OPERATOR_P (decl) 
+         && operator_code == NOP_EXPR)
        {
          tree parmtype;
 
-         if (list_length (argtypes) != 3 && methodp)
+         if (arity != 2 && methodp)
            {
              cp_error ("`%D' must take exactly one argument", decl);
              return;
            }
          parmtype = TREE_VALUE (TREE_CHAIN (argtypes));
 
+         /* [class.copy]
+
+            A user-declared copy assignment operator X::operator= is
+            a non-static non-template member function of class X with
+            exactly one parameter of type X, X&, const X&, volatile
+            X& or const volatile X&.  */
          if (copy_assignment_arg_p (parmtype, virtualp)
+             && !(DECL_TEMPLATE_INSTANTIATION (decl)
+                  && is_member_template (DECL_TI_TEMPLATE (decl)))
              && ! friendp)
            {
              TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
@@ -11824,19 +12510,55 @@ grok_op_properties (decl, virtualp, friendp)
                TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
            }
        }
-      else if (name == ansi_opname[(int) COND_EXPR])
+      else if (operator_code == COND_EXPR)
        {
          /* 13.4.0.3 */
-         cp_error ("ANSI C++ prohibits overloading operator ?:");
-       }         
-      else if (ambi_op_p (name))
+         cp_error ("ISO C++ prohibits overloading operator ?:");
+       }
+      else if (ambi_op_p (operator_code))
        {
-         if (list_length (argtypes) == 2)
-           /* prefix */;
-         else if (list_length (argtypes) == 3)
+         if (arity == 1)
+           /* We pick the one-argument operator codes by default, so
+              we don't have to change anything.  */
+           ;
+         else if (arity == 2)
            {
-             if ((name == ansi_opname[(int) POSTINCREMENT_EXPR]
-                  || name == ansi_opname[(int) POSTDECREMENT_EXPR])
+             /* If we thought this was a unary operator, we now know
+                it to be a binary operator.  */
+             switch (operator_code)
+               {
+               case INDIRECT_REF:
+                 operator_code = MULT_EXPR;
+                 break;
+
+               case ADDR_EXPR:
+                 operator_code = BIT_AND_EXPR;
+                 break;
+
+               case CONVERT_EXPR:
+                 operator_code = PLUS_EXPR;
+                 break;
+
+               case NEGATE_EXPR:
+                 operator_code = MINUS_EXPR;
+                 break;
+
+               case PREINCREMENT_EXPR:
+                 operator_code = POSTINCREMENT_EXPR;
+                 break;
+
+               case PREDECREMENT_EXPR:
+                 operator_code = POSTDECREMENT_EXPR;
+                 break;
+
+               default:
+                 my_friendly_abort (20000527);
+               }
+
+             SET_OVERLOADED_OPERATOR_CODE (decl, operator_code);
+
+             if ((operator_code == POSTINCREMENT_EXPR
+                  || operator_code == POSTDECREMENT_EXPR)
                  && ! processing_template_decl
                  && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), integer_type_node))
                {
@@ -11859,15 +12581,18 @@ grok_op_properties (decl, virtualp, friendp)
 
          /* More Effective C++ rule 6.  */
          if (warn_ecpp
-             && (name == ansi_opname[(int) POSTINCREMENT_EXPR]
-                 || name == ansi_opname[(int) POSTDECREMENT_EXPR]))
+             && (operator_code == POSTINCREMENT_EXPR
+                 || operator_code == POSTDECREMENT_EXPR
+                 || operator_code == PREINCREMENT_EXPR
+                 || operator_code == PREDECREMENT_EXPR))
            {
              tree arg = TREE_VALUE (argtypes);
              tree ret = TREE_TYPE (TREE_TYPE (decl));
              if (methodp || TREE_CODE (arg) == REFERENCE_TYPE)
                arg = TREE_TYPE (arg);
              arg = TYPE_MAIN_VARIANT (arg);
-             if (list_length (argtypes) == 2)
+             if (operator_code == PREINCREMENT_EXPR
+                 || operator_code == PREDECREMENT_EXPR)
                {
                  if (TREE_CODE (ret) != REFERENCE_TYPE
                      || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
@@ -11882,9 +12607,9 @@ grok_op_properties (decl, virtualp, friendp)
                }
            }
        }
-      else if (unary_op_p (name))
+      else if (unary_op_p (operator_code))
        {
-         if (list_length (argtypes) != 2)
+         if (arity != 1)
            {
              if (methodp)
                cp_error ("`%D' must take `void'", decl);
@@ -11892,9 +12617,9 @@ grok_op_properties (decl, virtualp, friendp)
                cp_error ("`%D' must take exactly one argument", decl);
            }
        }
-      else /* if (binary_op_p (name)) */
+      else /* if (binary_op_p (operator_code)) */
        {
-         if (list_length (argtypes) != 3)
+         if (arity != 2)
            {
              if (methodp)
                cp_error ("`%D' must take exactly one argument", decl);
@@ -11904,38 +12629,39 @@ grok_op_properties (decl, virtualp, friendp)
 
          /* More Effective C++ rule 7.  */
          if (warn_ecpp
-             && (name == ansi_opname [TRUTH_ANDIF_EXPR]
-                 || name == ansi_opname [TRUTH_ORIF_EXPR]
-                 || name == ansi_opname [COMPOUND_EXPR]))
+             && (operator_code == TRUTH_ANDIF_EXPR
+                 || operator_code == TRUTH_ORIF_EXPR
+                 || operator_code == COMPOUND_EXPR))
            cp_warning ("user-defined `%D' always evaluates both arguments",
                        decl);
        }
 
       /* Effective C++ rule 23.  */
       if (warn_ecpp
-         && list_length (argtypes) == 3
-         && (name == ansi_opname [PLUS_EXPR]
-             || name == ansi_opname [MINUS_EXPR]
-             || name == ansi_opname [TRUNC_DIV_EXPR]
-             || name == ansi_opname [MULT_EXPR])
+         && arity == 2
+         && (operator_code == PLUS_EXPR
+             || operator_code == MINUS_EXPR
+             || operator_code == TRUNC_DIV_EXPR
+             || operator_code == MULT_EXPR)
          && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
        cp_warning ("`%D' should return by value", decl);
 
       /* 13.4.0.8 */
-      if (argtypes)
-       for (; argtypes != void_list_node ; argtypes = TREE_CHAIN (argtypes))
-         if (TREE_PURPOSE (argtypes))
-           {
-             TREE_PURPOSE (argtypes) = NULL_TREE;
-             if (name == ansi_opname[(int) POSTINCREMENT_EXPR]
-                 || name == ansi_opname[(int) POSTDECREMENT_EXPR])
-               {
-                 if (pedantic)
-                   cp_pedwarn ("`%D' cannot have default arguments", decl);
-               }
-             else
-               cp_error ("`%D' cannot have default arguments", decl);
-           }
+      for (; argtypes && argtypes != void_list_node;
+          argtypes = TREE_CHAIN (argtypes))
+        if (TREE_PURPOSE (argtypes))
+          {
+            TREE_PURPOSE (argtypes) = NULL_TREE;
+            if (operator_code == POSTINCREMENT_EXPR
+               || operator_code == POSTDECREMENT_EXPR)
+              {
+                if (pedantic)
+                  cp_pedwarn ("`%D' cannot have default arguments", decl);
+              }
+            else
+              cp_error ("`%D' cannot have default arguments", decl);
+          }
+
     }
 }
 \f
@@ -11976,7 +12702,6 @@ xref_tag (code_type_node, name, globalize)
 {
   enum tag_types tag_code;
   enum tree_code code;
-  int temp = 0;
   register tree ref, t;
   struct binding_level *b = current_binding_level;
   int got_type = 0;
@@ -11993,7 +12718,7 @@ xref_tag (code_type_node, name, globalize)
       code_type_node = TREE_VALUE (code_type_node);
     }
 
-  tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node);
+  tag_code = (enum tag_types) tree_low_cst (code_type_node, 1);
   switch (tag_code)
     {
     case record_type:
@@ -12012,7 +12737,7 @@ xref_tag (code_type_node, name, globalize)
 
   /* If a cross reference is requested, look up the type
      already defined for this tag and return it.  */
-  if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+  if (TYPE_P (name))
     {
       t = name;
       name = TYPE_IDENTIFIER (t);
@@ -12021,8 +12746,24 @@ xref_tag (code_type_node, name, globalize)
   else
     t = IDENTIFIER_TYPE_VALUE (name);
 
+  /* Warn about 'friend struct Inherited;' doing the wrong thing.  */
+  if (t && globalize && TREE_CODE (t) == TYPENAME_TYPE)
+    {
+      static int explained;
+
+      cp_warning ("`%s %T' declares a new type at namespace scope;\n\
+to refer to the inherited type, say `%s %T::%T'%s",
+                 tag_name (tag_code), name, tag_name (tag_code),
+                 constructor_name (current_class_type), TYPE_IDENTIFIER (t),
+                 (!explained ? "\n\
+(names from dependent base classes are not visible to unqualified name lookup)"
+                  : ""));
+
+      explained = 1;
+    }
+
   if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM
-      && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM)
+      && TREE_CODE (t) != BOUND_TEMPLATE_TEMPLATE_PARM)
     t = NULL_TREE;
 
   if (! globalize)
@@ -12050,11 +12791,11 @@ xref_tag (code_type_node, name, globalize)
        }
       else
        ref = lookup_tag (code, name, b, 0);
-         
+
       if (! ref)
        {
          /* Try finding it as a type declaration.  If that wins,
-            use it.  */ 
+            use it.  */
          ref = lookup_name (name, 1);
 
          if (ref != NULL_TREE
@@ -12063,7 +12804,7 @@ xref_tag (code_type_node, name, globalize)
              && template_class_depth (current_class_type) == 0)
            /* Since GLOBALIZE is true, we're declaring a global
               template, so we want this type.  */
-           ref = DECL_RESULT (ref);
+           ref = DECL_TEMPLATE_RESULT (ref);
 
          if (ref && TREE_CODE (ref) == TYPE_DECL
              && TREE_CODE (TREE_TYPE (ref)) == code)
@@ -12072,9 +12813,9 @@ xref_tag (code_type_node, name, globalize)
            ref = NULL_TREE;
        }
 
-      if (ref && current_class_type 
-         && template_class_depth (current_class_type) 
-         && PROCESSING_REAL_TEMPLATE_DECL_P ()) 
+      if (ref && current_class_type
+         && template_class_depth (current_class_type)
+         && PROCESSING_REAL_TEMPLATE_DECL_P ())
        {
          /* Since GLOBALIZE is non-zero, we are not looking at a
             definition of this tag.  Since, in addition, we are currently
@@ -12117,22 +12858,12 @@ xref_tag (code_type_node, name, globalize)
        }
     }
 
-  push_obstacks_nochange ();
-
   if (! ref)
     {
       /* If no such tag is yet defined, create a forward-reference node
         and record it as the "definition".
         When a real declaration of this type is found,
         the forward-reference will be altered into a real type.  */
-
-      /* In C++, since these migrate into the global scope, we must
-        build them on the permanent obstack.  */
-
-      temp = allocation_temporary_p ();
-      if (temp)
-       end_temporary_allocation ();
-
       if (code == ENUMERAL_TYPE)
        {
          cp_error ("use of enum `%#D' without previous declaration", name);
@@ -12143,6 +12874,7 @@ xref_tag (code_type_node, name, globalize)
             to avoid crashing if it does not get defined.  */
          TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
          TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
+         TYPE_USER_ALIGN (ref) = 0;
          TREE_UNSIGNED (ref) = 1;
          TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
          TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
@@ -12159,7 +12891,7 @@ xref_tag (code_type_node, name, globalize)
        {
          struct binding_level *old_b = class_binding_level;
 
-         ref = make_lang_type (code);
+         ref = make_aggr_type (code);
          TYPE_CONTEXT (ref) = context;
 
 #ifdef NONNESTED_CLASSES
@@ -12172,21 +12904,13 @@ xref_tag (code_type_node, name, globalize)
     }
   else
     {
-      /* If it no longer looks like a nested type, make sure it's
-        in global scope.  
-         If it is not an IDENTIFIER, this is not a declaration */
-      if (b->namespace_p && !class_binding_level
-         && TREE_CODE (name) == IDENTIFIER_NODE
-         && IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
-       SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
-
       if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
        redeclare_class_template (ref, current_template_parms);
     }
 
   /* Until the type is defined, tentatively accept whatever
      structure tag the user hands us.  */
-  if (TYPE_SIZE (ref) == NULL_TREE
+  if (!COMPLETE_TYPE_P (ref)
       && ref != current_class_type
       /* Have to check this, in case we have contradictory tag info.  */
       && IS_AGGR_TYPE_CODE (TREE_CODE (ref)))
@@ -12197,8 +12921,6 @@ xref_tag (code_type_node, name, globalize)
        CLASSTYPE_DECLARED_CLASS (ref) = 0;
     }
 
-  pop_obstacks ();
-
   TREE_TYPE (ref) = attributes;
 
   return ref;
@@ -12241,7 +12963,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
   tree base;
 
   int i, len;
-  enum tag_types tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node);
+  enum tag_types tag_code = (enum tag_types) tree_low_cst (code_type_node, 1);
 
   if (tag_code == union_type)
     {
@@ -12250,7 +12972,6 @@ xref_basetypes (code_type_node, name, ref, binfo)
     }
 
   len = list_length (binfo);
-  push_obstacks (TYPE_OBSTACK (ref), TYPE_OBSTACK (ref));
 
   /* First, make sure that any templates in base-classes are
      instantiated.  This ensures that if we call ourselves recursively
@@ -12288,7 +13009,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
          || (TREE_CODE (basetype) != RECORD_TYPE
              && TREE_CODE (basetype) != TYPENAME_TYPE
              && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM
-             && TREE_CODE (basetype) != TEMPLATE_TEMPLATE_PARM))
+             && TREE_CODE (basetype) != BOUND_TEMPLATE_TEMPLATE_PARM))
        {
          cp_error ("base type `%T' fails to be a struct or class type",
                    TREE_VALUE (binfo));
@@ -12299,7 +13020,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
 
       /* This code replaces similar code in layout_basetypes.
          We put the complete_type first for implicit `typename'.  */
-      if (TYPE_SIZE (basetype) == NULL_TREE
+      if (!COMPLETE_TYPE_P (basetype)
          && ! (current_template_parms && uses_template_parms (basetype)))
        {
          cp_error ("base class `%T' has incomplete type", basetype);
@@ -12317,7 +13038,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
            }
 
          if (TYPE_FOR_JAVA (basetype)
-             && (current_lang_stack 
+             && (current_lang_stack
                  == &VARRAY_TREE (current_lang_base, 0)))
            TYPE_FOR_JAVA (ref) = 1;
 
@@ -12328,14 +13049,14 @@ xref_basetypes (code_type_node, name, ref, binfo)
             derived classes.  (Each BINFO record describing an
             individual inheritance contains flags which say what
             the `accessibility' of that particular inheritance is.)  */
-  
-         base_binfo 
-           = make_binfo (integer_zero_node, basetype,
+
+         base_binfo
+           = make_binfo (size_zero_node, basetype,
                          CLASS_TYPE_P (basetype)
                          ? TYPE_BINFO_VTABLE (basetype) : NULL_TREE,
                          CLASS_TYPE_P (basetype)
                          ? TYPE_BINFO_VIRTUALS (basetype) : NULL_TREE);
+
          TREE_VEC_ELT (binfos, i) = base_binfo;
          TREE_VIA_PUBLIC (base_binfo) = via_public;
          TREE_VIA_PROTECTED (base_binfo) = via_protected;
@@ -12353,13 +13074,26 @@ xref_basetypes (code_type_node, name, ref, binfo)
          if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
            {
              TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1;
-             TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
+             /* Converting to a virtual base class requires looking
+                up the offset of the virtual base.  */
+             TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref) = 1;
            }
 
          if (CLASS_TYPE_P (basetype))
            {
-             TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
+             TYPE_HAS_NEW_OPERATOR (ref) 
+               |= TYPE_HAS_NEW_OPERATOR (basetype);
+             TYPE_HAS_ARRAY_NEW_OPERATOR (ref) 
+               |= TYPE_HAS_ARRAY_NEW_OPERATOR (basetype);
              TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
+             /* If the base-class uses multiple inheritance, so do we.  */
+             TYPE_USES_MULTIPLE_INHERITANCE (ref)
+               |= TYPE_USES_MULTIPLE_INHERITANCE (basetype);
+             /* Likewise, if converting to a base of the base may require
+                code, then we may need to generate code to convert to a
+                base as well.  */
+             TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref)
+               |= TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype);
            }
 
          i += 1;
@@ -12371,19 +13105,13 @@ xref_basetypes (code_type_node, name, ref, binfo)
     BINFO_BASETYPES (TYPE_BINFO (ref)) = NULL_TREE;
 
   if (i > 1)
-    TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
-  else if (i == 1)
     {
-      tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, 0));
-      
-      if (CLASS_TYPE_P (basetype))
-       TYPE_USES_MULTIPLE_INHERITANCE (ref)
-         = TYPE_USES_MULTIPLE_INHERITANCE (basetype);
+      TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
+      /* If there is more than one non-empty they cannot be at the same
+        address.  */
+      TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref) = 1;
     }
 
-  if (TYPE_USES_MULTIPLE_INHERITANCE (ref))
-    TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
-
   /* Unmark all the types.  */
   while (--i >= 0)
     CLEAR_CLASSTYPE_MARKED (BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
@@ -12391,11 +13119,9 @@ xref_basetypes (code_type_node, name, ref, binfo)
 
   /* Now that we know all the base-classes, set up the list of virtual
      bases.  */
-  CLASSTYPE_VBASECLASSES (ref) = get_vbase_types (ref);
-
-  pop_obstacks ();
+  get_vbase_types (ref);
 }
-  
+
 \f
 /* Begin compiling the definition of an enumeration type.
    NAME is its name (or null if anonymous).
@@ -12410,10 +13136,6 @@ start_enum (name)
   register tree enumtype = NULL_TREE;
   struct binding_level *b = current_binding_level;
 
-  /* We are wasting space here and putting these on the permanent_obstack so
-     that typeid(local enum) will work correctly. */
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
   /* If this is the real definition for a previous forward reference,
      fill in the contents in the same object that used to be the
      forward reference.  */
@@ -12425,6 +13147,8 @@ start_enum (name)
     {
       cp_error ("multiple definition of `%#T'", enumtype);
       cp_error_at ("previous definition here", enumtype);
+      /* Clear out TYPE_VALUES, and start again.  */
+      TYPE_VALUES (enumtype) = NULL_TREE;
     }
   else
     {
@@ -12435,10 +13159,6 @@ start_enum (name)
   if (current_class_type)
     TREE_ADDRESSABLE (b->tags) = 1;
 
-  /* We don't copy this value because build_enumerator needs to do it.  */
-  enum_next_value = integer_zero_node;
-  enum_overflow = 0;
-
   GNU_xref_decl (current_function_decl, enumtype);
   return enumtype;
 }
@@ -12469,6 +13189,14 @@ finish_enum (enumtype)
             constant.  */
          decl = TREE_VALUE (pair);
 
+         /* [dcl.enum]
+
+            Following the closing brace of an enum-specifier, each
+            enumerator has the type of its enumeration.  Prior to the
+            closing brace, the type of each enumerator is the type of
+            its initializing value.  */
+         TREE_TYPE (decl) = enumtype;
+
          /* The DECL_INITIAL will be NULL if we are processing a
             template declaration and this enumeration constant had no
             explicit initializer.  */
@@ -12483,7 +13211,7 @@ finish_enum (enumtype)
                 reason to do that when processing_template_decl.
                 And, if the expression is something like a
                 TEMPLATE_PARM_INDEX or a CAST_EXPR doing so will
-                wreak havoc on the intended type of the expression.  
+                wreak havoc on the intended type of the expression.
 
                 Of course, there's also no point in trying to compute
                 minimum or maximum values if we're in a template.  */
@@ -12497,7 +13225,7 @@ finish_enum (enumtype)
                minnode = value;
            }
 
-         if (processing_template_decl) 
+         if (processing_template_decl)
            /* If this is just a template, leave the CONST_DECL
               alone.  That way tsubst_copy will find CONST_DECLs for
               CONST_DECLs, and not INTEGER_CSTs.  */
@@ -12517,7 +13245,7 @@ finish_enum (enumtype)
     {
       tree scope = current_scope ();
       if (scope && TREE_CODE (scope) == FUNCTION_DECL)
-       add_tree (build_min (TAG_DEFN, enumtype));
+       add_stmt (build_min (TAG_DEFN, enumtype));
     }
   else
     {
@@ -12539,7 +13267,7 @@ finish_enum (enumtype)
 
       if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node)))
        /* Use the width of the narrowest normal C type which is wide
-          enough.  */ 
+          enough.  */
        TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
                                                    (precision, 1));
       else
@@ -12547,7 +13275,7 @@ finish_enum (enumtype)
 
       TYPE_SIZE (enumtype) = 0;
       layout_type (enumtype);
-    
+
       /* Fix up all variant types of this enum type.  */
       for (tem = TYPE_MAIN_VARIANT (enumtype); tem;
           tem = TYPE_NEXT_VARIANT (tem))
@@ -12560,6 +13288,7 @@ finish_enum (enumtype)
          TYPE_MODE (tem) = TYPE_MODE (enumtype);
          TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
          TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
+         TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
          TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
        }
 
@@ -12567,125 +13296,150 @@ finish_enum (enumtype)
       rest_of_type_compilation (enumtype, namespace_bindings_p ());
     }
 
-  /* In start_enum we pushed obstacks.  Here, we must pop them.  */
-  pop_obstacks ();
-
   return enumtype;
 }
 
 /* Build and install a CONST_DECL for an enumeration constant of the
-   enumeration type TYPE whose NAME and VALUE (if any) are provided.
+   enumeration type ENUMTYPE whose NAME and VALUE (if any) are provided.
    Assignment of sequential values by default is handled here.  */
 
-tree
-build_enumerator (name, value, type)
+void
+build_enumerator (name, value, enumtype)
      tree name;
      tree value;
-     tree type;
+     tree enumtype;
 {
-  tree decl, result;
+  tree decl;
   tree context;
+  tree type;
+  tree values;
 
   /* Remove no-op casts from the value.  */
   if (value)
     STRIP_TYPE_NOPS (value);
 
- if (! processing_template_decl)
-   {
-     /* Validate and default VALUE.  */
-     if (value != NULL_TREE)
-       {
-        if (TREE_READONLY_DECL_P (value))
-          value = decl_constant_value (value);
-
-        if (TREE_CODE (value) == INTEGER_CST)
-          {
-            value = default_conversion (value);
-            constant_expression_warning (value);
-          }
-        else
-          {
-            cp_error ("enumerator value for `%D' not integer constant", name);
-            value = NULL_TREE;
-          }
-       }
-
-     /* Default based on previous value.  */
-     if (value == NULL_TREE && ! processing_template_decl)
-       {
-        value = enum_next_value;
-        if (enum_overflow)
-          cp_error ("overflow in enumeration values at `%D'", name);
-       }
-
-     /* Remove no-op casts from the value.  */
-     if (value)
-       STRIP_TYPE_NOPS (value);
+  if (! processing_template_decl)
+    {
+      /* Validate and default VALUE.  */
+      if (value != NULL_TREE)
+       {
+         value = decl_constant_value (value);
+
+         if (TREE_CODE (value) == INTEGER_CST)
+           {
+             value = default_conversion (value);
+             constant_expression_warning (value);
+           }
+         else
+           {
+             cp_error ("enumerator value for `%D' not integer constant", name);
+             value = NULL_TREE;
+           }
+       }
+
+      /* Default based on previous value.  */
+      if (value == NULL_TREE && ! processing_template_decl)
+       {
+         tree prev_value;
+
+         if (TYPE_VALUES (enumtype))
+           {
+             /* The next value is the previous value ... */
+             prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
+             /* ... plus one.  */
+             value = cp_build_binary_op (PLUS_EXPR,
+                                         prev_value,
+                                         integer_one_node);
+
+             if (tree_int_cst_lt (value, prev_value))
+               cp_error ("overflow in enumeration values at `%D'", name);
+           }
+         else
+           value = integer_zero_node;
+       }
+
+      /* Remove no-op casts from the value.  */
+      if (value)
+       STRIP_TYPE_NOPS (value);
 #if 0
-     /* To fix MAX_VAL enum consts. (bkoz)  */
-     TREE_TYPE (value) = integer_type_node;
+      /* To fix MAX_VAL enum consts. (bkoz)  */
+      TREE_TYPE (value) = integer_type_node;
 #endif
-   }
+    }
 
- /* We always have to copy here; not all INTEGER_CSTs are unshared.
-    Even in other cases, we will later (in finish_enum) be setting the
-    type of VALUE.  */
- if (value != NULL_TREE)
-   value = copy_node (value);
+  /* We always have to copy here; not all INTEGER_CSTs are unshared.
+     Even in other cases, we will later (in finish_enum) be setting
+     the type of VALUE.  But, we don't need to make a copy if this
+     VALUE is one of the enumeration constants for this same
+     enumeration type.  */
+  for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
+    if (TREE_VALUE (values) == value)
+      break;
+  /* If we didn't break out of the loop, then we do need a copy.  */
+  if (!values && value)
+    value = copy_node (value);
 
   /* C++ associates enums with global, function, or class declarations.  */
- context = current_scope ();
- if (context && context == current_class_type)
-   /* This enum declaration is local to the class.  */
-   decl = build_lang_decl (CONST_DECL, name, type);
- else
-   /* It's a global enum, or it's local to a function.  (Note local to
+  context = current_scope ();
+
+  /* Build the actual enumeration constant.  Note that the enumeration
+    constants have the type of their initializers until the
+    enumeration is complete:
+
+      [ dcl.enum ]
+
+      Following the closing brace of an enum-specifier, each enumer-
+      ator has the type of its enumeration.  Prior to the closing
+      brace, the type of each enumerator is the type of its
+      initializing value.
+
+    In finish_enum we will reset the type.  Of course, if we're
+    processing a template, there may be no value.   */
+  type = value ? TREE_TYPE (value) : NULL_TREE;
+
+  if (context && context == current_class_type)
+    /* This enum declaration is local to the class.  We need the full
+       lang_decl so that we can record DECL_CLASS_CONTEXT, for example.  */
+    decl = build_lang_decl (CONST_DECL, name, type);
+  else
+    /* It's a global enum, or it's local to a function.  (Note local to
       a function could mean local to a class method.  */
-   decl = build_decl (CONST_DECL, name, type);
+    decl = build_decl (CONST_DECL, name, type);
 
- DECL_CONTEXT (decl) = FROB_CONTEXT (context);
- DECL_INITIAL (decl) = value;
- TREE_READONLY (decl) = 1;
 DECL_CONTEXT (decl) = FROB_CONTEXT (context);
 DECL_INITIAL (decl) = value;
 TREE_READONLY (decl) = 1;
 
- if (context && context == current_class_type)
-   /* In something like `struct S { enum E { i = 7 }; };' we put `i'
 if (context && context == current_class_type)
+    /* In something like `struct S { enum E { i = 7 }; };' we put `i'
       on the TYPE_FIELDS list for `S'.  (That's so that you can say
       things like `S::i' later.)  */
-   finish_member_declaration (decl);
- else
-   {
-     pushdecl (decl);
-     GNU_xref_decl (current_function_decl, decl);
-   }
-
- if (! processing_template_decl)
-   {
-     /* Set basis for default for next value.  */
-     enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
-                                                 integer_one_node, PLUS_EXPR);
-     enum_overflow = tree_int_cst_lt (enum_next_value, value);
-   }
-
-  result = tree_cons (name, decl, NULL_TREE);
-  return result;
+    finish_member_declaration (decl);
+  else
+    {
+      pushdecl (decl);
+      GNU_xref_decl (current_function_decl, decl);
+    }
+
+  /* Add this enumeration constant to the list for this type.  */
+  TYPE_VALUES (enumtype) = tree_cons (name, decl, TYPE_VALUES (enumtype));
 }
 
 \f
-static int function_depth;
-
 /* We're defining DECL.  Make sure that it's type is OK.  */
 
 static void
-check_function_type (decl)
+check_function_type (decl, current_function_parms)
      tree decl;
+     tree current_function_parms;
 {
   tree fntype = TREE_TYPE (decl);
+  tree return_type = complete_type (TREE_TYPE (fntype));
 
   /* In a function definition, arg types must be complete.  */
   require_complete_types_for_parms (current_function_parms);
 
-  if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
+  if (!COMPLETE_OR_VOID_TYPE_P (return_type))
     {
       cp_error ("return type `%#T' is incomplete", TREE_TYPE (fntype));
 
@@ -12703,7 +13457,7 @@ check_function_type (decl)
        TREE_TYPE (decl)
          = build_function_type (void_type_node,
                                 TYPE_ARG_TYPES (TREE_TYPE (decl)));
-      TREE_TYPE (decl) 
+      TREE_TYPE (decl)
        = build_exception_variant (fntype,
                                   TYPE_RAISES_EXCEPTIONS (fntype));
     }
@@ -12719,10 +13473,8 @@ check_function_type (decl)
    FLAGS is a bitwise or of SF_PRE_PARSED (indicating that the
    DECLARATOR is really the DECL for the function we are about to
    process and that DECLSPECS should be ignored), SF_INCLASS_INLINE
-   indicating that the function is an inline defined in-class, and
-   SF_EXPAND indicating that we should generate RTL for this
-   function.  
-   
+   indicating that the function is an inline defined in-class.
+
    This function creates a binding context for the function body
    as well as setting up the FUNCTION_DECL in current_function_decl.
 
@@ -12748,6 +13500,7 @@ start_function (declspecs, declarator, attrs, flags)
   extern int used_extern_spec;
   int doing_friend = 0;
   struct binding_level *bl;
+  tree current_function_parms;
 
   /* Sanity check.  */
   my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
@@ -12768,12 +13521,11 @@ start_function (declspecs, declarator, attrs, flags)
       if (TREE_CODE (fntype) == METHOD_TYPE)
        ctype = TYPE_METHOD_BASETYPE (fntype);
 
-      /* ANSI C++ June 5 1992 WP 11.4.5.  A friend function defined in a
-        class is in the (lexical) scope of the class in which it is
-        defined.  */
+      /* ISO C++ 11.4/5.  A friend function defined in a class is in
+        the (lexical) scope of the class in which it is defined.  */
       if (!ctype && DECL_FRIEND_P (decl1))
        {
-         ctype = DECL_CLASS_CONTEXT (decl1);
+         ctype = DECL_FRIEND_CONTEXT (decl1);
 
          /* CTYPE could be null here if we're dealing with a template;
             for example, `inline friend float foo()' inside a template
@@ -12800,7 +13552,7 @@ start_function (declspecs, declarator, attrs, flags)
       if (CLASS_TYPE_P (restype) && !CLASSTYPE_GOT_SEMICOLON (restype))
        {
          cp_error ("semicolon missing after declaration of `%#T'", restype);
-         shadow_tag (build_expr_list (NULL_TREE, restype));
+         shadow_tag (build_tree_list (NULL_TREE, restype));
          CLASSTYPE_GOT_SEMICOLON (restype) = 1;
          if (TREE_CODE (fntype) == FUNCTION_TYPE)
            fntype = build_function_type (integer_type_node,
@@ -12825,13 +13577,13 @@ start_function (declspecs, declarator, attrs, flags)
            }
        }
     }
-  
+
   /* Sometimes we don't notice that a function is a static member, and
      build a METHOD_TYPE for it.  Fix that up now.  */
   if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
       && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
     {
-      revert_static_member_fn (&decl1, NULL, NULL);
+      revert_static_member_fn (decl1);
       last_function_parms = TREE_CHAIN (last_function_parms);
       ctype = NULL_TREE;
     }
@@ -12858,9 +13610,9 @@ start_function (declspecs, declarator, attrs, flags)
   if (flags & SF_INCLASS_INLINE)
     maybe_begin_member_template_processing (decl1);
 
-  /* Effective C++ rule 15.  See also c_expand_return.  */
+  /* Effective C++ rule 15.  */
   if (warn_ecpp
-      && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
+      && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
       && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
     cp_warning ("`operator=' should return a reference to `*this'");
 
@@ -12872,7 +13624,7 @@ start_function (declspecs, declarator, attrs, flags)
 #ifdef SET_DEFAULT_DECL_ATTRIBUTES
   SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
 #endif
-  
+
   /* This function exists in static storage.
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
@@ -12896,7 +13648,7 @@ start_function (declspecs, declarator, attrs, flags)
      you declare a function, these types can be incomplete, but they
      must be complete when you define the function.  */
   if (! processing_template_decl)
-    check_function_type (decl1);
+    check_function_type (decl1, current_function_parms);
 
   /* Build the return declaration for the function.  */
   restype = TREE_TYPE (fntype);
@@ -12906,8 +13658,8 @@ start_function (declspecs, declarator, attrs, flags)
        {
          DECL_RESULT (decl1)
            = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
-         c_apply_type_quals_to_decl (CP_TYPE_QUALS (restype), 
-                                     DECL_RESULT (decl1)); 
+         c_apply_type_quals_to_decl (CP_TYPE_QUALS (restype),
+                                     DECL_RESULT (decl1));
        }
     }
   else
@@ -12917,27 +13669,23 @@ start_function (declspecs, declarator, attrs, flags)
   /* Initialize RTL machinery.  We cannot do this until
      CURRENT_FUNCTION_DECL and DECL_RESULT are set up.  We do this
      even when processing a template; this is how we get
-     CURRENT_FUNCTION set up, and our per-function variables
-     initialized.  */
+     CFUN set up, and our per-function variables initialized.  */
   bl = current_binding_level;
   init_function_start (decl1, input_filename, lineno);
   current_binding_level = bl;
-  expanding_p = (flags & SF_EXPAND) != 0;
 
   /* Even though we're inside a function body, we still don't want to
      call expand_expr to calculate the size of a variable-sized array.
      We haven't necessarily assigned RTL to all variables yet, so it's
      not safe to try to expand expressions involving them.  */
   immediate_size_expand = 0;
-  current_function->x_dont_save_pending_sizes_p = 1;
+  cfun->x_dont_save_pending_sizes_p = 1;
 
-  /* If we're building a statement-tree, start the tree now.  */
-  if (processing_template_decl || !expanding_p)
-    begin_stmt_tree (&DECL_SAVED_TREE (decl1));
+  /* Start the statement-tree, start the tree now.  */
+  begin_stmt_tree (&DECL_SAVED_TREE (decl1));
 
   /* Let the user know we're compiling this function.  */
-  if (processing_template_decl || !building_stmt_tree ())
-    announce_function (decl1);
+  announce_function (decl1);
 
   /* Record the decl so that the function name is defined.
      If we already have a decl for this name, and it is a FUNCTION_DECL,
@@ -12945,8 +13693,7 @@ start_function (declspecs, declarator, attrs, flags)
   if (!processing_template_decl && !(flags & SF_PRE_PARSED))
     {
       /* A specialization is not used to guide overload resolution.  */
-      if ((flag_guiding_decls 
-          || !DECL_TEMPLATE_SPECIALIZATION (decl1))
+      if (!DECL_TEMPLATE_SPECIALIZATION (decl1)
          && ! DECL_FUNCTION_MEMBER_P (decl1))
        decl1 = pushdecl (decl1);
       else
@@ -12957,73 +13704,53 @@ start_function (declspecs, declarator, attrs, flags)
          /* And make sure we have enough default args.  */
          check_default_args (decl1);
        }
-      DECL_MAIN_VARIANT (decl1) = decl1;
       fntype = TREE_TYPE (decl1);
     }
 
   /* Reset these in case the call to pushdecl changed them.  */
   current_function_decl = decl1;
-  current_function->decl = decl1;
+  cfun->decl = decl1;
 
-  /* Initialize the per-function data.  */
-  if (!DECL_PENDING_INLINE_P (decl1) && DECL_SAVED_FUNCTION_DATA (decl1))
+  /* If we are (erroneously) defining a function that we have already
+     defined before, wipe out what we knew before.  */
+  if (!DECL_PENDING_INLINE_P (decl1) 
+      && DECL_SAVED_FUNCTION_DATA (decl1))
     {
-      /* If we already parsed this function, and we're just expanding it
-        now, restore saved state.  */
-      struct binding_level *bl = current_binding_level;
-      *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (decl1);
-      current_binding_level = bl;
-
-      /* This function is being processed in whole-function mode; we
-        already did semantic analysis.  */
-      current_function->x_whole_function_mode_p = 1;
-
-      /* If we decided that we didn't want to inline this function,
-        make sure the back-end knows that.  */
-      if (!current_function_cannot_inline)
-       current_function_cannot_inline = cp_function_chain->cannot_inline;
-
-      /* We don't need the saved data anymore.  */
       free (DECL_SAVED_FUNCTION_DATA (decl1));
       DECL_SAVED_FUNCTION_DATA (decl1) = NULL;
     }
-  else if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))
+
+  if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))
     {
       /* We know that this was set up by `grokclassfn'.  We do not
         wait until `store_parm_decls', since evil parse errors may
         never get us to that point.  Here we keep the consistency
         between `current_class_type' and `current_class_ptr'.  */
       tree t = DECL_ARGUMENTS (decl1);
-             
-      my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL, 
+
+      my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL,
                          162);
       my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
                          19990811);
-         
-      cp_function_chain->x_current_class_ref 
+
+      cp_function_chain->x_current_class_ref
        = build_indirect_ref (t, NULL_PTR);
       cp_function_chain->x_current_class_ptr = t;
 
       /* Constructors and destructors need to know whether they're "in
         charge" of initializing virtual base classes.  */
-      if (DECL_DESTRUCTOR_P (decl1))
-       current_in_charge_parm = TREE_CHAIN (t);
-      else if (DECL_CONSTRUCTOR_P (decl1)
-              && TREE_CHAIN (t)
-              && DECL_ARTIFICIAL (TREE_CHAIN (t))
-              && (DECL_NAME (TREE_CHAIN (t))
-                  == in_charge_identifier))
+      if (DECL_HAS_IN_CHARGE_PARM_P (decl1))
        current_in_charge_parm = TREE_CHAIN (t);
     }
 
   if (DECL_INTERFACE_KNOWN (decl1))
     {
-      tree ctx = hack_decl_function_context (decl1);
+      tree ctx = decl_function_context (decl1);
 
       if (DECL_NOT_REALLY_EXTERN (decl1))
        DECL_EXTERNAL (decl1) = 0;
 
-      if (ctx != NULL_TREE && DECL_THIS_INLINE (ctx) 
+      if (ctx != NULL_TREE && DECL_THIS_INLINE (ctx)
          && TREE_PUBLIC (ctx))
        /* This is a function in a local class in an extern inline
           function.  */
@@ -13075,26 +13802,21 @@ start_function (declspecs, declarator, attrs, flags)
       if ((DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1))
          && ! DECL_INTERFACE_KNOWN (decl1)
          /* Don't try to defer nested functions for now.  */
-         && ! hack_decl_function_context (decl1))
+         && ! decl_function_context (decl1))
        DECL_DEFER_OUTPUT (decl1) = 1;
       else
        DECL_INTERFACE_KNOWN (decl1) = 1;
     }
 
-  if (doing_semantic_analysis_p ())
-    {
-      pushlevel (0);
-      current_binding_level->parm_flag = 1;
-    }
+  pushlevel (0);
+  current_binding_level->parm_flag = 1;
 
   if (attrs)
     cplus_decl_attributes (decl1, NULL_TREE, attrs);
-  
-  if (!building_stmt_tree ())
-    {
-      GNU_xref_function (decl1, current_function_parms);
-      make_function_rtl (decl1);
-    }
+
+  /* We need to do this even if we aren't expanding yet so that
+     assemble_external works.  */
+  make_function_rtl (decl1);
 
   /* Promote the value to int before returning it.  */
   if (C_PROMOTING_INTEGER_TYPE_P (restype))
@@ -13113,40 +13835,38 @@ start_function (declspecs, declarator, attrs, flags)
       TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = CP_TYPE_VOLATILE_P (restype);
     }
 
-  /* Allocate further tree nodes temporarily during compilation
-     of this function only.  Tiemann moved up here from bottom of fn.  */
-  /* If this is a nested function, then we must continue to allocate RTL
-     on the permanent obstack in case we need to inline it later.  */
-  if (! hack_decl_function_context (decl1))
-    temporary_allocation ();
-  
   ++function_depth;
 
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
-      && DECL_LANGUAGE (decl1) == lang_cplusplus)
-    dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-  else if (DECL_CONSTRUCTOR_P (decl1))
-    ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+  if (DECL_DESTRUCTOR_P (decl1))
+    {
+      dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+      DECL_CONTEXT (dtor_label) = current_function_decl;
+    }
+  /* Under the old ABI we return `this' from constructors, so we make
+     ordinary `return' statements in constructors jump to CTOR_LABEL;
+     from there we return `this'.  Under the new ABI, we don't bother
+     with any of this.  By not setting CTOR_LABEL the remainder of the
+     machinery is automatically disabled.  */
+  else if (!flag_new_abi && DECL_CONSTRUCTOR_P (decl1))
+    {
+      ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+      DECL_CONTEXT (ctor_label) = current_function_decl;
+    }
+
+  store_parm_decls (current_function_parms);
 
   return 1;
 }
 \f
-/* Called after store_parm_decls for a function-try-block.  */
-
-void
-expand_start_early_try_stmts ()
-{
-  expand_start_try_stmts ();
-}
-
 /* Store the parameter declarations into the current function declaration.
    This is called after parsing the parameter declarations, before
    digesting the body of the function.
 
    Also install to binding contour return value identifier, if any.  */
 
-void
-store_parm_decls ()
+static void
+store_parm_decls (current_function_parms)
+     tree current_function_parms;
 {
   register tree fndecl = current_function_decl;
   register tree parm;
@@ -13161,10 +13881,6 @@ store_parm_decls ()
      then CONST_DECLs for foo and bar are put here.  */
   tree nonparms = NULL_TREE;
 
-  /* Create a binding level for the parms.  */
-  if (!building_stmt_tree ())
-    expand_start_bindings (2);
-
   if (current_function_parms)
     {
       /* This case is when the function was defined with an ANSI prototype.
@@ -13175,43 +13891,34 @@ store_parm_decls ()
       tree specparms = current_function_parms;
       tree next;
 
-      if (doing_semantic_analysis_p ())
-       {
-         /* Must clear this because it might contain TYPE_DECLs declared
+      /* Must clear this because it might contain TYPE_DECLs declared
             at class level.  */
-         storedecls (NULL_TREE);
+      storedecls (NULL_TREE);
 
-         /* If we're doing semantic analysis, then we'll call pushdecl
+      /* If we're doing semantic analysis, then we'll call pushdecl
             for each of these.  We must do them in reverse order so that
             they end in the correct forward order.  */
-         specparms = nreverse (specparms);
-       }
+      specparms = nreverse (specparms);
 
       for (parm = specparms; parm; parm = next)
        {
          next = TREE_CHAIN (parm);
          if (TREE_CODE (parm) == PARM_DECL)
            {
-             tree type = TREE_TYPE (parm);
+             tree cleanup;
 
-             if (doing_semantic_analysis_p ())
-               {
-                 tree cleanup;
-             
-                 if (DECL_NAME (parm) == NULL_TREE
-                     || TREE_CODE (parm) != VOID_TYPE)
-                   pushdecl (parm);
-                 else
-                   cp_error ("parameter `%D' declared void", parm);
+             if (DECL_NAME (parm) == NULL_TREE
+                 || TREE_CODE (parm) != VOID_TYPE)
+               pushdecl (parm);
+             else
+               cp_error ("parameter `%D' declared void", parm);
 
-                 cleanup = maybe_build_cleanup (parm);
-                 
-                 if (cleanup)
-                   cleanups = tree_cons (parm, cleanup, cleanups);
-               }
-             else if (type != error_mark_node
-                      && TYPE_NEEDS_DESTRUCTOR (type))
-               parms_have_cleanups = 1;
+             cleanup = (processing_template_decl 
+                        ? NULL_TREE
+                        : maybe_build_cleanup (parm));
+
+             if (cleanup)
+               cleanups = tree_cons (parm, cleanup, cleanups);
            }
          else
            {
@@ -13222,14 +13929,11 @@ store_parm_decls ()
            }
        }
 
-      if (doing_semantic_analysis_p ())
-       {
-         /* Get the decls in their original chain order
-            and record in the function.  This is all and only the
-            PARM_DECLs that were pushed into scope by the loop above.  */
-         DECL_ARGUMENTS (fndecl) = getdecls ();
-         storetags (chainon (parmtags, gettags ()));
-       }
+      /* Get the decls in their original chain order and record in the
+        function.  This is all and only the PARM_DECLs that were
+        pushed into scope by the loop above.  */
+      DECL_ARGUMENTS (fndecl) = getdecls ();
+      storetags (chainon (parmtags, gettags ()));
     }
   else
     DECL_ARGUMENTS (fndecl) = NULL_TREE;
@@ -13238,64 +13942,30 @@ store_parm_decls ()
      as the decl-chain of the current lexical scope.
      Put the enumerators in as well, at the front so that
      DECL_ARGUMENTS is not modified.  */
-  if (doing_semantic_analysis_p ())
-    storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
-
-  /* Initialize the RTL code for the function.  */
-  DECL_SAVED_INSNS (fndecl) = 0;
-  if (! building_stmt_tree ())
-    expand_function_start (fndecl, parms_have_cleanups);
-
-  current_function_parms_stored = 1;
-
-  /* If this function is `main', emit a call to `__main'
-     to run global initializers, etc.  */
-  if (DECL_MAIN_P (fndecl) && !building_stmt_tree ())
-    expand_main_function ();
+  storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
 
   /* Now that we have initialized the parms, we can start their
      cleanups.  We cannot do this before, since expand_decl_cleanup
      should not be called before the parm can be used.  */
   while (cleanups)
     {
-      finish_decl_cleanup (TREE_PURPOSE (cleanups), 
+      finish_decl_cleanup (TREE_PURPOSE (cleanups),
                           TREE_VALUE (cleanups));
       cleanups = TREE_CHAIN (cleanups);
     }
 
   /* Create a binding contour which can be used to catch
-     cleanup-generated temporaries.  Also, if the return value needs or
-     has initialization, deal with that now.  */
+     cleanup-generated temporaries.  */
   if (parms_have_cleanups)
-    {
-      pushlevel (0);
-      if (!building_stmt_tree ())
-       expand_start_bindings (2);
-    }
+    pushlevel (0);
 
   /* Do the starting of the exception specifications, if we have any.  */
-  if (flag_exceptions && !processing_template_decl 
-      && building_stmt_tree () 
+  if (flag_exceptions && !processing_template_decl
+      && flag_enforce_eh_specs
       && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
     current_eh_spec_try_block = expand_start_eh_spec ();
 }
 
-/* Bind a name and initialization to the return value of
-   the current function.  */
-
-void
-store_return_init (decl)
-     tree decl;
-{
-  /* If this named return value comes in a register, put it in a
-     pseudo-register.  */
-  if (DECL_REGISTER (decl))
-    {
-      original_result_rtx = DECL_RTL (decl);
-      DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
-    }
-}
-
 \f
 /* We have finished doing semantic analysis on DECL, but have not yet
    generated RTL for its body.  Save away our current state, so that
@@ -13305,26 +13975,23 @@ static void
 save_function_data (decl)
      tree decl;
 {
-  struct language_function *f;
+  struct cp_language_function *f;
 
   /* Save the language-specific per-function data so that we can
      get it back when we really expand this function.  */
   my_friendly_assert (!DECL_PENDING_INLINE_P (decl),
                      19990908);
-      
+
   /* Make a copy.  */
-  f = ((struct language_function *) 
-       xmalloc (sizeof (struct language_function)));
+  f = ((struct cp_language_function *)
+       xmalloc (sizeof (struct cp_language_function)));
   bcopy ((char *) cp_function_chain, (char *) f,
-        sizeof (struct language_function));
+        sizeof (struct cp_language_function));
   DECL_SAVED_FUNCTION_DATA (decl) = f;
 
   /* Clear out the bits we don't need.  */
-  f->x_base_init_list = NULL_TREE;
-  f->x_member_init_list = NULL_TREE;
-  f->x_stmt_tree.x_last_stmt = NULL_TREE;
-  f->x_stmt_tree.x_last_expr_type = NULL_TREE;
-  f->x_result_rtx = NULL_RTX;
+  f->base.x_stmt_tree.x_last_stmt = NULL_TREE;
+  f->base.x_stmt_tree.x_last_expr_type = NULL_TREE;
   f->x_named_label_uses = NULL;
   f->bindings = NULL;
 
@@ -13344,7 +14011,8 @@ static void
 finish_constructor_body ()
 {
   /* Any return from a constructor will end up here.  */
-  add_tree (build_min_nt (LABEL_STMT, ctor_label));
+  if (ctor_label)
+    add_stmt (build_stmt (LABEL_STMT, ctor_label));
 
   /* Clear CTOR_LABEL so that finish_return_stmt knows to really
      generate the return, rather than a goto to CTOR_LABEL.  */
@@ -13352,6 +14020,8 @@ finish_constructor_body ()
   /* In check_return_expr we translate an empty return from a
      constructor to a return of `this'.  */
   finish_return_stmt (NULL_TREE);
+  /* Mark the end of the constructor.  */
+  add_stmt (build_stmt (CTOR_STMT));
 }
 
 /* At the end of every destructor we generate code to restore virtual
@@ -13362,15 +14032,15 @@ static void
 finish_destructor_body ()
 {
   tree compound_stmt;
-  tree in_charge;
   tree virtual_size;
   tree exprstmt;
+  tree if_stmt;
 
   /* Create a block to contain all the extra code.  */
   compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
 
   /* Any return from a destructor will end up here.  */
-  add_tree (build_min_nt (LABEL_STMT, dtor_label));
+  add_stmt (build_stmt (LABEL_STMT, dtor_label));
 
   /* Generate the code to call destructor on base class.  If this
      destructor belongs to a class with virtual functions, then set
@@ -13382,17 +14052,10 @@ finish_destructor_body ()
      will set the flag again.  */
   TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
 
-  /* These are two cases where we cannot delegate deletion.  */
-  if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
-      || TYPE_GETS_REG_DELETE (current_class_type))
-    in_charge = integer_zero_node;
-  else
-    in_charge = current_in_charge_parm;
-
   exprstmt = build_delete (current_class_type,
-                          current_class_ref, 
-                          in_charge,
-                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 
+                          current_class_ref,
+                          sfk_base_destructor,
+                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
                           0);
 
   if (exprstmt != error_mark_node
@@ -13408,64 +14071,66 @@ finish_destructor_body ()
       /* Run destructors for all virtual baseclasses.  */
       if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
        {
-         tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
-         tree if_stmt = begin_if_stmt ();
+         tree vbases;
+         tree if_stmt;
+
+         if_stmt = begin_if_stmt ();
          finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
-                                     current_in_charge_parm, 
+                                     current_in_charge_parm,
                                      integer_two_node),
                               if_stmt);
 
-         while (vbases)
+         vbases = CLASSTYPE_VBASECLASSES (current_class_type);
+         /* The CLASSTYPE_VBASECLASSES list is in initialization
+            order, so we have to march through it in reverse order.  */
+         for (vbases = nreverse (copy_list (vbases));
+              vbases;
+              vbases = TREE_CHAIN (vbases))
            {
-             if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+             tree vbase = TREE_VALUE (vbases);
+
+             if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (vbase)))
                {
                  tree vb = get_vbase
-                   (BINFO_TYPE (vbases),
+                   (BINFO_TYPE (vbase),
                     TYPE_BINFO (current_class_type));
                  finish_expr_stmt
                    (build_scoped_method_call
-                    (current_class_ref, vb, dtor_identifier,
-                     build_expr_list (NULL_TREE, integer_zero_node)));
+                    (current_class_ref, vb, base_dtor_identifier,
+                     NULL_TREE));
                }
-             vbases = TREE_CHAIN (vbases);
            }
 
          finish_then_clause (if_stmt);
          finish_if_stmt ();
        }
     }
-  
+
   virtual_size = c_sizeof (current_class_type);
 
   /* At the end, call delete if that's what's requested.  */
-  
+
   /* FDIS sez: At the point of definition of a virtual destructor
      (including an implicit definition), non-placement operator delete
      shall be looked up in the scope of the destructor's class and if
      found shall be accessible and unambiguous.
-     
+
      This is somewhat unclear, but I take it to mean that if the class
      only defines placement deletes we don't do anything here.  So we
      pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
      they ever try to delete one of these.  */
-  if (TYPE_GETS_REG_DELETE (current_class_type)
-      || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-    {
-      tree if_stmt;
-
-      exprstmt = build_op_delete_call
-       (DELETE_EXPR, current_class_ptr, virtual_size,
-        LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
-
-      if_stmt = begin_if_stmt ();
-      finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
-                                 current_in_charge_parm,
-                                 integer_one_node),
-                          if_stmt);
-      finish_expr_stmt (exprstmt);
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
-    }
+  exprstmt = build_op_delete_call
+    (DELETE_EXPR, current_class_ptr, virtual_size,
+     LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+
+  if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+                             current_in_charge_parm,
+                             integer_one_node),
+                      if_stmt);
+  finish_expr_stmt (exprstmt);
+  finish_then_clause (if_stmt);
+  finish_if_stmt ();
 
   /* Close the block we started above.  */
   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
@@ -13475,11 +14140,8 @@ finish_destructor_body ()
    all the way to assembler language output.  The free the storage
    for the function definition.
 
-   This is called after parsing the body of the function definition.
-   LINENO is the current line number.
-
-   FLAGS is a bitwise or of the following values: 
-     1 - CALL_POPLEVEL 
+   FLAGS is a bitwise or of the following values:
+     1 - CALL_POPLEVEL
        An extra call to poplevel (and expand_end_bindings) must be
        made to take care of the binding contour for the base
        initializers.  This is only relevant for constructors.
@@ -13489,17 +14151,13 @@ finish_destructor_body ()
        after the class definition is complete.)  */
 
 tree
-finish_function (lineno, flags)
-     int lineno;
+finish_function (flags)
      int flags;
 {
   register tree fndecl = current_function_decl;
   tree fntype, ctype = NULL_TREE;
-  /* Label to use if this function is supposed to return a value.  */
-  tree no_return_label = NULL_TREE;
   int call_poplevel = (flags & 1) != 0;
   int inclass_inline = (flags & 2) != 0;
-  int expand_p;
   int nested;
 
   /* When we get some parse errors, we can end up without a
@@ -13514,14 +14172,11 @@ finish_function (lineno, flags)
       This caused &foo to be of type ptr-to-const-function
       which then got a warning when stored in a ptr-to-function variable.  */
 
-  /* This happens on strange parse errors.  */
-  if (! current_function_parms_stored)
-    {
-      call_poplevel = 0;
-      store_parm_decls ();
-    }
+  my_friendly_assert (building_stmt_tree (), 20000911);
 
-  if (building_stmt_tree ())
+  /* For a cloned function, we've already got all the code we need;
+     there's no need to add any extra bits.  */
+  if (!DECL_CLONED_FUNCTION_P (fndecl))
     {
       if (DECL_CONSTRUCTOR_P (fndecl))
        {
@@ -13543,135 +14198,22 @@ finish_function (lineno, flags)
 
       /* Finish dealing with exception specifiers.  */
       if (flag_exceptions && !processing_template_decl
+         && flag_enforce_eh_specs
          && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
-       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS 
+       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
                            (TREE_TYPE (current_function_decl)),
                            current_eh_spec_try_block);
     }
-  else
-    {
-      if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
-       {
-         tree ttype = target_type (fntype);
-         tree parmdecl;
-
-         if (IS_AGGR_TYPE (ttype))
-           /* Let debugger know it should output info for this type.  */
-           note_debug_info_needed (ttype);
-
-         for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
-           {
-             ttype = target_type (TREE_TYPE (parmdecl));
-             if (IS_AGGR_TYPE (ttype))
-               /* Let debugger know it should output info for this type.  */
-               note_debug_info_needed (ttype);
-           }
-       }
-
-      /* Clean house because we will need to reorder insns here.  */
-      do_pending_stack_adjust ();
-
-      if (dtor_label)
-       ;
-      else if (DECL_CONSTRUCTOR_P (fndecl))
-       {
-         /* All subobjects have been fully constructed at this point.  */
-         end_protect_partials ();
 
-         if (call_poplevel)
-           do_poplevel ();
-       }
-      else if (return_label != NULL_RTX
-              && flag_this_is_variable <= 0
-              && current_function_return_value == NULL_TREE
-              && ! DECL_NAME (DECL_RESULT (current_function_decl)))
-       no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
-      if (flag_exceptions)
-       expand_exception_blocks ();
-
-      /* If this function is supposed to return a value, ensure that
-        we do not fall into the cleanups by mistake.  The end of our
-        function will look like this:
-        
-        user code (may have return stmt somewhere)
-        goto no_return_label
-        cleanup_label:
-        cleanups
-        goto return_label
-        no_return_label:
-        NOTE_INSN_FUNCTION_END
-        return_label:
-        things for return
-        
-        If the user omits a return stmt in the USER CODE section, we
-        will have a control path which reaches NOTE_INSN_FUNCTION_END.
-        Otherwise, we won't.  */
-      if (no_return_label)
-       {
-         DECL_CONTEXT (no_return_label) = fndecl;
-         DECL_INITIAL (no_return_label) = error_mark_node;
-         DECL_SOURCE_FILE (no_return_label) = input_filename;
-         DECL_SOURCE_LINE (no_return_label) = lineno;
-         expand_goto (no_return_label);
-       }
-
-      if (cleanup_label)
-       {
-         /* Remove the binding contour which is used
-            to catch cleanup-generated temporaries.  */
-         expand_end_bindings (0, 0, 0);
-         poplevel (0, 0, 0);
-
-         /* Emit label at beginning of cleanup code for parameters.  */
-         emit_label (cleanup_label);
-       }
-
-      /* Get return value into register if that's where it's supposed
-        to be.  */
-      if (original_result_rtx)
-       fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
-
-      /* Finish building code that will trigger warnings if users forget
-        to make their functions return values.  */
-      if (no_return_label || cleanup_label)
-       emit_jump (return_label);
-      if (no_return_label)
-       {
-         /* We don't need to call `expand_*_return' here because we
-            don't need any cleanups here--this path of code is only
-            for error checking purposes.  */
-         expand_label (no_return_label);
-       }
-
-      /* We hard-wired immediate_size_expand to zero in
-        start_function.  Expand_function_end will decrement this
-        variable.  So, we set the variable to one here, so that after
-        the decrement it will remain zero.  */
-      immediate_size_expand = 1;
-
-      /* Generate rtl for function exit.  */
-      expand_function_end (input_filename, lineno, 1);
-    }
-
-  /* We have to save this value here in case
-     maybe_end_member_template_processing decides to pop all the
-     template parameters.  */
-  expand_p = !building_stmt_tree ();
-  
   /* If we're saving up tree structure, tie off the function now.  */
-  if (!expand_p)
-    finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
+  finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
 
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
      this function's blocks.  */
-  if (doing_semantic_analysis_p ())
-    {
-      if (current_binding_level->parm_flag != 1)
-       my_friendly_abort (122);
-      poplevel (1, 0, 1);
-    }
+  if (current_binding_level->parm_flag != 1)
+    my_friendly_abort (122);
+  poplevel (1, 0, 1);
 
   /* Remember that we were in class scope.  */
   if (current_class_name)
@@ -13685,113 +14227,27 @@ finish_function (lineno, flags)
   BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
 
   /* Save away current state, if appropriate.  */
-  if (!expanding_p && !processing_template_decl)
+  if (!processing_template_decl)
     save_function_data (fndecl);
 
-  if (expand_p)
-    {
-      int returns_null;
-      int returns_value;
-      int saved_flag_keep_inline_functions =
-       flag_keep_inline_functions;
-
-      /* So we can tell if jump_optimize sets it to 1.  */
-      can_reach_end = 0;
-
-      if (DECL_CONTEXT (fndecl) != NULL_TREE
-         && hack_decl_function_context (fndecl))
-       /* Trick rest_of_compilation into not deferring output of this
-          function, even if it is inline, since the rtl_obstack for
-          this function is the function_obstack of the enclosing
-          function and will be deallocated when the enclosing
-          function is gone.  See save_tree_status.  */
-       flag_keep_inline_functions = 1;
-
-      /* Before we call rest_of_compilation (which will pop the
-        CURRENT_FUNCTION), we must save these values.  */
-      returns_null = current_function_returns_null;
-      returns_value = current_function_returns_value;
-
-      /* If this is a nested function (like a template instantiation
-        that we're compiling in the midst of compiling something
-        else), push a new GC context.  That will keep local variables
-        on the stack from being collected while we're doing the
-        compilation of this function.  */
-      if (function_depth > 1)
-       ggc_push_context ();
-
-      /* Run the optimizers and output the assembler code for this
-         function.  */
-      if (DECL_ARTIFICIAL (fndecl))
-       {
-         /* Do we really *want* to inline this synthesized method?  */
-
-         int save_fif = flag_inline_functions;
-         flag_inline_functions = 1;
-
-         /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
-            will check our size.  */
-         DECL_INLINE (fndecl) = 0;
-
-         rest_of_compilation (fndecl);
-         flag_inline_functions = save_fif;
-       }
-      else
-       rest_of_compilation (fndecl);
-
-      /* Undo the call to ggc_push_context above.  */
-      if (function_depth > 1)
-       ggc_pop_context ();
-
-      flag_keep_inline_functions = saved_flag_keep_inline_functions;
-
-      if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
-       {
-         /* Set DECL_EXTERNAL so that assemble_external will be called as
-            necessary.  We'll clear it again in finish_file.  */
-         if (! DECL_EXTERNAL (fndecl))
-           DECL_NOT_REALLY_EXTERN (fndecl) = 1;
-         DECL_EXTERNAL (fndecl) = 1;
-         mark_inline_for_output (fndecl);
-       }
-
-      if (ctype && TREE_ASM_WRITTEN (fndecl))
-       note_debug_info_needed (ctype);
-
-      returns_null |= can_reach_end;
-
-      /* Since we don't normally go through c_expand_return for constructors,
-        this normally gets the wrong value.
-        Also, named return values have their return codes emitted after
-        NOTE_INSN_FUNCTION_END, confusing jump.c.  */
-      if (DECL_CONSTRUCTOR_P (fndecl)
-         || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE)
-       returns_null = 0;
-
-      if (TREE_THIS_VOLATILE (fndecl) && returns_null)
-       cp_warning ("`noreturn' function `%D' does return", fndecl);
-      else if ((warn_return_type || pedantic)
-              && returns_null
-              && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE)
-       {
-         /* If this function returns non-void and control can drop through,
-            complain.  */
-         cp_warning ("control reaches end of non-void function `%D'", fndecl);
-       }
-      /* With just -W, complain only if function returns both with
-        and without a value.  */
-      else if (extra_warnings && returns_value && returns_null)
-       warning ("this function may return with or without a value");
-    }
-  else
-    {
-      /* Clear out memory we no longer need.  */
-      free_after_parsing (current_function);
-      /* Since we never call rest_of_compilation, we never clear
-        CURRENT_FUNCTION.  Do so explicitly.  */
-      free_after_compilation (current_function);
-      current_function = NULL;
-    }
+  /* If this function calls `setjmp' it cannot be inlined.  When
+     `longjmp' is called it is not guaranteed to restore the value of
+     local variables that have been modified since the call to
+     `setjmp'.  So, if were to inline this function into some caller
+     `c', then when we `longjmp', we might not restore all variables
+     in `c'.  (It might seem, at first blush, that there's no way for
+     this function to modify local variables in `c', but their
+     addresses may have been stored somewhere accessible to this
+     function.)  */
+  if (!processing_template_decl && calls_setjmp_p (fndecl))
+    DECL_UNINLINABLE (fndecl) = 1;
+
+  /* Clear out memory we no longer need.  */
+  free_after_parsing (cfun);
+  /* Since we never call rest_of_compilation, we never clear
+     CFUN.  Do so explicitly.  */
+  free_after_compilation (cfun);
+  cfun = NULL;
 
   /* If this is a in-class inline definition, we may have to pop the
      bindings for the template parameters that we added in
@@ -13806,29 +14262,6 @@ finish_function (lineno, flags)
 
   --function_depth;
 
-  /* Free all the tree nodes making up this function.  */
-  /* Switch back to allocating nodes permanently
-     until we start another function.  */
-  if (! nested)
-    permanent_allocation (1);
-
-  if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
-    {
-      tree t;
-
-      /* Stop pointing to the local nodes about to be freed.  */
-      /* But DECL_INITIAL must remain nonzero so we know this
-        was an actual function definition.  */
-      DECL_INITIAL (fndecl) = error_mark_node;
-      for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t))
-       DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX;
-    }
-
-  if (DECL_STATIC_CONSTRUCTOR (fndecl))
-    static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
-  if (DECL_STATIC_DESTRUCTOR (fndecl))
-    static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
-
   /* Clean up.  */
   if (! nested)
     {
@@ -13836,6 +14269,9 @@ finish_function (lineno, flags)
          function.  For a nested function, this value is used in
          pop_cp_function_context and then reset via pop_function_context.  */
       current_function_decl = NULL_TREE;
+      /* We don't really care about obstacks, but the middle-end
+        sometimes cares on what obstck things are located.  */
+      permanent_allocation (1);
     }
 
   return fndecl;
@@ -13885,10 +14321,10 @@ start_method (declspecs, declarator, attrlist)
     {
       if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type)
        {
-         if (DECL_CONTEXT (fndecl) 
+         if (DECL_CONTEXT (fndecl)
              && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
-           cp_error ("`%D' is already defined in class %s", fndecl,
-                            TYPE_NAME_STRING (DECL_CONTEXT (fndecl)));
+           cp_error ("`%D' is already defined in class `%T'", fndecl,
+                     DECL_CONTEXT (fndecl));
        }
       return void_type_node;
     }
@@ -13904,12 +14340,6 @@ start_method (declspecs, declarator, attrlist)
   if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl))
     fndecl = push_template_decl (fndecl);
 
-  /* We read in the parameters on the maybepermanent_obstack,
-     but we won't be getting back to them until after we
-     may have clobbered them.  So the call to preserve_data
-     will keep them safe.  */
-  preserve_data ();
-
   if (! DECL_FRIEND_P (fndecl))
     {
       if (TREE_CHAIN (fndecl))
@@ -13927,12 +14357,12 @@ start_method (declspecs, declarator, attrlist)
        grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0);
     }
 
-  cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0, 0);
+  cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
 
   /* Make a place for the parms */
   pushlevel (0);
   current_binding_level->parm_flag = 1;
-  
+
   DECL_IN_AGGR_P (fndecl) = 1;
   return fndecl;
 }
@@ -14012,56 +14442,76 @@ hack_incomplete_structures (type)
      tree type;
 {
   tree *list;
-
-  if (current_binding_level->incomplete == NULL_TREE)
-    return;
+  struct binding_level *level;
 
   if (!type) /* Don't do this for class templates.  */
     return;
 
-  for (list = &current_binding_level->incomplete; *list; )
-    {
-      tree decl = TREE_VALUE (*list);
-      if ((decl && TREE_TYPE (decl) == type)
-         || (TREE_TYPE (decl)
-             && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-             && TREE_TYPE (TREE_TYPE (decl)) == type))
-       {
-         int toplevel = toplevel_bindings_p ();
-         if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-             && TREE_TYPE (TREE_TYPE (decl)) == type)
-           layout_type (TREE_TYPE (decl));
-         layout_decl (decl, 0);
-         rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
-         if (! toplevel)
+  if (namespace_bindings_p ())
+    {
+      level = 0;
+      list = &namespace_scope_incomplete;
+    }
+  else
+    {
+      level = innermost_nonclass_level ();
+      list = &level->incomplete;
+    }
+
+  while (1)
+    {
+      while (*list)
+       {
+         tree decl = TREE_VALUE (*list);
+         if ((decl && TREE_TYPE (decl) == type)
+             || (TREE_TYPE (decl)
+                 && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+                 && TREE_TYPE (TREE_TYPE (decl)) == type))
            {
-             tree cleanup;
-             expand_decl (decl);
-             cleanup = maybe_build_cleanup (decl);
-             expand_decl_init (decl);
-             if (! expand_decl_cleanup (decl, cleanup))
-               cp_error ("parser lost in parsing declaration of `%D'",
-                         decl);
+             int toplevel = toplevel_bindings_p ();
+             if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+                 && TREE_TYPE (TREE_TYPE (decl)) == type)
+               layout_type (TREE_TYPE (decl));
+             layout_decl (decl, 0);
+             rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
+             if (! toplevel)
+               {
+                 tree cleanup;
+                 expand_decl (decl);
+                 cleanup = maybe_build_cleanup (decl);
+                 expand_decl_init (decl);
+                 if (! expand_decl_cleanup (decl, cleanup))
+                   cp_error ("parser lost in parsing declaration of `%D'",
+                             decl);
+               }
+             *list = TREE_CHAIN (*list);
            }
-         *list = TREE_CHAIN (*list);
+         else
+           list = &TREE_CHAIN (*list);
+       }
+
+      /* Keep looking through artificial binding levels generated
+        for local variables.  */
+      if (level && level->keep == 2)
+       {
+         level = level->level_chain;
+         list = &level->incomplete;
        }
       else
-       list = &TREE_CHAIN (*list);
+       break;
     }
 }
 
-/* If DECL is of a type which needs a cleanup, build that cleanup here.
-   See build_delete for information about AUTO_DELETE.
-
-   Don't build these on the momentary obstack; they must live
-   the life of the binding contour.  */
+/* If DECL is of a type which needs a cleanup, build that cleanup
+   here.  */
 
-static tree
-maybe_build_cleanup_1 (decl, auto_delete)
-     tree decl, auto_delete;
+tree
+maybe_build_cleanup (decl)
+     tree decl;
 {
   tree type = TREE_TYPE (decl);
-  if (type != error_mark_node && TYPE_NEEDS_DESTRUCTOR (type))
+
+  if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
     {
       int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
       tree rval;
@@ -14079,86 +14529,19 @@ maybe_build_cleanup_1 (decl, auto_delete)
          || flag_expensive_optimizations)
        flags |= LOOKUP_NONVIRTUAL;
 
-      rval = build_delete (TREE_TYPE (rval), rval, auto_delete, flags, 0);
+      rval = build_delete (TREE_TYPE (rval), rval,
+                          sfk_complete_destructor, flags, 0);
 
       if (TYPE_USES_VIRTUAL_BASECLASSES (type)
          && ! TYPE_HAS_DESTRUCTOR (type))
        rval = build_compound_expr (tree_cons (NULL_TREE, rval,
-                                              build_expr_list (NULL_TREE, build_vbase_delete (type, decl))));
+                                              build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
 
       return rval;
     }
   return 0;
 }
-
-/* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
-
-tree
-build_target_expr (decl, value)
-     tree decl;
-     tree value;
-{
-  tree t;
-
-  t = build (TARGET_EXPR, TREE_TYPE (decl), decl, value, 
-            maybe_build_cleanup (decl), NULL_TREE);
-  /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
-     ignore the TARGET_EXPR.  If there really turn out to be no
-     side-effects, then the optimizer should be able to get rid of
-     whatever code is generated anyhow.  */
-  TREE_SIDE_EFFECTS (t) = 1;
-
-  return t;
-}
-
-/* If DECL is of a type which needs a cleanup, build that cleanup
-   here.  The cleanup does free the storage with a call to delete.  */
-
-tree
-maybe_build_cleanup_and_delete (decl)
-     tree decl;
-{
-  return maybe_build_cleanup_1 (decl, integer_three_node);
-}
-
-/* If DECL is of a type which needs a cleanup, build that cleanup
-   here.  The cleanup does not free the storage with a call a delete.  */
-
-tree
-maybe_build_cleanup (decl)
-     tree decl;
-{
-  return maybe_build_cleanup_1 (decl, integer_two_node);
-}
 \f
-/* Expand a C++ expression at the statement level.
-   This is needed to ferret out nodes which have UNKNOWN_TYPE.
-   The C++ type checker should get all of these out when
-   expressions are combined with other, type-providing, expressions,
-   leaving only orphan expressions, such as:
-
-   &class::bar;                / / takes its address, but does nothing with it.  */
-
-void
-cplus_expand_expr_stmt (exp)
-     tree exp;
-{
-  if (stmts_are_full_exprs_p)
-    exp = convert_to_void (exp, "statement");
-  
-#if 0
-  /* We should do this eventually, but right now this causes regex.o from
-     libg++ to miscompile, and tString to core dump.  */
-  exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
-#endif
-
-  /* If we don't do this, we end up down inside expand_expr
-     trying to do TYPE_MODE on the ERROR_MARK, and really
-     go outside the bounds of the type.  */
-  if (exp != error_mark_node)
-    expand_expr_stmt (exp);
-}
-
 /* When a stmt has been parsed, this function is called.  */
 
 void
@@ -14170,24 +14553,20 @@ finish_stmt ()
   last_expr_type = NULL_TREE;
 }
 
-/* Change a static member function definition into a FUNCTION_TYPE, instead
-   of the METHOD_TYPE that we create when it's originally parsed.
-
-   WARNING: DO NOT pass &TREE_TYPE (decl) to FN or &TYPE_ARG_TYPES
-   (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
-   other decls.  Either pass the addresses of local variables or NULL.  */
+/* DECL was originally constructed as a non-static member function,
+   but turned out to be static.  Update it accordingly.  */
 
 void
-revert_static_member_fn (decl, fn, argtypes)
-     tree *decl, *fn, *argtypes;
+revert_static_member_fn (decl)
+     tree decl;
 {
   tree tmp;
-  tree function = fn ? *fn : TREE_TYPE (*decl);
-  tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function);
+  tree function = TREE_TYPE (decl);
+  tree args = TYPE_ARG_TYPES (function);
 
-  if (CP_TYPE_QUALS (TREE_TYPE (TREE_VALUE (args))) 
+  if (CP_TYPE_QUALS (TREE_TYPE (TREE_VALUE (args)))
       != TYPE_UNQUALIFIED)
-    cp_error ("static member function `%#D' declared with type qualifiers", 
+    cp_error ("static member function `%#D' declared with type qualifiers",
              *decl);
 
   args = TREE_CHAIN (args);
@@ -14195,27 +14574,23 @@ revert_static_member_fn (decl, fn, argtypes)
   tmp = build_qualified_type (tmp, CP_TYPE_QUALS (function));
   tmp = build_exception_variant (tmp,
                                 TYPE_RAISES_EXCEPTIONS (function));
-  TREE_TYPE (*decl) = tmp;
-  if (DECL_ARGUMENTS (*decl))
-    DECL_ARGUMENTS (*decl) = TREE_CHAIN (DECL_ARGUMENTS (*decl));
-  DECL_STATIC_FUNCTION_P (*decl) = 1;
-  if (fn)
-    *fn = tmp;
-  if (argtypes)
-    *argtypes = args;
+  TREE_TYPE (decl) = tmp;
+  if (DECL_ARGUMENTS (decl))
+    DECL_ARGUMENTS (decl) = TREE_CHAIN (DECL_ARGUMENTS (decl));
+  DECL_STATIC_FUNCTION_P (decl) = 1;
 }
 
-/* Initialize the variables used during compilation of a C++ 
-   function.  */ 
+/* Initialize the variables used during compilation of a C++
+   function.  */
 
 static void
 push_cp_function_context (f)
      struct function *f;
 {
-  struct language_function *p 
-    = ((struct language_function *) 
-       xcalloc (1, sizeof (struct language_function)));
-  f->language = p;
+  struct cp_language_function *p
+    = ((struct cp_language_function *)
+       xcalloc (1, sizeof (struct cp_language_function)));
+  f->language = (struct language_function *) p;
 
   /* It takes an explicit call to expand_body to generate RTL for a
      function.  */
@@ -14223,7 +14598,7 @@ push_cp_function_context (f)
 
   /* Whenever we start a new function, we destroy temporaries in the
      usual way.  */
-  stmts_are_full_exprs_p = 1;
+  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
 }
 
 /* Free the language-specific parts of F, now that we've finished
@@ -14242,49 +14617,30 @@ pop_cp_function_context (f)
 
 static void
 mark_lang_function (p)
-     struct language_function *p;
+     struct cp_language_function *p;
 {
   if (!p)
     return;
 
-  ggc_mark_tree (p->x_named_labels);
+  mark_c_language_function (&p->base);
+
   ggc_mark_tree (p->x_ctor_label);
   ggc_mark_tree (p->x_dtor_label);
-  ggc_mark_tree (p->x_base_init_list);
-  ggc_mark_tree (p->x_member_init_list);
   ggc_mark_tree (p->x_current_class_ptr);
   ggc_mark_tree (p->x_current_class_ref);
   ggc_mark_tree (p->x_eh_spec_try_block);
-  ggc_mark_tree (p->x_scope_stmt_stack);
-
-  ggc_mark_rtx (p->x_result_rtx);
 
-  mark_stmt_tree (&p->x_stmt_tree);
+  mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
   mark_binding_level (&p->bindings);
 }
 
 /* Mark the language-specific data in F for GC.  */
 
-void
+static void
 mark_cp_function_context (f)
      struct function *f;
 {
-  mark_lang_function (f->language);
-}
-
-int
-in_function_p ()
-{
-  return function_depth != 0;
-}
-
-
-void
-lang_mark_false_label_stack (l)
-     struct label_node *l;
-{
-  /* C++ doesn't use false_label_stack.  It better be NULL.  */
-  my_friendly_assert (l == NULL, 19990904);
+  mark_lang_function ((struct cp_language_function *) f->language);
 }
 
 void
@@ -14327,18 +14683,24 @@ lang_mark_tree (t)
       if (ld)
        {
          ggc_mark (ld);
-         if (!DECL_GLOBAL_CTOR_P (t) && !DECL_GLOBAL_DTOR_P (t))
+         c_mark_lang_decl (&ld->decl_flags.base);
+         if (!DECL_GLOBAL_CTOR_P (t) 
+             && !DECL_GLOBAL_DTOR_P (t)
+             && !DECL_THUNK_P (t))
            ggc_mark_tree (ld->decl_flags.u2.access);
-         ggc_mark_tree (ld->decl_flags.context);
+         else if (DECL_THUNK_P (t))
+           ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
          if (TREE_CODE (t) != NAMESPACE_DECL)
            ggc_mark_tree (ld->decl_flags.u.template_info);
          else
            mark_binding_level (&NAMESPACE_LEVEL (t));
          if (CAN_HAVE_FULL_LANG_DECL_P (t))
            {
-             ggc_mark_tree (ld->main_decl_variant);
              ggc_mark_tree (ld->befriending_classes);
-             ggc_mark_tree (ld->saved_tree);
+             ggc_mark_tree (ld->context);
+             ggc_mark_tree (ld->cloned_function);
+             if (!DECL_OVERLOADED_OPERATOR_P (t))
+               ggc_mark_tree (ld->u2.vtt_parm);
              if (TREE_CODE (t) == TYPE_DECL)
                ggc_mark_tree (ld->u.sorted_fields);
              else if (TREE_CODE (t) == FUNCTION_DECL
@@ -14351,16 +14713,16 @@ lang_mark_tree (t)
     {
       struct lang_type *lt = TYPE_LANG_SPECIFIC (t);
 
-      if (lt && !(TREE_CODE (t) == POINTER_TYPE 
+      if (lt && !(TREE_CODE (t) == POINTER_TYPE
                  && TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE))
        {
          ggc_mark (lt);
+         ggc_mark_tree (lt->primary_base);
          ggc_mark_tree (lt->vfields);
          ggc_mark_tree (lt->vbases);
          ggc_mark_tree (lt->tags);
-         ggc_mark_tree (lt->search_slot);
          ggc_mark_tree (lt->size);
-         ggc_mark_tree (lt->abstract_virtuals);
+         ggc_mark_tree (lt->pure_virtuals);
          ggc_mark_tree (lt->friend_classes);
          ggc_mark_tree (lt->rtti);
          ggc_mark_tree (lt->methods);
@@ -14373,4 +14735,3 @@ lang_mark_tree (t)
        ggc_mark_tree ((tree) lt);
     }
 }
-