OSDN Git Service

* parse.y (extdefs): Call ggc_collect.
[pf3gnuchains/gcc-fork.git] / gcc / cp / parse.y
index f08393c..ab6012f 100644 (file)
@@ -1,5 +1,6 @@
 /* YACC parser for C++ syntax.
-   Copyright (C) 1988, 89, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -42,12 +43,12 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "except.h"
 #include "toplev.h"
+#include "ggc.h"
 
 /* Since parsers are distinct for each language, put the language string
    definition here.  (fnf) */
-char *language_string = "GNU C++";
+const char * const language_string = "GNU C++";
 
-extern tree void_list_node;
 extern struct obstack permanent_obstack;
 
 extern int end_of_file;
@@ -60,19 +61,42 @@ extern int end_of_file;
 
 /* Contains the statement keyword (if/while/do) to include in an
    error message if the user supplies an empty conditional expression.  */
-static char *cond_stmt_keyword;
-
-static tree empty_parms PROTO((void));
+static const char *cond_stmt_keyword;
 
 /* Nonzero if we have an `extern "C"' acting as an extern specifier.  */
 int have_extern_spec;
 int used_extern_spec;
 
+/* List of types and structure classes of the current declaration.  */
+static tree current_declspecs;
+
+/* List of prefix attributes in effect.
+   Prefix attributes are parsed by the reserved_declspecs and declmods
+   rules.  They create a list that contains *both* declspecs and attrs.  */
+/* ??? It is not clear yet that all cases where an attribute can now appear in
+   a declspec list have been updated.  */
+static tree prefix_attributes;
+
+/* When defining an aggregate, this is the kind of the most recent one
+   being defined.  (For example, this might be class_type_node.)  */
+static tree current_aggr;
+
+/* When defining an enumeration, this is the type of the enumeration.  */
+static tree current_enum_type;
+
+static tree empty_parms PARAMS ((void));
+static tree parse_decl0 PARAMS ((tree, tree, tree, tree, int));
+static tree parse_decl PARAMS ((tree, tree, int));
+static void parse_end_decl PARAMS ((tree, tree, tree));
+static tree parse_field0 PARAMS ((tree, tree, tree, tree, tree, tree));
+static tree parse_field PARAMS ((tree, tree, tree, tree));
+static tree parse_bitfield0 PARAMS ((tree, tree, tree, tree, tree));
+static tree parse_bitfield PARAMS ((tree, tree, tree));
+static tree parse_method PARAMS ((tree, tree, tree));
+static void frob_specs PARAMS ((tree, tree)); 
+
 /* Cons up an empty parameter list.  */
-#ifdef __GNUC__
-__inline
-#endif
-static tree
+static inline tree
 empty_parms ()
 {
   tree parms;
@@ -85,11 +109,123 @@ empty_parms ()
   return parms;
 }
 
+/* Record the decl-specifiers, attributes and type lookups from the
+   decl-specifier-seq in a declaration.  */
+
+static void
+frob_specs (specs_attrs, lookups)
+     tree specs_attrs, lookups;
+{
+  save_type_access_control (lookups);
+  split_specs_attrs (specs_attrs, &current_declspecs, &prefix_attributes);
+  if (current_declspecs
+      && TREE_CODE (current_declspecs) != TREE_LIST)
+    current_declspecs = build_decl_list (NULL_TREE, current_declspecs);
+  if (have_extern_spec && !used_extern_spec)
+    {
+      current_declspecs = decl_tree_cons (NULL_TREE, 
+                                         get_identifier ("extern"), 
+                                         current_declspecs);
+      used_extern_spec = 1;
+    }
+}
+
+static tree
+parse_decl (declarator, attributes, initialized)
+     tree declarator, attributes;
+     int initialized;
+{
+  return start_decl (declarator, current_declspecs, initialized,
+                    attributes, prefix_attributes);
+}
+
+static tree
+parse_decl0 (declarator, specs_attrs, lookups, attributes, initialized)
+     tree declarator, specs_attrs, lookups, attributes;
+     int initialized;
+{
+  frob_specs (specs_attrs, lookups);
+  return parse_decl (declarator, attributes, initialized);
+}
+
+static void
+parse_end_decl (decl, init, asmspec)
+     tree decl, init, asmspec;
+{
+  /* If decl is NULL_TREE, then this was a variable declaration using
+     () syntax for the initializer, so we handled it in grokdeclarator.  */
+  if (decl)
+    decl_type_access_control (decl);
+  cp_finish_decl (decl, init, asmspec, init ? LOOKUP_ONLYCONVERTING : 0);
+}
+
+static tree
+parse_field (declarator, attributes, asmspec, init)
+     tree declarator, attributes, asmspec, init;
+{
+  tree d = grokfield (declarator, current_declspecs, init, asmspec,
+                     build_tree_list (attributes, prefix_attributes));
+  decl_type_access_control (d);
+  return d;
+}
+
+static tree
+parse_field0 (declarator, specs_attrs, lookups, attributes, asmspec, init)
+     tree declarator, specs_attrs, lookups, attributes, asmspec, init;
+{
+  frob_specs (specs_attrs, lookups);
+  return parse_field (declarator, attributes, asmspec, init);
+}
+
+static tree
+parse_bitfield (declarator, attributes, width)
+     tree declarator, attributes, width;
+{
+  tree d = grokbitfield (declarator, current_declspecs, width);
+  cplus_decl_attributes (d, attributes, prefix_attributes);
+  decl_type_access_control (d);
+  return d;
+}
+
+static tree
+parse_bitfield0 (declarator, specs_attrs, lookups, attributes, width)
+     tree declarator, specs_attrs, lookups, attributes, width;
+{
+  frob_specs (specs_attrs, lookups);
+  return parse_bitfield (declarator, attributes, width);
+}
+
+static tree
+parse_method (declarator, specs_attrs, lookups)
+     tree declarator, specs_attrs, lookups;
+{
+  tree d;
+  frob_specs (specs_attrs, lookups);
+  d = start_method (current_declspecs, declarator, prefix_attributes);
+  decl_type_access_control (d);
+  return d;
+}
+
+void
+cp_parse_init ()
+{
+  ggc_add_tree_root (&current_declspecs, 1);
+  ggc_add_tree_root (&prefix_attributes, 1);
+  ggc_add_tree_root (&current_aggr, 1);
+  ggc_add_tree_root (&current_enum_type, 1);
+}
 %}
 
 %start program
 
-%union {long itype; tree ttype; char *strtype; enum tree_code code; flagged_type_tree ftype; }
+%union {
+  long itype; 
+  tree ttype; 
+  char *strtype; 
+  enum tree_code code; 
+  flagged_type_tree ftype; 
+  struct pending_inline *pi;
+}
 
 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -130,10 +266,10 @@ empty_parms ()
 /* the reserved words */
 /* SCO include files test "ASM", so use something else.  */
 %token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
-%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
+%token BREAK CONTINUE RETURN_KEYWORD GOTO ASM_KEYWORD TYPEOF ALIGNOF
 %token SIGOF
 %token ATTRIBUTE EXTENSION LABEL
-%token REALPART IMAGPART
+%token REALPART IMAGPART VA_ARG
 
 /* the reserved words... C++ extensions */
 %token <ttype> AGGR
@@ -178,7 +314,7 @@ empty_parms ()
 %left <code> POINTSAT_STAR DOT_STAR
 %right <code> UNARY PLUSPLUS MINUSMINUS '~'
 %left HYPERUNARY
-%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
+%left <ttype> LEFT_RIGHT
 %left <code> POINTSAT '.' '(' '['
 
 %right SCOPE                   /* C++ extension */
@@ -192,9 +328,7 @@ empty_parms ()
 %type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
 %type <ttype> reserved_declspecs boolean.literal
 %type <ttype> reserved_typespecquals
-%type <ttype> declmods 
 %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
-%type <itype> initdecls notype_initdecls initdcl       /* C++ modification */
 %type <ttype> init initlist maybeasm maybe_init defarg defarg1
 %type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
 %type <ttype> maybe_attribute attributes attribute attribute_list attrib
@@ -203,21 +337,22 @@ empty_parms ()
 %type <ttype> compstmt implicitly_scoped_stmt
 
 %type <ttype> declarator notype_declarator after_type_declarator
+%type <ttype> notype_declarator_intern absdcl_intern
+%type <ttype> after_type_declarator_intern
 %type <ttype> direct_notype_declarator direct_after_type_declarator
-
-%type <ttype> opt.component_decl_list component_decl_list
-%type <ttype> component_decl component_decl_1 components notype_components
-%type <ttype> component_declarator component_declarator0 self_reference
+%type <itype> components notype_components
+%type <ttype> component_decl component_decl_1 
+%type <ttype> component_declarator component_declarator0
 %type <ttype> notype_component_declarator notype_component_declarator0
 %type <ttype> after_type_component_declarator after_type_component_declarator0
-%type <ttype> enumlist enumerator
 %type <ttype> absdcl cv_qualifiers
 %type <ttype> direct_abstract_declarator conversion_declarator
 %type <ttype> new_declarator direct_new_declarator
 %type <ttype> xexpr parmlist parms bad_parm 
 %type <ttype> identifiers_or_typenames
 %type <ttype> fcast_or_absdcl regcast_or_absdcl
-%type <ttype> expr_or_declarator complex_notype_declarator
+%type <ttype> expr_or_declarator expr_or_declarator_intern
+%type <ttype> complex_notype_declarator
 %type <ttype> notype_unqualified_id unqualified_id qualified_id
 %type <ttype> template_id do_id object_template_id notype_template_declarator
 %type <ttype> overqualified_id notype_qualified_id any_id
@@ -228,30 +363,37 @@ empty_parms ()
 %type <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs
 %type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers
 %type <ftype> structsp typespecqual_reserved parm named_parm full_parm
+%type <ftype> declmods
+
+%type <itype> extension
 
 /* C++ extensions */
 %token <ttype> PTYPENAME
-%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
+%token <ttype> EXTERN_LANG_STRING ALL
 %token <ttype> PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER
+%token <pi> PRE_PARSED_FUNCTION_DECL 
 %type <ttype> component_constructor_declarator
-%type <ttype> fn.def2 return_id fn.defpen constructor_declarator
-%type <itype> ctor_initializer_opt
-%type <ttype> named_class_head named_class_head_sans_basetype
-%type <ttype> named_complex_class_head_sans_basetype
+%type <ttype> fn.def2 return_id constructor_declarator
+%type <pi> fn.defpen 
+%type <itype> ctor_initializer_opt function_try_block
+%type <ttype> named_class_head_sans_basetype
+%type <ftype> class_head named_class_head 
+%type <ftype> named_complex_class_head_sans_basetype 
 %type <ttype> unnamed_class_head
-%type <ttype> class_head base_class_list
+%type <ttype> base_class_list
 %type <ttype> base_class_access_list
 %type <ttype> base_class maybe_base_class_list base_class.1
 %type <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers
 %type <ttype> operator_name
 %type <ttype> object aggr
-%type <itype> new delete .begin_new_placement
+%type <itype> new delete
 /* %type <ttype> primary_no_id */
-%type <ttype> nonmomentary_expr maybe_parmlist
-%type <itype> initdcl0 notype_initdcl0 member_init_list initdcl0_innards
+%type <ttype> maybe_parmlist
+%type <itype> member_init_list
 %type <ttype> template_header template_parm_list template_parm
 %type <ttype> template_type_parm template_template_parm
 %type <code>  template_close_bracket
+%type <ttype> apparent_template_type
 %type <ttype> template_type template_arg_list template_arg_list_opt
 %type <ttype> template_arg
 %type <ttype> condition xcond paren_cond_or_null
@@ -266,8 +408,8 @@ empty_parms ()
 %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
 %type <ttype> named_class_head_sans_basetype_defn
 %type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
-
-%type <ttype> self_template_type
+%type <ttype> handler_args
+%type <ttype> self_template_type .finish_template_type
 
 %token NSNAME
 %type <ttype> NSNAME
@@ -280,51 +422,9 @@ empty_parms ()
 %token END_OF_SAVED_INPUT
 \f
 %{
-/* List of types and structure classes of the current declaration.  */
-static tree current_declspecs;
-
-/* List of prefix attributes in effect.
-   Prefix attributes are parsed by the reserved_declspecs and declmods
-   rules.  They create a list that contains *both* declspecs and attrs.  */
-/* ??? It is not clear yet that all cases where an attribute can now appear in
-   a declspec list have been updated.  */
-static tree prefix_attributes;
-
-/* When defining an aggregate, this is the most recent one being defined.  */
-static tree current_aggr;
-
 /* Tell yyparse how to print a token's value, if yydebug is set.  */
-
 #define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
-extern void yyprint                    PROTO((FILE *, int, YYSTYPE));
-extern tree combine_strings            PROTO((tree));
-
-static int
-parse_decl(declarator, specs_attrs, attributes, initialized, decl)
-  tree declarator;
-  tree specs_attrs;
-  tree attributes;
-  int initialized;
-  tree* decl;
-{
-  int  sm;
-
-  split_specs_attrs (specs_attrs, &current_declspecs, &prefix_attributes);
-  if (current_declspecs
-      && TREE_CODE (current_declspecs) != TREE_LIST)
-    current_declspecs = get_decl_list (current_declspecs);
-  if (have_extern_spec && !used_extern_spec)
-    {
-      current_declspecs = decl_tree_cons (NULL_TREE, 
-                                         get_identifier ("extern"), 
-                                         current_declspecs);
-      used_extern_spec = 1;
-    }
-  sm = suspend_momentary ();
-  *decl = start_decl (declarator, current_declspecs, initialized,
-                     attributes, prefix_attributes);
-  return sm;
-}
+extern void yyprint                    PARAMS ((FILE *, int, YYSTYPE));
 %}
 \f
 %%
@@ -341,9 +441,9 @@ program:
 extdefs:
                { $<ttype>$ = NULL_TREE; }
          lang_extdef
-               { $<ttype>$ = NULL_TREE; }
+               { $<ttype>$ = NULL_TREE; ggc_collect (); }
        | extdefs lang_extdef
-               { $<ttype>$ = NULL_TREE; }
+               { $<ttype>$ = NULL_TREE; ggc_collect (); }
        ;
 
 extdefs_opt:
@@ -362,7 +462,7 @@ extdefs_opt:
 
 extension:
        EXTENSION
-               { $<itype>$ = pedantic;
+               { $$ = pedantic;
                  pedantic = 0; }
        ;
 
@@ -371,9 +471,10 @@ asm_keyword:
        ;
 
 lang_extdef:
-               { if (pending_lang_change) do_pending_lang_change(); }
+               { if (pending_lang_change) do_pending_lang_change();
+                 type_lookups = NULL_TREE; }
          extdef
-               { if (! toplevel_bindings_p () && ! pseudo_global_level_p())
+               { if (! toplevel_bindings_p ())
                  pop_everything (); }
        ;
 
@@ -403,7 +504,16 @@ extdef:
                { push_namespace (NULL_TREE); }
          extdefs_opt '}'
                { pop_namespace (); }
-       | NAMESPACE identifier '=' 
+       | namespace_alias
+       | using_decl ';'
+               { do_toplevel_using_decl ($1); }
+       | using_directive
+       | extension extdef
+               { pedantic = $1; }
+       ;
+
+namespace_alias:
+          NAMESPACE identifier '=' 
                 { begin_only_namespace_names (); }
           any_id ';'
                {
@@ -412,11 +522,6 @@ extdef:
                    $5 = lastiddecl;
                  do_namespace_alias ($2, $5);
                }
-       | using_decl ';'
-               { do_toplevel_using_decl ($1); }
-       | using_directive
-       | extension extdef
-               { pedantic = $<itype>1; }
        ;
 
 using_decl:
@@ -552,22 +657,38 @@ template_parm:
        ;
 
 template_def:
-         template_header
-         extdef
-                { 
-                  if ($1) 
-                    end_template_decl (); 
-                 else
-                   end_specialization ();
-               }
-       | template_header
-         error  %prec EMPTY
-               { 
-                  if ($1) 
-                    end_template_decl ();
-                 else
-                   end_specialization (); 
-                }
+         template_header template_extdef
+                { finish_template_decl ($1); }
+       | template_header error  %prec EMPTY
+                { finish_template_decl ($1); }
+       ;
+
+template_extdef:
+         fndef eat_saved_input
+               { if (pending_inlines) do_pending_inlines (); }
+       | template_datadef
+               { if (pending_inlines) do_pending_inlines (); }
+       | template_def
+               { if (pending_inlines) do_pending_inlines (); }
+       | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
+               { if (pending_inlines) do_pending_inlines ();
+                 pop_lang_context (); }
+       | extern_lang_string .hush_warning template_datadef .warning_ok
+               { if (pending_inlines) do_pending_inlines ();
+                 pop_lang_context (); }
+       | extension template_extdef
+               { pedantic = $1; }
+       ;
+
+template_datadef:
+         nomods_initdecls ';'
+       | declmods notype_initdecls ';'
+               {}
+       | typed_declspecs initdecls ';'
+                { note_list_got_semicolon ($1.t); }
+       | structsp ';'
+                { maybe_process_partial_specialization ($1.t);
+                 note_got_semicolon ($1.t); }
        ;
 
 datadef:
@@ -575,9 +696,7 @@ datadef:
        | declmods notype_initdecls ';'
                {}
        | typed_declspecs initdecls ';'
-               {
-                 note_list_got_semicolon ($1.t);
-               }
+                { note_list_got_semicolon ($1.t); }
         | declmods ';'
                { pedwarn ("empty declaration"); }
        | explicit_instantiation ';'
@@ -613,9 +732,9 @@ eat_saved_input:
 
 fndef:
          fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
-               { finish_function (lineno, (int)$3, 0); }
+               { expand_body (finish_function (lineno, (int)$3)); }
        | fn.def1 maybe_return_init function_try_block
-               { }
+               { expand_body (finish_function (lineno, (int)$3)); }
        | fn.def1 maybe_return_init error
                { }
        ;
@@ -660,13 +779,13 @@ fn.def1:
                { if (!begin_function_definition ($1.t, $2))
                    YYERROR1; }
        | declmods notype_declarator
-               { if (!begin_function_definition ($1, $2))
+               { if (!begin_function_definition ($1.t, $2))
                    YYERROR1; }
        | notype_declarator
                { if (!begin_function_definition (NULL_TREE, $1))
                    YYERROR1; }
        | declmods constructor_declarator
-               { if (!begin_function_definition ($1, $2))
+               { if (!begin_function_definition ($1.t, $2))
                    YYERROR1; }
        | constructor_declarator
                { if (!begin_function_definition (NULL_TREE, $1))
@@ -688,8 +807,7 @@ component_constructor_declarator:
    reduce/reduce conflict introduced by these rules.  */
 fn.def2:
          declmods component_constructor_declarator
-               { tree specs = strip_attrs ($1);
-                 $$ = start_method (specs, $2);
+               { $$ = parse_method ($2, $1.t, $1.lookups);
                 rest_of_mdef:
                  if (! $$)
                    YYERROR1;
@@ -697,24 +815,24 @@ fn.def2:
                    yychar = YYLEX;
                  reinit_parse_for_method (yychar, $$); }
        | component_constructor_declarator
-               { $$ = start_method (NULL_TREE, $1); goto rest_of_mdef; }
+               { $$ = parse_method ($1, NULL_TREE, NULL_TREE); 
+                 goto rest_of_mdef; }
        | typed_declspecs declarator
-               { tree specs = strip_attrs ($1.t);
-                 $$ = start_method (specs, $2); goto rest_of_mdef; }
+               { $$ = parse_method ($2, $1.t, $1.lookups); goto rest_of_mdef;}
        | declmods notype_declarator
-               { tree specs = strip_attrs ($1);
-                 $$ = start_method (specs, $2); goto rest_of_mdef; }
+               { $$ = parse_method ($2, $1.t, $1.lookups); goto rest_of_mdef;}
        | notype_declarator
-               { $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
+               { $$ = parse_method ($1, NULL_TREE, NULL_TREE); 
+                 goto rest_of_mdef; }
        | declmods constructor_declarator
-               { tree specs = strip_attrs ($1);
-                 $$ = start_method (specs, $2); goto rest_of_mdef; }
+               { $$ = parse_method ($2, $1.t, $1.lookups); goto rest_of_mdef;}
        | constructor_declarator
-               { $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
+               { $$ = parse_method ($1, NULL_TREE, NULL_TREE); 
+                 goto rest_of_mdef; }
        ;
 
 return_id:
-         RETURN IDENTIFIER
+         RETURN_KEYWORD IDENTIFIER
                {
                  if (! current_function_parms_stored)
                    store_parm_decls ();
@@ -724,11 +842,11 @@ return_id:
 
 return_init:
          return_id maybe_init
-               { store_return_init ($<ttype>$, $2); }
+               { finish_named_return_value ($<ttype>$, $2); }
        | return_id '(' nonnull_exprlist ')'
-               { store_return_init ($<ttype>$, $3); }
+               { finish_named_return_value ($<ttype>$, $3); }
        | return_id LEFT_RIGHT
-               { store_return_init ($<ttype>$, NULL_TREE); }
+               { finish_named_return_value ($<ttype>$, NULL_TREE); }
        ;
 
 base_init:
@@ -737,10 +855,6 @@ base_init:
                  if ($3 == 0)
                    error ("no base initializers given following ':'");
                  setup_vtbl_ptr ();
-                 /* Always keep the BLOCK node associated with the outermost
-                    pair of curley braces of a function.  These are needed
-                    for correct operation of dwarfout.c.  */
-                 keep_next_level ();
                }
        ;
 
@@ -751,12 +865,8 @@ base_init:
                    store_parm_decls ();
 
                  if (DECL_CONSTRUCTOR_P (current_function_decl))
-                   {
-                     /* Make a contour for the initializer list.  */
-                     pushlevel (0);
-                     clear_last_expr ();
-                     expand_start_bindings (0);
-                   }
+                   /* Make a contour for the initializer list.  */
+                   do_pushlevel ();
                  else if (current_class_type == NULL_TREE)
                    error ("base initializers not allowed for non-member functions");
                  else if (! DECL_CONSTRUCTOR_P (current_function_decl))
@@ -800,6 +910,7 @@ member_init:
        | typename_sub LEFT_RIGHT
                { expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1),
                                      void_type_node); }
+        | error
        ;
 
 identifier:
@@ -866,29 +977,35 @@ end_explicit_instantiation:
 
 template_type:
          PTYPENAME '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        | TYPENAME  '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        | self_template_type
        ;
 
+apparent_template_type:
+         template_type
+       | identifier '<' template_arg_list_opt '>'
+           .finish_template_type
+               { $$ = $5; }
+
 self_template_type:
          SELFNAME  '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        ;
 
+.finish_template_type:
+                { 
+                 if (yychar == YYEMPTY)
+                   yychar = YYLEX;
+
+                 $$ = finish_template_type ($<ttype>-3, $<ttype>-1, 
+                                            yychar == SCOPE);
+               }
+
 template_close_bracket:
          '>'
        | RSHIFT 
@@ -941,7 +1058,7 @@ expr:
 
 paren_expr_or_null:
        LEFT_RIGHT
-               { error ("ANSI C++ forbids an empty condition for `%s'",
+               { error ("ISO C++ forbids an empty condition for `%s'",
                         cond_stmt_keyword);
                  $$ = integer_zero_node; }
        | '(' expr ')'
@@ -950,7 +1067,7 @@ paren_expr_or_null:
 
 paren_cond_or_null:
        LEFT_RIGHT
-               { error ("ANSI C++ forbids an empty condition for `%s'",
+               { error ("ISO C++ forbids an empty condition for `%s'",
                         cond_stmt_keyword);
                  $$ = integer_zero_node; }
        | '(' condition ')'
@@ -979,15 +1096,12 @@ condition:
                    }
                  }
                  current_declspecs = $1.t;
-                 $<itype>5 = suspend_momentary ();
-                 $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1,
-                                         $4, /*prefix_attributes*/ NULL_TREE);
+                 $<ttype>$ = parse_decl ($<ttype>2, $4, 1);
                }
          init
                { 
-                 cp_finish_decl ($<ttype>6, $7, $4, 1, LOOKUP_ONLYCONVERTING);
-                 resume_momentary ($<itype>5);
-                 $$ = $<ttype>6; 
+                 parse_end_decl ($<ttype>6, $7, $4);
+                 $$ = convert_from_reference ($<ttype>6); 
                  if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE)
                    cp_error ("definition of array `%#D' in condition", $$); 
                }
@@ -1012,20 +1126,20 @@ already_scoped_stmt:
 
 nontrivial_exprlist:
          expr_no_commas ',' expr_no_commas
-               { $$ = expr_tree_cons (NULL_TREE, $$, 
-                                 build_expr_list (NULL_TREE, $3)); }
+               { $$ = tree_cons (NULL_TREE, $$, 
+                                 build_tree_list (NULL_TREE, $3)); }
        | expr_no_commas ',' error
-               { $$ = expr_tree_cons (NULL_TREE, $$, 
-                                 build_expr_list (NULL_TREE, error_mark_node)); }
+               { $$ = tree_cons (NULL_TREE, $$, 
+                                 build_tree_list (NULL_TREE, error_mark_node)); }
        | nontrivial_exprlist ',' expr_no_commas
-               { chainon ($$, build_expr_list (NULL_TREE, $3)); }
+               { chainon ($$, build_tree_list (NULL_TREE, $3)); }
        | nontrivial_exprlist ',' error
-               { chainon ($$, build_expr_list (NULL_TREE, error_mark_node)); }
+               { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
        ;
 
 nonnull_exprlist:
          expr_no_commas
-               { $$ = build_expr_list (NULL_TREE, $$); }
+               { $$ = build_tree_list (NULL_TREE, $$); }
        | nontrivial_exprlist
        ;
 
@@ -1035,7 +1149,7 @@ unary_expr:
        /* __extension__ turns off -pedantic for following primary.  */
        | extension cast_expr     %prec UNARY
                { $$ = $2;
-                 pedantic = $<itype>1; }
+                 pedantic = $1; }
        | '*' cast_expr   %prec UNARY
                { $$ = build_x_indirect_ref ($2, "unary *"); }
        | '&' cast_expr   %prec UNARY
@@ -1047,12 +1161,13 @@ unary_expr:
        /* Refer to the address of a label as a pointer.  */
        | ANDAND identifier
                { if (pedantic)
-                   pedwarn ("ANSI C++ forbids `&&'");
+                   pedwarn ("ISO C++ forbids `&&'");
                  $$ = finish_label_address_expr ($2); }
        | SIZEOF unary_expr  %prec UNARY
                { $$ = expr_sizeof ($2); }
        | SIZEOF '(' type_id ')'  %prec HYPERUNARY
-               { $$ = c_sizeof (groktypename ($3.t)); }
+               { $$ = c_sizeof (groktypename ($3.t));
+                 check_for_new_type ("sizeof", $3); }
        | ALIGNOF unary_expr  %prec UNARY
                { $$ = grok_alignof ($2); }
        | ALIGNOF '(' type_id ')'  %prec HYPERUNARY
@@ -1073,32 +1188,20 @@ unary_expr:
        | new new_placement new_type_id new_initializer
                { $$ = build_new ($2, $3.t, $4, $1); 
                  check_for_new_type ("new", $3); }
-        /* The .begin_new_placement in the following rules is
-          necessary to avoid shift/reduce conflicts that lead to
-          mis-parsing some expressions.  Of course, these constructs
-          are not really new-placement and it is bogus to call
-          begin_new_placement.  But, the parser cannot always tell at this
-          point whether the next thing is an expression or a type-id,
-          so there is nothing we can do.  Fortunately,
-          begin_new_placement does nothing harmful.  When we rewrite
-          the parser, this lossage should be removed, of course.  */
-       | new '(' .begin_new_placement type_id .finish_new_placement
+       | new '(' type_id ')'
             %prec EMPTY
-               { $$ = build_new (NULL_TREE, groktypename($4.t),
+               { $$ = build_new (NULL_TREE, groktypename($3.t),
                                  NULL_TREE, $1); 
+                 check_for_new_type ("new", $3); }
+       | new '(' type_id ')' new_initializer
+               { $$ = build_new (NULL_TREE, groktypename($3.t), $5, $1); 
+                 check_for_new_type ("new", $3); }
+       | new new_placement '(' type_id ')' %prec EMPTY
+               { $$ = build_new ($2, groktypename($4.t), NULL_TREE, $1); 
                  check_for_new_type ("new", $4); }
-       | new '(' .begin_new_placement type_id .finish_new_placement
-            new_initializer
-               { $$ = build_new (NULL_TREE, groktypename($4.t), $6, $1); 
+       | new new_placement '(' type_id ')' new_initializer
+               { $$ = build_new ($2, groktypename($4.t), $6, $1); 
                  check_for_new_type ("new", $4); }
-       | new new_placement '(' .begin_new_placement type_id
-           .finish_new_placement   %prec EMPTY
-               { $$ = build_new ($2, groktypename($5.t), NULL_TREE, $1); 
-                 check_for_new_type ("new", $5); }
-       | new new_placement '(' .begin_new_placement type_id
-           .finish_new_placement  new_initializer
-               { $$ = build_new ($2, groktypename($5.t), $7, $1); 
-                 check_for_new_type ("new", $5); }
 
        | delete cast_expr  %prec UNARY
                { $$ = delete_sanity ($2, NULL_TREE, 0, $1); }
@@ -1114,26 +1217,17 @@ unary_expr:
                { $$ = build_x_unary_op (REALPART_EXPR, $2); }
        | IMAGPART cast_expr %prec UNARY
                { $$ = build_x_unary_op (IMAGPART_EXPR, $2); }
+       | VA_ARG '(' expr_no_commas ',' type_id ')'
+               { $$ = build_x_va_arg ($3, groktypename ($5.t));
+                 check_for_new_type ("__builtin_va_arg", $5); }
        ;
 
-        /* Note this rule is not suitable for use in new_placement
-          since it uses NULL_TREE as the argument to
-          finish_new_placement.  This rule serves only to avoid
-          reduce/reduce conflicts in unary_expr.  See the comments
-          there on the use of begin/finish_new_placement.  */
-.finish_new_placement:
-         ')'
-                { finish_new_placement (NULL_TREE, $<itype>-1); }
-
-.begin_new_placement:
-                { $$ = begin_new_placement (); }
-
 new_placement:
-         '(' .begin_new_placement nonnull_exprlist ')'
-                { $$ = finish_new_placement ($3, $2); }
-       | '{' .begin_new_placement nonnull_exprlist '}'
+         '(' nonnull_exprlist ')'
+                { $$ = $2; }
+       | '{' nonnull_exprlist '}'
                 { cp_pedwarn ("old style placement syntax, use () instead");
-                 $$ = finish_new_placement ($3, $2); }
+                 $$ = $2; }
        ;
 
 new_initializer:
@@ -1152,10 +1246,10 @@ new_initializer:
        | '=' init
                {
                  if (pedantic)
-                   pedwarn ("ANSI C++ forbids initialization of new expression with `='");
+                   pedwarn ("ISO C++ forbids initialization of new expression with `='");
                  if (TREE_CODE ($2) != TREE_LIST
                      && TREE_CODE ($2) != CONSTRUCTOR)
-                   $$ = build_expr_list (NULL_TREE, $2);
+                   $$ = build_tree_list (NULL_TREE, $2);
                  else
                    $$ = $2;
                }
@@ -1182,7 +1276,7 @@ cast_expr:
                  tree init = build_nt (CONSTRUCTOR, NULL_TREE,
                                        nreverse ($3)); 
                  if (pedantic)
-                   pedwarn ("ANSI C++ forbids constructor-expressions");
+                   pedwarn ("ISO C++ forbids constructor-expressions");
                  /* Indicate that this was a GNU C constructor expression.  */
                  TREE_HAS_CONSTRUCTOR (init) = 1;
 
@@ -1261,6 +1355,8 @@ expr_no_commas:
 notype_unqualified_id:
          '~' see_typename identifier
                { $$ = build_parse_node (BIT_NOT_EXPR, $3); }
+       | '~' see_typename template_type
+               { $$ = build_parse_node (BIT_NOT_EXPR, $3); }
         | template_id
        | operator_name
        | IDENTIFIER
@@ -1269,7 +1365,16 @@ notype_unqualified_id:
        ;
 
 do_id:
-               { $$ = do_identifier ($<ttype>-1, 1, NULL_TREE); }
+               {
+                 /* If lastiddecl is a TREE_LIST, it's a baselink, which
+                    means that we're in an expression like S::f<int>, so
+                    don't do_identifier; we only do that for unqualified
+                    identifiers.  */
+                 if (lastiddecl && TREE_CODE (lastiddecl) != TREE_LIST)
+                   $$ = do_identifier ($<ttype>-1, 1, NULL_TREE);
+                 else
+                   $$ = $<ttype>-1;
+               }
 
 template_id:
           PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket 
@@ -1294,13 +1399,23 @@ unqualified_id:
        | SELFNAME
        ;
 
+expr_or_declarator_intern:
+         expr_or_declarator
+       | attributes expr_or_declarator
+               {
+                 /* Provide support for '(' attributes '*' declarator ')'
+                    etc */
+                 $$ = decl_tree_cons ($1, $2, NULL_TREE);
+               }
+       ;
+
 expr_or_declarator:
          notype_unqualified_id
-       | '*' expr_or_declarator  %prec UNARY
+       | '*' expr_or_declarator_intern  %prec UNARY
                { $$ = build_parse_node (INDIRECT_REF, $2); }
-       | '&' expr_or_declarator  %prec UNARY
+       | '&' expr_or_declarator_intern  %prec UNARY
                { $$ = build_parse_node (ADDR_EXPR, $2); }
-       | '(' expr_or_declarator ')'
+       | '(' expr_or_declarator_intern ')'
                { $$ = $2; }
        ;
 
@@ -1313,10 +1428,12 @@ notype_template_declarator:
                
 direct_notype_declarator:
          complex_direct_notype_declarator
-       | notype_unqualified_id
+       /* This precedence declaration is to prefer this reduce
+          to the Koenig lookup shift in primary, below.  I hate yacc.  */
+       | notype_unqualified_id %prec '('
        | notype_template_declarator
-       | '(' expr_or_declarator ')'
-               { $$ = finish_decl_parsing ($2); }
+       | '(' expr_or_declarator_intern ')'
+                { $$ = finish_decl_parsing ($2); }
        ;
 
 primary:
@@ -1331,37 +1448,40 @@ primary:
        | boolean.literal
        | string
                {
-                 if (processing_template_decl)
-                   push_obstacks (&permanent_obstack, &permanent_obstack);
                  $$ = combine_strings ($$);
-                 if (processing_template_decl)
-                   pop_obstacks ();
+                 /* combine_strings doesn't set up TYPE_MAIN_VARIANT of
+                    a const array the way we want, so fix it.  */
+                 if (flag_const_strings)
+                   TREE_TYPE ($$) = build_cplus_array_type
+                     (TREE_TYPE (TREE_TYPE ($$)),
+                      TYPE_DOMAIN (TREE_TYPE ($$)));
                }
        | '(' expr ')'
                { $$ = finish_parenthesized_expr ($2); }
-       | '(' expr_or_declarator ')'
+       | '(' expr_or_declarator_intern ')'
                { $2 = reparse_decl_as_expr (NULL_TREE, $2);
                  $$ = finish_parenthesized_expr ($2); }
        | '(' error ')'
                { $$ = error_mark_node; }
        | '('
-               { if (current_function_decl == 0)
+               { tree scope = current_scope ();
+                 if (!scope || TREE_CODE (scope) != FUNCTION_DECL)
                    {
                      error ("braced-group within expression allowed only inside a function");
                      YYERROR;
                    }
                  if (pedantic)
-                   pedwarn ("ANSI C++ forbids braced-groups within expressions");  
+                   pedwarn ("ISO C++ forbids braced-groups within expressions");  
                  $<ttype>$ = begin_stmt_expr (); 
                }
          compstmt ')'
-               { $$ = finish_stmt_expr ($<ttype>2, $3); }
+               { $$ = finish_stmt_expr ($<ttype>2); }
         /* Koenig lookup support
            We could store lastiddecl in $1 to avoid another lookup,
            but that would result in many additional reduce/reduce conflicts. */
-        | IDENTIFIER '(' nonnull_exprlist ')'
+        | notype_unqualified_id '(' nonnull_exprlist ')'
                { $$ = finish_call_expr ($1, $3, 1); }
-        | IDENTIFIER LEFT_RIGHT
+        | notype_unqualified_id LEFT_RIGHT
                { $$ = finish_call_expr ($1, NULL_TREE, 1); }
        | primary '(' nonnull_exprlist ')'
                { $$ = finish_call_expr ($1, $3, 0); }
@@ -1378,47 +1498,14 @@ primary:
                { $$ = finish_this_expr (); }
        | CV_QUALIFIER '(' nonnull_exprlist ')'
                {
-                 tree type = NULL_TREE;
-                 tree id = $$;
+                 /* This is a C cast in C++'s `functional' notation
+                    using the "implicit int" extension so that:
+                    `const (3)' is equivalent to `const int (3)'.  */
+                 tree type;
 
-                 /* This is a C cast in C++'s `functional' notation.  */
-                 if ($3 == error_mark_node)
-                   {
-                     $$ = error_mark_node;
-                     break;
-                   }
-#if 0
-                 if ($3 == NULL_TREE)
-                   {
-                     error ("cannot cast null list to type `%s'",
-                            IDENTIFIER_POINTER (TYPE_NAME (id)));
-                     $$ = error_mark_node;
-                     break;
-                   }
-#endif
-#if 0
-                 /* type is not set! (mrs) */
-                 if (type == error_mark_node)
-                   $$ = error_mark_node;
-                 else
-#endif
-                   {
-                     if (id == ridpointers[(int) RID_CONST])
-                       type = build_type_variant (integer_type_node, 1, 0);
-                     else if (id == ridpointers[(int) RID_VOLATILE])
-                       type = build_type_variant (integer_type_node, 0, 1);
-#if 0
-                     /* should not be able to get here (mrs) */
-                     else if (id == ridpointers[(int) RID_FRIEND])
-                       {
-                         error ("cannot cast expression to `friend' type");
-                         $$ = error_mark_node;
-                         break;
-                       }
-#endif
-                     else my_friendly_abort (79);
-                     $$ = build_c_cast (type, build_compound_expr ($3));
-                   }
+                 type = hash_tree_cons (NULL_TREE, $1, NULL_TREE);
+                 type = groktypename (build_decl_list (type, NULL_TREE));
+                 $$ = build_functional_cast (type, $3);
                }
        | functional_cast
        | DYNAMIC_CAST '<' type_id '>' '(' expr ')'
@@ -1438,7 +1525,7 @@ primary:
                  check_for_new_type ("const_cast", $3);
                  $$ = build_const_cast (type, $6); }
        | TYPEID '(' expr ')'
-               { $$ = build_x_typeid ($3); }
+               { $$ = build_typeid ($3); }
        | TYPEID '(' type_id ')'
                { tree type = groktypename ($3.t);
                  check_for_new_type ("typeid", $3);
@@ -1458,9 +1545,9 @@ primary:
        | overqualified_id  %prec HYPERUNARY
                { $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
        | overqualified_id '(' nonnull_exprlist ')'
-                { $$ = finish_globally_qualified_member_call_expr ($1, $3); }
+                { $$ = finish_qualified_call_expr ($1, $3); }
        | overqualified_id LEFT_RIGHT
-               { $$ = finish_globally_qualified_member_call_expr ($1, NULL_TREE); }
+               { $$ = finish_qualified_call_expr ($1, NULL_TREE); }
         | object object_template_id %prec UNARY
                 { 
                  $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); 
@@ -1473,7 +1560,7 @@ primary:
                { $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); }
        | object overqualified_id  %prec UNARY
                { if (processing_template_decl)
-                   $$ = build_min_nt (COMPONENT_REF, $1, copy_to_permanent ($2));
+                   $$ = build_min_nt (COMPONENT_REF, $1, $2);
                  else
                    $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
        | object unqualified_id '(' nonnull_exprlist ')'
@@ -1511,7 +1598,7 @@ primary_no_id:
                  $<ttype>$ = expand_start_stmt_expr (); }
          compstmt ')'
                { if (pedantic)
-                   pedwarn ("ANSI C++ forbids braced-groups within expressions");
+                   pedwarn ("ISO C++ forbids braced-groups within expressions");
                  $$ = expand_end_stmt_expr ($<ttype>2); }
        | primary_no_id '(' nonnull_exprlist ')'
                { $$ = build_x_function_call ($$, $3, current_class_ref); }
@@ -1567,10 +1654,6 @@ nodecls:
                  if (! current_function_parms_stored)
                    store_parm_decls ();
                  setup_vtbl_ptr ();
-                 /* Always keep the BLOCK node associated with the outermost
-                    pair of curley braces of a function.  These are needed
-                    for correct operation of dwarfout.c.  */
-                 keep_next_level ();
                }
        ;
 
@@ -1587,17 +1670,15 @@ object:
 decl:
          typespec initdecls ';'
                {
-                 resume_momentary ($2);
                  if ($1.t && IS_AGGR_TYPE_CODE (TREE_CODE ($1.t)))
                    note_got_semicolon ($1.t);
                }
        | typed_declspecs initdecls ';'
                {
-                 resume_momentary ($2);
                  note_list_got_semicolon ($1.t);
                }
        | declmods notype_initdecls ';'
-               { resume_momentary ($2); }
+                {}
        | typed_declspecs ';'
                {
                  shadow_tag ($1.t);
@@ -1606,7 +1687,7 @@ decl:
        | declmods ';'
                { warning ("empty declaration"); }
        | extension decl
-               { pedantic = $<itype>1; }
+               { pedantic = $1; }
        ;
 
 /* Any kind of declarator (thus, all declarators allowed
@@ -1627,7 +1708,7 @@ fcast_or_absdcl:
                                             NULL_TREE); }
        ;
 
-/* ANSI type-id (8.1) */
+/* ISO type-id (8.1) */
 type_id:
          typed_typespecs absdcl
                { $$.t = build_decl_list ($1.t, $2); 
@@ -1636,7 +1717,8 @@ type_id:
                { $$.t = build_decl_list ($1.t, $2); 
                  $$.new_type_flag = $1.new_type_flag; }
        | typespec absdcl
-               { $$.t = build_decl_list (get_decl_list ($1.t), $2); 
+               { $$.t = build_decl_list (build_decl_list (NULL_TREE, $1.t),
+                                         $2); 
                  $$.new_type_flag = $1.new_type_flag; }
        | typed_typespecs  %prec EMPTY
                { $$.t = build_decl_list ($1.t, NULL_TREE);
@@ -1653,12 +1735,14 @@ type_id:
 
 typed_declspecs:
          typed_typespecs  %prec EMPTY
+               { $$.lookups = type_lookups; }
        | typed_declspecs1
+               { $$.lookups = type_lookups; }
        ;
 
 typed_declspecs1:
          declmods typespec
-               { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1); 
+               { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1.t); 
                  $$.new_type_flag = $2.new_type_flag; }
        | typespec reserved_declspecs  %prec HYPERUNARY
                { $$.t = decl_tree_cons (NULL_TREE, $1.t, $2); 
@@ -1667,14 +1751,14 @@ typed_declspecs1:
                { $$.t = decl_tree_cons (NULL_TREE, $1.t, chainon ($2, $3)); 
                  $$.new_type_flag = $1.new_type_flag; }
        | declmods typespec reserved_declspecs
-               { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1)); 
+               { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t)); 
                  $$.new_type_flag = $2.new_type_flag; }
        | declmods typespec reserved_typespecquals
-               { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1)); 
+               { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t)); 
                  $$.new_type_flag = $2.new_type_flag; }
        | declmods typespec reserved_typespecquals reserved_declspecs
                { $$.t = decl_tree_cons (NULL_TREE, $2.t,
-                                        chainon ($3, chainon ($4, $1))); 
+                                        chainon ($3, chainon ($4, $1.t))); 
                  $$.new_type_flag = $2.new_type_flag; }
        ;
 
@@ -1702,24 +1786,43 @@ reserved_declspecs:
    to redeclare a typedef-name.
    In the result, declspecs have a non-NULL TREE_VALUE, attributes do not.  */
 
+/* We use hash_tree_cons for lists of typeless declspecs so that they end
+   up on a persistent obstack.  Otherwise, they could appear at the
+   beginning of something like
+
+      static const struct { int foo () { } } b;
+
+   and would be discarded after we finish compiling foo.  We don't need to
+   worry once we see a type.  */
+
 declmods:
          nonempty_cv_qualifiers  %prec EMPTY
-               { $$ = $1.t; TREE_STATIC ($$) = 1; }
+               { $$.lookups = NULL_TREE; TREE_STATIC ($$.t) = 1; }
        | SCSPEC
-               { $$ = IDENTIFIER_AS_LIST ($$); }
+               {
+                 $$.t = hash_tree_cons (NULL_TREE, $1, NULL_TREE);
+                 $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+               }
        | declmods CV_QUALIFIER
-               { $$ = decl_tree_cons (NULL_TREE, $2, $$);
-                 TREE_STATIC ($$) = 1; }
+               {
+                 $$.t = hash_tree_cons (NULL_TREE, $2, $1.t);
+                 TREE_STATIC ($$.t) = 1;
+               }
        | declmods SCSPEC
-               { if (extra_warnings && TREE_STATIC ($$))
+               {
+                 if (extra_warnings && TREE_STATIC ($$.t))
                    warning ("`%s' is not at beginning of declaration",
                             IDENTIFIER_POINTER ($2));
-                 $$ = decl_tree_cons (NULL_TREE, $2, $$);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+                 $$.t = hash_tree_cons (NULL_TREE, $2, $1.t);
+                 TREE_STATIC ($$.t) = TREE_STATIC ($1.t);
+               }
        | declmods attributes
-               { $$ = decl_tree_cons ($2, NULL_TREE, $1); }
-       | attributes
-               { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
+               { $$.t = hash_tree_cons ($2, NULL_TREE, $1.t); }
+       | attributes  %prec EMPTY
+               {
+                 $$.t = hash_tree_cons ($1, NULL_TREE, NULL_TREE);
+                 $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+               }
        ;
 
 /* Used instead of declspecs where storage classes are not allowed
@@ -1730,7 +1833,7 @@ declmods:
 
 typed_typespecs:
          typespec  %prec EMPTY
-               { $$.t = get_decl_list ($1.t); 
+               { $$.t = build_decl_list (NULL_TREE, $1.t); 
                  $$.new_type_flag = $1.new_type_flag; }
        | nonempty_cv_qualifiers typespec
                { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1.t); 
@@ -1740,7 +1843,7 @@ typed_typespecs:
                  $$.new_type_flag = $1.new_type_flag; }
        | nonempty_cv_qualifiers typespec reserved_typespecquals
                { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t)); 
-                 $$.new_type_flag = $1.new_type_flag; }
+                 $$.new_type_flag = $2.new_type_flag; }
        ;
 
 reserved_typespecquals:
@@ -1756,20 +1859,21 @@ reserved_typespecquals:
 
 typespec:
          structsp
+               { $$.lookups = NULL_TREE; }
        | TYPESPEC  %prec EMPTY
-               { $$.t = $1; $$.new_type_flag = 0; }
+               { $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
        | complete_type_name
-               { $$.t = $1; $$.new_type_flag = 0; }
+               { $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
        | TYPEOF '(' expr ')'
-               { $$.t = TREE_TYPE ($3);
-                 $$.new_type_flag = 0; }
+               { $$.t = finish_typeof ($3);
+                 $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
        | TYPEOF '(' type_id ')'
                { $$.t = groktypename ($3.t);
-                 $$.new_type_flag = 0; }
+                 $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
        | SIGOF '(' expr ')'
                { tree type = TREE_TYPE ($3);
 
-                  $$.new_type_flag = 0;
+                  $$.new_type_flag = 0; $$.lookups = NULL_TREE;
                  if (IS_AGGR_TYPE (type))
                    {
                      sorry ("sigof type specifier");
@@ -1784,7 +1888,7 @@ typespec:
        | SIGOF '(' type_id ')'
                { tree type = groktypename ($3.t);
 
-                  $$.new_type_flag = 0;
+                  $$.new_type_flag = 0; $$.lookups = NULL_TREE;
                  if (IS_AGGR_TYPE (type))
                    {
                      sorry ("sigof type specifier");
@@ -1811,16 +1915,19 @@ typespecqual_reserved:
 initdecls:
          initdcl0
        | initdecls ',' initdcl
+            { check_multiple_declarators (); }
        ;
 
 notype_initdecls:
          notype_initdcl0
        | notype_initdecls ',' initdcl
+            { check_multiple_declarators (); }
        ;
 
 nomods_initdecls:
          nomods_initdcl0
        | nomods_initdecls ',' initdcl
+            { check_multiple_declarators (); }
        ;
 
 maybeasm:
@@ -1832,15 +1939,15 @@ maybeasm:
 
 initdcl:
          declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1,
-                                         $3, prefix_attributes); }
+               { $<ttype>$ = parse_decl ($<ttype>1, $3, 1); }
          init
 /* Note how the declaration of the variable is in effect while its init is parsed! */
-               { cp_finish_decl ($<ttype>5, $6, $2, 1, LOOKUP_ONLYCONVERTING); }
+               { parse_end_decl ($<ttype>5, $6, $2); }
        | declarator maybeasm maybe_attribute
-               { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0,
-                                         $3, prefix_attributes);
-                 cp_finish_decl ($<ttype>$, NULL_TREE, $2, 1, 0); }
+               {
+                 $<ttype>$ = parse_decl ($<ttype>1, $3, 0);
+                 parse_end_decl ($<ttype>$, NULL_TREE, $2);
+               }
        ;
 
         /* This rule assumes a certain configuration of the parser stack.
@@ -1851,40 +1958,38 @@ initdcl:
           we need that reduce so we prefer fn.def1 when appropriate.  */
 initdcl0_innards:
          maybe_attribute '='
-               { $<itype>2 = parse_decl ($<ttype>-1, $<ttype>-2, 
-                                          $1, 1, &$<ttype>$); }
+               { $<ttype>$ = parse_decl0 ($<ttype>-1, $<ftype>-2.t,
+                                          $<ftype>-2.lookups, $1, 1); }
           /* Note how the declaration of the variable is in effect
             while its init is parsed! */ 
          init
-               { cp_finish_decl ($<ttype>3, $4, $<ttype>0, 1,
-                                 LOOKUP_ONLYCONVERTING);
-                 $$ = $<itype>2; }
+               { parse_end_decl ($<ttype>3, $4, $<ttype>0); }
        | maybe_attribute
-               { tree d;
-                 $$ = parse_decl ($<ttype>-1, $<ttype>-2, $1, 0, &d);
-                 cp_finish_decl (d, NULL_TREE, $<ttype>0, 1, 0); }
+               { tree d = parse_decl0 ($<ttype>-1, $<ftype>-2.t,
+                                       $<ftype>-2.lookups, $1, 0);
+                 parse_end_decl (d, NULL_TREE, $<ttype>0); }
        ;
   
 initdcl0:
          declarator maybeasm initdcl0_innards
-            { $$ = $3; }
-  
+                {}
+       ;
+
 notype_initdcl0:
           notype_declarator maybeasm initdcl0_innards
-            { $$ = $3; }
+                {}
         ;
   
 nomods_initdcl0:
           notype_declarator maybeasm
             { /* Set things up as initdcl0_innards expects.  */
-             $<ttype>$ = $1; 
+             $<ttype>2 = $1; 
               $1 = NULL_TREE; }
           initdcl0_innards 
             {}
        | constructor_declarator maybeasm maybe_attribute
-               { tree d;
-                 parse_decl($1, NULL_TREE, $3, 0, &d);
-                 cp_finish_decl (d, NULL_TREE, $2, 1, 0); }
+               { tree d = parse_decl0 ($1, NULL_TREE, NULL_TREE, $3, 0);
+                 parse_end_decl (d, NULL_TREE, $2); }
        ;
 
 /* the * rules are dummies to accept the Apollo extended syntax
@@ -1976,34 +2081,38 @@ initlist:
          init
                { $$ = build_tree_list (NULL_TREE, $$); }
        | initlist ',' init
-               { $$ = expr_tree_cons (NULL_TREE, $3, $$); }
+               { $$ = tree_cons (NULL_TREE, $3, $$); }
        /* These are for labeled elements.  */
        | '[' expr_no_commas ']' init
-               { $$ = build_expr_list ($2, $4); }
+               { $$ = build_tree_list ($2, $4); }
        | identifier ':' init
-               { $$ = build_expr_list ($$, $3); }
+               { $$ = build_tree_list ($$, $3); }
        | initlist ',' identifier ':' init
-               { $$ = expr_tree_cons ($3, $5, $$); }
+               { $$ = tree_cons ($3, $5, $$); }
        ;
 
 fn.defpen:
        PRE_PARSED_FUNCTION_DECL
-               { start_function (NULL_TREE, TREE_VALUE ($1),
-                                 NULL_TREE, 1);
+               { start_function (NULL_TREE, $1->fndecl, NULL_TREE, 
+                                 (SF_DEFAULT | SF_PRE_PARSED 
+                                  | SF_INCLASS_INLINE));
                  reinit_parse_for_function (); }
 
 pending_inline:
          fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error
                {
-                 int nested = (hack_decl_function_context
-                               (current_function_decl) != NULL_TREE);
-                 finish_function (lineno, (int)$3, nested);
+                 expand_body (finish_function (lineno, (int)$3 | 2));
                  process_next_inline ($1);
                }
        | fn.defpen maybe_return_init function_try_block
-               { process_next_inline ($1); }
+               { 
+                 expand_body (finish_function (lineno, (int)$3 | 2)); 
+                  process_next_inline ($1);
+               }
        | fn.defpen maybe_return_init error
-               { process_next_inline ($1); }
+               { 
+                 finish_function (lineno, 2); 
+                 process_next_inline ($1); }
        ;
 
 pending_inlines:
@@ -2029,40 +2138,35 @@ pending_defargs:
 
 structsp:
          ENUM identifier '{'
-               { $<itype>3 = suspend_momentary ();
-                 $<ttype>$ = start_enum ($2); }
-         enumlist maybecomma_warn '}'
-               { $$.t = finish_enum ($<ttype>4, $5);
-                 $$.new_type_flag = 1;
-                 resume_momentary ((int) $<itype>3);
-                 check_for_missing_semicolon ($<ttype>4); }
-       | ENUM identifier '{' '}'
-               { $$.t = finish_enum (start_enum ($2), NULL_TREE);
+               { $<ttype>$ = current_enum_type;
+                 current_enum_type = start_enum ($2); }
+         enumlist_opt '}'
+               { $$.t = finish_enum (current_enum_type);
                  $$.new_type_flag = 1;
+                 current_enum_type = $<ttype>4;
                  check_for_missing_semicolon ($$.t); }
        | ENUM '{'
-               { $<itype>2 = suspend_momentary ();
-                 $<ttype>$ = start_enum (make_anon_name ()); }
-         enumlist maybecomma_warn '}'
-               { $$.t = finish_enum ($<ttype>3, $4);
-                 resume_momentary ((int) $<itype>1);
-                 check_for_missing_semicolon ($<ttype>3);
-                 $$.new_type_flag = 1; }
-       | ENUM '{' '}'
-               { $$.t = finish_enum (start_enum (make_anon_name()), NULL_TREE);
+               { $<ttype>$ = current_enum_type;
+                 current_enum_type = start_enum (make_anon_name ()); }
+         enumlist_opt '}'
+                { $$.t = finish_enum (current_enum_type);
                  $$.new_type_flag = 1;
+                 current_enum_type = $<ttype>3;
                  check_for_missing_semicolon ($$.t); }
        | ENUM identifier
-               { $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1); 
+               { $$.t = xref_tag (enum_type_node, $2, 1); 
                  $$.new_type_flag = 0; }
        | ENUM complex_type_name
-               { $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1); 
+               { $$.t = xref_tag (enum_type_node, $2, 1); 
                  $$.new_type_flag = 0; }
        | TYPENAME_KEYWORD typename_sub
                { $$.t = $2;
-                 $$.new_type_flag = 0; }
+                 $$.new_type_flag = 0; 
+                 if (!processing_template_decl)
+                   cp_pedwarn ("using `typename' outside of template"); }
        /* C++ extensions, merged with C to avoid shift/reduce conflicts */
-       | class_head left_curly 
+       | class_head '{'
+                { $1.t = begin_class_definition ($1.t); }
           opt.component_decl_list '}' maybe_attribute
                { 
                  int semi;
@@ -2071,27 +2175,38 @@ structsp:
                    yychar = YYLEX;
                  semi = yychar == ';';
 
-                 $<ttype>$ = finish_class_definition ($1, $3, $5, semi); 
+                 $<ttype>$ = finish_class_definition ($1.t, $6, semi,
+                                                      $1.new_type_flag); 
                }
          pending_defargs
-                { finish_default_args (); }
+                {
+                 begin_inline_definitions ();
+               }
          pending_inlines
-                { $$.t = $<ttype>6;
+                {
+                 finish_inline_definitions ();
+                 $$.t = $<ttype>7;
                  $$.new_type_flag = 1; 
-                 begin_inline_definitions (); }
+               }
        | class_head  %prec EMPTY
                {
+                 if ($1.new_type_flag && $1.t != error_mark_node)
+                   pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL ($1.t)));
                  $$.new_type_flag = 0;
-                 if (TYPE_BINFO ($1) == NULL_TREE)
+                 if ($1.t == error_mark_node)
+                   $$.t = $1.t;
+                 else if (TYPE_BINFO ($1.t) == NULL_TREE)
                    {
-                     cp_error ("%T is not a class type", $1);
+                     cp_error ("%T is not a class type", $1.t);
                      $$.t = error_mark_node;
                    } 
                  else
                    {
-                     $$.t = $1;
-                     /* struct B: public A; is not accepted by the WP grammar.  */
-                     if (TYPE_BINFO_BASETYPES ($$.t) && !TYPE_SIZE ($$.t)
+                     $$.t = $1.t;
+                     /* struct B: public A; is not accepted by the standard grammar.  */
+                     if (CLASS_TYPE_P ($$.t)
+                         && TYPE_BINFO_BASETYPES ($$.t) 
+                         && !TYPE_SIZE ($$.t)
                          && ! TYPE_BEING_DEFINED ($$.t))
                        cp_error ("base clause without member specification for `%#T'",
                                  $$.t);
@@ -2127,87 +2242,117 @@ aggr:
 
 named_class_head_sans_basetype:
          aggr identifier
-               { current_aggr = $$; $$ = $2; }
+               { 
+                 current_aggr = $1; 
+                 $$ = $2; 
+               }
        ;
 
 named_class_head_sans_basetype_defn:
          aggr identifier_defn  %prec EMPTY
                { current_aggr = $$; $$ = $2; }
+       | named_class_head_sans_basetype '{'
+               { yyungetc ('{', 1); }
+       | named_class_head_sans_basetype ':'
+               { yyungetc (':', 1); }
        ;
 
 named_complex_class_head_sans_basetype:
          aggr nested_name_specifier identifier
                {
                  current_aggr = $1;
-                 $$ = handle_class_head ($1, $2, $3);
+                 $$.t = handle_class_head ($1, $2, $3);
+                 $$.new_type_flag = 1;
                }
        | aggr global_scope nested_name_specifier identifier
                {
                  current_aggr = $1;
-                 $$ = handle_class_head ($1, $3, $4);
+                 $$.t = handle_class_head ($1, $3, $4);
+                 $$.new_type_flag = 1;
                }
        | aggr global_scope identifier
                {
                  current_aggr = $1;
-                 $$ = handle_class_head ($1, NULL_TREE, $3);
+                 $$.t = handle_class_head ($1, NULL_TREE, $3);
+                 $$.new_type_flag = 1;
+               }
+       | aggr apparent_template_type
+               { 
+                 current_aggr = $1; 
+                 $$.t = $2;
+                 $$.new_type_flag = 0;
+               }
+       | aggr nested_name_specifier apparent_template_type
+               { 
+                 current_aggr = $1; 
+                 $$.t = $3;
+                 if (CP_DECL_CONTEXT ($$.t))
+                   push_scope (CP_DECL_CONTEXT ($$.t));
+                 $$.new_type_flag = 1;
                }
-       | aggr template_type
-               { current_aggr = $$; $$ = $2; }
-       | aggr nested_name_specifier template_type
-               { current_aggr = $$; $$ = $3; }
-       ;
-
-do_xref_defn:
-         /* empty */  %prec EMPTY
-               { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 0); }
        ;
 
 named_class_head:
          named_class_head_sans_basetype  %prec EMPTY
-               { $$ = xref_tag (current_aggr, $1, NULL_TREE, 1); }
-       | named_class_head_sans_basetype_defn do_xref_defn
+               { 
+                 $$.t = xref_tag (current_aggr, $1, 1); 
+                 $$.new_type_flag = 0;
+               }
+       | named_class_head_sans_basetype_defn 
+                { $<ttype>$ = xref_tag (current_aggr, $1, 0); }
+          /* Class name is unqualified, so we look for base classes
+             in the current scope.  */
           maybe_base_class_list  %prec EMPTY
                { 
-                 $$ = $<ttype>2;
+                 $$.t = $<ttype>2;
+                 $$.new_type_flag = 0;
                  if ($3)
                     xref_basetypes (current_aggr, $1, $<ttype>2, $3); 
                }
-       | named_complex_class_head_sans_basetype maybe_base_class_list
+       | named_complex_class_head_sans_basetype 
+         maybe_base_class_list
                { 
-                 $$ = TREE_TYPE ($1);
-                 if (TREE_INT_CST_LOW (current_aggr) == union_type 
-                     && TREE_CODE ($$) != UNION_TYPE)
-                   cp_pedwarn ("`union' tag used in declaring `%#T'", $$);
-                 else if (TREE_CODE ($$) == UNION_TYPE
-                          && TREE_INT_CST_LOW (current_aggr) != union_type)
-                   cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$);
-                 if ($2)
+                 if ($1.t != error_mark_node)
                    {
-                     if (IS_AGGR_TYPE ($$) && CLASSTYPE_USE_TEMPLATE ($$))
-                       {
-                         if (CLASSTYPE_IMPLICIT_INSTANTIATION ($$)
-                             && TYPE_SIZE ($$) == NULL_TREE)
-                           {
-                             SET_CLASSTYPE_TEMPLATE_SPECIALIZATION ($$);
-                             if (processing_template_decl)
-                               push_template_decl (TYPE_MAIN_DECL ($$));
-                           }
-                         else if (CLASSTYPE_TEMPLATE_INSTANTIATION ($$))
-                           cp_error ("specialization after instantiation of `%T'", $$);
+                     $$.t = TREE_TYPE ($1.t);
+                     $$.new_type_flag = $1.new_type_flag;
+                     if (current_aggr == union_type_node
+                         && TREE_CODE ($$.t) != UNION_TYPE)
+                       cp_pedwarn ("`union' tag used in declaring `%#T'", 
+                                   $$.t);
+                     else if (TREE_CODE ($$.t) == UNION_TYPE
+                              && current_aggr != union_type_node)
+                       cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$);
+                     else if (TREE_CODE ($$.t) == RECORD_TYPE)
+                       /* We might be specializing a template with a different
+                          class-key; deal.  */
+                       CLASSTYPE_DECLARED_CLASS ($$.t) 
+                         = (current_aggr == class_type_node);
+                     if ($2)
+                       {
+                         maybe_process_partial_specialization ($$.t);
+                         xref_basetypes (current_aggr, $1.t, $$.t, $2); 
                        }
-                     xref_basetypes (current_aggr, $1, $$, $2); 
                    }
                }
        ;
 
 unnamed_class_head:
          aggr '{'
-               { $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0);
+               { $$ = xref_tag ($$, make_anon_name (), 0);
                  yyungetc ('{', 1); }
        ;
 
+/* The tree output of this nonterminal a declarationf or the type
+   named.  If NEW_TYPE_FLAG is set, then the name used in this
+   class-head was explicitly qualified, e.g.:  `struct X::Y'.  We have
+   already called push_scope for X.  */
 class_head:
          unnamed_class_head
+                {
+                 $$.t = $1;
+                 $$.new_type_flag = 0;
+               }
        | named_class_head
        ;
 
@@ -2228,105 +2373,20 @@ base_class_list:
 
 base_class:
          base_class.1
-               {
-                 tree type = TREE_TYPE ($1);
-                 if (! is_aggr_type (type, 1))
-                   $$ = NULL_TREE;
-                 else if (current_aggr == signature_type_node
-                          && (! type) && (! IS_SIGNATURE (type)))
-                   {
-                     error ("class name not allowed as base signature");
-                     $$ = NULL_TREE;
-                   }
-                 else if (current_aggr == signature_type_node)
-                   {
-                     sorry ("signature inheritance, base type `%s' ignored",
-                            IDENTIFIER_POINTER ($$));
-                     $$ = build_tree_list (access_public_node, type);
-                   }
-                 else if (type && IS_SIGNATURE (type))
-                   {
-                     error ("signature name not allowed as base class");
-                     $$ = NULL_TREE;
-                   }
-                 else
-                   $$ = build_tree_list (access_default_node, type);
-               }
+               { $$ = finish_base_specifier (access_default_node, $1); }
        | base_class_access_list see_typename base_class.1
-               {
-                 tree type = TREE_TYPE ($3);
-                 if (current_aggr == signature_type_node)
-                   error ("access and source specifiers not allowed in signature");
-                 if (! is_aggr_type (type, 1))
-                   $$ = NULL_TREE;
-                 else if (current_aggr == signature_type_node
-                          && (! type) && (! IS_SIGNATURE (type)))
-                   {
-                     error ("class name not allowed as base signature");
-                     $$ = NULL_TREE;
-                   }
-                 else if (current_aggr == signature_type_node)
-                   {
-                     sorry ("signature inheritance, base type `%s' ignored",
-                            IDENTIFIER_POINTER ($$));
-                     $$ = build_tree_list (access_public_node, type);
-                   }
-                 else if (type && IS_SIGNATURE (type))
-                   {
-                     error ("signature name not allowed as base class");
-                     $$ = NULL_TREE;
-                   }
-                 else
-                   $$ = build_tree_list ($$, type);
-               }
+                { $$ = finish_base_specifier ($1, $3); }
        ;
 
 base_class.1:
          typename_sub
-               { $$ = TYPE_MAIN_DECL ($1); }
+               { if ($$ == error_mark_node)
+                   ;
+                  else if (!TYPE_P ($$))
+                   $$ = error_mark_node;
+                 else 
+                   $$ = TYPE_MAIN_DECL ($1); }
        | nonnested_type
-       | SIGOF '(' expr ')'
-               {
-                 if (current_aggr == signature_type_node)
-                   {
-                     if (IS_AGGR_TYPE (TREE_TYPE ($3)))
-                       {
-                         sorry ("`sigof' as base signature specifier");
-                         $$ = TREE_TYPE ($3);
-                       }
-                     else
-                       {
-                         error ("`sigof' applied to non-aggregate expression");
-                         $$ = error_mark_node;
-                       }
-                   }
-                 else
-                   {
-                     error ("`sigof' in struct or class declaration");
-                     $$ = error_mark_node;
-                   }
-               }
-       | SIGOF '(' type_id ')'
-               {
-                 if (current_aggr == signature_type_node)
-                   {
-                     if (IS_AGGR_TYPE (groktypename ($3.t)))
-                       {
-                         sorry ("`sigof' as base signature specifier");
-                         $$ = groktypename ($3.t);
-                       }
-                     else
-                       {
-                         error ("`sigof' applied to non-aggregate expression");
-                         $$ = error_mark_node;
-                       }
-                   }
-                 else
-                   {
-                     error ("`sigof' in struct or class declaration");
-                     $$ = error_mark_node;
-                   }
-               }
        ;
 
 base_class_access_list:
@@ -2360,71 +2420,34 @@ base_class_access_list:
                }
        ;
 
-left_curly:
-         '{'
-                { $<ttype>0 = begin_class_definition ($<ttype>0); }
-       ;
-
-self_reference:
-         /* empty */
-               {
-                   $$ = build_self_reference ();
-               }
-       ;
-
 opt.component_decl_list:
-         self_reference
-               { if ($$) $$ = build_tree_list (access_public_node, $$); }
-       | self_reference component_decl_list
-               {
-                 if (current_aggr == signature_type_node)
-                   $$ = build_tree_list (access_public_node, $2);
-                 else
-                   $$ = build_tree_list (access_default_node, $2);
-                 if ($1) $$ = tree_cons (access_public_node, $1, $$);
-               }
-       | opt.component_decl_list VISSPEC ':' component_decl_list
-               {
-                 tree visspec = $2;
+       | component_decl_list
+       | opt.component_decl_list access_specifier component_decl_list
+       | opt.component_decl_list access_specifier 
+       ;
 
-                 if (current_aggr == signature_type_node)
-                   {
-                     error ("access specifier not allowed in signature");
-                     visspec = access_public_node;
-                   }
-                 $$ = chainon ($$, build_tree_list (visspec, $4));
-               }
-       | opt.component_decl_list VISSPEC ':'
-               {
-                 if (current_aggr == signature_type_node)
-                   error ("access specifier not allowed in signature");
-               }
+access_specifier:
+         VISSPEC ':'
+                {
+                 current_access_specifier = $1;
+                }
        ;
 
 /* Note: we no longer warn about the semicolon after a component_decl_list.
    ARM $9.2 says that the semicolon is optional, and therefore allowed.  */
 component_decl_list:
          component_decl
-               { if ($$ == void_type_node) $$ = NULL_TREE; 
+               { 
+                 finish_member_declaration ($1);
                }
        | component_decl_list component_decl
-               { /* In pushdecl, we created a reverse list of names
-                    in this binding level.  Make sure that the chain
-                    of what we're trying to add isn't the item itself
-                    (which can happen with what pushdecl's doing).  */
-                 if ($2 != NULL_TREE && $2 != void_type_node)
-                   {
-                     if (TREE_CHAIN ($2) != $$)
-                       $$ = chainon ($$, $2);
-                     else
-                       $$ = $2;
-                   }
+               { 
+                 finish_member_declaration ($2);
                }
        ;
 
 component_decl:
          component_decl_1 ';'
-               { }
        | component_decl_1 '}'
                { error ("missing ';' before right brace");
                  yyungetc ('}', 0); }
@@ -2434,7 +2457,7 @@ component_decl:
                { $$ = finish_method ($$); }
        | fn.def2 TRY /* base_init compstmt */
                { $$ = finish_method ($$); }
-       | fn.def2 RETURN /* base_init compstmt */
+       | fn.def2 RETURN_KEYWORD /* base_init compstmt */
                { $$ = finish_method ($$); }
        | fn.def2 '{' /* nodecls compstmt */
                { $$ = finish_method ($$); }
@@ -2442,11 +2465,22 @@ component_decl:
                { $$ = NULL_TREE; }
        | extension component_decl
                { $$ = $2;
-                 pedantic = $<itype>1; }
+                 pedantic = $1; }
         | template_header component_decl
-                { $$ = finish_member_template_decl ($1, $2); }
+                {  
+                 if ($2)
+                   $$ = finish_member_template_decl ($2);
+                 else
+                   /* The component was already processed.  */
+                   $$ = NULL_TREE;
+
+                 finish_template_decl ($1);
+               }
        | template_header typed_declspecs ';'
-                { $$ = finish_member_class_template ($1, $2.t); }
+                { 
+                 $$ = finish_member_class_template ($2.t); 
+                 finish_template_decl ($1);
+               }
        ;
 
 component_decl_1:
@@ -2454,9 +2488,32 @@ component_decl_1:
           speed; we need to call grok_x_components for enums, so the
           speedup would be insignificant.  */
          typed_declspecs components
-               { $$ = grok_x_components ($1.t, $2); }
+               {
+                 /* Most of the productions for component_decl only
+                    allow the creation of one new member, so we call
+                    finish_member_declaration in component_decl_list.
+                    For this rule and the next, however, there can be
+                    more than one member, e.g.:
+
+                      int i, j;
+
+                    and we need the first member to be fully
+                    registered before the second is processed.
+                    Therefore, the rules for components take care of
+                    this processing.  To avoid registering the
+                    components more than once, we send NULL_TREE up
+                    here; that lets finish_member_declaration know
+                    that there is nothing to do.  */
+                 if (!$2)
+                   grok_x_components ($1.t);
+                 $$ = NULL_TREE;
+               }
        | declmods notype_components
-               { $$ = grok_x_components ($1, $2); }
+               { 
+                 if (!$2)
+                   grok_x_components ($1.t);
+                 $$ = NULL_TREE; 
+               }
        | notype_declarator maybeasm maybe_attribute maybe_init
                { $$ = grokfield ($$, NULL_TREE, $4, $2,
                                  build_tree_list ($3, NULL_TREE)); }
@@ -2478,7 +2535,7 @@ component_decl_1:
           parmlist? */
        | declmods component_constructor_declarator maybeasm maybe_attribute maybe_init
                { tree specs, attrs;
-                 split_specs_attrs ($1, &specs, &attrs);
+                 split_specs_attrs ($1.t, &specs, &attrs);
                  $$ = grokfield ($2, specs, $5, $3,
                                  build_tree_list ($4, attrs)); }
        | component_constructor_declarator maybeasm maybe_attribute maybe_init
@@ -2491,31 +2548,41 @@ component_decl_1:
 /* ??? Huh? ^^^ */
 components:
          /* empty: possibly anonymous */
-               { $$ = NULL_TREE; }
+                { $$ = 0; }
        | component_declarator0
+                { 
+                 if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+                   $1 = finish_member_template_decl ($1);
+                 finish_member_declaration ($1); 
+                 $$ = 1;
+               }
        | components ',' component_declarator
-               {
-                 /* In this context, void_type_node encodes
-                    friends.  They have been recorded elsewhere.  */
-                 if ($$ == void_type_node)
-                   $$ = $3;
-                 else
-                   $$ = chainon ($$, $3);
+                { 
+                 check_multiple_declarators ();
+                 if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+                   $3 = finish_member_template_decl ($3);
+                 finish_member_declaration ($3);
+                 $$ = 2;
                }
        ;
 
 notype_components:
          /* empty: possibly anonymous */
-               { $$ = NULL_TREE; }
+                { $$ = 0; }
        | notype_component_declarator0
+                { 
+                 if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+                   $1 = finish_member_template_decl ($1);
+                 finish_member_declaration ($1);
+                 $$ = 1;
+               }
        | notype_components ',' notype_component_declarator
-               {
-                 /* In this context, void_type_node encodes
-                    friends.  They have been recorded elsewhere.  */
-                 if ($$ == void_type_node)
-                   $$ = $3;
-                 else
-                   $$ = chainon ($$, $3);
+                { 
+                 check_multiple_declarators ();
+                 if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+                   $3 = finish_member_template_decl ($3);
+                 finish_member_declaration ($3); 
+                 $$ = 2;
                }
        ;
 
@@ -2531,65 +2598,47 @@ component_declarator:
 
 after_type_component_declarator0:
          after_type_declarator maybeasm maybe_attribute maybe_init
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokfield ($$, current_declspecs, $4, $2,
-                                 build_tree_list ($3, prefix_attributes)); }
+               { $$ = parse_field0 ($1, $<ftype>0.t, $<ftype>0.lookups,
+                                    $3, $2, $4); }
        | TYPENAME ':' expr_no_commas maybe_attribute
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokbitfield ($$, current_declspecs, $3);
-                 cplus_decl_attributes ($$, $4, prefix_attributes); }
+               { $$ = parse_bitfield0 ($1, $<ftype>0.t, $<ftype>0.lookups,
+                                       $4, $3); }
        ;
 
 notype_component_declarator0:
          notype_declarator maybeasm maybe_attribute maybe_init
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokfield ($$, current_declspecs, $4, $2,
-                                 build_tree_list ($3, prefix_attributes)); }
+               { $$ = parse_field0 ($1, $<ftype>0.t, $<ftype>0.lookups,
+                                    $3, $2, $4); }
        | constructor_declarator maybeasm maybe_attribute maybe_init
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokfield ($$, current_declspecs, $4, $2,
-                                 build_tree_list ($3, prefix_attributes)); }
+               { $$ = parse_field0 ($1, $<ftype>0.t, $<ftype>0.lookups,
+                                    $3, $2, $4); }
        | IDENTIFIER ':' expr_no_commas maybe_attribute
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokbitfield ($$, current_declspecs, $3);
-                 cplus_decl_attributes ($$, $4, prefix_attributes); }
+               { $$ = parse_bitfield0 ($1, $<ftype>0.t, $<ftype>0.lookups,
+                                       $4, $3); }
        | ':' expr_no_commas maybe_attribute
-               { split_specs_attrs ($<ttype>0, &current_declspecs,
-                                    &prefix_attributes);
-                 $<ttype>0 = current_declspecs;
-                 $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
-                 cplus_decl_attributes ($$, $3, prefix_attributes); }
+               { $$ = parse_bitfield0 (NULL_TREE, $<ftype>0.t,
+                                       $<ftype>0.lookups, $3, $2); }
        ;
 
 after_type_component_declarator:
          after_type_declarator maybeasm maybe_attribute maybe_init
-               { $$ = grokfield ($$, current_declspecs, $4, $2,
-                                 build_tree_list ($3, prefix_attributes)); }
+               { $$ = parse_field ($1, $3, $2, $4); }
        | TYPENAME ':' expr_no_commas maybe_attribute
-               { $$ = grokbitfield ($$, current_declspecs, $3);
-                 cplus_decl_attributes ($$, $4, prefix_attributes); }
+               { $$ = parse_bitfield ($1, $4, $3); }
        ;
 
 notype_component_declarator:
          notype_declarator maybeasm maybe_attribute maybe_init
-               { $$ = grokfield ($$, current_declspecs, $4, $2,
-                                 build_tree_list ($3, prefix_attributes)); }
+               { $$ = parse_field ($1, $3, $2, $4); }
        | IDENTIFIER ':' expr_no_commas maybe_attribute
-               { $$ = grokbitfield ($$, current_declspecs, $3);
-                 cplus_decl_attributes ($$, $4, prefix_attributes); }
+               { $$ = parse_bitfield ($1, $4, $3); }
        | ':' expr_no_commas maybe_attribute
-               { $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
-                 cplus_decl_attributes ($$, $3, prefix_attributes); }
+               { $$ = parse_bitfield (NULL_TREE, $3, $2); }
+       ;
+
+enumlist_opt:
+         enumlist maybecomma_warn
+       | maybecomma_warn
        ;
 
 /* We chain the enumerators in reverse order.
@@ -2599,17 +2648,16 @@ notype_component_declarator:
 enumlist:
          enumerator
        | enumlist ',' enumerator
-               { TREE_CHAIN ($3) = $$; $$ = $3; }
        ;
 
 enumerator:
          identifier
-               { $$ = build_enumerator ($$, NULL_TREE); }
+               { build_enumerator ($1, NULL_TREE, current_enum_type); }
        | identifier '=' expr_no_commas
-               { $$ = build_enumerator ($$, $3); }
+               { build_enumerator ($1, $3, current_enum_type); }
        ;
 
-/* ANSI new-type-id (5.3.4) */
+/* ISO new-type-id (5.3.4) */
 new_type_id:
          type_specifier_seq new_declarator
                { $$.t = build_decl_list ($1.t, $2); 
@@ -2618,16 +2666,14 @@ new_type_id:
                { $$.t = build_decl_list ($1.t, NULL_TREE); 
                  $$.new_type_flag = $1.new_type_flag; }
        /* GNU extension to allow arrays of arbitrary types with
-          non-constant dimension.  For the use of begin_new_placement
-          here, see the comments in unary_expr above.  */
-       | '(' .begin_new_placement type_id .finish_new_placement
-             '[' expr ']'
+          non-constant dimension.  */
+       | '(' type_id ')' '[' expr ']'
                {
                  if (pedantic)
-                   pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
-                 $$.t = build_parse_node (ARRAY_REF, TREE_VALUE ($3.t), $6);
-                 $$.t = build_decl_list (TREE_PURPOSE ($3.t), $$.t);
-                 $$.new_type_flag = $3.new_type_flag;
+                   pedwarn ("ISO C++ forbids array dimensions with parenthesized type in new");
+                 $$.t = build_parse_node (ARRAY_REF, TREE_VALUE ($2.t), $5);
+                 $$.t = build_decl_list (TREE_PURPOSE ($2.t), $$.t);
+                 $$.new_type_flag = $2.new_type_flag;
                }
        ;
 
@@ -2640,70 +2686,80 @@ cv_qualifiers:
 
 nonempty_cv_qualifiers:
          CV_QUALIFIER
-               { $$.t = IDENTIFIER_AS_LIST ($1); 
+               { $$.t = hash_tree_cons (NULL_TREE, $1, NULL_TREE);
                  $$.new_type_flag = 0; }
        | nonempty_cv_qualifiers CV_QUALIFIER
-               { $$.t = decl_tree_cons (NULL_TREE, $2, $1.t); 
+               { $$.t = hash_tree_cons (NULL_TREE, $2, $1.t); 
                  $$.new_type_flag = $1.new_type_flag; }
        ;
 
 /* These rules must follow the rules for function declarations
    and component declarations.  That way, longer rules are preferred.  */
 
-suspend_mom:
-         /* empty */
-               { $<itype>$ = suspend_momentary (); } 
-
-/* An expression which will not live on the momentary obstack.  */
-nonmomentary_expr:
-         suspend_mom expr
-               { resume_momentary ((int) $<itype>1); $$ = $2; }
-       ;
-
 /* An expression which will not live on the momentary obstack.  */
 maybe_parmlist:
-         suspend_mom '(' nonnull_exprlist ')'
-               { resume_momentary ((int) $<itype>1); $$ = $3; }
-       | suspend_mom '(' parmlist ')'
-               { resume_momentary ((int) $<itype>1); $$ = $3; }
-       | suspend_mom LEFT_RIGHT
-               { resume_momentary ((int) $<itype>1); $$ = empty_parms (); }
-       | suspend_mom '(' error ')'
-               { resume_momentary ((int) $<itype>1); $$ = NULL_TREE; }
+         '(' nonnull_exprlist ')'
+               { $$ = $2; }
+       | '(' parmlist ')'
+               { $$ = $2; }
+       | LEFT_RIGHT
+               { $$ = empty_parms (); }
+       | '(' error ')'
+               { $$ = NULL_TREE; }
        ;
 
 /* A declarator that is allowed only after an explicit typespec.  */
+
+after_type_declarator_intern:
+         after_type_declarator
+       | attributes after_type_declarator
+                {
+                 /* Provide support for '(' attributes '*' declarator ')'
+                    etc */
+                 $$ = decl_tree_cons ($1, $2, NULL_TREE);
+               }
+       ;
+
 /* may all be followed by prec '.' */
 after_type_declarator:
-         '*' nonempty_cv_qualifiers after_type_declarator  %prec UNARY
+         '*' nonempty_cv_qualifiers after_type_declarator_intern  %prec UNARY
                { $$ = make_pointer_declarator ($2.t, $3); }
-       | '&' nonempty_cv_qualifiers after_type_declarator  %prec UNARY
+       | '&' nonempty_cv_qualifiers after_type_declarator_intern  %prec UNARY
                { $$ = make_reference_declarator ($2.t, $3); }
-       | '*' after_type_declarator  %prec UNARY
+       | '*' after_type_declarator_intern  %prec UNARY
                { $$ = make_pointer_declarator (NULL_TREE, $2); }
-       | '&' after_type_declarator  %prec UNARY
+       | '&' after_type_declarator_intern  %prec UNARY
                { $$ = make_reference_declarator (NULL_TREE, $2); }
-       | ptr_to_mem cv_qualifiers after_type_declarator
+       | ptr_to_mem cv_qualifiers after_type_declarator_intern
                { tree arg = make_pointer_declarator ($2, $3);
                  $$ = build_parse_node (SCOPE_REF, $1, arg);
                }
        | direct_after_type_declarator
        ;
 
+direct_after_type_declarator:
+         direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt  %prec '.'
+               { $$ = make_call_declarator ($$, $2, $3, $4); }
+       | direct_after_type_declarator '[' expr ']'
+               { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+       | direct_after_type_declarator '[' ']'
+               { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+       | '(' after_type_declarator_intern ')'
+               { $$ = $2; }
+       | nested_name_specifier type_name  %prec EMPTY
+               { push_nested_class ($1, 3);
+                 $$ = build_parse_node (SCOPE_REF, $$, $2);
+                 TREE_COMPLEXITY ($$) = current_class_depth; }
+       | type_name  %prec EMPTY
+       ;
+
 nonnested_type:
          type_name  %prec EMPTY
                {
                  if (TREE_CODE ($1) == IDENTIFIER_NODE)
                    {
                      $$ = lookup_name ($1, 1);
-                     if (current_class_type
-                         && TYPE_BEING_DEFINED (current_class_type)
-                         && ! IDENTIFIER_CLASS_VALUE ($1))
-                       {
-                         /* Remember that this name has been used in the class
-                            definition, as per [class.scope0] */
-                         pushdecl_class_level ($$);
-                       }
+                     maybe_note_name_used_in_class ($1, $$);
                    }
                  else
                    $$ = $1;
@@ -2730,35 +2786,29 @@ nested_type:
                { $$ = get_type_decl ($2); }
        ;
 
-direct_after_type_declarator:
-         direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt  %prec '.'
-               { $$ = make_call_declarator ($$, $2, $3, $4); }
-       | direct_after_type_declarator '[' nonmomentary_expr ']'
-               { $$ = build_parse_node (ARRAY_REF, $$, $3); }
-       | direct_after_type_declarator '[' ']'
-               { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
-       | '(' after_type_declarator ')'
-               { $$ = $2; }
-       | nested_name_specifier type_name  %prec EMPTY
-               { push_nested_class ($1, 3);
-                 $$ = build_parse_node (SCOPE_REF, $$, $2);
-                 TREE_COMPLEXITY ($$) = current_class_depth; }
-       | type_name  %prec EMPTY
-       ;
-
 /* A declarator allowed whether or not there has been
    an explicit typespec.  These cannot redeclare a typedef-name.  */
 
+notype_declarator_intern:
+         notype_declarator
+       | attributes notype_declarator
+                {
+                 /* Provide support for '(' attributes '*' declarator ')'
+                    etc */
+                 $$ = decl_tree_cons ($1, $2, NULL_TREE);
+               }
+       ;
+       
 notype_declarator:
-         '*' nonempty_cv_qualifiers notype_declarator  %prec UNARY
+         '*' nonempty_cv_qualifiers notype_declarator_intern  %prec UNARY
                { $$ = make_pointer_declarator ($2.t, $3); }
-       | '&' nonempty_cv_qualifiers notype_declarator  %prec UNARY
+       | '&' nonempty_cv_qualifiers notype_declarator_intern  %prec UNARY
                { $$ = make_reference_declarator ($2.t, $3); }
-       | '*' notype_declarator  %prec UNARY
+       | '*' notype_declarator_intern  %prec UNARY
                { $$ = make_pointer_declarator (NULL_TREE, $2); }
-       | '&' notype_declarator  %prec UNARY
+       | '&' notype_declarator_intern  %prec UNARY
                { $$ = make_reference_declarator (NULL_TREE, $2); }
-       | ptr_to_mem cv_qualifiers notype_declarator
+       | ptr_to_mem cv_qualifiers notype_declarator_intern
                { tree arg = make_pointer_declarator ($2, $3);
                  $$ = build_parse_node (SCOPE_REF, $1, arg);
                }
@@ -2766,15 +2816,15 @@ notype_declarator:
        ;
 
 complex_notype_declarator:
-         '*' nonempty_cv_qualifiers notype_declarator  %prec UNARY
+         '*' nonempty_cv_qualifiers notype_declarator_intern  %prec UNARY
                { $$ = make_pointer_declarator ($2.t, $3); }
-       | '&' nonempty_cv_qualifiers notype_declarator  %prec UNARY
+       | '&' nonempty_cv_qualifiers notype_declarator_intern  %prec UNARY
                { $$ = make_reference_declarator ($2.t, $3); }
        | '*' complex_notype_declarator  %prec UNARY
                { $$ = make_pointer_declarator (NULL_TREE, $2); }
        | '&' complex_notype_declarator  %prec UNARY
                { $$ = make_reference_declarator (NULL_TREE, $2); }
-       | ptr_to_mem cv_qualifiers notype_declarator
+       | ptr_to_mem cv_qualifiers notype_declarator_intern
                { tree arg = make_pointer_declarator ($2, $3);
                  $$ = build_parse_node (SCOPE_REF, $1, arg);
                }
@@ -2786,30 +2836,16 @@ complex_direct_notype_declarator:
                { $$ = make_call_declarator ($$, $2, $3, $4); }
        | '(' complex_notype_declarator ')'
                { $$ = $2; }
-       | direct_notype_declarator '[' nonmomentary_expr ']'
+       | direct_notype_declarator '[' expr ']'
                { $$ = build_parse_node (ARRAY_REF, $$, $3); }
        | direct_notype_declarator '[' ']'
                { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
        | notype_qualified_id
-               { if (TREE_CODE (OP0 ($1)) == NAMESPACE_DECL)
-                   {
-                     push_decl_namespace (OP0 ($1));
-                     TREE_COMPLEXITY ($1) = -1;
-                   }
-                 else if (OP0 ($1) != current_class_type)
-                   {
-                     push_nested_class (OP0 ($1), 3);
-                     TREE_COMPLEXITY ($1) = current_class_depth;
-                   }
-               }
+                { enter_scope_of ($1); }
         | nested_name_specifier notype_template_declarator
                 { got_scope = NULL_TREE;
                  $$ = build_parse_node (SCOPE_REF, $1, $2);
-                 if ($1 != current_class_type)
-                   {
-                     push_nested_class ($1, 3);
-                     TREE_COMPLEXITY ($$) = current_class_depth;
-                   }
+                 enter_scope_of ($$);
                }
        ;
 
@@ -2840,7 +2876,7 @@ overqualified_id:
 functional_cast:
          typespec '(' nonnull_exprlist ')'
                { $$ = build_functional_cast ($1.t, $3); }
-       | typespec '(' expr_or_declarator ')'
+       | typespec '(' expr_or_declarator_intern ')'
                { $$ = reparse_decl_as_expr ($1.t, $3); }
        | typespec fcast_or_absdcl  %prec EMPTY
                { $$ = reparse_absdcl_as_expr ($1.t, $2); }
@@ -2857,7 +2893,8 @@ nested_name_specifier:
        | nested_name_specifier nested_name_specifier_1
                { $$ = $2; }
        | nested_name_specifier TEMPLATE explicit_template_type SCOPE
-               { got_scope = $$ = make_typename_type ($1, $3); }
+                { got_scope = $$ 
+                   = make_typename_type ($1, $3, /*complain=*/1); }
        ;
 
 /* Why the @#$%^& do type_name and notype_identifier need to be expanded
@@ -2868,14 +2905,10 @@ nested_name_specifier_1:
                  if (TREE_CODE ($1) == IDENTIFIER_NODE)
                    {
                      $$ = lastiddecl;
-                     /* Remember that this name has been used in the class
-                        definition, as per [class.scope0] */
-                     if (current_class_type
-                         && TYPE_BEING_DEFINED (current_class_type)
-                         && ! IDENTIFIER_CLASS_VALUE ($1))
-                       pushdecl_class_level ($$);
+                     maybe_note_name_used_in_class ($1, $$);
                    }
-                 got_scope = $$ = TREE_TYPE ($$);
+                 got_scope = $$ =
+                   complete_type (TYPE_MAIN_VARIANT (TREE_TYPE ($$)));
                }
        | SELFNAME SCOPE
                {
@@ -2913,7 +2946,7 @@ typename_sub0:
          typename_sub1 identifier %prec EMPTY
                {
                  if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
-                   $$ = make_typename_type ($1, $2);
+                   $$ = make_typename_type ($1, $2, /*complain=*/1);
                  else if (TREE_CODE ($2) == IDENTIFIER_NODE)
                    cp_error ("`%T' is not a class or namespace", $2);
                  else
@@ -2926,9 +2959,9 @@ typename_sub0:
        | typename_sub1 template_type %prec EMPTY
                { $$ = TREE_TYPE ($2); }
        | typename_sub1 explicit_template_type %prec EMPTY
-               { $$ = make_typename_type ($1, $2); }
+                { $$ = make_typename_type ($1, $2, /*complain=*/1); }
        | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY
-               { $$ = make_typename_type ($1, $3); }
+                { $$ = make_typename_type ($1, $3, /*complain=*/1); }
        ;
 
 typename_sub1:
@@ -2940,7 +2973,7 @@ typename_sub1:
        | typename_sub1 typename_sub2
                {
                  if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
-                   $$ = make_typename_type ($1, $2);
+                   $$ = make_typename_type ($1, $2, /*complain=*/1);
                  else if (TREE_CODE ($2) == IDENTIFIER_NODE)
                    cp_error ("`%T' is not a class or namespace", $2);
                  else
@@ -2951,9 +2984,11 @@ typename_sub1:
                    }
                }
        | typename_sub1 explicit_template_type SCOPE
-               { got_scope = $$ = make_typename_type ($1, $2); }
+                { got_scope = $$ 
+                   = make_typename_type ($1, $2, /*complain=*/1); }
        | typename_sub1 TEMPLATE explicit_template_type SCOPE
-               { got_scope = $$ = make_typename_type ($1, $3); }
+                { got_scope = $$ 
+                   = make_typename_type ($1, $3, /*complain=*/1); }
        ;
 
 typename_sub2:
@@ -3020,7 +3055,7 @@ global_scope:
                { got_scope = void_type_node; }
        ;
 
-/* ANSI new-declarator (5.3.4) */
+/* ISO new-declarator (5.3.4) */
 new_declarator:
          '*' cv_qualifiers new_declarator
                { $$ = make_pointer_declarator ($2, $3); }
@@ -3041,27 +3076,37 @@ new_declarator:
        | direct_new_declarator  %prec EMPTY
        ;
 
-/* ANSI direct-new-declarator (5.3.4) */
+/* ISO direct-new-declarator (5.3.4) */
 direct_new_declarator:
          '[' expr ']'
                { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
-       | direct_new_declarator '[' nonmomentary_expr ']'
+       | direct_new_declarator '[' expr ']'
                { $$ = build_parse_node (ARRAY_REF, $$, $3); }
        ;
 
-/* ANSI abstract-declarator (8.1) */
+absdcl_intern:
+         absdcl
+       | attributes absdcl
+                {
+                 /* Provide support for '(' attributes '*' declarator ')'
+                    etc */
+                 $$ = decl_tree_cons ($1, $2, NULL_TREE);
+               }
+       ;
+       
+/* ISO abstract-declarator (8.1) */
 absdcl:
-         '*' nonempty_cv_qualifiers absdcl
+         '*' nonempty_cv_qualifiers absdcl_intern
                { $$ = make_pointer_declarator ($2.t, $3); }
-       | '*' absdcl
+       | '*' absdcl_intern
                { $$ = make_pointer_declarator (NULL_TREE, $2); }
        | '*' nonempty_cv_qualifiers  %prec EMPTY
                { $$ = make_pointer_declarator ($2.t, NULL_TREE); }
        | '*'  %prec EMPTY
                { $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); }
-       | '&' nonempty_cv_qualifiers absdcl
+       | '&' nonempty_cv_qualifiers absdcl_intern
                { $$ = make_reference_declarator ($2.t, $3); }
-       | '&' absdcl
+       | '&' absdcl_intern
                { $$ = make_reference_declarator (NULL_TREE, $2); }
        | '&' nonempty_cv_qualifiers  %prec EMPTY
                { $$ = make_reference_declarator ($2.t, NULL_TREE); }
@@ -3071,24 +3116,23 @@ absdcl:
                { tree arg = make_pointer_declarator ($2, NULL_TREE);
                  $$ = build_parse_node (SCOPE_REF, $1, arg);
                }
-       | ptr_to_mem cv_qualifiers absdcl
+       | ptr_to_mem cv_qualifiers absdcl_intern
                { tree arg = make_pointer_declarator ($2, $3);
                  $$ = build_parse_node (SCOPE_REF, $1, arg);
                }
        | direct_abstract_declarator  %prec EMPTY
        ;
 
-/* ANSI direct-abstract-declarator (8.1) */
+/* ISO direct-abstract-declarator (8.1) */
 direct_abstract_declarator:
-         '(' absdcl ')'
+         '(' absdcl_intern ')'
                { $$ = $2; }
          /* `(typedef)1' is `int'.  */
-       | PAREN_STAR_PAREN
        | direct_abstract_declarator '(' parmlist ')' cv_qualifiers exception_specification_opt  %prec '.'
                { $$ = make_call_declarator ($$, $3, $5, $6); }
        | direct_abstract_declarator LEFT_RIGHT cv_qualifiers exception_specification_opt  %prec '.'
                { $$ = make_call_declarator ($$, empty_parms (), $3, $4); }
-       | direct_abstract_declarator '[' nonmomentary_expr ']'  %prec '.'
+       | direct_abstract_declarator '[' expr ']'  %prec '.'
                { $$ = build_parse_node (ARRAY_REF, $$, $3); }
        | direct_abstract_declarator '[' ']'  %prec '.'
                { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
@@ -3098,7 +3142,7 @@ direct_abstract_declarator:
                { set_quals_and_spec ($$, $2, $3); }
        | fcast_or_absdcl cv_qualifiers exception_specification_opt  %prec '.'
                { set_quals_and_spec ($$, $2, $3); }
-       | '[' nonmomentary_expr ']'  %prec '.'
+       | '[' expr ']'  %prec '.'
                { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
        | '[' ']'  %prec '.'
                { $$ = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); }
@@ -3125,7 +3169,7 @@ maybe_label_decls:
          /* empty */
        | label_decls
                { if (pedantic)
-                   pedwarn ("ANSI C++ forbids label declarations"); }
+                   pedwarn ("ISO C++ forbids label declarations"); }
        ;
 
 label_decls:
@@ -3135,12 +3179,11 @@ label_decls:
 
 label_decl:
          LABEL identifiers_or_typenames ';'
-               { tree link;
-                 for (link = $2; link; link = TREE_CHAIN (link))
+                { 
+                 while ($2)
                    {
-                     tree label = shadow_label (TREE_VALUE (link));
-                     C_DECLARED_LABEL_FLAG (label) = 1;
-                     declare_nonlocal_label (label);
+                     finish_label_decl (TREE_VALUE ($2));
+                     $2 = TREE_CHAIN ($2);
                    }
                }
        ;
@@ -3228,11 +3271,11 @@ simple_stmt:
          already_scoped_stmt
                 { finish_for_stmt ($9, $<ttype>2); }
        | SWITCH 
-                { begin_switch_stmt (); }
+                { $<ttype>$ = begin_switch_stmt (); }
            '(' condition ')'
-                { $<ttype>$ = finish_switch_cond ($4); }
+                { finish_switch_cond ($4, $<ttype>2); }
          implicitly_scoped_stmt
-                { finish_switch_stmt ($4, $<ttype>6); }
+                { finish_switch_stmt ($4, $<ttype>2); }
        | CASE expr_no_commas ':'
                 { finish_case_label ($2, NULL_TREE); }
          stmt
@@ -3246,9 +3289,9 @@ simple_stmt:
                 { finish_break_stmt (); }
        | CONTINUE ';'
                 { finish_continue_stmt (); }
-       | RETURN ';'
+       | RETURN_KEYWORD ';'
                 { finish_return_stmt (NULL_TREE); }
-       | RETURN expr ';'
+       | RETURN_KEYWORD expr ';'
                 { finish_return_stmt ($2); }
        | asm_keyword maybe_cv_qualifier '(' string ')' ';'
                { 
@@ -3264,49 +3307,48 @@ simple_stmt:
        /* This is the case with input operands as well.  */
        | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ')' ';'
                { finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
+       | asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ')' ';'
+               { finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
        /* This is the case with clobbered registers as well.  */
        | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
          asm_operands ':' asm_clobbers ')' ';'
                { finish_asm_stmt ($2, $4, $6, $8, $10); }
+       | asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ':'
+         asm_clobbers ')' ';'
+               { finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); }
+       | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands SCOPE
+         asm_clobbers ')' ';'
+               { finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
        | GOTO '*' expr ';'
                 { 
                  if (pedantic)
-                   pedwarn ("ANSI C++ forbids computed gotos");
+                   pedwarn ("ISO C++ forbids computed gotos");
                  finish_goto_stmt ($3);
                }
        | GOTO identifier ';'
                 { finish_goto_stmt ($2); }
        | label_colon stmt
-               { finish_stmt (); }
        | label_colon '}'
                { error ("label must be followed by statement");
-                 yyungetc ('}', 0);
-                 finish_stmt (); }
+                 yyungetc ('}', 0); }
        | ';'
                { finish_stmt (); }
        | try_block
        | using_directive
        | namespace_using_decl
                { do_local_using_decl ($1); }
+       | namespace_alias
        ;
 
 function_try_block:
          TRY
-               {
-                 if (! current_function_parms_stored)
-                   store_parm_decls ();
-                 expand_start_early_try_stmts ();
-               }
+               { $<ttype>$ = begin_function_try_block (); }
          ctor_initializer_opt compstmt
-               { 
-                  expand_start_all_catch (); 
-                }
+               { finish_function_try_block ($<ttype>2); }
          handler_seq
                {
-                 int nested = (hack_decl_function_context
-                               (current_function_decl) != NULL_TREE);
-                 expand_end_all_catch ();
-                 finish_function (lineno, (int)$3, nested);
+                 finish_function_handler_sequence ($<ttype>2);
+                 $$ = $3;
                }
        ;
 
@@ -3328,9 +3370,9 @@ handler:
          CATCH
                 { $<ttype>$ = begin_handler(); }
           handler_args
-                { finish_handler_parms ($<ttype>2); }
+                { $<ttype>$ = finish_handler_parms ($3, $<ttype>2); }
          compstmt
-                { finish_handler ($<ttype>2); }
+                { finish_handler ($<ttype>4, $<ttype>2); }
        ;
 
 type_specifier_seq:
@@ -3340,7 +3382,7 @@ type_specifier_seq:
 
 handler_args:
          '(' ELLIPSIS ')'
-               { expand_start_catch_block (NULL_TREE, NULL_TREE); }
+               { $$ = NULL_TREE; }
        /* This doesn't allow reference parameters, the below does.
        | '(' type_specifier_seq absdcl ')'
                { check_for_new_type ("inside exception declarations", $2);
@@ -3356,34 +3398,31 @@ handler_args:
                  expand_start_catch_block ($2.t, $3); }
        This allows reference parameters...  */
        | '(' parm ')'
-               { check_for_new_type ("inside exception declarations", $2);
-                 expand_start_catch_block (TREE_PURPOSE ($2.t),
-                                           TREE_VALUE ($2.t)); }
+               { 
+                 check_for_new_type ("inside exception declarations", $2);
+                 $$ = start_handler_parms (TREE_PURPOSE ($2.t),
+                                           TREE_VALUE ($2.t));
+               }
        ;
 
 label_colon:
          IDENTIFIER ':'
-               { tree label;
-               do_label:
-                 label = define_label (input_filename, lineno, $1);
-                 if (label && ! minimal_parse_mode)
-                   expand_label (label);
-               }
+                { finish_label_stmt ($1); }
        | PTYPENAME ':'
-               { goto do_label; }
+                { finish_label_stmt ($1); }
        | TYPENAME ':'
-               { goto do_label; }
+                { finish_label_stmt ($1); }
        | SELFNAME ':'
-               { goto do_label; }
+                { finish_label_stmt ($1); }
        ;
 
 for.init.statement:
          xexpr ';'
-               { if ($1) cplus_expand_expr_stmt ($1); }
+                { finish_expr_stmt ($1); }
        | decl
        | '{' compstmtend
                { if (pedantic)
-                   pedwarn ("ANSI C++ forbids compound statements inside for initializations");
+                   pedwarn ("ISO C++ forbids compound statements inside for initializations");
                }
        ;
 
@@ -3391,10 +3430,8 @@ for.init.statement:
 
 maybe_cv_qualifier:
          /* empty */
-               { emit_line_note (input_filename, lineno);
-                 $$ = NULL_TREE; }
+               { $$ = NULL_TREE; }
        | CV_QUALIFIER
-               { emit_line_note (input_filename, lineno); }
        ;
 
 xexpr:
@@ -3536,7 +3573,8 @@ named_parm:
                { $$.t = build_tree_list ($1.t, $2); 
                  $$.new_type_flag = $1.new_type_flag; }
        | typespec declarator
-               { $$.t = build_tree_list (get_decl_list ($1.t), $2); 
+               { $$.t = build_tree_list (build_decl_list (NULL_TREE, $1.t),
+                                         $2); 
                  $$.new_type_flag = $1.new_type_flag; }
        | typed_declspecs1 absdcl
                { tree specs = strip_attrs ($1.t);
@@ -3547,7 +3585,7 @@ named_parm:
                  $$.t = build_tree_list (specs, NULL_TREE); 
                  $$.new_type_flag = $1.new_type_flag; }
        | declmods notype_declarator
-               { tree specs = strip_attrs ($1);
+               { tree specs = strip_attrs ($1.t);
                  $$.t = build_tree_list (specs, $2); 
                  $$.new_type_flag = 0; }
        ;
@@ -3594,21 +3632,22 @@ exception_specification_opt:
        | THROW '(' ansi_raise_identifiers  ')'  %prec EMPTY
                { $$ = $3; }
        | THROW LEFT_RIGHT  %prec EMPTY
-               { $$ = build_decl_list (NULL_TREE, NULL_TREE); }
+               { $$ = empty_except_spec; }
        ;
 
 ansi_raise_identifier:
          type_id
-               { $$ = build_decl_list (NULL_TREE, groktypename($1.t)); }
+               {
+                 check_for_new_type ("exception specifier", $1);
+                 $$ = groktypename ($1.t);
+               }
        ;
 
 ansi_raise_identifiers:
          ansi_raise_identifier
+               { $$ = add_exception_specifier (NULL_TREE, $1, 1); }
        | ansi_raise_identifiers ',' ansi_raise_identifier
-               {
-                 TREE_CHAIN ($3) = $$;
-                 $$ = $3;
-               }
+               { $$ = add_exception_specifier ($1, $3, 1); }
        ;
 
 conversion_declarator: