Make-lang.in (po-generated): Remove parse.c.
authorMark Mitchell <mark@codesourcery.com>
Sat, 28 Dec 2002 08:03:42 +0000 (08:03 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sat, 28 Dec 2002 08:03:42 +0000 (08:03 +0000)
* Make-lang.in (po-generated): Remove parse.c.
(CXX_OBJS): Remove parse.o and spew.o.  Add parser.o.
($(srcdir)/cp/parse.h): Remove target.
($(srcdir)/cp/parse.c): Likewise.
(gt-cp-parse.h): Likewise.
(gt-cp-parser.h): New target.
(c++.distclean): Do not remove parse.output.
(c++.maintainer-clean): Do not remove parse.c or parse.h.
(cp/spew.o): Remove target.
(cp/lex.o): Adjust dependencies.
(cp/pt.o): Likewise.
(cp/parse.o): Likewise.
(cp/TAGS): Do not mention parse.c.
(cp/parser.o): New target.
* NEWS: Mention the new parser.
* call.c (build_scoped_method_call): Simplify.
(build_method_call): Likewise.
(build_new_function_call): Adjust calls to add_function_candidate
and add_template_candidate.
(build_new_op): Improve handling of erroroneous operands.
(convert_default_arg): Remove circular argument processing.
(name_as_c_string): New function.
(build_new_method_call): Use it.
(perform_implicit_conversion): Use error_operand_p.
* class.c (finish_struct_anon): Use constructor_name_p.
(check_field_decls): Likewise.
(pop_nested_class): Use OVL_NEXT, not OVL_CHAIN.
(resolve_address_of_overloaded_function): Likewise.
(instantiate_type): Tweak pointer-to-member handling.
(get_primary_binfo): Remove incorrect assertion.
* config-lang.in (gtfiles): Add parser.c, remove parse.c.
* cp-tree.h (DEFARG_TOKENS): New macro.
(default_arg): New structure.
(cp_tree_node_structure_enum): Add TS_CP_DEFAULT_ARG.
(lang_tree_node): Add default_arg.
(cp_tree_index): Add CPTI_TYPE_INFO_REF_TYPE.
(type_info_ref_type): New macro.
(saved_scope): Make processing_explicit_instantiation a boolean.
(check_access): New field.
(unparsed_text): Remove.
(language_function): Remove unparsed_inlines.
(error_operand_p): New macro.
(lang_decl): Adjust pending_inline_info.
(DEFARG_POINTER): Remove.
(tag_types): Add typenames.
(lookup_ualified_name): Declare.
(lookup_name_real): Likewise.
(shadow_tag): Adjust prototype.
(get_scope_of_declarator): Declare it.
(process_next_inline): Remove it.
(check_for_missing_semicolon): Likewise.
(maybe_get_template_decl_from_type_decl): Declare it.
(finish_label_stmt): Adjust prototype.
(finish_non_static_data_meber): Declare it.
(finish_pseudo_destructor_call_expr): Rename to ...
(finish_pseudo_destructor_expr): ... this.
(finish_compound_literal): Declare it.
(begin_inline_definitions): Remove it.
(init_spew): Remove.
(peekyylex): Likewise.
(arbitrate_lookup): Likewise.
(frob_opname): Likewise.
(maybe_snarf_defarg): Likewise.
(add_defarg_fn): Likewise.
(do_pending_defargs): Likewise.
(done_pending_defargs): Likewise.
(unprocessed_defarg_fn): Likewise.
(replace_defarg): Likewise.
(end_input): Likewise.
(get_overloaded_fn): Likewise.
* cvt.c (convert_to_reference): Improve error handling.
* decl.c (lookup_name_real): Do not declare it static.
(maybe_push_to_top_level): Set check_access.
(identifier_type_value): Adjust call to lookup_name_real.
(lookup_qualified_name): New method.
(lookup_name_real): Remove special-case parsing code.
(lookup_name-nonclass): Adjust call to lookup_name_real.
(lookup_name_namespace_only): Likewise.
(lookup_name): Likewise.
(check_tag_decl): Return the type declared.
(shadow_tag): Likewise.
(register_dtor_fn): Tweak check_access.
(grokfndecl): Use constructor_name_p.
(get_scope_of_declarator): New function.
(grokdeclarator): Obscure tweaks for slightly different declarator
representations.
(start_method): Return error_mark_node to indicate failure.
(cp_tree_node_structure_enum): Use TS_CP_DEFAULT_ARG for DEFAULT_ARGs.
* decl2.c (constructor_name_full): Simplify.
(constructor_name): Use it.
(build_expr_from_tree): Adjust for changes to do new parser.
(push_scope): Improve robustness.
(validate_nonmember_using_decl): Process declarations, not names.
(do_class_using_decl): Likewise.
(handle_class_head): Do not mess with CLASSTYPE_DECLARED_CLASS
here.
* error.c (dump_expr): Handle IDENTIFIER_NODEs and BASELINKs.
* expr.c (cxx_expand_expr): Handle BASELINKs.
* init.c (member_init_ok_or_else): Issue more errors.
(build_offset_ref): Tweak handling of FUNCTION_DECLs.
* lex.c: Do not include parse.h.
(yypring): Do not declare.
(yylval): Likewise.
(make_reference_declarator): Remove error-generating code.
(rid_to_yy): Remove.
(cxx_init): Do not call init_spew.
(yypring): Remove.
(check_for_missing_semicolon): Remove.
* lex.h (got_scope): Remove.
(got_object): Remove.
* method.c (hack_identifier): Use finish_non_static_data_member.
(implicitly_declare_fn): Adjust use of constructor_name.
* parser.c: New file.
* pt.c (parse.h): Do not include it.
(maybe_get_template_decl_from_template): Do not declare it.
(finish_member_template_decl): Tweak.
(begin_explicit_instantiation): Adjust for
processing_explicit_instantiation being boolean.
(end_explicit_instantiation): Likewise.
(maybe_process_partial_specialization): Tighten specialization
test.
(retrieve_local_specialization): Adjust ue of hash table.
(eq_local_specializations): New function.
(register_local_specialization): Likewise.
(push_template_decl_real): Remove unnecessary test.
(maybe_get_template_decl_from_type_decl): Don't make it static.
(for_each_template_parm_r): Handle TYPEOF_TYPE.
(tsubst_copy): Use retrieive_local_specialization to handle
PARM_DECL.  Adjust handling of CONST_DECLs.  Handle BASELINKs.
Handle COMPONENT_REFs with pseudo-destructor-expressions.
Simplify handling of CALL_EXPR and METHOD_CALL_EXPR.
(tsubst_expr): Pass decls, not names, to do_local_using_decl.
(unify): Tweak handling of CONST_DECLs.
(regenerate_decl_from_template): Use push_nested_class.
(template_for_substitution): New funciton.
(instantiate_decl): Use it.  Register parameters as local
specializations.
* rtti.c (init_rtti_processing): Set type_info_ref_type.
(build_typeid): Use it.
(get_typeid): Likeise.
* search.c (accessible_p): Use check_access, not
flag_access_control.
(adjust_result_of_qualified_name_lookup): Pay attention to the
context_class.
* semantics.c (finish_asm_stmt): Adjust error handling.
(finish_label_stmt): Return the statement.
(finish_non_static_data_member): New function.
(finish_class_expr): Handle BASELINKs.
(finish_call_expr): Handle PSEUDO_DTOR_EXPR.
(finish_object_call_expr): Simplify handling during templates.
(finish_pseudo_destructor_call_expr): Rename to ...
(finish_pseudo_dtor_expr): ... this.
(finish_compound_literal): New function.
(begin_inline_definitions): Remove.
(finish_sizeof): Remove special template handling.
* spew.c: Do not include parse.h.
* tree.c (get_overloaded_fn): Remove.
* typeck.c (build_class_member_access_expr): Handle
PSEUDO_DTOR_EXPR.  Adjust handling of static member functions.
(lookup_destructor): New function.
(finish_class_member_access_expr): Use it.
(convert_arguments): Simplify.
(build_unary_op): Handle BASELINKs.

From-SVN: r60560

24 files changed:
gcc/cp/ChangeLog
gcc/cp/Make-lang.in
gcc/cp/NEWS
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/config-lang.in
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/expr.c
gcc/cp/init.c
gcc/cp/lex.c
gcc/cp/lex.h
gcc/cp/method.c
gcc/cp/parser.c [new file with mode: 0644]
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/cp/spew.c
gcc/cp/tree.c
gcc/cp/typeck.c

index 08177c091fa5243e8bb02e1f8bf10878c1044f15..077b97b1acbfa3d0b74810e1c5d2df01fc90ad9b 100644 (file)
@@ -1,3 +1,169 @@
+2002-12-27  Mark Mitchell  <mark@codesourcery.com>
+
+       * Make-lang.in (po-generated): Remove parse.c.
+       (CXX_OBJS): Remove parse.o and spew.o.  Add parser.o.
+       ($(srcdir)/cp/parse.h): Remove target.
+       ($(srcdir)/cp/parse.c): Likewise.
+       (gt-cp-parse.h): Likewise.
+       (gt-cp-parser.h): New target.
+       (c++.distclean): Do not remove parse.output.
+       (c++.maintainer-clean): Do not remove parse.c or parse.h.
+       (cp/spew.o): Remove target.
+       (cp/lex.o): Adjust dependencies.
+       (cp/pt.o): Likewise.
+       (cp/parse.o): Likewise.
+       (cp/TAGS): Do not mention parse.c.
+       (cp/parser.o): New target.
+       * NEWS: Mention the new parser.
+       * call.c (build_scoped_method_call): Simplify.
+       (build_method_call): Likewise.
+       (build_new_function_call): Adjust calls to add_function_candidate
+       and add_template_candidate.
+       (build_new_op): Improve handling of erroroneous operands.
+       (convert_default_arg): Remove circular argument processing.
+       (name_as_c_string): New function.
+       (build_new_method_call): Use it.
+       (perform_implicit_conversion): Use error_operand_p.
+       * class.c (finish_struct_anon): Use constructor_name_p.
+       (check_field_decls): Likewise.
+       (pop_nested_class): Use OVL_NEXT, not OVL_CHAIN.
+       (resolve_address_of_overloaded_function): Likewise.
+       (instantiate_type): Tweak pointer-to-member handling.
+       (get_primary_binfo): Remove incorrect assertion.
+       * config-lang.in (gtfiles): Add parser.c, remove parse.c.
+       * cp-tree.h (DEFARG_TOKENS): New macro.
+       (default_arg): New structure.
+       (cp_tree_node_structure_enum): Add TS_CP_DEFAULT_ARG.
+       (lang_tree_node): Add default_arg.
+       (cp_tree_index): Add CPTI_TYPE_INFO_REF_TYPE.
+       (type_info_ref_type): New macro.
+       (saved_scope): Make processing_explicit_instantiation a boolean.
+       (check_access): New field.
+       (unparsed_text): Remove.
+       (language_function): Remove unparsed_inlines.
+       (error_operand_p): New macro.
+       (lang_decl): Adjust pending_inline_info.
+       (DEFARG_POINTER): Remove.
+       (tag_types): Add typenames.
+       (lookup_ualified_name): Declare.
+       (lookup_name_real): Likewise.
+       (shadow_tag): Adjust prototype.
+       (get_scope_of_declarator): Declare it.
+       (process_next_inline): Remove it.
+       (check_for_missing_semicolon): Likewise.
+       (maybe_get_template_decl_from_type_decl): Declare it.
+       (finish_label_stmt): Adjust prototype.
+       (finish_non_static_data_meber): Declare it.
+       (finish_pseudo_destructor_call_expr): Rename to ...
+       (finish_pseudo_destructor_expr): ... this.
+       (finish_compound_literal): Declare it.
+       (begin_inline_definitions): Remove it.
+       (init_spew): Remove.
+       (peekyylex): Likewise.
+       (arbitrate_lookup): Likewise.
+       (frob_opname): Likewise.
+       (maybe_snarf_defarg): Likewise.
+       (add_defarg_fn): Likewise.
+       (do_pending_defargs): Likewise.
+       (done_pending_defargs): Likewise.
+       (unprocessed_defarg_fn): Likewise.
+       (replace_defarg): Likewise.
+       (end_input): Likewise.
+       (get_overloaded_fn): Likewise.
+       * cvt.c (convert_to_reference): Improve error handling.
+       * decl.c (lookup_name_real): Do not declare it static.
+       (maybe_push_to_top_level): Set check_access.
+       (identifier_type_value): Adjust call to lookup_name_real.
+       (lookup_qualified_name): New method.
+       (lookup_name_real): Remove special-case parsing code.
+       (lookup_name-nonclass): Adjust call to lookup_name_real.
+       (lookup_name_namespace_only): Likewise.
+       (lookup_name): Likewise.
+       (check_tag_decl): Return the type declared.
+       (shadow_tag): Likewise.
+       (register_dtor_fn): Tweak check_access.
+       (grokfndecl): Use constructor_name_p.
+       (get_scope_of_declarator): New function.
+       (grokdeclarator): Obscure tweaks for slightly different declarator
+       representations.
+       (start_method): Return error_mark_node to indicate failure.
+       (cp_tree_node_structure_enum): Use TS_CP_DEFAULT_ARG for DEFAULT_ARGs. 
+       * decl2.c (constructor_name_full): Simplify.
+       (constructor_name): Use it.
+       (build_expr_from_tree): Adjust for changes to do new parser.
+       (push_scope): Improve robustness.
+       (validate_nonmember_using_decl): Process declarations, not names.
+       (do_class_using_decl): Likewise.
+       (handle_class_head): Do not mess with CLASSTYPE_DECLARED_CLASS
+       here.
+       * error.c (dump_expr): Handle IDENTIFIER_NODEs and BASELINKs.
+       * expr.c (cxx_expand_expr): Handle BASELINKs.
+       * init.c (member_init_ok_or_else): Issue more errors.
+       (build_offset_ref): Tweak handling of FUNCTION_DECLs.
+       * lex.c: Do not include parse.h.
+       (yypring): Do not declare.
+       (yylval): Likewise.
+       (make_reference_declarator): Remove error-generating code.
+       (rid_to_yy): Remove.
+       (cxx_init): Do not call init_spew.
+       (yypring): Remove.
+       (check_for_missing_semicolon): Remove.
+       * lex.h (got_scope): Remove.
+       (got_object): Remove.
+       * method.c (hack_identifier): Use finish_non_static_data_member.
+       (implicitly_declare_fn): Adjust use of constructor_name.
+       * parser.c: New file.
+       * pt.c (parse.h): Do not include it.
+       (maybe_get_template_decl_from_template): Do not declare it.
+       (finish_member_template_decl): Tweak.
+       (begin_explicit_instantiation): Adjust for
+       processing_explicit_instantiation being boolean.
+       (end_explicit_instantiation): Likewise.
+       (maybe_process_partial_specialization): Tighten specialization
+       test.
+       (retrieve_local_specialization): Adjust ue of hash table.
+       (eq_local_specializations): New function.
+       (register_local_specialization): Likewise.
+       (push_template_decl_real): Remove unnecessary test.
+       (maybe_get_template_decl_from_type_decl): Don't make it static.
+       (for_each_template_parm_r): Handle TYPEOF_TYPE.
+       (tsubst_copy): Use retrieive_local_specialization to handle
+       PARM_DECL.  Adjust handling of CONST_DECLs.  Handle BASELINKs.
+       Handle COMPONENT_REFs with pseudo-destructor-expressions.
+       Simplify handling of CALL_EXPR and METHOD_CALL_EXPR.
+       (tsubst_expr): Pass decls, not names, to do_local_using_decl.
+       (unify): Tweak handling of CONST_DECLs.
+       (regenerate_decl_from_template): Use push_nested_class.
+       (template_for_substitution): New funciton.
+       (instantiate_decl): Use it.  Register parameters as local
+       specializations.
+       * rtti.c (init_rtti_processing): Set type_info_ref_type.
+       (build_typeid): Use it.
+       (get_typeid): Likeise.
+       * search.c (accessible_p): Use check_access, not
+       flag_access_control.
+       (adjust_result_of_qualified_name_lookup): Pay attention to the
+       context_class.
+       * semantics.c (finish_asm_stmt): Adjust error handling.
+       (finish_label_stmt): Return the statement.
+       (finish_non_static_data_member): New function.
+       (finish_class_expr): Handle BASELINKs.
+       (finish_call_expr): Handle PSEUDO_DTOR_EXPR.
+       (finish_object_call_expr): Simplify handling during templates.
+       (finish_pseudo_destructor_call_expr): Rename to ...
+       (finish_pseudo_dtor_expr): ... this.
+       (finish_compound_literal): New function.
+       (begin_inline_definitions): Remove.
+       (finish_sizeof): Remove special template handling.
+       * spew.c: Do not include parse.h.
+       * tree.c (get_overloaded_fn): Remove.
+       * typeck.c (build_class_member_access_expr): Handle
+       PSEUDO_DTOR_EXPR.  Adjust handling of static member functions.
+       (lookup_destructor): New function.
+       (finish_class_member_access_expr): Use it.
+       (convert_arguments): Simplify.
+       (build_unary_op): Handle BASELINKs.
+       
 2002-12-26  Nathan Sidwell  <nathan@codesourcery.com>
 
        PR c++/4803
index 6c7a6753165fa3de7aa922747d49795329f72621..294ee52a3a07242e66f88693d21015ac8cf04318 100644 (file)
@@ -63,7 +63,7 @@ g++spec.o: $(srcdir)/cp/g++spec.c $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) $(CON
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \
                $(INCLUDES) $(srcdir)/cp/g++spec.c)
 
-po-generated: $(srcdir)/cp/parse.c
+po-generated:
 
 # Create the compiler driver for g++.
 GXX_OBJS = gcc.o g++spec.o intl.o prefix.o version.o 
@@ -83,8 +83,8 @@ CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \
 
 # Language-specific object files.
 CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
- cp/class.o cp/decl2.o cp/error.o cp/lex.o cp/parse.o cp/ptree.o cp/rtti.o \
- cp/spew.o cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
+ cp/class.o cp/decl2.o cp/error.o cp/lex.o cp/parser.o cp/ptree.o cp/rtti.o \
+ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o \
  cp/optimize.o cp/mangle.o cp/cp-lang.o
 
@@ -101,21 +101,8 @@ $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.gperf
        gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
                $(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
 
-$(srcdir)/cp/parse.h: $(srcdir)/cp/parse.c
-$(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
-       @echo "Expect 33 shift/reduce conflicts and 58 reduce/reduce conflicts."
-       cd $(srcdir)/cp && \
-       if $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y; then \
-         grep '^#define[       ]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
-         test -f p$$$$.output && mv -f p$$$$.output parse.output ; \
-         mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h ; \
-       else \
-         rm -f p$$$$.* ; \
-         false ; \
-       fi
-
 gtype-cp.h gt-cp-call.h gt-cp-decl.h gt-cp-decl2.h : s-gtype; @true
-gt-cp-parse.h gt-cp-pt.h gt-cp-repo.h gt-cp-spew.h : s-gtype; @true
+gt-cp-pt.h gt-cp-repo.h gt-cp-spew.h gt-cp-parser.h : s-gtype; @true
 gt-cp-tree.h : s-gtype; @true
 
 #\f
@@ -199,10 +186,8 @@ c++.mostlyclean:
 c++.clean:
 c++.distclean:
        -rm -f cp/config.status cp/Makefile
-       -rm -f $(srcdir)/cp/parse.output
 c++.extraclean:
 c++.maintainer-clean:
-       -rm -f $(srcdir)/cp/parse.c $(srcdir)/cp/parse.h
 #\f
 # Stage hooks:
 # The main makefile has already created stage?/cp.
@@ -222,9 +207,7 @@ CXX_TREE_H = $(TREE_H) cp/cp-tree.h c-common.h cp/cp-tree.def c-common.def \
        function.h varray.h $(SYSTEM_H) coretypes.h $(CONFIG_H) $(TARGET_H) \
        $(srcdir)/../include/hashtab.h $(srcdir)/../include/splay-tree.h
 
-cp/spew.o: cp/spew.c $(CXX_TREE_H) $(TM_H) $(srcdir)/cp/parse.h flags.h cp/lex.h \
-  toplev.h gt-cp-spew.h
-cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(srcdir)/cp/parse.h flags.h cp/lex.h \
+cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h \
   c-pragma.h toplev.h output.h mbchar.h $(GGC_H) input.h diagnostic.h \
   cp/operators.def $(TM_P_H)
 cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) toplev.h langhooks.h \
@@ -257,7 +240,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) except.h toplev.
   cp/cfns.h $(EXPR_H) libfuncs.h tree-inline.h
 cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \
   except.h $(TM_P_H)
-cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h $(srcdir)/cp/parse.h cp/lex.h \
+cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/lex.h \
   toplev.h $(GGC_H) $(RTL_H) except.h tree-inline.h gt-cp-pt.h
 cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) toplev.h diagnostic.h flags.h real.h \
   $(LANGHOOKS_DEF_H)
@@ -271,17 +254,13 @@ cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config
   input.h $(PARAMS_H) debug.h tree-inline.h
 cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h real.h
 
-cp/parse.o: cp/parse.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h except.h output.h \
-       cp/decl.h toplev.h $(GGC_H) gt-cp-parse.h
-       $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
-               $(srcdir)/cp/parse.c $(OUTPUT_OPTION)
+cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) diagnostic.h gt-cp-parser.h output.h
 #\f
 # These exist for maintenance purposes.
 
 # Update the tags table.
 cp/TAGS: force
        cd $(srcdir)/cp ;                       \
-       etags --no-globals -l c `echo *.c | sed 's/parse.c//'` \
-         parse.y *.h ../*.c ../*.h;
+       etags --no-globals -l c *.c *.h ../*.c ../*.h;
 
 .PHONY: cp/TAGS
index 36720c60443a050cb210ad38f81c5386ed13df97..a94852cfac7367c2e48ad4e518560866d3ac7558 100644 (file)
@@ -1,3 +1,75 @@
+*** Changes in GCC 3.4:
+
+* The C++ parser in G++ has been rewritten from scratch.  As a result, G++ 
+  is considerably more compliant to the C++ standard.  As a result, it 
+  accepts more valid programs, and rejects more invalid programs.  
+
+  Many of the changes below are a consequence of the new parser.
+
+* Friend declarations that refer to template specializations are rejected
+  if the template has not already been declared.
+
+  For example:
+
+    template <typename T>
+    class C {
+      friend void f<>(C&);
+    };
+
+  is rejected; you must first declare `f' as a template:
+
+    template <typename T>
+    void f(T);
+
+* You must use "template <>" to introduce template specializations, as 
+  required by the standard.  For example:
+
+    template <typename T>
+    struct S;
+    
+    struct S<int> { };
+
+  is rejected; you must write:
+
+    template <> struct S<int> {};
+
+* You must now use the `typename' and `template' keywords to disambiguate
+  dependent names, as required by the C++ standard.
+
+* The "named return value" extension has been removed.
+
+* The "implicit typename" extension has been removed.
+
+* G++ used to accept code like this:
+
+    struct S {
+      int h();
+      void f(int i = g());
+      int g(int i = h());
+    };
+
+  This behavior is not mandated by the standard. 
+
+  Now G++ issues an error about this code.  To avoid the error, you must
+  move the declaration of `g' before the declaration of `f'.  The 
+  default arguments for `g' must be visible at the point where it is
+  called.
+
+* When -pedantic is used, G++ now issues errors about spurious semicolons;
+  for example:
+
+    namespace N {}; // Invalid semicolon.
+    void f() {}; // Invalid semicolon.
+  
+* G++ no longer accepts attributes for a declarator after the
+  initializer associated with that declarator.  For example:
+
+    X x(1) __attribute__((...));
+
+  is no longer accepted.  Instead, use:
+
+    X x __attribute__((...)) (1);
+
 *** Changes in GCC 3.3:
 
 * The "new X = 3" extension has been removed; you must now use "new X(3)".
index 919087059d83e13871b361011298755f279aad86..805e5b27e3decc83544055b441ee92b4100d93e2 100644 (file)
@@ -102,6 +102,7 @@ static tree convert_class_to_reference (tree, tree, tree);
 static tree direct_reference_binding (tree, tree);
 static bool promoted_arithmetic_type_p (tree);
 static tree conditional_conversion (tree, tree);
+static char *name_as_c_string (tree, tree, bool *);
 static tree call_builtin_trap (void);
 
 tree
@@ -221,13 +222,6 @@ build_scoped_method_call (tree exp, tree basetype, tree name, tree parms)
 
   if (processing_template_decl)
     {
-      if (TREE_CODE (name) == BIT_NOT_EXPR
-         && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
-       {
-         tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
-         if (type)
-           name = build_min_nt (BIT_NOT_EXPR, type);
-       }
       name = build_min_nt (SCOPE_REF, basetype, name);
       return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
     }
@@ -477,24 +471,7 @@ build_method_call (tree instance, tree name, tree parms,
     return error_mark_node;
 
   if (processing_template_decl)
-    {
-      /* We need to process template parm names here so that tsubst catches
-        them properly.  Other type names can wait.  */
-      if (TREE_CODE (name) == BIT_NOT_EXPR)
-       {
-         tree type = NULL_TREE;
-
-         if (TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
-           type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
-         else if (TREE_CODE (TREE_OPERAND (name, 0)) == TYPE_DECL)
-           type = TREE_TYPE (TREE_OPERAND (name, 0));
-
-         if (type && TREE_CODE (type) == TEMPLATE_TYPE_PARM)
-           name = build_min_nt (BIT_NOT_EXPR, type);
-       }
-
-      return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
-    }
+    return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
 
   if (TREE_CODE (instance) == OFFSET_REF)
     instance = resolve_offset_ref (instance);
@@ -2685,8 +2662,8 @@ resolve_args (tree args)
   return args;
 }
 
-/* Return an expression for a call to FN (a namespace-scope function)
-   with the ARGS.  */
+/* Return an expression for a call to FN (a namespace-scope function,
+   or a static member function) with the ARGS.  */
       
 tree
 build_new_function_call (tree fn, tree args)
@@ -2726,18 +2703,21 @@ build_new_function_call (tree fn, tree args)
        {
          tree t = OVL_CURRENT (t1);
 
+         my_friendly_assert (!DECL_FUNCTION_MEMBER_P (t), 20020913);
+
          if (TREE_CODE (t) == TEMPLATE_DECL)
            {
              templates = tree_cons (NULL_TREE, t, templates);
              candidates = add_template_candidate
                (candidates, t, NULL_TREE, explicit_targs, args, 
-                NULL_TREE,
-                /*access_path=*/NULL_TREE, /*conversion_path=*/NULL_TREE,
+                NULL_TREE, /*access_path=*/NULL_TREE, 
+                /*conversion_path=*/NULL_TREE,
                 LOOKUP_NORMAL, DEDUCE_CALL);  
            }
          else if (! template_only)
            candidates = add_function_candidate
-             (candidates, t, NULL_TREE, args, /*access_path=*/NULL_TREE, 
+             (candidates, t, NULL_TREE, args, 
+              /*access_path=*/NULL_TREE,
               /*conversion_path=*/NULL_TREE, LOOKUP_NORMAL);
        }
 
@@ -3318,9 +3298,9 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
   tree conv;
   bool viable_candidates;
 
-  if (arg1 == error_mark_node
-      || arg2 == error_mark_node
-      || arg3 == error_mark_node)
+  if (error_operand_p (arg1) 
+      || error_operand_p (arg2) 
+      || error_operand_p (arg3))
     return error_mark_node;
 
   /* This can happen if a template takes all non-type parameters, e.g.
@@ -4186,24 +4166,14 @@ cxx_type_promotes_to (tree type)
 tree
 convert_default_arg (tree type, tree arg, tree fn, int parmnum)
 {
+  /* If the ARG is an unparsed default argument expression, the
+     conversion cannot be performed.  */
   if (TREE_CODE (arg) == DEFAULT_ARG)
     {
-      /* When processing the default args for a class, we can find that
-         there is an ordering constraint, and we call a function who's
-         default args have not yet been converted. For instance,
-          class A {
-              A (int = 0);
-              void Foo (A const & = A ());
-          };
-         We must process A::A before A::Foo's default arg can be converted.
-         Remember the dependent function, so do_pending_defargs can retry,
-         and check loops.  */
-      unprocessed_defarg_fn (fn);
-      
-      /* Don't return error_mark node, as we won't be able to distinguish
-         genuine errors from this case, and that would lead to repeated
-         diagnostics.  Just make something of the right type.  */
-      return build1 (NOP_EXPR, type, integer_zero_node);
+      error ("the default argument for parameter %d of `%D' has "
+            "not yet been parsed",
+            parmnum, fn);
+      return error_mark_node;
     }
 
   if (fn && DECL_TEMPLATE_INFO (fn))
@@ -4685,6 +4655,42 @@ build_special_member_call (tree instance, tree name, tree args,
   return build_new_method_call (instance, fns, args, binfo, flags);
 }
 
+/* Return the NAME, as a C string.  The NAME indicates a function that
+   is a member of TYPE.  *FREE_P is set to true if the caller must
+   free the memory returned.  
+
+   Rather than go through all of this, we should simply set the names
+   of constructors and destructors appropriately, and dispense with
+   ctor_identifier, dtor_identifier, etc.  */
+
+static char *
+name_as_c_string (tree name, tree type, bool *free_p)
+{
+  char *pretty_name;
+
+  /* Assume that we will not allocate memory.  */
+  *free_p = false;
+  /* Constructors and destructors are special.  */
+  if (IDENTIFIER_CTOR_OR_DTOR_P (name))
+    {
+      pretty_name 
+       = (char *) IDENTIFIER_POINTER (constructor_name (type));
+      /* For a destructor, add the '~'.  */
+      if (name == complete_dtor_identifier
+         || name == base_dtor_identifier
+         || name == deleting_dtor_identifier)
+       {
+         pretty_name = concat ("~", pretty_name, NULL);
+         /* Remember that we need to free the memory allocated.  */
+         *free_p = true;
+       }
+    }
+  else
+    pretty_name = (char *) IDENTIFIER_POINTER (name);
+
+  return pretty_name;
+}
+
 /* Build a call to "INSTANCE.FN (ARGS)".  */
 
 tree
@@ -4697,15 +4703,18 @@ build_new_method_call (tree instance, tree fns, tree args,
   tree access_binfo;
   tree optype;
   tree mem_args = NULL_TREE, instance_ptr;
-  tree name, pretty_name;
+  tree name;
   tree user_args;
   tree templates = NULL_TREE;
   tree call;
+  tree fn;
+  tree class_type;
   int template_only = 0;
 
   my_friendly_assert (instance != NULL_TREE, 20020729);
 
-  if (instance == error_mark_node || fns == error_mark_node 
+  if (error_operand_p (instance) 
+      || error_operand_p (fns)
       || args == error_mark_node)
     return error_mark_node;
 
@@ -4759,7 +4768,8 @@ build_new_method_call (tree instance, tree fns, tree args,
       return error_mark_node;
     }
 
-  name = DECL_NAME (get_first_fn (fns));
+  fn = get_first_fn (fns);
+  name = DECL_NAME (fn);
 
   if (IDENTIFIER_CTOR_OR_DTOR_P (name))
     {
@@ -4768,61 +4778,56 @@ build_new_method_call (tree instance, tree fns, tree args,
       my_friendly_assert (name != ctor_identifier, 20000408);
       /* Similarly for destructors.  */
       my_friendly_assert (name != dtor_identifier, 20000408);
-      
-      if (name == complete_ctor_identifier
-         || name == base_ctor_identifier)
-       pretty_name = constructor_name (basetype);
-      else
-       pretty_name = dtor_identifier;
     }
-  else
-    pretty_name = name;
 
-  if (fns)
+  /* It's OK to call destructors on cv-qualified objects.  Therefore,
+     convert the INSTANCE_PTR to the unqualified type, if necessary.  */
+  if (DECL_DESTRUCTOR_P (fn))
     {
-      tree fn;
-      tree class_type = (conversion_path 
-                        ? BINFO_TYPE (conversion_path)
-                        : NULL_TREE);
+      tree type = build_pointer_type (basetype);
+      if (!same_type_p (type, TREE_TYPE (instance_ptr)))
+       instance_ptr = build1 (NOP_EXPR, type, instance_ptr);
+    }
 
-      mem_args = tree_cons (NULL_TREE, instance_ptr, args);
-      for (fn = fns; fn; fn = OVL_NEXT (fn))
-       {
-         tree t = OVL_CURRENT (fn);
-         tree this_arglist;
+  class_type = (conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE);
+  mem_args = tree_cons (NULL_TREE, instance_ptr, args);
 
-         /* We can end up here for copy-init of same or base class.  */
-         if ((flags & LOOKUP_ONLYCONVERTING)
-             && DECL_NONCONVERTING_P (t))
-           continue;
+  for (fn = fns; fn; fn = OVL_NEXT (fn))
+    {
+      tree t = OVL_CURRENT (fn);
+      tree this_arglist;
 
-         if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t))
-           this_arglist = mem_args;
-         else
-           this_arglist = args;
+      /* We can end up here for copy-init of same or base class.  */
+      if ((flags & LOOKUP_ONLYCONVERTING)
+         && DECL_NONCONVERTING_P (t))
+       continue;
 
-         if (TREE_CODE (t) == TEMPLATE_DECL)
-           {
-             /* A member template.  */
-             templates = tree_cons (NULL_TREE, t, templates);
-             candidates = 
-               add_template_candidate (candidates, t, 
-                                       class_type,
-                                       explicit_targs,
-                                       this_arglist, optype,
-                                       access_binfo, 
-                                       conversion_path,
-                                       flags,
-                                       DEDUCE_CALL);
-           }
-         else if (! template_only)
-           candidates = add_function_candidate (candidates, t, 
-                                                class_type,
-                                                this_arglist,
-                                                access_binfo,
-                                                conversion_path,
-                                                flags);
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t))
+       this_arglist = mem_args;
+      else
+       this_arglist = args;
+
+      if (TREE_CODE (t) == TEMPLATE_DECL)
+       {
+         /* A member template.  */
+         templates = tree_cons (NULL_TREE, t, templates);
+         candidates = 
+           add_template_candidate (candidates, t, 
+                                   class_type,
+                                   explicit_targs,
+                                   this_arglist, optype,
+                                   access_binfo, 
+                                   conversion_path,
+                                   flags,
+                                   DEDUCE_CALL);
        }
+      else if (! template_only)
+       candidates = add_function_candidate (candidates, t, 
+                                            class_type,
+                                            this_arglist,
+                                            access_binfo,
+                                            conversion_path,
+                                            flags);
     }
 
   if (! any_viable (candidates))
@@ -4833,9 +4838,17 @@ build_new_method_call (tree instance, tree fns, tree args,
       if (!COMPLETE_TYPE_P (basetype))
        cxx_incomplete_type_error (instance_ptr, basetype);
       else
-       error ("no matching function for call to `%T::%D(%A)%#V'",
-              basetype, pretty_name, user_args,
-              TREE_TYPE (TREE_TYPE (instance_ptr)));
+       {
+         char *pretty_name;
+         bool free_p;
+
+         pretty_name = name_as_c_string (name, basetype, &free_p);
+         error ("no matching function for call to `%T::%s(%A)%#V'",
+                basetype, pretty_name, user_args,
+                TREE_TYPE (TREE_TYPE (instance_ptr)));
+         if (free_p)
+           free (pretty_name);
+       }
       print_z_candidates (candidates);
       return error_mark_node;
     }
@@ -4844,9 +4857,15 @@ build_new_method_call (tree instance, tree fns, tree args,
 
   if (cand == 0)
     {
+      char *pretty_name;
+      bool free_p;
+
+      pretty_name = name_as_c_string (name, basetype, &free_p);
       error ("call of overloaded `%D(%A)' is ambiguous", pretty_name,
-               user_args);
+            user_args);
       print_z_candidates (candidates);
+      if (free_p)
+       free (pretty_name);
       return error_mark_node;
     }
 
@@ -5745,7 +5764,7 @@ perform_implicit_conversion (tree type, tree expr)
 {
   tree conv;
   
-  if (expr == error_mark_node)
+  if (error_operand_p (expr))
     return error_mark_node;
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
                              LOOKUP_NORMAL);
index bf75d9de4bc6fe68b98ec6a4b7e4f5066ac53fd5..32f49a7bb116cb43baf506c67e2c9180613c5bde 100644 (file)
@@ -2739,7 +2739,7 @@ finish_struct_anon (t)
                      || TYPE_ANONYMOUS_P (TREE_TYPE (elt))))
                continue;
 
-             if (DECL_NAME (elt) == constructor_name (t))
+             if (constructor_name_p (DECL_NAME (elt), t))
                cp_pedwarn_at ("ISO C++ forbids member `%D' with same name as enclosing class",
                               elt);
 
@@ -3341,8 +3341,7 @@ check_field_decls (tree t, tree *access_decls,
       /* Core issue 80: A nonstatic data member is required to have a
         different name from the class iff the class has a
         user-defined constructor.  */
-      if (DECL_NAME (x) == constructor_name (t)
-         && TYPE_HAS_CONSTRUCTOR (t))
+      if (constructor_name_p (x, t) && TYPE_HAS_CONSTRUCTOR (t))
        cp_pedwarn_at ("field `%#D' with same name as class", x);
 
       /* We set DECL_C_BIT_FIELD in grokbitfield.
@@ -5642,15 +5641,8 @@ init_class_processing ()
   ridpointers[(int) RID_PROTECTED] = access_protected_node;
 }
 
-/* Set current scope to NAME. CODE tells us if this is a
-   STRUCT, UNION, or ENUM environment.
-
-   NAME may end up being NULL_TREE if this is an anonymous or
-   late-bound struct (as in "struct { ... } foo;")  */
-
-/* Set global variables CURRENT_CLASS_NAME and CURRENT_CLASS_TYPE to
-   appropriate values, found by looking up the type definition of
-   NAME (as a CODE).
+/* Set global variables CURRENT_CLASS_NAME and CURRENT_CLASS_TYPE as
+   appropriate for TYPE.
 
    If MODIFY is 1, we set IDENTIFIER_CLASS_VALUE's of names
    which can be seen locally to the class.  They are shadowed by
@@ -5860,7 +5852,7 @@ push_nested_class (type, modify)
   pushclass (type, modify);
 }
 
-/* Undoes a push_nested_class call.  MODIFY is passed on to popclass.  */
+/* Undoes a push_nested_class call.  */
 
 void
 pop_nested_class ()
@@ -6024,9 +6016,9 @@ cannot resolve overloaded function `%D' based on conversion to type `%T'",
     {
       tree fns;
 
-      for (fns = overload; fns; fns = OVL_CHAIN (fns))
+      for (fns = overload; fns; fns = OVL_NEXT (fns))
        {
-         tree fn = OVL_FUNCTION (fns);
+         tree fn = OVL_CURRENT (fns);
          tree fntype;
 
          if (TREE_CODE (fn) == TEMPLATE_DECL)
@@ -6073,9 +6065,9 @@ cannot resolve overloaded function `%D' based on conversion to type `%T'",
       if (TREE_CODE (target_fn_type) == METHOD_TYPE)
        target_arg_types = TREE_CHAIN (target_arg_types);
          
-      for (fns = overload; fns; fns = OVL_CHAIN (fns))
+      for (fns = overload; fns; fns = OVL_NEXT (fns))
        {
-         tree fn = OVL_FUNCTION (fns);
+         tree fn = OVL_CURRENT (fns);
          tree instantiation;
          tree instantiation_type;
          tree targs;
@@ -6235,10 +6227,19 @@ instantiate_type (lhstype, rhs, flags)
     {
       if (comptypes (lhstype, TREE_TYPE (rhs), strict))
        return rhs;
-      if (complain)
-       error ("argument of type `%T' does not match `%T'",
-                 TREE_TYPE (rhs), lhstype);
-      return error_mark_node;
+      if (flag_ms_extensions 
+         && TYPE_PTRMEMFUNC_P (lhstype)
+         && !TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+       /* Microsoft allows `A::f' to be resolved to a
+          pointer-to-member.  */
+       ;
+      else
+       {
+         if (complain)
+           error ("argument of type `%T' does not match `%T'",
+                  TREE_TYPE (rhs), lhstype);
+         return error_mark_node;
+       }
     }
 
   if (TREE_CODE (rhs) == BASELINK)
@@ -6314,6 +6315,7 @@ instantiate_type (lhstype, rhs, flags)
       }
 
     case OVERLOAD:
+    case FUNCTION_DECL:
       return 
        resolve_address_of_overloaded_function (lhstype, 
                                                rhs,
@@ -6771,10 +6773,8 @@ get_primary_binfo (binfo)
 
   if (TREE_CHAIN (virtuals))
     {
-      /* We found more than one instance of the base. We must make
-         sure that, if one is the canonical one, it is the first one
-         we found. As the chain is in reverse dfs order, that means
-         the last on the list.  */
+      /* We found more than one instance of the base.  If one is the
+        canonical one, choose that one.  */
       tree complete_binfo;
       tree canonical;
       
@@ -6790,12 +6790,7 @@ get_primary_binfo (binfo)
          result = TREE_VALUE (virtuals);
 
          if (canonical == result)
-           {
-             /* This is the unshared instance. Make sure it was the
-                first one found.  */
-             my_friendly_assert (!TREE_CHAIN (virtuals), 20010612);
-             break;
-           }
+           break;
        }
     }
   else
index eeebb1aac5753508b5b74d38f8c8fd8e4bb63290..73617f576edff550595e00c413d3f2473f4f0afb 100644 (file)
@@ -34,4 +34,4 @@ stagestuff="g++\$(exeext) g++-cross\$(exeext) cc1plus\$(exeext)"
 
 target_libs="${libstdcxx_version} target-gperf"
 
-gtfiles="\$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/lex.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/parse.y \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/spew.c \$(srcdir)/cp/tree.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c"
+gtfiles="\$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/lex.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c"
index b805f976419d73f7a3372ac156eae0866e1c562e..5ffc6176b74fd916fc43b364cef9d9e4236250b4 100644 (file)
@@ -501,6 +501,17 @@ struct tree_srcloc GTY(())
 #define C_SET_EXP_ORIGINAL_CODE(EXP, CODE) \
   (TREE_COMPLEXITY (EXP) = (int)(CODE))
 
+/* The tokens stored in the default argument.  */
+
+#define DEFARG_TOKENS(NODE) \
+  (((struct tree_default_arg *)DEFAULT_ARG_CHECK (NODE))->tokens)
+
+struct tree_default_arg GTY (())
+{
+  struct tree_common common;
+  struct cp_token_cache *tokens;
+};
+
 enum cp_tree_node_structure_enum {
   TS_CP_COMMON,
   TS_CP_GENERIC,
@@ -511,6 +522,7 @@ enum cp_tree_node_structure_enum {
   TS_CP_OVERLOAD,
   TS_CP_WRAPPER,
   TS_CP_SRCLOC,
+  TS_CP_DEFAULT_ARG,
   LAST_TS_CP_ENUM
 };
 
@@ -527,6 +539,7 @@ union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"),
   struct tree_overload GTY ((tag ("TS_CP_OVERLOAD"))) overload;
   struct tree_wrapper GTY ((tag ("TS_CP_WRAPPER"))) wrapper;
   struct tree_srcloc GTY ((tag ("TS_CP_SRCLOC"))) srcloc;
+  struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg;
   struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
 };
 
@@ -572,6 +585,7 @@ enum cp_tree_index
     CPTI_ABI,
     CPTI_TYPE_INFO_TYPE,
     CPTI_TYPE_INFO_PTR_TYPE,
+    CPTI_TYPE_INFO_REF_TYPE,
     CPTI_ABORT_FNDECL,
     CPTI_GLOBAL_DELETE_FNDECL,
     CPTI_AGGR_TAG,
@@ -661,6 +675,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define abi_node                        cp_global_trees[CPTI_ABI]
 #define type_info_type_node            cp_global_trees[CPTI_TYPE_INFO_TYPE]
 #define type_info_ptr_type             cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE]
+#define type_info_ref_type              cp_global_trees[CPTI_TYPE_INFO_REF_TYPE]
 #define abort_fndecl                   cp_global_trees[CPTI_ABORT_FNDECL]
 #define global_delete_fndecl           cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
 #define current_aggr                   cp_global_trees[CPTI_AGGR_TAG]
@@ -772,8 +787,9 @@ struct saved_scope GTY(())
 
   HOST_WIDE_INT x_processing_template_decl;
   int x_processing_specialization;
-  int x_processing_explicit_instantiation;
+  bool x_processing_explicit_instantiation;
   int need_pop_function_context;
+  int check_access;
 
   struct stmt_tree_s x_stmt_tree;
 
@@ -837,8 +853,6 @@ struct saved_scope GTY(())
 
 extern GTY(()) struct saved_scope *scope_chain;
 
-struct unparsed_text;
-
 /* Global state pertinent to the current function.  */
 
 struct language_function GTY(())
@@ -865,7 +879,6 @@ struct language_function GTY(())
   varray_type x_local_names;
 
   const char *cannot_inline;
-  struct unparsed_text *unparsed_inlines;
 };
 
 /* The current C++-specific per-function global variables.  */
@@ -943,6 +956,12 @@ extern GTY(()) tree global_namespace;
 #define ansi_assopname(CODE) \
   (assignment_operator_name_info[(int) (CODE)].identifier)
 
+/* True if NODE is an erroneous expression.  */
+
+#define error_operand_p(NODE)                                  \
+  ((NODE) == error_mark_node                                   \
+   || ((NODE) && TREE_TYPE ((NODE)) == error_mark_node))
+
 /* INTERFACE_ONLY nonzero means that we are in an "interface"
    section of the compiler.  INTERFACE_UNKNOWN nonzero means
    we cannot trust the value of INTERFACE_ONLY.  If INTERFACE_UNKNOWN
@@ -1799,7 +1818,7 @@ struct lang_decl GTY(())
        union lang_decl_u3
        {
          tree GTY ((tag ("0"))) sorted_fields;
-         struct unparsed_text * GTY ((tag ("2"))) pending_inline_info;
+         struct cp_token_cache * GTY ((tag ("2"))) pending_inline_info;
          struct language_function * GTY ((tag ("1"))) 
               saved_language_function;
        } GTY ((desc ("%1.u3sel + %1.pending_inline_p"))) u;
@@ -1822,8 +1841,6 @@ struct lang_decl GTY(())
 
 #endif /* ENABLE_TREE_CHECKING */
 
-#define DEFARG_POINTER(NODE) (DEFAULT_ARG_CHECK (NODE)->identifier.id.str)
-
 /* DECL_NEEDED_P holds of a declaration when we need to emit its
    definition.  This is true when the back-end tells us that
    the symbol has been referenced in the generated code.  If, however,
@@ -2998,7 +3015,14 @@ struct lang_decl GTY(())
   (TREE_TYPE (NODE))
 
 /* An enumeration of the kind of tags that C++ accepts.  */
-enum tag_types { record_type, class_type, union_type, enum_type };
+enum tag_types { 
+  none_type = 0, /* Not a tag type.  */
+  record_type,   /* "struct" types.  */
+  class_type,    /* "class" types.  */
+  union_type,    /* "union" types.  */
+  enum_type,     /* "enum" types.  */
+  typename_type  /* "typename" types.  */
+};
 
 /* The various kinds of lvalues we distinguish.  */
 typedef enum cp_lvalue_kind {
@@ -3703,10 +3727,12 @@ extern tree make_typename_type                  PARAMS ((tree, tree, tsubst_flags_t));
 extern tree make_unbound_class_template                PARAMS ((tree, tree, tsubst_flags_t));
 extern tree lookup_name_nonclass               PARAMS ((tree));
 extern tree lookup_function_nonclass            PARAMS ((tree, tree));
+extern tree lookup_qualified_name               (tree, tree, bool, int);
 extern tree lookup_name                                PARAMS ((tree, int));
 extern tree lookup_name_current_level          PARAMS ((tree));
 extern tree lookup_type_current_level          PARAMS ((tree));
 extern tree lookup_name_namespace_only          PARAMS ((tree));
+extern tree lookup_name_real                    (tree, int, int, int, int);
 extern void begin_only_namespace_names          PARAMS ((void));
 extern void end_only_namespace_names            PARAMS ((void));
 extern tree namespace_ancestor                 PARAMS ((tree, tree));
@@ -3722,7 +3748,7 @@ extern tree push_void_library_fn          PARAMS ((tree, tree));
 extern tree push_throw_library_fn              PARAMS ((tree, tree));
 extern int init_type_desc                      PARAMS ((void));
 extern tree check_tag_decl                     PARAMS ((tree));
-extern void shadow_tag                         PARAMS ((tree));
+extern tree shadow_tag                         PARAMS ((tree));
 extern tree groktypename                       PARAMS ((tree));
 extern tree start_decl                         PARAMS ((tree, tree, int, tree, tree));
 extern void start_decl_1                       PARAMS ((tree));
@@ -3736,6 +3762,7 @@ extern tree build_ptrmem_type                   (tree, tree);
 /* the grokdeclarator prototype is in decl.h */
 extern int parmlist_is_exprlist                        PARAMS ((tree));
 extern int copy_fn_p                           PARAMS ((tree));
+extern tree get_scope_of_declarator             PARAMS ((tree));
 extern void grok_special_member_properties     PARAMS ((tree));
 extern int grok_ctor_properties                        PARAMS ((tree, tree));
 extern void grok_op_properties                 PARAMS ((tree, int));
@@ -3937,12 +3964,9 @@ extern tree make_call_declarator         PARAMS ((tree, tree, tree, tree));
 extern void set_quals_and_spec                 PARAMS ((tree, tree, tree));
 extern void print_parse_statistics             PARAMS ((void));
 extern void do_pending_inlines                 PARAMS ((void));
-extern void process_next_inline                        PARAMS ((struct unparsed_text *));
-
 extern void yyungetc                           PARAMS ((int, int));
 extern void snarf_method                       PARAMS ((tree));
 
-extern void check_for_missing_semicolon                PARAMS ((tree));
 extern void note_got_semicolon                 PARAMS ((tree));
 extern void note_list_got_semicolon            PARAMS ((tree));
 extern void do_pending_lang_change             PARAMS ((void));
@@ -4037,6 +4061,7 @@ extern tree get_mostly_instantiated_function_type PARAMS ((tree));
 extern int problematic_instantiation_changed    PARAMS ((void));
 extern void record_last_problematic_instantiation PARAMS ((void));
 extern tree current_instantiation               PARAMS ((void));
+extern tree maybe_get_template_decl_from_type_decl (tree);
 extern int processing_template_parmlist;
 
 /* in repo.c */
@@ -4154,10 +4179,11 @@ extern void finish_cleanup                      PARAMS ((tree, tree));
 extern tree begin_compound_stmt                 PARAMS ((int));
 extern tree finish_compound_stmt                PARAMS ((int, tree));
 extern tree finish_asm_stmt                     PARAMS ((tree, tree, tree, tree, tree));
-extern void finish_label_stmt                   PARAMS ((tree));
+extern tree finish_label_stmt                   PARAMS ((tree));
 extern void finish_label_decl                   PARAMS ((tree));
 extern void finish_subobject                    PARAMS ((tree));
 extern tree finish_parenthesized_expr           PARAMS ((tree));
+extern tree finish_non_static_data_member       PARAMS ((tree, tree));
 extern tree begin_stmt_expr                     PARAMS ((void));
 extern tree finish_stmt_expr                    PARAMS ((tree));
 extern tree finish_call_expr                    (tree, tree, bool);
@@ -4165,9 +4191,10 @@ extern tree finish_increment_expr               PARAMS ((tree, enum tree_code));
 extern tree finish_this_expr                    PARAMS ((void));
 extern tree finish_object_call_expr             PARAMS ((tree, tree, tree));
 extern tree finish_qualified_object_call_expr   PARAMS ((tree, tree, tree));
-extern tree finish_pseudo_destructor_call_expr  PARAMS ((tree, tree, tree));
+extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
 extern tree finish_unary_op_expr                PARAMS ((enum tree_code, tree));
 extern tree finish_id_expr                      PARAMS ((tree));
+extern tree finish_compound_literal             (tree, tree);
 extern tree finish_fname                        (tree);
 extern void save_type_access_control           PARAMS ((tree));
 extern void reset_type_access_control           PARAMS ((void));
@@ -4182,7 +4209,6 @@ extern tree finish_parmlist                     PARAMS ((tree, int));
 extern tree begin_class_definition              PARAMS ((tree));
 extern tree finish_class_definition             PARAMS ((tree, tree, int, int));
 extern void finish_default_args                 PARAMS ((void));
-extern void begin_inline_definitions            PARAMS ((void));
 extern tree finish_member_class_template        PARAMS ((tree));
 extern void finish_template_decl                PARAMS ((tree));
 extern tree finish_template_type                PARAMS ((tree, tree, int));
@@ -4208,19 +4234,6 @@ extern tree begin_global_stmt_expr              PARAMS ((void));
 extern tree finish_global_stmt_expr             PARAMS ((tree));
 extern tree check_template_template_default_arg (tree);
 
-/* in spew.c */
-extern void init_spew                          PARAMS ((void));
-extern int peekyylex                           PARAMS ((void));
-extern tree arbitrate_lookup                   PARAMS ((tree, tree, tree));
-extern tree frob_opname                         PARAMS ((tree));
-extern void maybe_snarf_defarg                 PARAMS ((void));
-extern void add_defarg_fn                      PARAMS ((tree));
-extern void do_pending_defargs                 PARAMS ((void));
-extern void done_pending_defargs               PARAMS ((void));
-extern void unprocessed_defarg_fn               PARAMS ((tree));
-extern void replace_defarg                     PARAMS ((tree, tree));
-extern void end_input                          PARAMS ((void));
-
 /* in tree.c */
 extern void lang_check_failed                  PARAMS ((const char *, int,
                                                         const char *));
@@ -4252,7 +4265,6 @@ extern tree make_binfo                            PARAMS ((tree, tree, tree, tree));
 extern tree reverse_path                       PARAMS ((tree));
 extern int count_functions                     PARAMS ((tree));
 extern int is_overloaded_fn                    PARAMS ((tree));
-extern tree get_overloaded_fn                   PARAMS ((tree));
 extern tree get_first_fn                       PARAMS ((tree));
 extern int bound_pmf_p                         PARAMS ((tree));
 extern tree ovl_cons                            PARAMS ((tree, tree));
index 2443505bd8ff896688570b59721930e4557f6c5b..50d4a2ae953cb972fe95f34bbb0f34863dbdf6ec 100644 (file)
@@ -484,20 +484,16 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
 
   if (TREE_CODE (type) == FUNCTION_TYPE 
       && TREE_TYPE (expr) == unknown_type_node)
-    {
-      expr = instantiate_type (type, expr, 
-                              (flags & LOOKUP_COMPLAIN)
-                              ? tf_error | tf_warning : tf_none);
-      if (expr == error_mark_node)
-       return error_mark_node;
-
-      intype = TREE_TYPE (expr);
-    }
+    expr = instantiate_type (type, expr, 
+                            (flags & LOOKUP_COMPLAIN)
+                            ? tf_error | tf_warning : tf_none);
   else
-    {
-      expr = convert_from_reference (expr);
-      intype = TREE_TYPE (expr);
-    }
+    expr = convert_from_reference (expr);
+
+  if (expr == error_mark_node)
+    return error_mark_node;
+
+  intype = TREE_TYPE (expr);
 
   my_friendly_assert (TREE_CODE (intype) != REFERENCE_TYPE, 364);
 
index 95680dd60fa10b919655d215d6c44cb2c15ee389..fd3fc00a8ce8dbe2e35c491fdffe0d5f2f5d0cfc 100644 (file)
@@ -69,7 +69,6 @@ static int ambi_op_p PARAMS ((enum tree_code));
 static int unary_op_p PARAMS ((enum tree_code));
 static tree store_bindings PARAMS ((tree, tree));
 static tree lookup_tag_reverse PARAMS ((tree, tree));
-static tree lookup_name_real PARAMS ((tree, int, int, int));
 static void push_local_name PARAMS ((tree));
 static void warn_extern_redeclared_static PARAMS ((tree, tree));
 static tree grok_reference_init PARAMS ((tree, tree, tree));
@@ -2428,6 +2427,7 @@ maybe_push_to_top_level (pseudo)
   s->need_pop_function_context = need_pop;
   s->function_decl = current_function_decl;
   s->last_parms = last_function_parms;
+  s->check_access = flag_access_control;
 
   scope_chain = s;
   current_function_decl = NULL_TREE;
@@ -2532,8 +2532,8 @@ identifier_type_value (id)
   if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node)
     return REAL_IDENTIFIER_TYPE_VALUE (id);
   /* Have to search for it. It must be on the global level, now.
-     Ask lookup_name not to return non-types.  */
-  id = lookup_name_real (id, 2, 1, 0);
+     Ask lookup_name not to return non-types. */
+  id = lookup_name_real (id, 2, 1, 0, LOOKUP_COMPLAIN);
   if (id)
     return TREE_TYPE (id);
   return NULL_TREE;
@@ -5980,6 +5980,32 @@ warn_about_implicit_typename_lookup (typename, binding)
     }
 }
 
+/* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL
+   or a class TYPE).  If IS_TYPE_P is TRUE, then ignore non-type
+   bindings.  
+
+   Returns a DECL (or OVERLOAD, or BASELINK) representing the
+   declaration found.  */
+
+tree
+lookup_qualified_name (tree scope, tree name, bool is_type_p, int flags)
+{
+  if (TREE_CODE (scope) == NAMESPACE_DECL)
+    {
+      tree val;
+
+      val = make_node (CPLUS_BINDING);
+      flags |= LOOKUP_COMPLAIN;
+      if (is_type_p)
+       flags |= LOOKUP_PREFER_TYPES;
+      if (!qualified_lookup_using_namespace (name, scope, val, flags))
+       return NULL_TREE;
+      return select_decl (val, flags);
+    }
+  else
+    return lookup_member (scope, name, 0, is_type_p);
+}
+
 /* Check to see whether or not DECL is a variable that would have been
    in scope under the ARM, but is not in scope under the ANSI/ISO
    standard.  If so, issue an error message.  If name lookup would
@@ -6047,112 +6073,58 @@ check_for_out_of_scope_variable (tree decl)
 
    If PREFER_TYPE is > 0, we prefer TYPE_DECLs or namespaces.
    If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces).
-   If PREFER_TYPE is -2, we're being called from yylex(). (UGLY)
    Otherwise we prefer non-TYPE_DECLs.
 
    If NONCLASS is nonzero, we don't look for the NAME in class scope,
    using IDENTIFIER_CLASS_VALUE.  */
 
-static tree
-lookup_name_real (name, prefer_type, nonclass, namespaces_only)
-     tree name;
-     int prefer_type, nonclass, namespaces_only;
+tree
+lookup_name_real (tree name, 
+                 int prefer_type, 
+                 int nonclass, 
+                 int namespaces_only,
+                 int flags)
 {
   tree t;
   tree val = NULL_TREE;
   int yylex = 0;
-  tree from_obj = NULL_TREE;
-  int flags;
   int val_is_implicit_typename = 0;
 
-  /* Hack: copy flag set by parser, if set.  */
-  if (only_namespace_names)
-    namespaces_only = 1;
-
-  if (prefer_type == -2)
+  /* Conversion operators are handled specially because ordinary
+     unqualified name lookup will not find template conversion
+     operators.  */
+  if (IDENTIFIER_TYPENAME_P (name)) 
     {
-      extern int looking_for_typename;
-      tree type = NULL_TREE;
-
-      yylex = 1;
-      prefer_type = looking_for_typename;
-
-      flags = lookup_flags (prefer_type, namespaces_only);
-      /* If the next thing is '<', class templates are types.  */
-      if (looking_for_template)
-        flags |= LOOKUP_TEMPLATES_EXPECTED;
-
-      if (got_scope)
-       type = got_scope;
-      else if (got_object != error_mark_node)
-       type = got_object;
+      struct cp_binding_level *level;
 
-      if (type)
+      for (level = current_binding_level; 
+          level && !level->namespace_p; 
+          level = level->level_chain)
        {
-         if (type == error_mark_node)
-           return error_mark_node;
-         if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type))
-           type = TREE_TYPE (type);
-
-         if (TYPE_P (type))
-           type = complete_type (type);
-
-         if (TREE_CODE (type) == VOID_TYPE)
-           type = global_namespace;
-         if (TREE_CODE (type) == NAMESPACE_DECL)
-           {
-             val = make_node (CPLUS_BINDING);
-             flags |= LOOKUP_COMPLAIN;
-             if (!qualified_lookup_using_namespace (name, type, val, flags))
-               return NULL_TREE;
-             val = select_decl (val, flags);
-           }
-         else if (! IS_AGGR_TYPE (type)
-                  || TREE_CODE (type) == TEMPLATE_TYPE_PARM
-                  || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
-                  || TREE_CODE (type) == TYPENAME_TYPE)
-           /* Someone else will give an error about this if needed.  */
-           val = NULL_TREE;
-         else if (type == current_class_type)
-           val = IDENTIFIER_CLASS_VALUE (name);
-         else
-           {
-             val = lookup_member (type, name, 0, prefer_type);
-             if (!uses_template_parms (type))
-               type_access_control (type, val);
-
-             /* Restore the containing TYPENAME_TYPE if we looked
-                through it before.  */
-             if (got_scope && got_scope != type
-                 && val && TREE_CODE (val) == TYPE_DECL
-                 && TREE_CODE (TREE_TYPE (val)) == TYPENAME_TYPE)
-               {
-                 val = TREE_TYPE (val);
-                 val = build_typename_type (got_scope, name,
-                                            TYPENAME_TYPE_FULLNAME (val),
-                                            TREE_TYPE (val));
-                 val = TYPE_STUB_DECL (val);
-               }
-           }
+         tree class_type;
+         tree operators;
+         
+         /* A conversion operator can only be declared in a class 
+            scope.  */
+         if (level->parm_flag != 2)
+           continue;
+         
+         /* Lookup the conversion operator in the class.  */
+         class_type = level->this_class;
+         operators = lookup_fnfields (class_type, name, /*protect=*/0);
+         if (operators)
+           return operators;
        }
-      else
-       val = NULL_TREE;
 
-      if (got_scope)
-       goto done;
-      else if (got_object && val)
-       {
-         from_obj = val;
-         val = NULL_TREE;
-       }
-    }
-  else
-    {
-      flags = lookup_flags (prefer_type, namespaces_only);
-      /* If we're not parsing, we need to complain.  */
-      flags |= LOOKUP_COMPLAIN;
+      return NULL_TREE;
     }
 
+  /* Hack: copy flag set by parser, if set. */
+  if (only_namespace_names)
+    namespaces_only = 1;
+
+  flags |= lookup_flags (prefer_type, namespaces_only);
+
   /* First, look in non-namespace scopes.  */
 
   if (current_class_type == NULL_TREE)
@@ -6175,11 +6147,6 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
       else
        binding = NULL_TREE;
 
-      /* Handle access control on types from enclosing or base classes.  */
-      if (binding && ! yylex
-         && BINDING_LEVEL (t) && BINDING_LEVEL (t)->parm_flag == 2)
-       type_access_control (BINDING_LEVEL (t)->this_class, binding);
-
       if (binding
          && (!val || !IMPLICIT_TYPENAME_TYPE_DECL_P (binding)))
        {
@@ -6205,36 +6172,12 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
        }
     }
 
- done:
   if (val)
     {
-      /* This should only warn about types used in qualified-ids.  */
-      if (from_obj && from_obj != val)
-       {
-         if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL
-             && TREE_CODE (val) == TYPE_DECL
-             && ! same_type_p (TREE_TYPE (from_obj), TREE_TYPE (val)))
-           pedwarn ("\
-lookup of `%D' in the scope of `%#T' (`%#D') \
-does not match lookup in the current scope (`%#D')",
-                       name, got_object, from_obj, val);
-
-         /* We don't change val to from_obj if got_object depends on
-            template parms because that breaks implicit typename for
-            destructor calls.  */
-         if (! uses_template_parms (got_object))
-           val = from_obj;
-       }
-
       /* If we have a single function from a using decl, pull it out.  */
       if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
        val = OVL_FUNCTION (val);
     }
-  else if (from_obj)
-    val = from_obj;
-
-  if (val && TREE_CODE (val) == ALIAS_DECL)
-    val = DECL_INITIAL (val);
 
   return val;
 }
@@ -6243,7 +6186,7 @@ tree
 lookup_name_nonclass (name)
      tree name;
 {
-  return lookup_name_real (name, 0, 1, 0);
+  return lookup_name_real (name, 0, 1, 0, LOOKUP_COMPLAIN);
 }
 
 tree
@@ -6259,7 +6202,7 @@ lookup_name_namespace_only (name)
      tree name;
 {
   /* type-or-namespace, nonclass, namespace_only */
-  return lookup_name_real (name, 1, 1, 1);
+  return lookup_name_real (name, 1, 1, 1, LOOKUP_COMPLAIN);
 }
 
 tree
@@ -6267,7 +6210,7 @@ lookup_name (name, prefer_type)
      tree name;
      int prefer_type;
 {
-  return lookup_name_real (name, prefer_type, 0, 0);
+  return lookup_name_real (name, prefer_type, 0, 0, LOOKUP_COMPLAIN);
 }
 
 /* Similar to `lookup_name' but look only in the innermost non-class
@@ -7062,9 +7005,9 @@ fixup_anonymous_aggr (t)
 }
 
 /* Make sure that a declaration with no declarator is well-formed, i.e.
-   just defines a tagged type or anonymous union.
+   just declares a tagged type or anonymous union.
 
-   Returns the type defined, if any.  */
+   Returns the type declared; or NULL_TREE if none.  */
 
 tree
 check_tag_decl (declspecs)
@@ -7075,11 +7018,16 @@ check_tag_decl (declspecs)
   int saw_typedef = 0;
   tree ob_modifier = NULL_TREE;
   register tree link;
-  register tree t = NULL_TREE;
+  /* If a class, struct, or enum type is declared by the DECLSPECS
+     (i.e, if a class-specifier, enum-specifier, or non-typename
+     elaborated-type-specifier appears in the DECLSPECS),
+     DECLARED_TYPE is set to the corresponding type.  */
+  tree declared_type = NULL_TREE;
+  bool error_p = false;
 
   for (link = declspecs; link; link = TREE_CHAIN (link))
     {
-      register tree value = TREE_VALUE (link);
+      tree value = TREE_VALUE (link);
 
       if (TYPE_P (value)
          || TREE_CODE (value) == TYPE_DECL
@@ -7101,7 +7049,7 @@ check_tag_decl (declspecs)
                  || TREE_CODE (value) == ENUMERAL_TYPE))
            {
              my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
-             t = value;
+             declared_type = value;
            }
        }
       else if (value == ridpointers[(int) RID_TYPEDEF])
@@ -7125,17 +7073,18 @@ check_tag_decl (declspecs)
               || value == ridpointers[(int) RID_EXPLICIT]
               || value == ridpointers[(int) RID_THREAD])
        ob_modifier = value;
+      else if (value == error_mark_node)
+       error_p = true;
     }
 
   if (found_type > 1)
     error ("multiple types in one declaration");
 
-  if (t == NULL_TREE && ! saw_friend)
+  if (declared_type == NULL_TREE && ! saw_friend && !error_p)
     pedwarn ("declaration does not declare anything");
-
   /* Check for an anonymous union.  */
-  else if (t && IS_AGGR_TYPE_CODE (TREE_CODE (t))
-          && TYPE_ANONYMOUS_P (t))
+  else if (declared_type && IS_AGGR_TYPE_CODE (TREE_CODE (declared_type))
+          && TYPE_ANONYMOUS_P (declared_type))
     {
       /* 7/3 In a simple-declaration, the optional init-declarator-list
          can be omitted only when declaring a class (clause 9) or
@@ -7159,9 +7108,10 @@ check_tag_decl (declspecs)
           return NULL_TREE;
         }
       /* Anonymous unions are objects, so they can have specifiers.  */;
-      SET_ANON_AGGR_TYPE_P (t);
+      SET_ANON_AGGR_TYPE_P (declared_type);
 
-      if (TREE_CODE (t) != UNION_TYPE && pedantic && ! in_system_header)
+      if (TREE_CODE (declared_type) != UNION_TYPE && pedantic 
+         && !in_system_header)
        pedwarn ("ISO C++ prohibits anonymous structs");
     }
 
@@ -7180,7 +7130,7 @@ check_tag_decl (declspecs)
                  ob_modifier);
     }
 
-  return t;
+  return declared_type;
 }
 
 /* Called when a declaration is seen that contains no names to declare.
@@ -7192,23 +7142,27 @@ check_tag_decl (declspecs)
    Otherwise, it is an error.
 
    C++: may have to grok the declspecs to learn about static,
-   complain for anonymous unions.  */
+   complain for anonymous unions.  
 
-void
+   Returns the TYPE declared -- or NULL_TREE if none.  */
+
+tree
 shadow_tag (declspecs)
      tree declspecs;
 {
   tree t = check_tag_decl (declspecs);
 
-  if (t)
-    maybe_process_partial_specialization (t);
+  if (!t)
+    return NULL_TREE;
+
+  maybe_process_partial_specialization (t);
 
   /* This is where the variables in an anonymous union are
      declared.  An anonymous union declaration looks like:
      union { ... } ;
      because there is no declarator after the union, the parser
      sends that declaration here.  */
-  if (t && ANON_AGGR_TYPE_P (t))
+  if (ANON_AGGR_TYPE_P (t))
     {
       fixup_anonymous_aggr (t);
 
@@ -7219,6 +7173,8 @@ shadow_tag (declspecs)
          finish_anon_union (decl);
        }
     }
+
+  return t;
 }
 \f
 /* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
@@ -7374,9 +7330,10 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
            {
              if (DECL_CONTEXT (field) != context)
                {
-                 pedwarn ("ISO C++ does not permit `%T::%D' to be defined as `%T::%D'",
-                             DECL_CONTEXT (field), DECL_NAME (decl),
-                             context, DECL_NAME (decl));
+                 if (!same_type_p (DECL_CONTEXT (field), context))
+                   pedwarn ("ISO C++ does not permit `%T::%D' to be defined as `%T::%D'",
+                            DECL_CONTEXT (field), DECL_NAME (decl),
+                            context, DECL_NAME (decl));
                  DECL_CONTEXT (decl) = DECL_CONTEXT (field);
                }
              /* Static data member are tricky; an in-class initialization
@@ -7529,9 +7486,6 @@ grok_reference_init (decl, type, init)
       return NULL_TREE;
     }
 
-  if (init == error_mark_node)
-    return NULL_TREE;
-
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
       error ("ISO C++ forbids use of initializer list to initialize reference `%D'", decl);
@@ -8800,7 +8754,6 @@ register_dtor_fn (decl)
   tree compound_stmt;
   tree args;
   tree fcall;
-
   int saved_flag_access_control;
 
   if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
@@ -8819,9 +8772,9 @@ register_dtor_fn (decl)
      will make the back-end think that nested functions are in use,
      which causes confusion.  */
   saved_flag_access_control = flag_access_control;
-  flag_access_control = 0;
+  scope_chain->check_access = flag_access_control = 0;
   fcall = build_cleanup (decl);
-  flag_access_control = saved_flag_access_control;
+  scope_chain->check_access = flag_access_control = saved_flag_access_control;
 
   /* Create the body of the anonymous function.  */
   compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
@@ -9333,9 +9286,6 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        }
     }
 
-  if (has_default_arg)
-    add_defarg_fn (decl);
-
   if (funcdef_flag)
     /* Make the init_value nonzero so pushdecl knows this is not
        tentative.  error_mark_node is replaced later with the BLOCK.  */
@@ -9348,7 +9298,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   if (check < 0)
     return decl;
 
-  if (flags == NO_SPECIAL && ctype && constructor_name (ctype) == declarator)
+  if (flags == NO_SPECIAL && ctype && constructor_name_p (declarator, ctype))
     DECL_CONSTRUCTOR_P (decl) = 1;
 
   /* Function gets the ugly name, field gets the nice one.  This call
@@ -9782,6 +9732,48 @@ compute_array_index_type (name, size)
   return build_index_type (itype);
 }
 
+/* Returns the scope (if any) in which the entity declared by
+   DECLARATOR will be located.  If the entity was declared with an
+   unqualified name, NULL_TREE is returned.  */
+
+tree
+get_scope_of_declarator (declarator)
+     tree declarator;
+{
+  if (!declarator)
+    return NULL_TREE;
+  
+  switch (TREE_CODE (declarator))
+    {
+    case CALL_EXPR:
+    case ARRAY_REF:
+    case INDIRECT_REF:
+    case ADDR_EXPR:
+      /* For any of these, the main declarator is the first operand.  */
+      return get_scope_of_declarator (TREE_OPERAND
+                                     (declarator, 0));
+
+    case SCOPE_REF:
+      /* For a pointer-to-member, continue descending.  */
+      if (TREE_CODE (TREE_OPERAND (declarator, 1))
+         == INDIRECT_REF)
+       return get_scope_of_declarator (TREE_OPERAND
+                                       (declarator, 1));
+      /* Otherwise, if the declarator-id is a SCOPE_REF, the scope in
+        which the declaration occurs is the first operand.  */
+      return TREE_OPERAND (declarator, 0);
+
+    case TREE_LIST:
+      /* Attributes to be applied. The declarator is TREE_VALUE.  */
+      return get_scope_of_declarator (TREE_VALUE (declarator));
+      
+    default:
+      /* Otherwise, we have a declarator-id which is not a qualified
+        name; the entity will be declared in the current scope.  */
+      return NULL_TREE;
+    }
+}
+
 /* Returns an ARRAY_TYPE for an array with SIZE elements of the
    indicated TYPE.  If non-NULL, NAME is the NAME of the declaration
    with this type.  */
@@ -9906,11 +9898,9 @@ check_special_function_return_type (sfk, type, optype)
   return type;
 }
 
-/* Given declspecs and a declarator,
-   determine the name and type of the object declared
-   and construct a ..._DECL node for it.
-   (In one case we can return a ..._TYPE node instead.
-    For invalid input we sometimes return 0.)
+/* Given declspecs and a declarator (abstract or otherwise), determine
+   the name and type of the object declared and construct a DECL node
+   for it.
 
    DECLSPECS is a chain of tree_list nodes whose value fields
     are the storage classes and type specifiers.
@@ -9937,35 +9927,15 @@ check_special_function_return_type (sfk, type, optype)
    if there are none; *ATTRLIST may be modified if attributes from inside
    the declarator should be applied to the declaration.
 
-   In the TYPENAME case, DECLARATOR is really an abstract declarator.
-   It may also be so in the PARM case, for a prototype where the
-   argument type is specified but not the name.
+   When this function is called, scoping variables (such as
+   CURRENT_CLASS_TYPE) should reflect the scope in which the
+   declaration occurs, not the scope in which the new declaration will
+   be placed.  For example, on:
 
-   This function is where the complicated C meanings of `static'
-   and `extern' are interpreted.
+     void S::f() { ... }
 
-   For C++, if there is any monkey business to do, the function which
-   calls this one must do it, i.e., prepending instance variables,
-   renaming overloaded function names, etc.
-
-   Note that for this C++, it is an error to define a method within a class
-   which does not belong to that class.
-
-   Except in the case where SCOPE_REFs are implicitly known (such as
-   methods within a class being redundantly qualified),
-   declarations which involve SCOPE_REFs are returned as SCOPE_REFs
-   (class_name::decl_name).  The caller must also deal with this.
-
-   If a constructor or destructor is seen, and the context is FIELD,
-   then the type gains the attribute TREE_HAS_x.  If such a declaration
-   is erroneous, NULL_TREE is returned.
-
-   QUALS is used only for FUNCDEF and MEMFUNCDEF cases.  For a member
-   function, these are the qualifiers to give to the `this' pointer. We
-   apply TYPE_QUAL_RESTRICT to the this ptr, not the object.
-
-   May return void_type_node if the declarator turned out to be a friend.
-   See grokfield for details.  */
+   when grokdeclarator is called for `S::f', the CURRENT_CLASS_TYPE
+   should not be `S'.  */
 
 tree
 grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
@@ -10016,6 +9986,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   int template_count = 0;
   tree in_namespace = NULL_TREE;
   tree returned_attrs = NULL_TREE;
+  tree scope = NULL_TREE;
 
   RIDBIT_RESET_ALL (specbits);
   if (decl_context == FUNCDEF)
@@ -10055,7 +10026,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              my_friendly_assert (flags == NO_SPECIAL, 152);
              flags = DTOR_FLAG;
              sfk = sfk_destructor;
-             if (TREE_CODE (name) == TYPE_DECL)
+             if (TYPE_P (name))
                TREE_OPERAND (decl, 0) = name = constructor_name (name);
              my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
              if (ctype == NULL_TREE)
@@ -10067,7 +10038,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    }
                  else
                    {
-                     tree t = constructor_name (current_class_name);
+                     tree t = constructor_name (current_class_type);
                      if (t != name)
                        rename = t;
                    }
@@ -10153,7 +10124,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            decl = *next;
            if (ctype != NULL_TREE
                && decl != NULL_TREE && flags != DTOR_FLAG
-               && decl == constructor_name (ctype))
+               && constructor_name_p (decl, ctype))
              {
                sfk = sfk_constructor;
                ctor_return_type = ctype;
@@ -10220,10 +10191,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                {
                  ctype = NULL_TREE;
                  in_namespace = TREE_OPERAND (decl, 0);
-                 TREE_OPERAND (decl, 0) = NULL_TREE;
                }
              else if (! is_aggr_type (cname, 1))
-               TREE_OPERAND (decl, 0) = NULL_TREE;
+               ctype = NULL_TREE;
              /* Must test TREE_OPERAND (decl, 1), in case user gives
                 us `typedef (class::memfunc)(int); memfunc *memfuncptr;'  */
              else if (TREE_OPERAND (decl, 1)
@@ -10240,19 +10210,35 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              else if (ctype == NULL_TREE)
                ctype = cname;
              else if (TREE_COMPLEXITY (decl) == current_class_depth)
-               TREE_OPERAND (decl, 0) = ctype;
+               ;
              else
                {
                  if (! UNIQUELY_DERIVED_FROM_P (cname, ctype))
                    {
                      error ("type `%T' is not derived from type `%T'",
                                cname, ctype);
-                     TREE_OPERAND (decl, 0) = NULL_TREE;
+                     ctype = NULL_TREE;
                    }
                  else
                    ctype = cname;
                }
 
+             /* It is valid to write:
+
+                  class C { void f(); };
+                  typedef C D;
+                  void D::f();
+
+                The standard is not clear about whether `typedef const C D' is
+                legal; as of 2002-09-15 the committee is considering
+                that question.  EDG 3.0 allows that syntax.
+                Therefore, we do as well.  */
+             if (ctype)
+               ctype = TYPE_MAIN_VARIANT (ctype);
+             /* Update the declarator so that when we process it
+                again the correct type is present.  */
+             TREE_OPERAND (decl, 0) = ctype;
+
              if (ctype && TREE_CODE (TREE_OPERAND (decl, 1)) == TYPE_DECL
                  && constructor_name_p (DECL_NAME (TREE_OPERAND (decl, 1)),
                                         ctype))
@@ -10262,7 +10248,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              if (ctype)
                {
                  if (TREE_CODE (decl) == IDENTIFIER_NODE
-                     && constructor_name (ctype) == decl)
+                     && constructor_name_p (decl, ctype))
                    {
                      sfk = sfk_constructor;
                      ctor_return_type = ctype;
@@ -10890,6 +10876,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   if (nclasses > 0 && friendp)
     error ("storage class specifiers invalid in friend function declarations");
 
+  scope = get_scope_of_declarator (declarator);
+
   /* Now figure out the structure of the declarator proper.
      Descend through it, creating more complex types, until we reach
      the declared identifier (or NULL_TREE, in an abstract declarator).  */
@@ -10937,7 +10925,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
              grok_method_quals (ctype, dummy, quals);
              type = TREE_TYPE (dummy);
-             ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
              quals = NULL_TREE;
            }
        }
@@ -11045,7 +11032,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            if (ctype && sfk == sfk_conversion)
              TYPE_HAS_CONVERSION (ctype) = 1;
-           if (ctype && constructor_name (ctype) == dname)
+           if (ctype && constructor_name_p (dname, ctype))
              {
                /* We are within a class's scope. If our declarator name
                   is the same as the class name, and we are defining
@@ -11163,17 +11150,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            /* ANSI says that `const int foo ();'
               does not make the function foo const.  */
            type = build_function_type (type, arg_types);
-
-           {
-             tree t;
-             for (t = arg_types; t; t = TREE_CHAIN (t))
-               if (TREE_PURPOSE (t)
-                   && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG)
-                 {
-                   add_defarg_fn (type);
-                   break;
-                 }
-           }
          }
          break;
 
@@ -11278,44 +11254,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            if (TREE_CODE (sname) == BIT_NOT_EXPR)
              sname = TREE_OPERAND (sname, 0);
 
-           if (TREE_COMPLEXITY (declarator) == 0)
-             /* This needs to be here, in case we are called
-                multiple times.  */ ;
-           else if (TREE_COMPLEXITY (declarator) == -1)
-             /* Namespace member.  */
-             pop_decl_namespace ();
-           else if (friendp && (TREE_COMPLEXITY (declarator) < 2))
-             /* Don't fall out into global scope. Hides real bug? --eichin */ ;
-           else if (!TREE_OPERAND (declarator, 0)
-                    || !IS_AGGR_TYPE_CODE
-                         (TREE_CODE (TREE_OPERAND (declarator, 0))))
-             ;
-           else if (TREE_COMPLEXITY (declarator) == current_class_depth)
-             {
-               /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq
-                  that refer to ctype.  They couldn't be resolved earlier
-                  because we hadn't pushed into the class yet.
-                  Example: resolve 'B<T>::type' in
-                  'B<typename B<T>::type> B<T>::f () { }'.  */
-               if (current_template_parms
-                   && uses_template_parms (type)
-                   && uses_template_parms (current_class_type))
-                 {
-                   tree args = current_template_args ();
-                   type = tsubst (type, args, tf_error | tf_warning,
-                                  NULL_TREE);
-                 }
-
-               /* This pop_nested_class corresponds to the
-                   push_nested_class used to push into class scope for
-                   parsing the argument list of a function decl, in
-                   qualified_id.  */
-               pop_nested_class ();
-               TREE_COMPLEXITY (declarator) = current_class_depth;
-             }
-           else
-             abort ();
-
            if (TREE_OPERAND (declarator, 0) == NULL_TREE)
              {
                /* We had a reference to a global decl, or
@@ -11379,7 +11317,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      {
                        error ("cannot declare member function `%T::%s' within `%T'",
                                  ctype, name, current_class_type);
-                       return void_type_node;
+                       return error_mark_node;
                      }
                  }
                else if (RIDBIT_SETP (RID_TYPEDEF, specbits)
@@ -11452,6 +11390,35 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        attrlist = &returned_attrs;
     }
 
+  /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq that refer
+     to ctype.  They couldn't be resolved earlier because we hadn't
+     pushed into the class yet.  
+
+     For example, consider:
+
+       template <typename T>
+       struct S {
+         typedef T X;
+         X f();
+       };
+
+       template <typename T>
+       typename S<T>::X f() {}
+
+       When parsing the decl-specifier-seq for the definition of `f',
+       we construct a TYPENAME_TYPE for `S<T>::X'.  By substituting
+       here, we resolve it to the correct type.  */
+  if (scope && CLASS_TYPE_P (scope)
+      && current_template_parms
+      && uses_template_parms (scope))
+    {
+      tree args = current_template_args ();
+      push_scope (scope);
+      type = tsubst (type, args, tf_error | tf_warning,
+                    NULL_TREE);
+      pop_scope (scope);
+    }
+
   /* Now TYPE has the actual type.  */
 
   /* Did array size calculations overflow?  */
@@ -11540,7 +11507,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
       if (decl_context == FIELD)
        {
-         if (declarator == constructor_name (current_class_type))
+         if (constructor_name_p (declarator, current_class_type))
            pedwarn ("ISO C++ forbids nested type `%D' with same name as enclosing class",
                        declarator);
          decl = build_lang_decl (TYPE_DECL, declarator, type);
@@ -11548,6 +11515,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       else
        {
          decl = build_decl (TYPE_DECL, declarator, type);
+         if (in_namespace || ctype)
+           cp_error_at ("typedef name may not be a nested-name-specifier",
+                        decl);
          if (!current_function_decl)
            DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
        }
@@ -11588,12 +11558,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
             type with external linkage have external linkage.  */
        }
 
-      if (TREE_CODE (type) == OFFSET_TYPE || TREE_CODE (type) == METHOD_TYPE)
-       {
-         cp_error_at ("typedef name may not be class-qualified", decl);
-         return NULL_TREE;
-       }
-      else if (quals)
+      if (quals)
        {
          if (ctype == NULL_TREE)
            {
@@ -12011,7 +11976,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              }
 
            /* 9.2p13 [class.mem] */
-           if (declarator == constructor_name (current_class_type)
+           if (constructor_name_p (declarator, current_class_type)
                /* The standard does not allow non-static data members
                   here either, but we agreed at the 10/99 meeting
                   to change that in TC 1 so that they are allowed in
@@ -14616,9 +14581,14 @@ start_method (declspecs, declarator, attrlist)
   tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
                                &attrlist);
 
-  /* Something too ugly to handle.  */
-  if (fndecl == NULL_TREE)
-    return NULL_TREE;
+  if (fndecl == error_mark_node)
+    return error_mark_node;
+
+  if (fndecl == NULL || TREE_CODE (fndecl) != FUNCTION_DECL)
+    {
+      error ("invalid member function declaration");
+      return error_mark_node;
+    }
 
   if (attrlist)
     cplus_decl_attributes (&fndecl, attrlist, 0);
@@ -14627,10 +14597,6 @@ start_method (declspecs, declarator, attrlist)
   if (fndecl == void_type_node)
     return fndecl;
 
-  if (TREE_CODE (fndecl) != FUNCTION_DECL)
-    /* Not a function, tell parser to report parse error.  */
-    return NULL_TREE;
-
   if (DECL_IN_AGGR_P (fndecl))
     {
       if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type)
@@ -14908,7 +14874,7 @@ cp_tree_node_structure (t)
 {
   switch (TREE_CODE (&t->generic))
     {
-    case DEFAULT_ARG:          return TS_CP_IDENTIFIER;
+    case DEFAULT_ARG:          return TS_CP_DEFAULT_ARG;
     case IDENTIFIER_NODE:      return TS_CP_IDENTIFIER;
     case CPLUS_BINDING:                return TS_CP_BINDING;
     case OVERLOAD:             return TS_CP_OVERLOAD;
index 1607e379090addb1bf85ca43180451e2aea6cca4..be91e713f3bb10bbe3e37d23b6b43e7a79fcb84f 100644 (file)
@@ -1220,51 +1220,34 @@ cplus_decl_attributes (decl, attributes, flags)
     SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
 }
 \f
-/* CONSTRUCTOR_NAME:
-   Return the name for the constructor (or destructor) for the
-   specified class.  Argument can be RECORD_TYPE, TYPE_DECL, or
-   IDENTIFIER_NODE.  When given a template, this routine doesn't
+/* Return the name for the constructor (or destructor) for the
+   specified class TYPE.  When given a template, this routine doesn't
    lose the specialization.  */
 
 tree
-constructor_name_full (thing)
-     tree thing;
+constructor_name_full (tree type)
 {
-  if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM
-      || TREE_CODE (thing) == BOUND_TEMPLATE_TEMPLATE_PARM
-      || TREE_CODE (thing) == TYPENAME_TYPE)
-    thing = TYPE_NAME (thing);
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
-    {
-      if (TYPE_WAS_ANONYMOUS (thing) && TYPE_HAS_CONSTRUCTOR (thing))
-       thing = DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0)));
-      else
-       thing = TYPE_NAME (thing);
-    }
-  if (TREE_CODE (thing) == TYPE_DECL
-      || (TREE_CODE (thing) == TEMPLATE_DECL
-         && TREE_CODE (DECL_TEMPLATE_RESULT (thing)) == TYPE_DECL))
-    thing = DECL_NAME (thing);
-  my_friendly_assert (TREE_CODE (thing) == IDENTIFIER_NODE, 197);
-  return thing;
+  type = TYPE_MAIN_VARIANT (type);
+  if (CLASS_TYPE_P (type) && TYPE_WAS_ANONYMOUS (type) 
+      && TYPE_HAS_CONSTRUCTOR (type))
+    return DECL_NAME (OVL_CURRENT (CLASSTYPE_CONSTRUCTORS (type)));
+  else
+    return TYPE_IDENTIFIER (type);
 }
 
-/* CONSTRUCTOR_NAME:
-   Return the name for the constructor (or destructor) for the
-   specified class.  Argument can be RECORD_TYPE, TYPE_DECL, or
-   IDENTIFIER_NODE.  When given a template, return the plain
+/* Return the name for the constructor (or destructor) for the
+   specified class.  When given a template, return the plain
    unspecialized name.  */
 
 tree
-constructor_name (thing)
-     tree thing;
+constructor_name (type)
+     tree type;
 {
-  tree t;
-  thing = constructor_name_full (thing);
-  t = IDENTIFIER_TEMPLATE (thing);
-  if (!t)
-    return thing;
-  return t;
+  tree name;
+  name = constructor_name_full (type);
+  if (IDENTIFIER_TEMPLATE (name))
+    name = IDENTIFIER_TEMPLATE (name);
+  return name;
 }
 
 /* Returns TRUE if NAME is the name for the constructor for TYPE.  */
@@ -3036,7 +3019,12 @@ build_expr_from_tree (t)
          return do_scoped_id (token, IDENTIFIER_GLOBAL_VALUE (token));
        }
       else
-       return do_identifier (TREE_OPERAND (t, 0), 0, NULL_TREE);
+       {
+         t = do_identifier (TREE_OPERAND (t, 0), 0, NULL_TREE);
+         if (TREE_CODE (t) == ALIAS_DECL)
+           t = DECL_INITIAL (t);
+         return t;
+       }
 
     case TEMPLATE_ID_EXPR:
       {
@@ -3292,7 +3280,7 @@ build_expr_from_tree (t)
         build_expr_from_tree (TREE_OPERAND (t, 2)));
 
     case PSEUDO_DTOR_EXPR:
-      return (finish_pseudo_destructor_call_expr 
+      return (finish_pseudo_destructor_expr 
              (build_expr_from_tree (TREE_OPERAND (t, 0)),
               build_expr_from_tree (TREE_OPERAND (t, 1)),
               build_expr_from_tree (TREE_OPERAND (t, 2))));
@@ -3319,8 +3307,48 @@ build_expr_from_tree (t)
     case COMPONENT_REF:
       {
        tree object = build_expr_from_tree (TREE_OPERAND (t, 0));
-       return finish_class_member_access_expr (object, 
-                                               TREE_OPERAND (t, 1));
+       tree member = TREE_OPERAND (t, 1);
+
+       if (!CLASS_TYPE_P (TREE_TYPE (object)))
+         {
+           if (TREE_CODE (member) == BIT_NOT_EXPR)
+             return finish_pseudo_destructor_expr (object, 
+                                                   NULL_TREE,
+                                                   TREE_TYPE (object));
+           else if (TREE_CODE (member) == SCOPE_REF
+                    && (TREE_CODE (TREE_OPERAND (member, 1)) == BIT_NOT_EXPR))
+             return finish_pseudo_destructor_expr (object, 
+                                                   TREE_OPERAND (t, 0),
+                                                   TREE_TYPE (object));
+         }
+       else if (TREE_CODE (member) == SCOPE_REF
+                && TREE_CODE (TREE_OPERAND (member, 1)) == TEMPLATE_ID_EXPR)
+         {
+           tree tmpl;
+           tree args;
+       
+           /* Lookup the template functions now that we know what the
+              scope is.  */
+           tmpl = TREE_OPERAND (TREE_OPERAND (member, 1), 0);
+           args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
+           member = lookup_qualified_name (TREE_OPERAND (member, 0),
+                                           tmpl, 
+                                           /*is_type=*/0,
+                                           /*flags=*/0);
+           if (BASELINK_P (member))
+             BASELINK_FUNCTIONS (member) 
+               = build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
+                           args);
+           else
+             {
+               error ("`%D' is not a member of `%T'",
+                      tmpl, TREE_TYPE (object));
+               return error_mark_node;
+             }
+         }
+
+
+       return finish_class_member_access_expr (object, member);
       }
 
     case THROW_EXPR:
@@ -3366,6 +3394,7 @@ build_expr_from_tree (t)
        return get_typeid (TREE_OPERAND (t, 0));
       return build_typeid (build_expr_from_tree (TREE_OPERAND (t, 0)));
 
+    case PARM_DECL:
     case VAR_DECL:
       return convert_from_reference (t);
 
@@ -3857,13 +3886,19 @@ set_decl_namespace (decl, scope, friendp)
       if (!is_overloaded_fn (old))
        goto complain;
       if (processing_template_decl || processing_specialization)
-       /* We have not yet called push_template_decl to turn the
+       /* We have not yet called push_template_decl to turn a
           FUNCTION_DECL into a TEMPLATE_DECL, so the declarations
           won't match.  But, we'll check later, when we construct the
           template.  */
        return;
-      for (; old; old = OVL_NEXT (old))
-       if (decls_match (decl, OVL_CURRENT (old)))
+      if (is_overloaded_fn (old))
+       {
+         for (; old; old = OVL_NEXT (old))
+           if (decls_match (decl, OVL_CURRENT (old)))
+             return;
+       }
+      else
+       if (decls_match (decl, old))
          return;
     }
   else
@@ -3939,8 +3974,8 @@ push_scope (t)
 {
   if (TREE_CODE (t) == NAMESPACE_DECL)
     push_decl_namespace (t);
-  else
-    pushclass (t, 2);
+  else if CLASS_TYPE_P (t)
+    push_nested_class (t, 2);
 }
 
 /* Leave scope pushed by push_scope.  */
@@ -3951,8 +3986,8 @@ pop_scope (t)
 {
   if (TREE_CODE (t) == NAMESPACE_DECL)
     pop_decl_namespace ();
-  else
-    popclass ();
+  else if CLASS_TYPE_P (t)
+    pop_nested_class ();
 }
 
 /* [basic.lookup.koenig] */
@@ -4340,52 +4375,47 @@ validate_nonmember_using_decl (decl, scope, name)
      tree *scope;
      tree *name;
 {
-  if (TREE_CODE (decl) == SCOPE_REF)
-    {
-      *scope = TREE_OPERAND (decl, 0);
-      *name = TREE_OPERAND (decl, 1);
+  *scope = global_namespace;
+  *name = NULL_TREE;
 
-      if (!processing_template_decl)
-        {
-          /* [namespace.udecl]
-             A using-declaration for a class member shall be a
-             member-declaration.  */
-          if(TREE_CODE (*scope) != NAMESPACE_DECL)
-            {
-              if (TYPE_P (*scope))
-                error ("`%T' is not a namespace", *scope);
-              else
-                error ("`%D' is not a namespace", *scope);
-              return NULL_TREE;
-            }
-          
-          /* 7.3.3/5
-             A using-declaration shall not name a template-id.  */
-          if (TREE_CODE (*name) == TEMPLATE_ID_EXPR)
-            {
-              *name = TREE_OPERAND (*name, 0);
-              error ("a using-declaration cannot specify a template-id.  Try `using %D'", *name);
-              return NULL_TREE;
-            }
-        }
-    }
-  else if (TREE_CODE (decl) == IDENTIFIER_NODE
-           || TREE_CODE (decl) == TYPE_DECL
-          || TREE_CODE (decl) == TEMPLATE_DECL)
+  if (TREE_CODE (decl) == TEMPLATE_ID_EXPR)
     {
-      *scope = global_namespace;
-      *name = decl;
+      *name = TREE_OPERAND (decl, 0);
+      /* 7.3.3/5
+          A using-declaration shall not name a template-id.  */
+      error ("a using-declaration cannot specify a template-id.  Try `using %D'", *name);
+      return NULL_TREE;
     }
-  else if (TREE_CODE (decl) == NAMESPACE_DECL)
+
+  if (TREE_CODE (decl) == NAMESPACE_DECL)
     {
       error ("namespace `%D' not allowed in using-declaration", decl);
       return NULL_TREE;
     }
+
+  if (is_overloaded_fn (decl))
+    decl = get_first_fn (decl);
+
+  my_friendly_assert (DECL_P (decl), 20020908);
+
+  if (TREE_CODE (decl) == CONST_DECL)
+    /* Enumeration constants to not have DECL_CONTEXT set.  */
+    *scope = TYPE_CONTEXT (TREE_TYPE (decl));
   else
-    abort ();
-  if (DECL_P (*name))
-    *name = DECL_NAME (*name);
-  /* Make a USING_DECL.  */
+    *scope = DECL_CONTEXT (decl);
+  if (!*scope)
+    *scope = global_namespace;
+
+  /* [namespace.udecl]
+       A using-declaration for a class member shall be a
+       member-declaration.  */
+  if (TYPE_P (*scope))
+    {
+      error ("`%T' is not a namespace", *scope);
+      return NULL_TREE;
+    }
+  *name = DECL_NAME (decl);
+  /* Make a USING_DECL. */
   return push_using_decl (*scope, *name);
 }
 
@@ -4591,14 +4621,32 @@ do_class_using_decl (decl)
       error ("a using-declaration cannot specify a template-id.  Try  `using %T::%D'", TREE_OPERAND (decl, 0), name);
       return NULL_TREE;
     }
-  if (TREE_CODE (name) == TYPE_DECL || TREE_CODE (name) == TEMPLATE_DECL)
-    name = DECL_NAME (name);
+  if (TREE_CODE (name) == TYPE_DECL)
+    {
+      tree type = TREE_TYPE (name);
+      if (CLASSTYPE_USE_TEMPLATE (TREE_TYPE (name)))
+       {
+         name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (type));
+         error ("a using-declaration cannot specify a template-id.");
+         return NULL_TREE;
+       }
+      name = DECL_NAME (name);
+    }
+  else if (TREE_CODE (name) == TEMPLATE_DECL)
+     name = DECL_NAME (name);
   else if (BASELINK_P (name))
     {
-      name = BASELINK_FUNCTIONS (name);
-      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-       name = TREE_OPERAND (name, 0);
-      name = DECL_NAME (get_first_fn (name));
+      tree fns;
+
+      fns = BASELINK_FUNCTIONS (name);
+      if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+       {
+         fns = TREE_OPERAND (fns, 0);
+         error ("a using-declaration cannot specify a template-id.  Try  `using %T::%D'", 
+                BASELINK_ACCESS_BINFO (name),
+                DECL_NAME (get_first_fn (fns)));
+       }
+      name = DECL_NAME (get_first_fn (fns));
     }
 
   my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 980716);
@@ -4785,13 +4833,9 @@ handle_class_head (tag_kind, scope, id, attributes, defn_p, new_type_p)
       if (*new_type_p)
        push_scope (context);
 
-      if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
-       /* It is valid to define a class with a different class key,
-          and this changes the default member access.  */
-       CLASSTYPE_DECLARED_CLASS (TREE_TYPE (decl))
-         = (tag_kind == class_type);
-       
-      if (!xrefd_p && PROCESSING_REAL_TEMPLATE_DECL_P ())
+      if (!xrefd_p 
+         && PROCESSING_REAL_TEMPLATE_DECL_P ()
+         && !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
        decl = push_template_decl (decl);
     }
 
index 9ede84a715616a2a278c8494c71cbdbbc83bcac2..d7b293f7ba4f8daf98e54781707a23302ab4d394 100644 (file)
@@ -1439,6 +1439,7 @@ dump_expr (t, flags)
     case TEMPLATE_DECL:
     case NAMESPACE_DECL:
     case OVERLOAD:
+    case IDENTIFIER_NODE:
       dump_decl (t, flags & ~TFF_DECL_SPECIFIERS);
       break;
 
@@ -1913,10 +1914,6 @@ dump_expr (t, flags)
       dump_decl (TEMPLATE_PARM_DECL (t), flags & ~TFF_DECL_SPECIFIERS);
       break;
 
-    case IDENTIFIER_NODE:
-      print_tree_identifier (scratch_buffer, t);
-      break;
-
     case SCOPE_REF:
       dump_type (TREE_OPERAND (t, 0), flags);
       print_scope_operator (scratch_buffer);
@@ -2031,12 +2028,10 @@ dump_expr (t, flags)
       output_add_string (scratch_buffer, ") break; ");
       break;
 
-    case TREE_LIST:
-      if (TREE_VALUE (t) && TREE_CODE (TREE_VALUE (t)) == FUNCTION_DECL)
-       {
-         print_tree_identifier (scratch_buffer, DECL_NAME (TREE_VALUE (t)));
-         break;
-       }
+    case BASELINK:
+      print_tree_identifier (scratch_buffer, DECL_NAME (get_first_fn (t)));
+      break;
+
       /* else fall through */
 
       /*  This list is incomplete, but should suffice for now.
index ede1c473677094adc68e00597ba962d0739d8e99..a550c675f44a89103ce5b333cc14294d2d4cb732 100644 (file)
@@ -122,6 +122,10 @@ cxx_expand_expr (exp, target, tmode, modifier)
       /* We don't need to generate any code for an empty class.  */
       return const0_rtx;
 
+    case BASELINK:
+      return expand_expr (BASELINK_FUNCTIONS (exp), target, tmode,
+                         modifier);
+
     default:
       return c_expand_expr (exp, target, tmode, modifier);
     }
index bfce5564b4b8699f1f524b8a5a56bb6d232d9484..91dbf8a141ccebdc4aad4708a06cc5eb2a7e6e2f 100644 (file)
@@ -913,16 +913,29 @@ member_init_ok_or_else (field, type, member_name)
 {
   if (field == error_mark_node)
     return 0;
-  if (field == NULL_TREE || initializing_context (field) != type)
+  if (!field)
     {
       error ("class `%T' does not have any field named `%D'", type,
-               member_name);
+            member_name);
       return 0;
     }
-  if (TREE_STATIC (field))
+  if (TREE_CODE (field) == VAR_DECL)
     {
-      error ("field `%#D' is static; the only point of initialization is its definition",
-               field);
+      error ("`%#D' is a static data member; it can only be "
+            "initialized at its definition",
+            field);
+      return 0;
+    }
+  if (TREE_CODE (field) != FIELD_DECL)
+    {
+      error ("`%#D' is not a non-static data member of `%T'",
+            field, type);
+      return 0;
+    }
+  if (initializing_context (field) != type)
+    {
+      error ("class `%T' does not have any field named `%D'", type,
+               member_name);
       return 0;
     }
 
@@ -1601,7 +1614,7 @@ build_offset_ref (type, name)
 
   decl = maybe_dummy_object (type, &basebinfo);
 
-  if (BASELINK_P (name))
+  if (BASELINK_P (name) || DECL_P (name))
     member = name;
   else
     {
index e60ebe8761e80ff4c5fc774370fcdb78c38e614c..92d0aa6384881d9068dbf321a3be80dc9757c974 100644 (file)
@@ -32,7 +32,6 @@ Boston, MA 02111-1307, USA.  */
 #include "cp-tree.h"
 #include "cpplib.h"
 #include "lex.h"
-#include "parse.h"
 #include "flags.h"
 #include "c-pragma.h"
 #include "toplev.h"
@@ -47,8 +46,6 @@ Boston, MA 02111-1307, USA.  */
 #include <locale.h>
 #endif
 
-extern void yyprint PARAMS ((FILE *, int, YYSTYPE));
-
 static int interface_strcmp PARAMS ((const char *));
 static int *init_cpp_parse PARAMS ((void));
 static void init_cp_pragma PARAMS ((void));
@@ -80,8 +77,6 @@ static void copy_lang_type PARAMS ((tree));
 #include "cpplib.h"
 
 extern int yychar;             /*  the lookahead symbol                */
-extern YYSTYPE yylval;         /*  the semantic value of the           */
-                               /*  lookahead symbol                    */
 
 /* the declaration found for the last IDENTIFIER token read in.  yylex
    must look this up to detect typedefs, which get token type
@@ -153,21 +148,6 @@ tree
 make_reference_declarator (cv_qualifiers, target)
      tree cv_qualifiers, target;
 {
-  if (target)
-    {
-      if (TREE_CODE (target) == ADDR_EXPR)
-       {
-         error ("cannot declare references to references");
-         return target;
-       }
-      if (TREE_CODE (target) == INDIRECT_REF)
-       {
-         error ("cannot declare pointers to references");
-         return target;
-       }
-      if (TREE_CODE (target) == IDENTIFIER_NODE && ANON_AGGRNAME_P (target))
-         error ("type name expected before `&'");
-    }
   target = build_nt (ADDR_EXPR, target);
   TREE_TYPE (target) = cv_qualifiers;
   return target;
@@ -431,134 +411,6 @@ static const struct resword reswords[] =
 
 };
 
-/* Table mapping from RID_* constants to yacc token numbers.
-   Unfortunately we have to have entries for all the keywords in all
-   three languages.  */
-const short rid_to_yy[RID_MAX] =
-{
-  /* RID_STATIC */     SCSPEC,
-  /* RID_UNSIGNED */   TYPESPEC,
-  /* RID_LONG */       TYPESPEC,
-  /* RID_CONST */      CV_QUALIFIER,
-  /* RID_EXTERN */     SCSPEC,
-  /* RID_REGISTER */   SCSPEC,
-  /* RID_TYPEDEF */    SCSPEC,
-  /* RID_SHORT */      TYPESPEC,
-  /* RID_INLINE */     SCSPEC,
-  /* RID_VOLATILE */   CV_QUALIFIER,
-  /* RID_SIGNED */     TYPESPEC,
-  /* RID_AUTO */       SCSPEC,
-  /* RID_RESTRICT */   CV_QUALIFIER,
-
-  /* C extensions.  Bounded pointers are not yet in C++ */
-  /* RID_BOUNDED */    0,
-  /* RID_UNBOUNDED */  0,
-  /* RID_COMPLEX */    TYPESPEC,
-  /* RID_THREAD */     SCSPEC,
-
-  /* C++ */
-  /* RID_FRIEND */     SCSPEC,
-  /* RID_VIRTUAL */    SCSPEC,
-  /* RID_EXPLICIT */   SCSPEC,
-  /* RID_EXPORT */     EXPORT,
-  /* RID_MUTABLE */    SCSPEC,
-
-  /* ObjC */
-  /* RID_IN */         0,
-  /* RID_OUT */                0,
-  /* RID_INOUT */      0,
-  /* RID_BYCOPY */     0,
-  /* RID_BYREF */      0,
-  /* RID_ONEWAY */     0,
-
-  /* C */
-  /* RID_INT */                TYPESPEC,
-  /* RID_CHAR */       TYPESPEC,
-  /* RID_FLOAT */      TYPESPEC,
-  /* RID_DOUBLE */     TYPESPEC,
-  /* RID_VOID */       TYPESPEC,
-  /* RID_ENUM */       ENUM,
-  /* RID_STRUCT */     AGGR,
-  /* RID_UNION */      AGGR,
-  /* RID_IF */         IF,
-  /* RID_ELSE */       ELSE,
-  /* RID_WHILE */      WHILE,
-  /* RID_DO */         DO,
-  /* RID_FOR */                FOR,
-  /* RID_SWITCH */     SWITCH,
-  /* RID_CASE */       CASE,
-  /* RID_DEFAULT */    DEFAULT,
-  /* RID_BREAK */      BREAK,
-  /* RID_CONTINUE */   CONTINUE,
-  /* RID_RETURN */     RETURN_KEYWORD,
-  /* RID_GOTO */       GOTO,
-  /* RID_SIZEOF */     SIZEOF,
-
-  /* C extensions */
-  /* RID_ASM */                ASM_KEYWORD,
-  /* RID_TYPEOF */     TYPEOF,
-  /* RID_ALIGNOF */    ALIGNOF,
-  /* RID_ATTRIBUTE */  ATTRIBUTE,
-  /* RID_VA_ARG */     VA_ARG,
-  /* RID_EXTENSION */  EXTENSION,
-  /* RID_IMAGPART */   IMAGPART,
-  /* RID_REALPART */   REALPART,
-  /* RID_LABEL */      LABEL,
-  /* RID_PTRBASE */    0,
-  /* RID_PTREXTENT */  0,
-  /* RID_PTRVALUE */   0,
-  /* RID_CHOOSE_EXPR */        0,
-  /* RID_TYPES_COMPATIBLE_P */ 0,
-
-  /* RID_FUNCTION_NAME */      VAR_FUNC_NAME,
-  /* RID_PRETTY_FUNCTION_NAME */ VAR_FUNC_NAME,
-  /* RID_c99_FUNCTION_NAME */  VAR_FUNC_NAME,
-
-  /* C++ */
-  /* RID_BOOL */       TYPESPEC,
-  /* RID_WCHAR */      TYPESPEC,
-  /* RID_CLASS */      AGGR,
-  /* RID_PUBLIC */     VISSPEC,
-  /* RID_PRIVATE */    VISSPEC,
-  /* RID_PROTECTED */  VISSPEC,
-  /* RID_TEMPLATE */   TEMPLATE,
-  /* RID_NULL */       CONSTANT,
-  /* RID_CATCH */      CATCH,
-  /* RID_DELETE */     DELETE,
-  /* RID_FALSE */      CXX_FALSE,
-  /* RID_NAMESPACE */  NAMESPACE,
-  /* RID_NEW */                NEW,
-  /* RID_OPERATOR */   OPERATOR,
-  /* RID_THIS */       THIS,
-  /* RID_THROW */      THROW,
-  /* RID_TRUE */       CXX_TRUE,
-  /* RID_TRY */                TRY,
-  /* RID_TYPENAME */   TYPENAME_KEYWORD,
-  /* RID_TYPEID */     TYPEID,
-  /* RID_USING */      USING,
-
-  /* casts */
-  /* RID_CONSTCAST */  CONST_CAST,
-  /* RID_DYNCAST */    DYNAMIC_CAST,
-  /* RID_REINTCAST */  REINTERPRET_CAST,
-  /* RID_STATCAST */   STATIC_CAST,
-
-  /* Objective-C */
-  /* RID_ID */                 0,
-  /* RID_AT_ENCODE */          0,
-  /* RID_AT_END */             0,
-  /* RID_AT_CLASS */           0,
-  /* RID_AT_ALIAS */           0,
-  /* RID_AT_DEFS */            0,
-  /* RID_AT_PRIVATE */         0,
-  /* RID_AT_PROTECTED */       0,
-  /* RID_AT_PUBLIC */          0,
-  /* RID_AT_PROTOCOL */                0,
-  /* RID_AT_SELECTOR */                0,
-  /* RID_AT_INTERFACE */       0,
-  /* RID_AT_IMPLEMENTATION */  0
-};
-
 void
 init_reswords ()
 {
@@ -609,7 +461,6 @@ cxx_init (filename)
   input_filename = "<internal>";
 
   init_reswords ();
-  init_spew ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
@@ -655,75 +506,6 @@ cxx_init (filename)
   return filename;
 }
 \f
-inline void
-yyprint (file, yychar, yylval)
-     FILE *file;
-     int yychar;
-     YYSTYPE yylval;
-{
-  tree t;
-  switch (yychar)
-    {
-    case IDENTIFIER:
-    case tTYPENAME:
-    case TYPESPEC:
-    case PTYPENAME:
-    case PFUNCNAME:
-    case IDENTIFIER_DEFN:
-    case TYPENAME_DEFN:
-    case PTYPENAME_DEFN:
-    case SCSPEC:
-    case PRE_PARSED_CLASS_DECL:
-      t = yylval.ttype;
-      if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == TEMPLATE_DECL)
-       {
-         fprintf (file, " `%s'", IDENTIFIER_POINTER (DECL_NAME (t)));
-         break;
-       }
-      my_friendly_assert (TREE_CODE (t) == IDENTIFIER_NODE, 224);
-      if (IDENTIFIER_POINTER (t))
-         fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
-      break;
-
-    case AGGR:
-      if (yylval.ttype == class_type_node)
-       fprintf (file, " `class'");
-      else if (yylval.ttype == record_type_node)
-       fprintf (file, " `struct'");
-      else if (yylval.ttype == union_type_node)
-       fprintf (file, " `union'");
-      else if (yylval.ttype == enum_type_node)
-       fprintf (file, " `enum'");
-      else
-       abort ();
-      break;
-
-    case CONSTANT:
-      t = yylval.ttype;
-      if (TREE_CODE (t) == INTEGER_CST)
-       fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-                " 0x%x%016x",
-#else
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-                " 0x%lx%016lx",
-#else
-                " 0x%llx%016llx",
-#endif
-#endif
-#else
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
-                " 0x%lx%08lx",
-#else
-                " 0x%x%08x",
-#endif
-#endif
-                TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t));
-      break;
-    }
-}
-
 #if defined(GATHER_STATISTICS) && defined(REDUCE_LENGTH)
 static int *reduce_count;
 #endif
@@ -873,36 +655,6 @@ interface_strcmp (s)
   return 1;
 }
 
-/* Heuristic to tell whether the user is missing a semicolon
-   after a struct or enum declaration.  Emit an error message
-   if we know the user has blown it.  */
-
-void
-check_for_missing_semicolon (type)
-     tree type;
-{
-  if (yychar < 0)
-    yychar = yylex ();
-
-  if ((yychar > 255
-       && yychar != SCSPEC
-       && yychar != IDENTIFIER
-       && yychar != tTYPENAME
-       && yychar != CV_QUALIFIER
-       && yychar != SELFNAME)
-      || yychar == 0  /* EOF */)
-    {
-      if (TYPE_ANONYMOUS_P (type))
-       error ("semicolon missing after %s declaration",
-              TREE_CODE (type) == ENUMERAL_TYPE ? "enum" : "struct");
-      else
-       error ("semicolon missing after declaration of `%T'", type);
-      shadow_tag (build_tree_list (0, type));
-    }
-  /* Could probably also hack cases where class { ... } f (); appears.  */
-  clear_anon_tags ();
-}
-
 void
 note_got_semicolon (type)
      tree type;
index 15de16866b72cb0dfd009f22ada14f37215a2ed1..ecd5861f686426188150c5c9c7797bed7fa84ed8 100644 (file)
@@ -74,10 +74,6 @@ extern GTY(()) tree lastiddecl;
 extern int looking_for_typename;
 extern int looking_for_template;
 
-/* Tell the lexer where to look for names.  */
-extern GTY(()) tree got_scope;
-extern GTY(()) tree got_object;
-
 /* Pending language change.
    Positive is push count, negative is pop count.  */
 extern int pending_lang_change;
index e5a3bd974fb3008a42f4c4e5df41789fb5411459..707a4987e91af3c465a7b636391b5c7ba60c8c40 100644 (file)
@@ -145,43 +145,8 @@ hack_identifier (tree value, tree name)
 
   type = TREE_TYPE (value);
   if (TREE_CODE (value) == FIELD_DECL)
-    {
-      if (current_class_ptr == NULL_TREE)
-       {
-         if (current_function_decl 
-             && DECL_STATIC_FUNCTION_P (current_function_decl))
-           error ("invalid use of member `%D' in static member function",
-                     value);
-         else
-           /* We can get here when processing a bad default
-              argument, like:
-                struct S { int a; void f(int i = a); }  */
-           error ("invalid use of member `%D'", value);
-
-         return error_mark_node;
-       }
-      TREE_USED (current_class_ptr) = 1;
-      if (processing_template_decl)
-       value = build_min_nt (COMPONENT_REF, current_class_ref, name);
-      else
-       {
-         tree access_type = current_class_type;
-         
-         while (!DERIVED_FROM_P (context_for_name_lookup (value), 
-                                 access_type))
-           {
-             access_type = TYPE_CONTEXT (access_type);
-             while (DECL_P (access_type))
-               access_type = DECL_CONTEXT (access_type);
-           }
-
-         enforce_access (access_type, value);
-         value 
-           = build_class_member_access_expr (current_class_ref, value,
-                                             /*access_path=*/NULL_TREE,
-                                             /*preserve_reference=*/false);
-       }
-    }
+    value = finish_non_static_data_member (value, 
+                                          /*qualifying_scope=*/NULL_TREE);
   else if ((TREE_CODE (value) == FUNCTION_DECL
            && DECL_FUNCTION_MEMBER_P (value))
           || (TREE_CODE (value) == OVERLOAD
@@ -1013,7 +978,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   tree raises = empty_except_spec;
   bool retref = false;
   bool has_parm = false;
-  tree name = constructor_name (TYPE_IDENTIFIER (type));
+  tree name = constructor_name (type);
 
   switch (kind)
     {
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
new file mode 100644 (file)
index 0000000..af5410e
--- /dev/null
@@ -0,0 +1,14825 @@
+/* C++ Parser.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Written by Mark Mitchell <mark@codesourcery.com>.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "dyn-string.h"
+#include "varray.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic.h"
+#include "ggc.h"
+#include "toplev.h"
+#include "output.h"
+
+\f
+/* The lexer.  */
+
+/* Overview
+   --------
+
+   A cp_lexer represents a stream of cp_tokens.  It allows arbitrary
+   look-ahead.
+
+   Methodology
+   -----------
+
+   We use a circular buffer to store incoming tokens.
+
+   Some artifacts of the C++ language (such as the
+   expression/declaration ambiguity) require arbitrary look-ahead.
+   The strategy we adopt for dealing with these problems is to attempt
+   to parse one construct (e.g., the declaration) and fall back to the
+   other (e.g., the expression) if that attempt does not succeed.
+   Therefore, we must sometimes store an arbitrary number of tokens.
+
+   The parser routinely peeks at the next token, and then consumes it
+   later.  That also requires a buffer in which to store the tokens.
+     
+   In order to easily permit adding tokens to the end of the buffer,
+   while removing them from the beginning of the buffer, we use a
+   circular buffer.  */
+
+/* A C++ token.  */
+
+typedef struct cp_token GTY (())
+{
+  /* The kind of token.  */
+  enum cpp_ttype type;
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  enum rid keyword;
+  /* The file in which this token was found.  */
+  const char *file_name;
+  /* The line at which this token was found.  */
+  int line_number;
+} cp_token;
+
+/* The number of tokens in a single token block.  */
+
+#define CP_TOKEN_BLOCK_NUM_TOKENS 32
+
+/* A group of tokens.  These groups are chained together to store
+   large numbers of tokens.  (For example, a token block is created
+   when the body of an inline member function is first encountered;
+   the tokens are processed later after the class definition is
+   complete.)  
+
+   This somewhat ungainly data structure (as opposed to, say, a
+   variable-length array), is used due to contraints imposed by the
+   current garbage-collection methodology.  If it is made more
+   flexible, we could perhaps simplify the data structures involved.  */
+
+typedef struct cp_token_block GTY (())
+{
+  /* The tokens.  */
+  cp_token tokens[CP_TOKEN_BLOCK_NUM_TOKENS];
+  /* The number of tokens in this block.  */
+  size_t num_tokens;
+  /* The next token block in the chain.  */
+  struct cp_token_block *next;
+  /* The previous block in the chain.  */
+  struct cp_token_block *prev;
+} cp_token_block;
+
+typedef struct cp_token_cache GTY (())
+{
+  /* The first block in the cache.  NULL if there are no tokens in the
+     cache.  */
+  cp_token_block *first;
+  /* The last block in the cache.  NULL If there are no tokens in the
+     cache.  */
+  cp_token_block *last;
+} cp_token_cache;
+
+/* Prototypes. */
+
+static cp_token_cache *cp_token_cache_new 
+  (void);
+static void cp_token_cache_push_token
+  (cp_token_cache *, cp_token *);
+
+/* Create a new cp_token_cache.  */
+
+static cp_token_cache *
+cp_token_cache_new ()
+{
+  return (cp_token_cache *) ggc_alloc_cleared (sizeof (cp_token_cache));
+}
+
+/* Add *TOKEN to *CACHE.  */
+
+static void
+cp_token_cache_push_token (cp_token_cache *cache,
+                          cp_token *token)
+{
+  cp_token_block *b = cache->last;
+
+  /* See if we need to allocate a new token block.  */
+  if (!b || b->num_tokens == CP_TOKEN_BLOCK_NUM_TOKENS)
+    {
+      b = ((cp_token_block *) ggc_alloc_cleared (sizeof (cp_token_block)));
+      b->prev = cache->last;
+      if (cache->last)
+       {
+         cache->last->next = b;
+         cache->last = b;
+       }
+      else
+       cache->first = cache->last = b;
+    }
+  /* Add this token to the current token block.  */
+  b->tokens[b->num_tokens++] = *token;
+}
+
+/* The cp_lexer structure represents the C++ lexer.  It is responsible
+   for managing the token stream from the preprocessor and supplying
+   it to the parser.  */
+
+typedef struct cp_lexer GTY (())
+{
+  /* The memory allocated for the buffer.  Never NULL.  */
+  cp_token * GTY ((length ("(%h.buffer_end - %h.buffer)"))) buffer;
+  /* A pointer just past the end of the memory allocated for the buffer.  */
+  cp_token * GTY ((skip (""))) buffer_end;
+  /* The first valid token in the buffer, or NULL if none.  */
+  cp_token * GTY ((skip (""))) first_token;
+  /* The next available token.  If NEXT_TOKEN is NULL, then there are
+     no more available tokens.  */
+  cp_token * GTY ((skip (""))) next_token;
+  /* A pointer just past the last available token.  If FIRST_TOKEN is
+     NULL, however, there are no available tokens, and then this
+     location is simply the place in which the next token read will be
+     placed.  If LAST_TOKEN == FIRST_TOKEN, then the buffer is full.
+     When the LAST_TOKEN == BUFFER, then the last token is at the
+     highest memory address in the BUFFER.  */
+  cp_token * GTY ((skip (""))) last_token;
+
+  /* A stack indicating positions at which cp_lexer_save_tokens was
+     called.  The top entry is the most recent position at which we
+     began saving tokens.  The entries are differences in token
+     position between FIRST_TOKEN and the first saved token.
+
+     If the stack is non-empty, we are saving tokens.  When a token is
+     consumed, the NEXT_TOKEN pointer will move, but the FIRST_TOKEN
+     pointer will not.  The token stream will be preserved so that it
+     can be reexamined later.
+
+     If the stack is empty, then we are not saving tokens.  Whenever a
+     token is consumed, the FIRST_TOKEN pointer will be moved, and the
+     consumed token will be gone forever.  */
+  varray_type saved_tokens;
+
+  /* The STRING_CST tokens encountered while processing the current
+     string literal.  */
+  varray_type string_tokens;
+
+  /* True if we should obtain more tokens from the preprocessor; false
+     if we are processing a saved token cache.  */
+  bool main_lexer_p;
+
+  /* True if we should output debugging information.  */
+  bool debugging_p;
+
+  /* The next lexer in a linked list of lexers.  */
+  struct cp_lexer *next;
+} cp_lexer;
+
+/* Prototypes.  */
+
+static cp_lexer *cp_lexer_new
+  PARAMS ((bool));
+static cp_lexer *cp_lexer_new_from_tokens
+  PARAMS ((struct cp_token_cache *));
+static int cp_lexer_saving_tokens
+  PARAMS ((const cp_lexer *));
+static cp_token *cp_lexer_next_token
+  PARAMS ((cp_lexer *, cp_token *));
+static ptrdiff_t cp_lexer_token_difference
+  PARAMS ((cp_lexer *, cp_token *, cp_token *));
+static cp_token *cp_lexer_read_token
+  PARAMS ((cp_lexer *));
+static void cp_lexer_maybe_grow_buffer
+  PARAMS ((cp_lexer *));
+static void cp_lexer_get_preprocessor_token
+  PARAMS ((cp_lexer *, cp_token *));
+static cp_token *cp_lexer_peek_token
+  PARAMS ((cp_lexer *));
+static cp_token *cp_lexer_peek_nth_token
+  PARAMS ((cp_lexer *, size_t));
+static bool cp_lexer_next_token_is
+  PARAMS ((cp_lexer *, enum cpp_ttype));
+static bool cp_lexer_next_token_is_not
+  PARAMS ((cp_lexer *, enum cpp_ttype));
+static bool cp_lexer_next_token_is_keyword
+  PARAMS ((cp_lexer *, enum rid));
+static cp_token *cp_lexer_consume_token
+  PARAMS ((cp_lexer *));
+static void cp_lexer_purge_token
+  (cp_lexer *);
+static void cp_lexer_purge_tokens_after
+  (cp_lexer *, cp_token *);
+static void cp_lexer_save_tokens
+  PARAMS ((cp_lexer *));
+static void cp_lexer_commit_tokens
+  PARAMS ((cp_lexer *));
+static void cp_lexer_rollback_tokens
+  PARAMS ((cp_lexer *));
+static void cp_lexer_set_source_position_from_token 
+  PARAMS ((cp_lexer *, const cp_token *));
+static void cp_lexer_print_token
+  PARAMS ((FILE *, cp_token *));
+static bool cp_lexer_debugging_p 
+  PARAMS ((cp_lexer *));
+static void cp_lexer_start_debugging
+  PARAMS ((cp_lexer *)) ATTRIBUTE_UNUSED;
+static void cp_lexer_stop_debugging
+  PARAMS ((cp_lexer *)) ATTRIBUTE_UNUSED;
+
+/* Manifest constants.  */
+
+#define CP_TOKEN_BUFFER_SIZE 5
+#define CP_SAVED_TOKENS_SIZE 5
+
+/* A token type for keywords, as opposed to ordinary identifiers.  */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* A token type for template-ids.  If a template-id is processed while
+   parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
+   the value of the CPP_TEMPLATE_ID is whatever was returned by
+   cp_parser_template_id.  */
+#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
+
+/* A token type for nested-name-specifiers.  If a
+   nested-name-specifier is processed while parsing tentatively, it is
+   replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
+   CPP_NESTED_NAME_SPECIFIER is whatever was returned by
+   cp_parser_nested_name_specifier_opt.  */
+#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
+
+/* A token type for tokens that are not tokens at all; these are used
+   to mark the end of a token block.  */
+#define CPP_NONE (CPP_NESTED_NAME_SPECIFIER + 1)
+
+/* Variables.  */
+
+/* The stream to which debugging output should be written.  */
+static FILE *cp_lexer_debug_stream;
+
+/* Create a new C++ lexer.  If MAIN_LEXER_P is true the new lexer is
+   the main lexer -- i.e, the lexer that gets tokens from the
+   preprocessor.  Otherwise, it is a lexer that uses a cache of stored
+   tokens.  */
+
+static cp_lexer *
+cp_lexer_new (bool main_lexer_p)
+{
+  cp_lexer *lexer;
+
+  /* Allocate the memory.  */
+  lexer = (cp_lexer *) ggc_alloc_cleared (sizeof (cp_lexer));
+
+  /* Create the circular buffer.  */
+  lexer->buffer = ((cp_token *) 
+                  ggc_alloc (CP_TOKEN_BUFFER_SIZE * sizeof (cp_token)));
+  lexer->buffer_end = lexer->buffer + CP_TOKEN_BUFFER_SIZE;
+
+  /* There are no tokens in the buffer.  */
+  lexer->last_token = lexer->buffer;
+
+  /* This lexer obtains more tokens by calling c_lex.  */
+  lexer->main_lexer_p = main_lexer_p;
+
+  /* Create the SAVED_TOKENS stack.  */
+  VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
+  
+  /* Create the STRINGS array.  */
+  VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
+
+  /* Assume we are not debugging.  */
+  lexer->debugging_p = false;
+
+  return lexer;
+}
+
+/* Create a new lexer whose token stream is primed with the TOKENS.
+   When these tokens are exhausted, no new tokens will be read.  */
+
+static cp_lexer *
+cp_lexer_new_from_tokens (cp_token_cache *tokens)
+{
+  cp_lexer *lexer;
+  cp_token *token;
+  cp_token_block *block;
+  ptrdiff_t num_tokens;
+
+  /* Create the lexer.  */
+  lexer = cp_lexer_new (/*main_lexer_p=*/false);
+
+  /* Create a new buffer, appropriately sized.  */
+  num_tokens = 0;
+  for (block = tokens->first; block != NULL; block = block->next)
+    num_tokens += block->num_tokens;
+  lexer->buffer = ((cp_token *) 
+                  ggc_alloc (num_tokens * sizeof (cp_token)));
+  lexer->buffer_end = lexer->buffer + num_tokens;
+  
+  /* Install the tokens.  */
+  token = lexer->buffer;
+  for (block = tokens->first; block != NULL; block = block->next)
+    {
+      memcpy (token, block->tokens, block->num_tokens * sizeof (cp_token));
+      token += block->num_tokens;
+    }
+
+  /* The FIRST_TOKEN is the beginning of the buffer.  */
+  lexer->first_token = lexer->buffer;
+  /* The next available token is also at the beginning of the buffer.  */
+  lexer->next_token = lexer->buffer;
+  /* The buffer is full.  */
+  lexer->last_token = lexer->first_token;
+
+  return lexer;
+}
+
+/* Non-zero if we are presently saving tokens.  */
+
+static int
+cp_lexer_saving_tokens (lexer)
+     const cp_lexer *lexer;
+{
+  return VARRAY_ACTIVE_SIZE (lexer->saved_tokens) != 0;
+}
+
+/* TOKEN points into the circular token buffer.  Return a pointer to
+   the next token in the buffer.  */
+
+static cp_token *
+cp_lexer_next_token (lexer, token)
+     cp_lexer *lexer;
+     cp_token *token;
+{
+  token++;
+  if (token == lexer->buffer_end)
+    token = lexer->buffer;
+  return token;
+}
+
+/* Return a pointer to the token that is N tokens beyond TOKEN in the
+   buffer.  */
+
+static cp_token *
+cp_lexer_advance_token (cp_lexer *lexer, cp_token *token, ptrdiff_t n)
+{
+  token += n;
+  if (token >= lexer->buffer_end)
+    token = lexer->buffer + (token - lexer->buffer_end);
+  return token;
+}
+
+/* Returns the number of times that START would have to be incremented
+   to reach FINISH.  If START and FINISH are the same, returns zero.  */
+
+static ptrdiff_t
+cp_lexer_token_difference (lexer, start, finish)
+     cp_lexer *lexer;
+     cp_token *start;
+     cp_token *finish;
+{
+  if (finish >= start)
+    return finish - start;
+  else
+    return ((lexer->buffer_end - lexer->buffer)
+           - (start - finish));
+}
+
+/* Obtain another token from the C preprocessor and add it to the
+   token buffer.  Returns the newly read token.  */
+
+static cp_token *
+cp_lexer_read_token (lexer)
+     cp_lexer *lexer;
+{
+  cp_token *token;
+
+  /* Make sure there is room in the buffer.  */
+  cp_lexer_maybe_grow_buffer (lexer);
+
+  /* If there weren't any tokens, then this one will be the first.  */
+  if (!lexer->first_token)
+    lexer->first_token = lexer->last_token;
+  /* Similarly, if there were no available tokens, there is one now.  */
+  if (!lexer->next_token)
+    lexer->next_token = lexer->last_token;
+
+  /* Figure out where we're going to store the new token.  */
+  token = lexer->last_token;
+
+  /* Get a new token from the preprocessor.  */
+  cp_lexer_get_preprocessor_token (lexer, token);
+
+  /* Increment LAST_TOKEN.  */
+  lexer->last_token = cp_lexer_next_token (lexer, token);
+
+  /* The preprocessor does not yet do translation phase six, i.e., the
+     combination of adjacent string literals.  Therefore, we do it
+     here.  */
+  if (token->type == CPP_STRING || token->type == CPP_WSTRING)
+    {
+      ptrdiff_t delta;
+      int i;
+
+      /* When we grow the buffer, we may invalidate TOKEN.  So, save
+        the distance from the beginning of the BUFFER so that we can
+        recaulate it.  */
+      delta = cp_lexer_token_difference (lexer, lexer->buffer, token);
+      /* Make sure there is room in the buffer for another token.  */
+      cp_lexer_maybe_grow_buffer (lexer);
+      /* Restore TOKEN.  */
+      token = lexer->buffer;
+      for (i = 0; i < delta; ++i)
+       token = cp_lexer_next_token (lexer, token);
+
+      VARRAY_PUSH_TREE (lexer->string_tokens, token->value);
+      while (true)
+       {
+         /* Read the token after TOKEN.  */
+         cp_lexer_get_preprocessor_token (lexer, lexer->last_token);
+         /* See whether it's another string constant.  */
+         if (lexer->last_token->type != token->type)
+           {
+             /* If not, then it will be the next real token.  */
+             lexer->last_token = cp_lexer_next_token (lexer, 
+                                                      lexer->last_token);
+             break;
+           }
+
+         /* Chain the strings together.  */
+         VARRAY_PUSH_TREE (lexer->string_tokens, 
+                           lexer->last_token->value);
+       }
+
+      /* Create a single STRING_CST.  Curiously we have to call
+        combine_strings even if there is only a single string in
+        order to get the type set correctly.  */
+      token->value = combine_strings (lexer->string_tokens);
+      VARRAY_CLEAR (lexer->string_tokens);
+      token->value = fix_string_type (token->value);
+      /* Strings should have type `const char []'.  Right now, we will
+        have an ARRAY_TYPE that is constant rather than an array of
+        constant elements.  */
+      if (flag_const_strings)
+       {
+         tree type;
+
+         /* Get the current type.  It will be an ARRAY_TYPE.  */
+         type = TREE_TYPE (token->value);
+         /* Use build_cplus_array_type to rebuild the array, thereby
+            getting the right type.  */
+         type = build_cplus_array_type (TREE_TYPE (type),
+                                        TYPE_DOMAIN (type));
+         /* Reset the type of the token.  */
+         TREE_TYPE (token->value) = type;
+       }
+    }
+
+  return token;
+}
+
+/* If the circular buffer is full, make it bigger.  */
+
+static void
+cp_lexer_maybe_grow_buffer (lexer)
+     cp_lexer *lexer;
+{
+  /* If the buffer is full, enlarge it.  */
+  if (lexer->last_token == lexer->first_token)
+    {
+      cp_token *new_buffer;
+      cp_token *old_buffer;
+      cp_token *new_first_token;
+      ptrdiff_t buffer_length;
+      size_t num_tokens_to_copy;
+
+      /* Remember the current buffer pointer.  It will become invalid,
+        but we will need to do pointer arithmetic involving this
+        value.  */
+      old_buffer = lexer->buffer;
+      /* Compute the current buffer size.  */
+      buffer_length = lexer->buffer_end - lexer->buffer;
+      /* Allocate a buffer twice as big.  */
+      new_buffer = ((cp_token *)
+                   ggc_realloc (lexer->buffer, 
+                                2 * buffer_length * sizeof (cp_token)));
+      
+      /* Because the buffer is circular, logically consecutive tokens
+        are not necessarily placed consecutively in memory.
+        Therefore, we must keep move the tokens that were before
+        FIRST_TOKEN to the second half of the newly allocated
+        buffer.  */
+      num_tokens_to_copy = (lexer->first_token - old_buffer);
+      memcpy (new_buffer + buffer_length,
+             new_buffer,
+             num_tokens_to_copy * sizeof (cp_token));
+      /* Clear the rest of the buffer.  We never look at this storage,
+        but the garbage collector may.  */
+      memset (new_buffer + buffer_length + num_tokens_to_copy, 0, 
+             (buffer_length - num_tokens_to_copy) * sizeof (cp_token));
+
+      /* Now recompute all of the buffer pointers.  */
+      new_first_token 
+       = new_buffer + (lexer->first_token - old_buffer);
+      if (lexer->next_token != NULL)
+       {
+         ptrdiff_t next_token_delta;
+
+         if (lexer->next_token > lexer->first_token)
+           next_token_delta = lexer->next_token - lexer->first_token;
+         else
+           next_token_delta = 
+             buffer_length - (lexer->first_token - lexer->next_token);
+         lexer->next_token = new_first_token + next_token_delta;
+       }
+      lexer->last_token = new_first_token + buffer_length;
+      lexer->buffer = new_buffer;
+      lexer->buffer_end = new_buffer + buffer_length * 2;
+      lexer->first_token = new_first_token;
+    }
+}
+
+/* Store the next token from the preprocessor in *TOKEN.  */
+
+static void 
+cp_lexer_get_preprocessor_token (lexer, token)
+     cp_lexer *lexer ATTRIBUTE_UNUSED;
+     cp_token *token;
+{
+  bool done;
+
+  /* If this not the main lexer, return a terminating CPP_EOF token.  */
+  if (!lexer->main_lexer_p)
+    {
+      token->type = CPP_EOF;
+      token->line_number = 0;
+      token->file_name = NULL;
+      token->value = NULL_TREE;
+      token->keyword = RID_MAX;
+
+      return;
+    }
+
+  done = false;
+  /* Keep going until we get a token we like.  */
+  while (!done)
+    {
+      /* Get a new token from the preprocessor.  */
+      token->type = c_lex (&token->value);
+      /* Issue messages about tokens we cannot process.  */
+      switch (token->type)
+       {
+       case CPP_ATSIGN:
+       case CPP_HASH:
+       case CPP_PASTE:
+         error ("invalid token");
+         break;
+
+       case CPP_OTHER:
+         /* These tokens are already warned about by c_lex.  */
+         break;
+
+       default:
+         /* This is a good token, so we exit the loop.  */
+         done = true;
+         break;
+       }
+    }
+  /* Now we've got our token.  */
+  token->line_number = lineno;
+  token->file_name = input_filename;
+
+  /* Check to see if this token is a keyword.  */
+  if (token->type == CPP_NAME 
+      && C_IS_RESERVED_WORD (token->value))
+    {
+      /* Mark this token as a keyword.  */
+      token->type = CPP_KEYWORD;
+      /* Record which keyword.  */
+      token->keyword = C_RID_CODE (token->value);
+      /* Update the value.  Some keywords are mapped to particular
+        entities, rather than simply having the value of the
+        corresponding IDENTIFIER_NODE.  For example, `__const' is
+        mapped to `const'.  */
+      token->value = ridpointers[token->keyword];
+    }
+  else
+    token->keyword = RID_MAX;
+}
+
+/* Return a pointer to the next token in the token stream, but do not
+   consume it.  */
+
+static cp_token *
+cp_lexer_peek_token (lexer)
+     cp_lexer *lexer;
+{
+  cp_token *token;
+
+  /* If there are no tokens, read one now.  */
+  if (!lexer->next_token)
+    cp_lexer_read_token (lexer);
+
+  /* Provide debugging output.  */
+  if (cp_lexer_debugging_p (lexer))
+    {
+      fprintf (cp_lexer_debug_stream, "cp_lexer: peeking at token: ");
+      cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
+      fprintf (cp_lexer_debug_stream, "\n");
+    }
+
+  token = lexer->next_token;
+  cp_lexer_set_source_position_from_token (lexer, token);
+  return token;
+}
+
+/* Return true if the next token has the indicated TYPE.  */
+
+static bool
+cp_lexer_next_token_is (lexer, type)
+     cp_lexer *lexer;
+     enum cpp_ttype type;
+{
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (lexer);
+  /* Check to see if it has the indicated TYPE.  */
+  return token->type == type;
+}
+
+/* Return true if the next token does not have the indicated TYPE.  */
+
+static bool
+cp_lexer_next_token_is_not (lexer, type)
+     cp_lexer *lexer;
+     enum cpp_ttype type;
+{
+  return !cp_lexer_next_token_is (lexer, type);
+}
+
+/* Return true if the next token is the indicated KEYWORD.  */
+
+static bool
+cp_lexer_next_token_is_keyword (lexer, keyword)
+     cp_lexer *lexer;
+     enum rid keyword;
+{
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (lexer);
+  /* Check to see if it is the indicated keyword.  */
+  return token->keyword == keyword;
+}
+
+/* Return a pointer to the Nth token in the token stream.  If N is 1,
+   then this is precisely equivalent to cp_lexer_peek_token.  */
+
+static cp_token *
+cp_lexer_peek_nth_token (lexer, n)
+     cp_lexer *lexer;
+     size_t n;
+{
+  cp_token *token;
+
+  /* N is 1-based, not zero-based.  */
+  my_friendly_assert (n > 0, 20000224);
+
+  /* Skip ahead from NEXT_TOKEN, reading more tokens as necessary.  */
+  token = lexer->next_token;
+  /* If there are no tokens in the buffer, get one now.  */
+  if (!token)
+    {
+      cp_lexer_read_token (lexer);
+      token = lexer->next_token;
+    }
+
+  /* Now, read tokens until we have enough.  */
+  while (--n > 0)
+    {
+      /* Advance to the next token.  */
+      token = cp_lexer_next_token (lexer, token);
+      /* If that's all the tokens we have, read a new one.  */
+      if (token == lexer->last_token)
+       token = cp_lexer_read_token (lexer);
+    }
+
+  return token;
+}
+
+/* Consume the next token.  The pointer returned is valid only until
+   another token is read.  Callers should preserve copy the token
+   explicitly if they will need its value for a longer period of
+   time.  */
+
+static cp_token *
+cp_lexer_consume_token (lexer)
+     cp_lexer *lexer;
+{
+  cp_token *token;
+
+  /* If there are no tokens, read one now.  */
+  if (!lexer->next_token)
+    cp_lexer_read_token (lexer);
+
+  /* Remember the token we'll be returning.  */
+  token = lexer->next_token;
+
+  /* Increment NEXT_TOKEN.  */
+  lexer->next_token = cp_lexer_next_token (lexer, 
+                                          lexer->next_token);
+  /* Check to see if we're all out of tokens.  */
+  if (lexer->next_token == lexer->last_token)
+    lexer->next_token = NULL;
+
+  /* If we're not saving tokens, then move FIRST_TOKEN too.  */
+  if (!cp_lexer_saving_tokens (lexer))
+    {
+      /* If there are no tokens available, set FIRST_TOKEN to NULL.  */
+      if (!lexer->next_token)
+       lexer->first_token = NULL;
+      else
+       lexer->first_token = lexer->next_token;
+    }
+
+  /* Provide debugging output.  */
+  if (cp_lexer_debugging_p (lexer))
+    {
+      fprintf (cp_lexer_debug_stream, "cp_lexer: consuming token: ");
+      cp_lexer_print_token (cp_lexer_debug_stream, token);
+      fprintf (cp_lexer_debug_stream, "\n");
+    }
+
+  return token;
+}
+
+/* Permanently remove the next token from the token stream.  There
+   must be a valid next token already; this token never reads
+   additional tokens from the preprocessor.  */
+
+static void
+cp_lexer_purge_token (cp_lexer *lexer)
+{
+  cp_token *token;
+  cp_token *next_token;
+
+  token = lexer->next_token;
+  while (true) 
+    {
+      next_token = cp_lexer_next_token (lexer, token);
+      if (next_token == lexer->last_token)
+       break;
+      *token = *next_token;
+      token = next_token;
+    }
+
+  lexer->last_token = token;
+  /* The token purged may have been the only token remaining; if so,
+     clear NEXT_TOKEN.  */
+  if (lexer->next_token == token)
+    lexer->next_token = NULL;
+}
+
+/* Permanently remove all tokens after TOKEN, up to, but not
+   including, the token that will be returned next by
+   cp_lexer_peek_token.  */
+
+static void
+cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *token)
+{
+  cp_token *peek;
+  cp_token *t1;
+  cp_token *t2;
+
+  if (lexer->next_token)
+    {
+      /* Copy the tokens that have not yet been read to the location
+        immediately following TOKEN.  */
+      t1 = cp_lexer_next_token (lexer, token);
+      t2 = peek = cp_lexer_peek_token (lexer);
+      /* Move tokens into the vacant area between TOKEN and PEEK.  */
+      while (t2 != lexer->last_token)
+       {
+         *t1 = *t2;
+         t1 = cp_lexer_next_token (lexer, t1);
+         t2 = cp_lexer_next_token (lexer, t2);
+       }
+      /* Now, the next available token is right after TOKEN.  */
+      lexer->next_token = cp_lexer_next_token (lexer, token);
+      /* And the last token is wherever we ended up.  */
+      lexer->last_token = t1;
+    }
+  else
+    {
+      /* There are no tokens in the buffer, so there is nothing to
+        copy.  The last token in the buffer is TOKEN itself.  */
+      lexer->last_token = cp_lexer_next_token (lexer, token);
+    }
+}
+
+/* Begin saving tokens.  All tokens consumed after this point will be
+   preserved.  */
+
+static void
+cp_lexer_save_tokens (lexer)
+     cp_lexer *lexer;
+{
+  /* Provide debugging output.  */
+  if (cp_lexer_debugging_p (lexer))
+    fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
+
+  /* Make sure that LEXER->NEXT_TOKEN is non-NULL so that we can
+     restore the tokens if required.  */
+  if (!lexer->next_token)
+    cp_lexer_read_token (lexer);
+
+  VARRAY_PUSH_INT (lexer->saved_tokens,
+                  cp_lexer_token_difference (lexer,
+                                             lexer->first_token,
+                                             lexer->next_token));
+}
+
+/* Commit to the portion of the token stream most recently saved.  */
+
+static void
+cp_lexer_commit_tokens (lexer)
+     cp_lexer *lexer;
+{
+  /* Provide debugging output.  */
+  if (cp_lexer_debugging_p (lexer))
+    fprintf (cp_lexer_debug_stream, "cp_lexer: committing tokens\n");
+
+  VARRAY_POP (lexer->saved_tokens);
+}
+
+/* Return all tokens saved since the last call to cp_lexer_save_tokens
+   to the token stream.  Stop saving tokens.  */
+
+static void
+cp_lexer_rollback_tokens (lexer)
+     cp_lexer *lexer;
+{
+  size_t delta;
+
+  /* Provide debugging output.  */
+  if (cp_lexer_debugging_p (lexer))
+    fprintf (cp_lexer_debug_stream, "cp_lexer: restoring tokens\n");
+
+  /* Find the token that was the NEXT_TOKEN when we started saving
+     tokens.  */
+  delta = VARRAY_TOP_INT(lexer->saved_tokens);
+  /* Make it the next token again now.  */
+  lexer->next_token = cp_lexer_advance_token (lexer,
+                                             lexer->first_token, 
+                                             delta);
+  /* It might be the case that there wer no tokens when we started
+     saving tokens, but that there are some tokens now.  */
+  if (!lexer->next_token && lexer->first_token)
+    lexer->next_token = lexer->first_token;
+
+  /* Stop saving tokens.  */
+  VARRAY_POP (lexer->saved_tokens);
+}
+
+/* Set the current source position from the information stored in
+   TOKEN.  */
+
+static void
+cp_lexer_set_source_position_from_token (lexer, token)
+     cp_lexer *lexer ATTRIBUTE_UNUSED;
+     const cp_token *token;
+{
+  /* Ideally, the source position information would not be a global
+     variable, but it is.  */
+
+  /* Update the line number.  */
+  if (token->type != CPP_EOF)
+    {
+      lineno = token->line_number;
+      input_filename = token->file_name;
+    }
+}
+
+/* Print a representation of the TOKEN on the STREAM.  */
+
+static void
+cp_lexer_print_token (stream, token)
+     FILE *stream;
+     cp_token *token;
+{
+  const char *token_type = NULL;
+
+  /* Figure out what kind of token this is.  */
+  switch (token->type)
+    {
+    case CPP_EQ:
+      token_type = "EQ";
+      break;
+
+    case CPP_COMMA:
+      token_type = "COMMA";
+      break;
+
+    case CPP_OPEN_PAREN:
+      token_type = "OPEN_PAREN";
+      break;
+
+    case CPP_CLOSE_PAREN:
+      token_type = "CLOSE_PAREN";
+      break;
+
+    case CPP_OPEN_BRACE:
+      token_type = "OPEN_BRACE";
+      break;
+
+    case CPP_CLOSE_BRACE:
+      token_type = "CLOSE_BRACE";
+      break;
+
+    case CPP_SEMICOLON:
+      token_type = "SEMICOLON";
+      break;
+
+    case CPP_NAME:
+      token_type = "NAME";
+      break;
+
+    case CPP_EOF:
+      token_type = "EOF";
+      break;
+
+    case CPP_KEYWORD:
+      token_type = "keyword";
+      break;
+
+      /* This is not a token that we know how to handle yet.  */
+    default:
+      break;
+    }
+
+  /* If we have a name for the token, print it out.  Otherwise, we
+     simply give the numeric code.  */
+  if (token_type)
+    fprintf (stream, "%s", token_type);
+  else
+    fprintf (stream, "%d", token->type);
+  /* And, for an identifier, print the identifier name.  */
+  if (token->type == CPP_NAME 
+      /* Some keywords have a value that is not an IDENTIFIER_NODE.
+        For example, `struct' is mapped to an INTEGER_CST.  */
+      || (token->type == CPP_KEYWORD 
+         && TREE_CODE (token->value) == IDENTIFIER_NODE))
+    fprintf (stream, " %s", IDENTIFIER_POINTER (token->value));
+}
+
+/* Returns non-zero if debugging information should be output.  */
+
+static bool
+cp_lexer_debugging_p (lexer)
+     cp_lexer *lexer;
+{
+  return lexer->debugging_p;
+}
+
+/* Start emitting debugging information.  */
+
+static void
+cp_lexer_start_debugging (lexer)
+     cp_lexer *lexer;
+{
+  ++lexer->debugging_p;
+}
+  
+/* Stop emitting debugging information.  */
+
+static void
+cp_lexer_stop_debugging (lexer)
+     cp_lexer *lexer;
+{
+  --lexer->debugging_p;
+}
+
+\f
+/* The parser.  */
+
+/* Overview
+   --------
+
+   A cp_parser parses the token stream as specified by the C++
+   grammar.  Its job is purely parsing, not semantic analysis.  For
+   example, the parser breaks the token stream into declarators,
+   expressions, statements, and other similar syntactic constructs.
+   It does not check that the types of the expressions on either side
+   of an assignment-statement are compatible, or that a function is
+   not declared with a parameter of type `void'.
+
+   The parser invokes routines elsewhere in the compiler to perform
+   semantic analysis and to build up the abstract syntax tree for the
+   code processed.  
+
+   The parser (and the template instantiation code, which is, in a
+   way, a close relative of parsing) are the only parts of the
+   compiler that should be calling push_scope and pop_scope, or
+   related functions.  The parser (and template instantiation code)
+   keeps track of what scope is presently active; everything else
+   should simply honor that.  (The code that generates static
+   initializers may also need to set the scope, in order to check
+   access control correctly when emitting the initializers.)
+
+   Methodology
+   -----------
+   
+   The parser is of the standard recursive-descent variety.  Upcoming
+   tokens in the token stream are examined in order to determine which
+   production to use when parsing a non-terminal.  Some C++ constructs
+   require arbitrary look ahead to disambiguate.  For example, it is
+   impossible, in the general case, to tell whether a statement is an
+   expression or declaration without scanning the entire statement.
+   Therefore, the parser is capable of "parsing tentatively."  When the
+   parser is not sure what construct comes next, it enters this mode.
+   Then, while we attempt to parse the construct, the parser queues up
+   error messages, rather than issuing them immediately, and saves the
+   tokens it consumes.  If the construct is parsed successfully, the
+   parser "commits", i.e., it issues any queued error messages and
+   the tokens that were being preserved are permanently discarded.
+   If, however, the construct is not parsed successfully, the parser
+   rolls back its state completely so that it can resume parsing using
+   a different alternative.
+
+   Future Improvements
+   -------------------
+   
+   The performance of the parser could probably be improved
+   substantially.  Some possible improvements include:
+
+     - The expression parser recurses through the various levels of
+       precedence as specified in the grammar, rather than using an
+       operator-precedence technique.  Therefore, parsing a simple
+       identifier requires multiple recursive calls.
+
+     - We could often eliminate the need to parse tentatively by
+       looking ahead a little bit.  In some places, this approach
+       might not entirely eliminate the need to parse tentatively, but
+       it might still speed up the average case.  */
+
+/* Flags that are passed to some parsing functions.  These values can
+   be bitwise-ored together.  */
+
+typedef enum cp_parser_flags
+{
+  /* No flags.  */
+  CP_PARSER_FLAGS_NONE = 0x0,
+  /* The construct is optional.  If it is not present, then no error
+     should be issued.  */
+  CP_PARSER_FLAGS_OPTIONAL = 0x1,
+  /* When parsing a type-specifier, do not allow user-defined types.  */
+  CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2
+} cp_parser_flags;
+
+/* The different kinds of ids that we ecounter.  */
+
+typedef enum cp_parser_id_kind
+{
+  /* Not an id at all.  */
+  CP_PARSER_ID_KIND_NONE,
+  /* An unqualified-id that is not a template-id.  */
+  CP_PARSER_ID_KIND_UNQUALIFIED,
+  /* An unqualified template-id.  */
+  CP_PARSER_ID_KIND_TEMPLATE_ID,
+  /* A qualified-id.  */
+  CP_PARSER_ID_KIND_QUALIFIED
+} cp_parser_id_kind;
+
+/* A mapping from a token type to a corresponding tree node type.  */
+
+typedef struct cp_parser_token_tree_map_node
+{
+  /* The token type.  */
+  enum cpp_ttype token_type;
+  /* The corresponding tree code.  */
+  enum tree_code tree_type;
+} cp_parser_token_tree_map_node;
+
+/* A complete map consists of several ordinary entries, followed by a
+   terminator.  The terminating entry has a token_type of CPP_EOF.  */
+
+typedef cp_parser_token_tree_map_node cp_parser_token_tree_map[];
+
+/* The status of a tentative parse.  */
+
+typedef enum cp_parser_status_kind
+{
+  /* No errors have occurred.  */
+  CP_PARSER_STATUS_KIND_NO_ERROR,
+  /* An error has occurred.  */
+  CP_PARSER_STATUS_KIND_ERROR,
+  /* We are committed to this tentative parse, whether or not an error
+     has occurred.  */
+  CP_PARSER_STATUS_KIND_COMMITTED
+} cp_parser_status_kind;
+
+/* Context that is saved and restored when parsing tentatively.  */
+
+typedef struct cp_parser_context GTY (())
+{
+  /* If this is a tentative parsing context, the status of the
+     tentative parse.  */
+  enum cp_parser_status_kind status;
+  /* If non-NULL, we have just seen a `x->' or `x.' expression.  Names
+     that are looked up in this context must be looked up both in the
+     scope given by OBJECT_TYPE (the type of `x' or `*x') and also in
+     the context of the containing expression.  */
+  tree object_type;
+  /* A TREE_LIST representing name-lookups for which we have deferred
+     checking access controls.  We cannot check the accessibility of
+     names used in a decl-specifier-seq until we know what is being
+     declared because code like:
+
+       class A { 
+         class B {};
+         B* f();
+       }
+
+       A::B* A::f() { return 0; }
+
+     is valid, even though `A::B' is not generally accessible.  
+
+     The TREE_PURPOSE of each node is the scope used to qualify the
+     name being looked up; the TREE_VALUE is the DECL to which the
+     name was resolved.  */
+  tree deferred_access_checks;
+  /* TRUE iff we are deferring access checks.  */
+  bool deferring_access_checks_p;
+  /* The next parsing context in the stack.  */
+  struct cp_parser_context *next;
+} cp_parser_context;
+
+/* Prototypes.  */
+
+/* Constructors and destructors.  */
+
+static cp_parser_context *cp_parser_context_new
+  PARAMS ((cp_parser_context *));
+
+/* Constructors and destructors.  */
+
+/* Construct a new context.  The context below this one on the stack
+   is given by NEXT.  */
+
+static cp_parser_context *
+cp_parser_context_new (next)
+     cp_parser_context *next;
+{
+  cp_parser_context *context;
+
+  /* Allocate the storage.  */
+  context = ((cp_parser_context *) 
+            ggc_alloc_cleared (sizeof (cp_parser_context)));
+  /* No errors have occurred yet in this context.  */
+  context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
+  /* If this is not the bottomost context, copy information that we
+     need from the previous context.  */
+  if (next)
+    {
+      /* If, in the NEXT context, we are parsing an `x->' or `x.'
+        expression, then we are parsing one in this context, too.  */
+      context->object_type = next->object_type;
+      /* We are deferring access checks here if we were in the NEXT
+        context.  */
+      context->deferring_access_checks_p 
+       = next->deferring_access_checks_p;
+      /* Thread the stack.  */
+      context->next = next;
+    }
+
+  return context;
+}
+
+/* The cp_parser structure represents the C++ parser.  */
+
+typedef struct cp_parser GTY(())
+{
+  /* The lexer from which we are obtaining tokens.  */
+  cp_lexer *lexer;
+
+  /* The scope in which names should be looked up.  If NULL_TREE, then
+     we look up names in the scope that is currently open in the
+     source program.  If non-NULL, this is either a TYPE or
+     NAMESPACE_DECL for the scope in which we should look.  
+
+     This value is not cleared automatically after a name is looked
+     up, so we must be careful to clear it before starting a new look
+     up sequence.  (If it is not cleared, then `X::Y' followed by `Z'
+     will look up `Z' in the scope of `X', rather than the current
+     scope.)  Unfortunately, it is difficult to tell when name lookup
+     is complete, because we sometimes peek at a token, look it up,
+     and then decide not to consume it.  */
+  tree scope;
+
+  /* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
+     last lookup took place.  OBJECT_SCOPE is used if an expression
+     like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
+     respectively.  QUALIFYING_SCOPE is used for an expression of the 
+     form "X::Y"; it refers to X.  */
+  tree object_scope;
+  tree qualifying_scope;
+
+  /* A stack of parsing contexts.  All but the bottom entry on the
+     stack will be tentative contexts.
+
+     We parse tentatively in order to determine which construct is in
+     use in some situations.  For example, in order to determine
+     whether a statement is an expression-statement or a
+     declaration-statement we parse it tentatively as a
+     declaration-statement.  If that fails, we then reparse the same
+     token stream as an expression-statement.  */
+  cp_parser_context *context;
+
+  /* True if we are parsing GNU C++.  If this flag is not set, then
+     GNU extensions are not recognized.  */
+  bool allow_gnu_extensions_p;
+
+  /* TRUE if the `>' token should be interpreted as the greater-than
+     operator.  FALSE if it is the end of a template-id or
+     template-parameter-list.  */
+  bool greater_than_is_operator_p;
+
+  /* TRUE if default arguments are allowed within a parameter list
+     that starts at this point. FALSE if only a gnu extension makes
+     them permissable.  */
+  bool default_arg_ok_p;
+  
+  /* TRUE if we are parsing an integral constant-expression.  See
+     [expr.const] for a precise definition.  */
+  /* FIXME: Need to implement code that checks this flag.  */
+  bool constant_expression_p;
+
+  /* TRUE if local variable names and `this' are forbidden in the
+     current context.  */
+  bool local_variables_forbidden_p;
+
+  /* TRUE if the declaration we are parsing is part of a
+     linkage-specification of the form `extern string-literal
+     declaration'.  */
+  bool in_unbraced_linkage_specification_p;
+
+  /* TRUE if we are presently parsing a declarator, after the
+     direct-declarator.  */
+  bool in_declarator_p;
+
+  /* If non-NULL, then we are parsing a construct where new type
+     definitions are not permitted.  The string stored here will be
+     issued as an error message if a type is defined.  */
+  const char *type_definition_forbidden_message;
+
+  /* List of FUNCTION_TYPEs which contain unprocessed DEFAULT_ARGs
+     during class parsing, and are not FUNCTION_DECLs.  G++ has an
+     awkward extension allowing default args on pointers to functions
+     etc.  */
+  tree default_arg_types;
+
+  /* A TREE_LIST of queues of functions whose bodies have been lexed,
+     but may not have been parsed.  These functions are friends of
+     members defined within a class-specification; they are not
+     procssed until the class is complete.  The active queue is at the
+     front of the list.
+
+     Within each queue, functions appear in the reverse order that
+     they appeared in the source.  The TREE_PURPOSE of each node is
+     the class in which the function was defined or declared; the
+     TREE_VALUE is the FUNCTION_DECL itself.  */
+  tree unparsed_functions_queues;
+
+  /* The number of classes whose definitions are currently in
+     progress.  */
+  unsigned num_classes_being_defined;
+
+  /* The number of template parameter lists that apply directly to the
+     current declaration.  */
+  unsigned num_template_parameter_lists;
+} cp_parser;
+
+/* The type of a function that parses some kind of expression  */
+typedef tree (*cp_parser_expression_fn) PARAMS ((cp_parser *));
+
+/* Prototypes.  */
+
+/* Constructors and destructors.  */
+
+static cp_parser *cp_parser_new
+  PARAMS ((void));
+
+/* Routines to parse various constructs.  
+
+   Those that return `tree' will return the error_mark_node (rather
+   than NULL_TREE) if a parse error occurs, unless otherwise noted.
+   Sometimes, they will return an ordinary node if error-recovery was
+   attempted, even though a parse error occurrred.  So, to check
+   whether or not a parse error occurred, you should always use
+   cp_parser_error_occurred.  If the construct is optional (indicated
+   either by an `_opt' in the name of the function that does the
+   parsing or via a FLAGS parameter), then NULL_TREE is returned if
+   the construct is not present.  */
+
+/* Lexical conventions [gram.lex]  */
+
+static tree cp_parser_identifier
+  PARAMS ((cp_parser *));
+
+/* Basic concepts [gram.basic]  */
+
+static bool cp_parser_translation_unit
+  PARAMS ((cp_parser *));
+
+/* Expressions [gram.expr]  */
+
+static tree cp_parser_primary_expression
+  (cp_parser *, cp_parser_id_kind *, tree *);
+static tree cp_parser_id_expression
+  PARAMS ((cp_parser *, bool, bool, bool *));
+static tree cp_parser_unqualified_id
+  PARAMS ((cp_parser *, bool, bool));
+static tree cp_parser_nested_name_specifier_opt
+  (cp_parser *, bool, bool, bool);
+static tree cp_parser_nested_name_specifier
+  (cp_parser *, bool, bool, bool);
+static tree cp_parser_class_or_namespace_name
+  (cp_parser *, bool, bool, bool, bool);
+static tree cp_parser_postfix_expression
+  (cp_parser *, bool);
+static tree cp_parser_expression_list
+  PARAMS ((cp_parser *));
+static void cp_parser_pseudo_destructor_name
+  PARAMS ((cp_parser *, tree *, tree *));
+static tree cp_parser_unary_expression
+  (cp_parser *, bool);
+static enum tree_code cp_parser_unary_operator
+  PARAMS ((cp_token *));
+static tree cp_parser_new_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_new_placement
+  PARAMS ((cp_parser *));
+static tree cp_parser_new_type_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_new_declarator_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_direct_new_declarator
+  PARAMS ((cp_parser *));
+static tree cp_parser_new_initializer
+  PARAMS ((cp_parser *));
+static tree cp_parser_delete_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_cast_expression 
+  (cp_parser *, bool);
+static tree cp_parser_pm_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_multiplicative_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_additive_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_shift_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_relational_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_equality_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_and_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_exclusive_or_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_inclusive_or_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_logical_and_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_logical_or_expression 
+  PARAMS ((cp_parser *));
+static tree cp_parser_conditional_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_question_colon_clause
+  PARAMS ((cp_parser *, tree));
+static tree cp_parser_assignment_expression
+  PARAMS ((cp_parser *));
+static enum tree_code cp_parser_assignment_operator_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_constant_expression
+  PARAMS ((cp_parser *));
+
+/* Statements [gram.stmt.stmt]  */
+
+static void cp_parser_statement
+  PARAMS ((cp_parser *));
+static tree cp_parser_labeled_statement
+  PARAMS ((cp_parser *));
+static tree cp_parser_expression_statement
+  PARAMS ((cp_parser *));
+static tree cp_parser_compound_statement
+  (cp_parser *);
+static void cp_parser_statement_seq_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_selection_statement
+  PARAMS ((cp_parser *));
+static tree cp_parser_condition
+  PARAMS ((cp_parser *));
+static tree cp_parser_iteration_statement
+  PARAMS ((cp_parser *));
+static void cp_parser_for_init_statement
+  PARAMS ((cp_parser *));
+static tree cp_parser_jump_statement
+  PARAMS ((cp_parser *));
+static void cp_parser_declaration_statement
+  PARAMS ((cp_parser *));
+
+static tree cp_parser_implicitly_scoped_statement
+  PARAMS ((cp_parser *));
+static void cp_parser_already_scoped_statement
+  PARAMS ((cp_parser *));
+
+/* Declarations [gram.dcl.dcl] */
+
+static void cp_parser_declaration_seq_opt
+  PARAMS ((cp_parser *));
+static void cp_parser_declaration
+  PARAMS ((cp_parser *));
+static void cp_parser_block_declaration
+  PARAMS ((cp_parser *, bool));
+static void cp_parser_simple_declaration
+  PARAMS ((cp_parser *, bool));
+static tree cp_parser_decl_specifier_seq 
+  PARAMS ((cp_parser *, cp_parser_flags, tree *, bool *));
+static tree cp_parser_storage_class_specifier_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_function_specifier_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_type_specifier
+ (cp_parser *, cp_parser_flags, bool, bool, bool *, bool *);
+static tree cp_parser_simple_type_specifier
+  PARAMS ((cp_parser *, cp_parser_flags));
+static tree cp_parser_type_name
+  PARAMS ((cp_parser *));
+static tree cp_parser_elaborated_type_specifier
+  PARAMS ((cp_parser *, bool, bool));
+static tree cp_parser_enum_specifier
+  PARAMS ((cp_parser *));
+static void cp_parser_enumerator_list
+  PARAMS ((cp_parser *, tree));
+static void cp_parser_enumerator_definition 
+  PARAMS ((cp_parser *, tree));
+static tree cp_parser_namespace_name
+  PARAMS ((cp_parser *));
+static void cp_parser_namespace_definition
+  PARAMS ((cp_parser *));
+static void cp_parser_namespace_body
+  PARAMS ((cp_parser *));
+static tree cp_parser_qualified_namespace_specifier
+  PARAMS ((cp_parser *));
+static void cp_parser_namespace_alias_definition
+  PARAMS ((cp_parser *));
+static void cp_parser_using_declaration
+  PARAMS ((cp_parser *));
+static void cp_parser_using_directive
+  PARAMS ((cp_parser *));
+static void cp_parser_asm_definition
+  PARAMS ((cp_parser *));
+static void cp_parser_linkage_specification
+  PARAMS ((cp_parser *));
+
+/* Declarators [gram.dcl.decl] */
+
+static tree cp_parser_init_declarator
+  PARAMS ((cp_parser *, tree, tree, tree, bool, bool, bool *));
+static tree cp_parser_declarator
+  PARAMS ((cp_parser *, bool, bool *));
+static tree cp_parser_direct_declarator
+  PARAMS ((cp_parser *, bool, bool *));
+static enum tree_code cp_parser_ptr_operator
+  PARAMS ((cp_parser *, tree *, tree *));
+static tree cp_parser_cv_qualifier_seq_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_cv_qualifier_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_declarator_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_type_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_type_specifier_seq
+  PARAMS ((cp_parser *));
+static tree cp_parser_parameter_declaration_clause
+  PARAMS ((cp_parser *));
+static tree cp_parser_parameter_declaration_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_parameter_declaration
+  PARAMS ((cp_parser *, bool));
+static tree cp_parser_function_definition
+  PARAMS ((cp_parser *, bool *));
+static void cp_parser_function_body
+  (cp_parser *);
+static tree cp_parser_initializer
+  PARAMS ((cp_parser *, bool *));
+static tree cp_parser_initializer_clause
+  PARAMS ((cp_parser *));
+static tree cp_parser_initializer_list
+  PARAMS ((cp_parser *));
+
+static bool cp_parser_ctor_initializer_opt_and_function_body
+  (cp_parser *);
+
+/* Classes [gram.class] */
+
+static tree cp_parser_class_name
+  (cp_parser *, bool, bool, bool, bool, bool, bool);
+static tree cp_parser_class_specifier
+  PARAMS ((cp_parser *));
+static tree cp_parser_class_head
+  PARAMS ((cp_parser *, bool *, bool *, tree *));
+static enum tag_types cp_parser_class_key
+  PARAMS ((cp_parser *));
+static void cp_parser_member_specification_opt
+  PARAMS ((cp_parser *));
+static void cp_parser_member_declaration
+  PARAMS ((cp_parser *));
+static tree cp_parser_pure_specifier
+  PARAMS ((cp_parser *));
+static tree cp_parser_constant_initializer
+  PARAMS ((cp_parser *));
+
+/* Derived classes [gram.class.derived] */
+
+static tree cp_parser_base_clause
+  PARAMS ((cp_parser *));
+static tree cp_parser_base_specifier
+  PARAMS ((cp_parser *));
+
+/* Special member functions [gram.special] */
+
+static tree cp_parser_conversion_function_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_conversion_type_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_conversion_declarator_opt
+  PARAMS ((cp_parser *));
+static bool cp_parser_ctor_initializer_opt
+  PARAMS ((cp_parser *));
+static void cp_parser_mem_initializer_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_mem_initializer
+  PARAMS ((cp_parser *));
+static tree cp_parser_mem_initializer_id
+  PARAMS ((cp_parser *));
+
+/* Overloading [gram.over] */
+
+static tree cp_parser_operator_function_id
+  PARAMS ((cp_parser *));
+static tree cp_parser_operator
+  PARAMS ((cp_parser *));
+
+/* Templates [gram.temp] */
+
+static void cp_parser_template_declaration
+  PARAMS ((cp_parser *, bool));
+static tree cp_parser_template_parameter_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_template_parameter
+  PARAMS ((cp_parser *));
+static tree cp_parser_type_parameter
+  PARAMS ((cp_parser *));
+static tree cp_parser_template_id
+  PARAMS ((cp_parser *, bool, bool));
+static tree cp_parser_template_name
+  PARAMS ((cp_parser *, bool, bool));
+static tree cp_parser_template_argument_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_template_argument
+  PARAMS ((cp_parser *));
+static void cp_parser_explicit_instantiation
+  PARAMS ((cp_parser *));
+static void cp_parser_explicit_specialization
+  PARAMS ((cp_parser *));
+
+/* Exception handling [gram.exception] */
+
+static tree cp_parser_try_block 
+  PARAMS ((cp_parser *));
+static bool cp_parser_function_try_block
+  PARAMS ((cp_parser *));
+static void cp_parser_handler_seq
+  PARAMS ((cp_parser *));
+static void cp_parser_handler
+  PARAMS ((cp_parser *));
+static tree cp_parser_exception_declaration
+  PARAMS ((cp_parser *));
+static tree cp_parser_throw_expression
+  PARAMS ((cp_parser *));
+static tree cp_parser_exception_specification_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_type_id_list
+  PARAMS ((cp_parser *));
+
+/* GNU Extensions */
+
+static tree cp_parser_asm_specification_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_asm_operand_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_asm_clobber_list
+  PARAMS ((cp_parser *));
+static tree cp_parser_attributes_opt
+  PARAMS ((cp_parser *));
+static tree cp_parser_attribute_list
+  PARAMS ((cp_parser *));
+static bool cp_parser_extension_opt
+  PARAMS ((cp_parser *, int *));
+static void cp_parser_label_declaration
+  PARAMS ((cp_parser *));
+
+/* Utility Routines */
+
+static tree cp_parser_lookup_name
+  PARAMS ((cp_parser *, tree, bool, bool, bool));
+static tree cp_parser_lookup_name_simple
+  PARAMS ((cp_parser *, tree));
+static tree cp_parser_resolve_typename_type
+  PARAMS ((cp_parser *, tree));
+static tree cp_parser_maybe_treat_template_as_class
+  (tree, bool);
+static bool cp_parser_check_declarator_template_parameters
+  PARAMS ((cp_parser *, tree));
+static bool cp_parser_check_template_parameters
+  PARAMS ((cp_parser *, unsigned));
+static tree cp_parser_binary_expression
+  PARAMS ((cp_parser *, 
+          cp_parser_token_tree_map,
+          cp_parser_expression_fn));
+static tree cp_parser_global_scope_opt
+  PARAMS ((cp_parser *, bool));
+static bool cp_parser_constructor_declarator_p
+  (cp_parser *, bool);
+static tree cp_parser_function_definition_from_specifiers_and_declarator
+  PARAMS ((cp_parser *, tree, tree, tree, tree));
+static tree cp_parser_function_definition_after_declarator
+  PARAMS ((cp_parser *, bool));
+static void cp_parser_template_declaration_after_export
+  PARAMS ((cp_parser *, bool));
+static tree cp_parser_single_declaration
+  PARAMS ((cp_parser *, bool, bool *));
+static tree cp_parser_functional_cast
+  PARAMS ((cp_parser *, tree));
+static void cp_parser_late_parsing_for_member
+  PARAMS ((cp_parser *, tree));
+static void cp_parser_late_parsing_default_args
+  PARAMS ((cp_parser *, tree));
+static tree cp_parser_sizeof_operand
+  PARAMS ((cp_parser *, enum rid));
+static bool cp_parser_declares_only_class_p
+  PARAMS ((cp_parser *));
+static bool cp_parser_friend_p
+  PARAMS ((tree));
+static cp_token *cp_parser_require
+  PARAMS ((cp_parser *, enum cpp_ttype, const char *));
+static cp_token *cp_parser_require_keyword
+  PARAMS ((cp_parser *, enum rid, const char *));
+static bool cp_parser_token_starts_function_definition_p 
+  PARAMS ((cp_token *));
+static bool cp_parser_next_token_starts_class_definition_p
+  (cp_parser *);
+static enum tag_types cp_parser_token_is_class_key
+  PARAMS ((cp_token *));
+static void cp_parser_check_class_key
+  (enum tag_types, tree type);
+static bool cp_parser_optional_template_keyword
+  (cp_parser *);
+static void cp_parser_cache_group
+  (cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned);
+static void cp_parser_parse_tentatively 
+  PARAMS ((cp_parser *));
+static void cp_parser_commit_to_tentative_parse
+  PARAMS ((cp_parser *));
+static void cp_parser_abort_tentative_parse
+  PARAMS ((cp_parser *));
+static bool cp_parser_parse_definitely
+  PARAMS ((cp_parser *));
+static bool cp_parser_parsing_tentatively
+  PARAMS ((cp_parser *));
+static bool cp_parser_committed_to_tentative_parse
+  PARAMS ((cp_parser *));
+static void cp_parser_error
+  PARAMS ((cp_parser *, const char *));
+static void cp_parser_simulate_error
+  PARAMS ((cp_parser *));
+static void cp_parser_check_type_definition
+  PARAMS ((cp_parser *));
+static bool cp_parser_skip_to_closing_parenthesis
+  PARAMS ((cp_parser *));
+static bool cp_parser_skip_to_closing_parenthesis_or_comma
+  (cp_parser *);
+static void cp_parser_skip_to_end_of_statement
+  PARAMS ((cp_parser *));
+static void cp_parser_skip_to_end_of_block_or_statement
+  PARAMS ((cp_parser *));
+static void cp_parser_skip_to_closing_brace
+  (cp_parser *);
+static void cp_parser_skip_until_found
+  PARAMS ((cp_parser *, enum cpp_ttype, const char *));
+static bool cp_parser_error_occurred
+  PARAMS ((cp_parser *));
+static bool cp_parser_allow_gnu_extensions_p
+  PARAMS ((cp_parser *));
+static bool cp_parser_is_string_literal
+  PARAMS ((cp_token *));
+static bool cp_parser_is_keyword 
+  PARAMS ((cp_token *, enum rid));
+static bool cp_parser_dependent_type_p
+  (tree);
+static bool cp_parser_value_dependent_expression_p
+  (tree);
+static bool cp_parser_type_dependent_expression_p
+  (tree);
+static bool cp_parser_dependent_template_arg_p
+  (tree);
+static bool cp_parser_dependent_template_id_p
+  (tree, tree);
+static bool cp_parser_dependent_template_p
+  (tree);
+static void cp_parser_defer_access_check
+  (cp_parser *, tree, tree);
+static void cp_parser_start_deferring_access_checks
+  (cp_parser *);
+static tree cp_parser_stop_deferring_access_checks
+  PARAMS ((cp_parser *));
+static void cp_parser_perform_deferred_access_checks
+  PARAMS ((tree));
+static tree cp_parser_scope_through_which_access_occurs
+  (tree, tree, tree);
+
+/* Returns non-zero if TOKEN is a string literal.  */
+
+static bool
+cp_parser_is_string_literal (token)
+     cp_token *token;
+{
+  return (token->type == CPP_STRING || token->type == CPP_WSTRING);
+}
+
+/* Returns non-zero if TOKEN is the indicated KEYWORD.  */
+
+static bool
+cp_parser_is_keyword (token, keyword)
+     cp_token *token;
+     enum rid keyword;
+{
+  return token->keyword == keyword;
+}
+
+/* Returns TRUE if TYPE is dependent, in the sense of
+   [temp.dep.type].  */
+
+static bool
+cp_parser_dependent_type_p (type)
+     tree type;
+{
+  tree scope;
+
+  if (!processing_template_decl)
+    return false;
+
+  /* If the type is NULL, we have not computed a type for the entity
+     in question; in that case, the type is dependent.  */
+  if (!type)
+    return true;
+
+  /* Erroneous types can be considered non-dependent.  */
+  if (type == error_mark_node)
+    return false;
+
+  /* [temp.dep.type]
+
+     A type is dependent if it is:
+
+     -- a template parameter.  */
+  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+    return true;
+  /* -- a qualified-id with a nested-name-specifier which contains a
+        class-name that names a dependent type or whose unqualified-id
+       names a dependent type.  */
+  if (TREE_CODE (type) == TYPENAME_TYPE)
+    return true;
+  /* -- a cv-qualified type where the cv-unqualified type is
+        dependent.  */
+  type = TYPE_MAIN_VARIANT (type);
+  /* -- a compound type constructed from any dependent type.  */
+  if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
+    return (cp_parser_dependent_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
+           || cp_parser_dependent_type_p (TYPE_PTRMEM_POINTED_TO_TYPE 
+                                          (type)));
+  else if (TREE_CODE (type) == POINTER_TYPE
+          || TREE_CODE (type) == REFERENCE_TYPE)
+    return cp_parser_dependent_type_p (TREE_TYPE (type));
+  else if (TREE_CODE (type) == FUNCTION_TYPE
+          || TREE_CODE (type) == METHOD_TYPE)
+    {
+      tree arg_type;
+
+      if (cp_parser_dependent_type_p (TREE_TYPE (type)))
+       return true;
+      for (arg_type = TYPE_ARG_TYPES (type); 
+          arg_type; 
+          arg_type = TREE_CHAIN (arg_type))
+       if (cp_parser_dependent_type_p (TREE_VALUE (arg_type)))
+         return true;
+      return false;
+    }
+  /* -- an array type constructed from any dependent type or whose
+        size is specified by a constant expression that is
+       value-dependent.  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (TREE_TYPE (type))
+         && ((cp_parser_value_dependent_expression_p 
+              (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+             || (cp_parser_type_dependent_expression_p
+                 (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))))
+       return true;
+      return cp_parser_dependent_type_p (TREE_TYPE (type));
+    }
+  /* -- a template-id in which either the template name is a template
+        parameter or any of the template arguments is a dependent type or
+       an expression that is type-dependent or value-dependent.  
+
+     This language seems somewhat confused; for example, it does not
+     discuss template template arguments.  Therefore, we use the
+     definition for dependent template arguments in [temp.dep.temp].  */
+  if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type)
+      && (cp_parser_dependent_template_id_p
+         (CLASSTYPE_TI_TEMPLATE (type),
+          CLASSTYPE_TI_ARGS (type))))
+    return true;
+  else if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    return true;
+  /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof'
+     expression is not type-dependent, then it should already been
+     have resolved.  */
+  if (TREE_CODE (type) == TYPEOF_TYPE)
+    return true;
+  /* The standard does not specifically mention types that are local
+     to template functions or local classes, but they should be
+     considered dependent too.  For example:
+
+       template <int I> void f() { 
+         enum E { a = I }; 
+        S<sizeof (E)> s;
+       }
+
+     The size of `E' cannot be known until the value of `I' has been
+     determined.  Therefore, `E' must be considered dependent.  */
+  scope = TYPE_CONTEXT (type);
+  if (scope && TYPE_P (scope))
+    return cp_parser_dependent_type_p (scope);
+  else if (scope && TREE_CODE (scope) == FUNCTION_DECL)
+    return cp_parser_type_dependent_expression_p (scope);
+
+  /* Other types are non-dependent.  */
+  return false;
+}
+
+/* Returns TRUE if the EXPRESSION is value-dependent.  */
+
+static bool
+cp_parser_value_dependent_expression_p (tree expression)
+{
+  if (!processing_template_decl)
+    return false;
+
+  /* A name declared with a dependent type.  */
+  if (DECL_P (expression)
+      && cp_parser_dependent_type_p (TREE_TYPE (expression)))
+    return true;
+  /* A non-type template parameter.  */
+  if ((TREE_CODE (expression) == CONST_DECL
+       && DECL_TEMPLATE_PARM_P (expression))
+      || TREE_CODE (expression) == TEMPLATE_PARM_INDEX)
+    return true;
+  /* A constant with integral or enumeration type and is initialized 
+     with an expression that is value-dependent.  */
+  if (TREE_CODE (expression) == VAR_DECL
+      && DECL_INITIAL (expression)
+      && (CP_INTEGRAL_TYPE_P (TREE_TYPE (expression))
+         || TREE_CODE (TREE_TYPE (expression)) == ENUMERAL_TYPE)
+      && cp_parser_value_dependent_expression_p (DECL_INITIAL (expression)))
+    return true;
+  /* These expressions are value-dependent if the type to which the
+     cast occurs is dependent.  */
+  if ((TREE_CODE (expression) == DYNAMIC_CAST_EXPR
+       || TREE_CODE (expression) == STATIC_CAST_EXPR
+       || TREE_CODE (expression) == CONST_CAST_EXPR
+       || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
+       || TREE_CODE (expression) == CAST_EXPR)
+      && cp_parser_dependent_type_p (TREE_TYPE (expression)))
+    return true;
+  /* A `sizeof' expression where the sizeof operand is a type is
+     value-dependent if the type is dependent.  If the type was not
+     dependent, we would no longer have a SIZEOF_EXPR, so any
+     SIZEOF_EXPR is dependent.  */
+  if (TREE_CODE (expression) == SIZEOF_EXPR)
+    return true;
+  /* A constant expression is value-dependent if any subexpression is
+     value-dependent.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
+    {
+      switch (TREE_CODE_CLASS (TREE_CODE (expression)))
+       {
+       case '1':
+         return (cp_parser_value_dependent_expression_p 
+                 (TREE_OPERAND (expression, 0)));
+       case '<':
+       case '2':
+         return ((cp_parser_value_dependent_expression_p 
+                  (TREE_OPERAND (expression, 0)))
+                 || (cp_parser_value_dependent_expression_p 
+                     (TREE_OPERAND (expression, 1))));
+       case 'e':
+         {
+           int i;
+           for (i = 0; 
+                i < TREE_CODE_LENGTH (TREE_CODE (expression));
+                ++i)
+             if (cp_parser_value_dependent_expression_p
+                 (TREE_OPERAND (expression, i)))
+               return true;
+           return false;
+         }
+       }
+    }
+
+  /* The expression is not value-dependent.  */
+  return false;
+}
+
+/* Returns TRUE if the EXPRESSION is type-dependent, in the sense of
+   [temp.dep.expr].  */
+
+static bool
+cp_parser_type_dependent_expression_p (expression)
+     tree expression;
+{
+  if (!processing_template_decl)
+    return false;
+
+  /* Some expression forms are never type-dependent.  */
+  if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
+      || TREE_CODE (expression) == SIZEOF_EXPR
+      || TREE_CODE (expression) == ALIGNOF_EXPR
+      || TREE_CODE (expression) == TYPEID_EXPR
+      || TREE_CODE (expression) == DELETE_EXPR
+      || TREE_CODE (expression) == VEC_DELETE_EXPR
+      || TREE_CODE (expression) == THROW_EXPR)
+    return false;
+
+  /* The types of these expressions depends only on the type to which
+     the cast occurs.  */
+  if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
+      || TREE_CODE (expression) == STATIC_CAST_EXPR
+      || TREE_CODE (expression) == CONST_CAST_EXPR
+      || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
+      || TREE_CODE (expression) == CAST_EXPR)
+    return cp_parser_dependent_type_p (TREE_TYPE (expression));
+  /* The types of these expressions depends only on the type created
+     by the expression.  */
+  else if (TREE_CODE (expression) == NEW_EXPR
+          || TREE_CODE (expression) == VEC_NEW_EXPR)
+    return cp_parser_dependent_type_p (TREE_OPERAND (expression, 1));
+
+  if (TREE_CODE (expression) == FUNCTION_DECL
+      && DECL_LANG_SPECIFIC (expression)
+      && DECL_TEMPLATE_INFO (expression)
+      && (cp_parser_dependent_template_id_p
+         (DECL_TI_TEMPLATE (expression),
+          INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
+    return true;
+
+  return (cp_parser_dependent_type_p (TREE_TYPE (expression)));
+}
+
+/* Returns TRUE if the ARG (a template argument) is dependent.  */
+
+static bool
+cp_parser_dependent_template_arg_p (tree arg)
+{
+  if (!processing_template_decl)
+    return false;
+
+  if (TREE_CODE (arg) == TEMPLATE_DECL
+      || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+    return cp_parser_dependent_template_p (arg);
+  else if (TYPE_P (arg))
+    return cp_parser_dependent_type_p (arg);
+  else
+    return (cp_parser_type_dependent_expression_p (arg)
+           || cp_parser_value_dependent_expression_p (arg));
+}
+
+/* Returns TRUE if the specialization TMPL<ARGS> is dependent.  */
+
+static bool
+cp_parser_dependent_template_id_p (tree tmpl, tree args)
+{
+  int i;
+
+  if (cp_parser_dependent_template_p (tmpl))
+    return true;
+  for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+    if (cp_parser_dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+      return true;
+  return false;
+}
+
+/* Returns TRUE if the template TMPL is dependent.  */
+
+static bool
+cp_parser_dependent_template_p (tree tmpl)
+{
+  /* Template template parameters are dependent.  */
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
+      || TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
+    return true;
+  /* So are member templates of dependent classes.  */
+  if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
+    return cp_parser_dependent_type_p (DECL_CONTEXT (tmpl));
+  return false;
+}
+
+/* Defer checking the accessibility of DECL, when looked up in
+   CLASS_TYPE.  */
+
+static void
+cp_parser_defer_access_check (cp_parser *parser, 
+                             tree class_type,
+                             tree decl)
+{
+  tree check;
+
+  /* If we are not supposed to defer access checks, just check now.  */
+  if (!parser->context->deferring_access_checks_p)
+    {
+      enforce_access (class_type, decl);
+      return;
+    }
+
+  /* See if we are already going to perform this check.  */
+  for (check = parser->context->deferred_access_checks;
+       check;
+       check = TREE_CHAIN (check))
+    if (TREE_VALUE (check) == decl
+       && same_type_p (TREE_PURPOSE (check), class_type))
+      return;
+  /* If not, record the check.  */
+  parser->context->deferred_access_checks
+    = tree_cons (class_type, decl, parser->context->deferred_access_checks);
+}
+
+/* Start deferring access control checks.  */
+
+static void
+cp_parser_start_deferring_access_checks (cp_parser *parser)
+{
+  parser->context->deferring_access_checks_p = true;
+}
+
+/* Stop deferring access control checks.  Returns a TREE_LIST
+   representing the deferred checks.  The TREE_PURPOSE of each node is
+   the type through which the access occurred; the TREE_VALUE is the
+   declaration named.  */
+
+static tree
+cp_parser_stop_deferring_access_checks (parser)
+     cp_parser *parser;
+{
+  tree access_checks;
+
+  parser->context->deferring_access_checks_p = false;
+  access_checks = parser->context->deferred_access_checks;
+  parser->context->deferred_access_checks = NULL_TREE;
+
+  return access_checks;
+}
+
+/* Perform the deferred ACCESS_CHECKS, whose representation is as
+   documented with cp_parser_stop_deferrring_access_checks.  */
+
+static void
+cp_parser_perform_deferred_access_checks (access_checks)
+     tree access_checks;
+{
+  tree deferred_check;
+
+  /* Look through all the deferred checks.  */
+  for (deferred_check = access_checks;
+       deferred_check;
+       deferred_check = TREE_CHAIN (deferred_check))
+    /* Check access.  */
+    enforce_access (TREE_PURPOSE (deferred_check), 
+                   TREE_VALUE (deferred_check));
+}
+
+/* Returns the scope through which DECL is being accessed, or
+   NULL_TREE if DECL is not a member.  If OBJECT_TYPE is non-NULL, we
+   have just seen `x->' or `x.' and OBJECT_TYPE is the type of `*x',
+   or `x', respectively.  If the DECL was named as `A::B' then
+   NESTED_NAME_SPECIFIER is `A'.  */
+
+tree
+cp_parser_scope_through_which_access_occurs (decl, 
+                                            object_type,
+                                            nested_name_specifier)
+     tree decl;
+     tree object_type;
+     tree nested_name_specifier;
+{
+  tree scope;
+  tree qualifying_type = NULL_TREE;
+  
+  /* Determine the SCOPE of DECL.  */
+  scope = context_for_name_lookup (decl);
+  /* If the SCOPE is not a type, then DECL is not a member.  */
+  if (!TYPE_P (scope))
+    return NULL_TREE;
+  /* Figure out the type through which DECL is being accessed.  */
+  if (object_type && DERIVED_FROM_P (scope, object_type))
+    /* If we are processing a `->' or `.' expression, use the type of the
+       left-hand side.  */
+    qualifying_type = object_type;
+  else if (nested_name_specifier)
+    {
+      /* If the reference is to a non-static member of the
+        current class, treat it as if it were referenced through
+        `this'.  */
+      if (DECL_NONSTATIC_MEMBER_P (decl)
+         && current_class_ptr
+         && DERIVED_FROM_P (scope, current_class_type))
+       qualifying_type = current_class_type;
+      /* Otherwise, use the type indicated by the
+        nested-name-specifier.  */
+      else
+       qualifying_type = nested_name_specifier;
+    }
+  else
+    /* Otherwise, the name must be from the current class or one of
+       its bases.  */
+    qualifying_type = currently_open_derived_class (scope);
+
+  return qualifying_type;
+}
+
+/* Issue the indicated error MESSAGE.  */
+
+static void
+cp_parser_error (parser, message)
+     cp_parser *parser;
+     const char *message;
+{
+  /* Remember that we have issued an error.  */
+  cp_parser_simulate_error (parser);
+  /* Output the MESSAGE -- unless we're parsing tentatively.  */
+  if (!cp_parser_parsing_tentatively (parser) 
+      || cp_parser_committed_to_tentative_parse (parser))
+    error (message);
+}
+
+/* If we are parsing tentatively, remember that an error has occurred
+   during this tentative parse.  */
+
+static void
+cp_parser_simulate_error (parser)
+     cp_parser *parser;
+{
+  if (cp_parser_parsing_tentatively (parser)
+      && !cp_parser_committed_to_tentative_parse (parser))
+    parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
+}
+
+/* This function is called when a type is defined.  If type
+   definitions are forbidden at this point, an error message is
+   issued.  */
+
+static void
+cp_parser_check_type_definition (parser)
+     cp_parser *parser;
+{
+  /* If types are forbidden here, issue a message.  */
+  if (parser->type_definition_forbidden_message)
+    /* Use `%s' to print the string in case there are any escape
+       characters in the message.  */
+    error ("%s", parser->type_definition_forbidden_message);
+}
+
+/* Consume tokens up to, and including, the next non-nested closing `)'. 
+   Returns TRUE iff we found a closing `)'.  */
+
+static bool
+cp_parser_skip_to_closing_parenthesis (cp_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      cp_token *token;
+
+      /* If we've run out of tokens, then there is no closing `)'.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+       return false;
+      /* Consume the token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+      /* If it is an `(', we have entered another level of nesting.  */
+      if (token->type == CPP_OPEN_PAREN)
+       ++nesting_depth;
+      /* If it is a `)', then we might be done.  */
+      else if (token->type == CPP_CLOSE_PAREN && nesting_depth-- == 0)
+       return true;
+    }
+}
+
+/* Consume tokens until the next token is a `)', or a `,'.  Returns
+   TRUE if the next token is a `,'.  */
+
+static bool
+cp_parser_skip_to_closing_parenthesis_or_comma (cp_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+      /* If we've run out of tokens, then there is no closing `)'.  */
+      if (token->type == CPP_EOF)
+       return false;
+      /* If it is a `,' stop.  */
+      else if (token->type == CPP_COMMA && nesting_depth-- == 0)
+       return true;
+      /* If it is a `)', stop.  */
+      else if (token->type == CPP_CLOSE_PAREN && nesting_depth-- == 0)
+       return false;
+      /* If it is an `(', we have entered another level of nesting.  */
+      else if (token->type == CPP_OPEN_PAREN)
+       ++nesting_depth;
+      /* Consume the token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+    }
+}
+
+/* Consume tokens until we reach the end of the current statement.
+   Normally, that will be just before consuming a `;'.  However, if a
+   non-nested `}' comes first, then we stop before consuming that.  */
+
+static void
+cp_parser_skip_to_end_of_statement (parser)
+     cp_parser *parser;
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      cp_token *token;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       break;
+      /* If the next token is a `;', we have reached the end of the
+        statement.  */
+      if (token->type == CPP_SEMICOLON && !nesting_depth)
+       break;
+      /* If the next token is a non-nested `}', then we have reached
+        the end of the current block.  */
+      if (token->type == CPP_CLOSE_BRACE)
+       {
+         /* If this is a non-nested `}', stop before consuming it.
+            That way, when confronted with something like:
+
+              { 3 + } 
+
+            we stop before consuming the closing `}', even though we
+            have not yet reached a `;'.  */
+         if (nesting_depth == 0)
+           break;
+         /* If it is the closing `}' for a block that we have
+            scanned, stop -- but only after consuming the token.
+            That way given:
+
+               void f g () { ... }
+               typedef int I;
+
+            we will stop after the body of the erroneously declared
+            function, but before consuming the following `typedef'
+            declaration.  */
+         if (--nesting_depth == 0)
+           {
+             cp_lexer_consume_token (parser->lexer);
+             break;
+           }
+       }
+      /* If it the next token is a `{', then we are entering a new
+        block.  Consume the entire block.  */
+      else if (token->type == CPP_OPEN_BRACE)
+       ++nesting_depth;
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+}
+
+/* Skip tokens until we have consumed an entire block, or until we
+   have consumed a non-nested `;'.  */
+
+static void
+cp_parser_skip_to_end_of_block_or_statement (parser)
+     cp_parser *parser;
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      cp_token *token;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       break;
+      /* If the next token is a `;', we have reached the end of the
+        statement.  */
+      if (token->type == CPP_SEMICOLON && !nesting_depth)
+       {
+         /* Consume the `;'.  */
+         cp_lexer_consume_token (parser->lexer);
+         break;
+       }
+      /* Consume the token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+      /* If the next token is a non-nested `}', then we have reached
+        the end of the current block.  */
+      if (token->type == CPP_CLOSE_BRACE 
+         && (nesting_depth == 0 || --nesting_depth == 0))
+       break;
+      /* If it the next token is a `{', then we are entering a new
+        block.  Consume the entire block.  */
+      if (token->type == CPP_OPEN_BRACE)
+       ++nesting_depth;
+    }
+}
+
+/* Skip tokens until a non-nested closing curly brace is the next
+   token.  */
+
+static void
+cp_parser_skip_to_closing_brace (cp_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      cp_token *token;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       break;
+      /* If the next token is a non-nested `}', then we have reached
+        the end of the current block.  */
+      if (token->type == CPP_CLOSE_BRACE && nesting_depth-- == 0)
+       break;
+      /* If it the next token is a `{', then we are entering a new
+        block.  Consume the entire block.  */
+      else if (token->type == CPP_OPEN_BRACE)
+       ++nesting_depth;
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+}
+
+/* Create a new C++ parser.  */
+
+static cp_parser *
+cp_parser_new ()
+{
+  cp_parser *parser;
+
+  parser = (cp_parser *) ggc_alloc_cleared (sizeof (cp_parser));
+  parser->lexer = cp_lexer_new (/*main_lexer_p=*/true);
+  parser->context = cp_parser_context_new (NULL);
+
+  /* For now, we always accept GNU extensions.  */
+  parser->allow_gnu_extensions_p = 1;
+
+  /* The `>' token is a greater-than operator, not the end of a
+     template-id.  */
+  parser->greater_than_is_operator_p = true;
+
+  parser->default_arg_ok_p = true;
+  
+  /* We are not parsing a constant-expression.  */
+  parser->constant_expression_p = false;
+
+  /* Local variable names are not forbidden.  */
+  parser->local_variables_forbidden_p = false;
+
+  /* We are not procesing an `extern "C"' declaration.  */
+  parser->in_unbraced_linkage_specification_p = false;
+
+  /* We are not processing a declarator.  */
+  parser->in_declarator_p = false;
+
+  /* There are no default args to process.  */
+  parser->default_arg_types = NULL;
+
+  /* The unparsed function queue is empty.  */
+  parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
+
+  /* There are no classes being defined.  */
+  parser->num_classes_being_defined = 0;
+
+  /* No template parameters apply.  */
+  parser->num_template_parameter_lists = 0;
+
+  return parser;
+}
+
+/* Lexical conventions [gram.lex]  */
+
+/* Parse an identifier.  Returns an IDENTIFIER_NODE representing the
+   identifier.  */
+
+static tree 
+cp_parser_identifier (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+
+  /* Look for the identifier.  */
+  token = cp_parser_require (parser, CPP_NAME, "identifier");
+  /* Return the value.  */
+  return token ? token->value : error_mark_node;
+}
+
+/* Basic concepts [gram.basic]  */
+
+/* Parse a translation-unit.
+
+   translation-unit:
+     declaration-seq [opt]  
+
+   Returns TRUE if all went well.  */
+
+static bool
+cp_parser_translation_unit (parser)
+     cp_parser *parser;
+{
+  while (true)
+    {
+      cp_parser_declaration_seq_opt (parser);
+
+      /* If there are no tokens left then all went well.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+       break;
+      
+      /* Otherwise, issue an error message.  */
+      cp_parser_error (parser, "expected declaration");
+      return false;
+    }
+
+  /* Consume the EOF token.  */
+  cp_parser_require (parser, CPP_EOF, "end-of-file");
+  
+  /* Finish up.  */
+  finish_translation_unit ();
+
+  /* All went well.  */
+  return true;
+}
+
+/* Expressions [gram.expr] */
+
+/* Parse a primary-expression.
+
+   primary-expression:
+     literal
+     this
+     ( expression )
+     id-expression
+
+   GNU Extensions:
+
+   primary-expression:
+     ( compound-statement )
+     __builtin_va_arg ( assignment-expression , type-id )
+
+   literal:
+     __null
+
+   Returns a representation of the expression.  
+
+   *IDK indicates what kind of id-expression (if any) was present.  
+
+   *QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be
+   used as the operand of a pointer-to-member.  In that case,
+   *QUALIFYING_CLASS gives the class that is used as the qualifying
+   class in the pointer-to-member.  */
+
+static tree
+cp_parser_primary_expression (cp_parser *parser, 
+                             cp_parser_id_kind *idk,
+                             tree *qualifying_class)
+{
+  cp_token *token;
+
+  /* Assume the primary expression is not an id-expression.  */
+  *idk = CP_PARSER_ID_KIND_NONE;
+  /* And that it cannot be used as pointer-to-member.  */
+  *qualifying_class = NULL_TREE;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  switch (token->type)
+    {
+      /* literal:
+          integer-literal
+          character-literal
+          floating-literal
+          string-literal
+          boolean-literal  */
+    case CPP_CHAR:
+    case CPP_WCHAR:
+    case CPP_STRING:
+    case CPP_WSTRING:
+    case CPP_NUMBER:
+      token = cp_lexer_consume_token (parser->lexer);
+      return token->value;
+
+    case CPP_OPEN_PAREN:
+      {
+       tree expr;
+       bool saved_greater_than_is_operator_p;
+
+       /* Consume the `('.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Within a parenthesized expression, a `>' token is always
+          the greater-than operator.  */
+       saved_greater_than_is_operator_p 
+         = parser->greater_than_is_operator_p;
+       parser->greater_than_is_operator_p = true;
+       /* If we see `( { ' then we are looking at the beginning of
+          a GNU statement-expression.  */
+       if (cp_parser_allow_gnu_extensions_p (parser)
+           && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+         {
+           /* Statement-expressions are not allowed by the standard.  */
+           if (pedantic)
+             pedwarn ("ISO C++ forbids braced-groups within expressions");  
+           
+           /* And they're not allowed outside of a function-body; you
+              cannot, for example, write:
+              
+                int i = ({ int j = 3; j + 1; });
+              
+              at class or namespace scope.  */
+           if (!at_function_scope_p ())
+             error ("statement-expressions are allowed only inside functions");
+           /* Start the statement-expression.  */
+           expr = begin_stmt_expr ();
+           /* Parse the compound-statement.  */
+           cp_parser_compound_statement (parser);
+           /* Finish up.  */
+           expr = finish_stmt_expr (expr);
+         }
+       else
+         {
+           /* Parse the parenthesized expression.  */
+           expr = cp_parser_expression (parser);
+           /* Let the front end know that this expression was
+              enclosed in parentheses. This matters in case, for
+              example, the expression is of the form `A::B', since
+              `&A::B' might be a pointer-to-member, but `&(A::B)' is
+              not.  */
+           finish_parenthesized_expr (expr);
+         }
+       /* The `>' token might be the end of a template-id or
+          template-parameter-list now.  */
+       parser->greater_than_is_operator_p 
+         = saved_greater_than_is_operator_p;
+       /* Consume the `)'.  */
+       if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+         cp_parser_skip_to_end_of_statement (parser);
+
+       return expr;
+      }
+
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+         /* These two are the boolean literals.  */
+       case RID_TRUE:
+         cp_lexer_consume_token (parser->lexer);
+         return boolean_true_node;
+       case RID_FALSE:
+         cp_lexer_consume_token (parser->lexer);
+         return boolean_false_node;
+         
+         /* The `__null' literal.  */
+       case RID_NULL:
+         cp_lexer_consume_token (parser->lexer);
+         return null_node;
+
+         /* Recognize the `this' keyword.  */
+       case RID_THIS:
+         cp_lexer_consume_token (parser->lexer);
+         if (parser->local_variables_forbidden_p)
+           {
+             error ("`this' may not be used in this context");
+             return error_mark_node;
+           }
+         return finish_this_expr ();
+
+         /* The `operator' keyword can be the beginning of an
+            id-expression.  */
+       case RID_OPERATOR:
+         goto id_expression;
+
+       case RID_FUNCTION_NAME:
+       case RID_PRETTY_FUNCTION_NAME:
+       case RID_C99_FUNCTION_NAME:
+         /* The symbols __FUNCTION__, __PRETTY_FUNCTION__, and
+            __func__ are the names of variables -- but they are
+            treated specially.  Therefore, they are handled here,
+            rather than relying on the generic id-expression logic
+            below.  Gramatically, these names are id-expressions.  
+
+            Consume the token.  */
+         token = cp_lexer_consume_token (parser->lexer);
+         /* Look up the name.  */
+         return finish_fname (token->value);
+
+       case RID_VA_ARG:
+         {
+           tree expression;
+           tree type;
+
+           /* The `__builtin_va_arg' construct is used to handle
+              `va_arg'.  Consume the `__builtin_va_arg' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Look for the opening `('.  */
+           cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+           /* Now, parse the assignment-expression.  */
+           expression = cp_parser_assignment_expression (parser);
+           /* Look for the `,'.  */
+           cp_parser_require (parser, CPP_COMMA, "`,'");
+           /* Parse the type-id.  */
+           type = cp_parser_type_id (parser);
+           /* Look for the closing `)'.  */
+           cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+           return build_x_va_arg (expression, type);
+         }
+
+       default:
+         cp_parser_error (parser, "expected primary-expression");
+         return error_mark_node;
+       }
+      /* Fall through. */
+
+      /* An id-expression can start with either an identifier, a
+        `::' as the beginning of a qualified-id, or the "operator"
+        keyword.  */
+    case CPP_NAME:
+    case CPP_SCOPE:
+    case CPP_TEMPLATE_ID:
+    case CPP_NESTED_NAME_SPECIFIER:
+      {
+       tree id_expression;
+       tree decl;
+
+      id_expression:
+       /* Parse the id-expression.  */
+       id_expression 
+         = cp_parser_id_expression (parser, 
+                                    /*template_keyword_p=*/false,
+                                    /*check_dependency_p=*/true,
+                                    /*template_p=*/NULL);
+       if (id_expression == error_mark_node)
+         return error_mark_node;
+       /* If we have a template-id, then no further lookup is
+          required.  If the template-id was for a template-class, we
+          will sometimes have a TYPE_DECL at this point.  */
+       else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
+           || TREE_CODE (id_expression) == TYPE_DECL)
+         decl = id_expression;
+       /* Look up the name.  */
+       else 
+         {
+           decl = cp_parser_lookup_name_simple (parser, id_expression);
+           /* If name lookup gives us a SCOPE_REF, then the
+              qualifying scope was dependent.  Just propagate the
+              name.  */
+           if (TREE_CODE (decl) == SCOPE_REF)
+             {
+               if (TYPE_P (TREE_OPERAND (decl, 0)))
+                 *qualifying_class = TREE_OPERAND (decl, 0);
+               return decl;
+             }
+           /* Check to see if DECL is a local variable in a context
+              where that is forbidden.  */
+           if (parser->local_variables_forbidden_p
+               && local_variable_p (decl))
+             {
+               /* It might be that we only found DECL because we are
+                  trying to be generous with pre-ISO scoping rules.
+                  For example, consider:
+
+                    int i;
+                    void g() {
+                      for (int i = 0; i < 10; ++i) {}
+                      extern void f(int j = i);
+                    }
+
+                  Here, name look up will originally find the out 
+                  of scope `i'.  We need to issue a warning message,
+                  but then use the global `i'.  */
+               decl = check_for_out_of_scope_variable (decl);
+               if (local_variable_p (decl))
+                 {
+                   error ("local variable `%D' may not appear in this context",
+                          decl);
+                   return error_mark_node;
+                 }
+             }
+
+           /* If unqualified name lookup fails while processing a
+              template, that just means that we need to do name
+              lookup again when the template is instantiated.  */
+           if (!parser->scope 
+               && decl == error_mark_node
+               && processing_template_decl)
+             {
+               *idk = CP_PARSER_ID_KIND_UNQUALIFIED;
+               return build_min_nt (LOOKUP_EXPR, id_expression);
+             }
+           else if (decl == error_mark_node
+                    && !processing_template_decl)
+             {
+               if (!parser->scope)
+                 {
+                   /* It may be resolvable as a koenig lookup function
+                      call.  */
+                   *idk = CP_PARSER_ID_KIND_UNQUALIFIED;
+                   return id_expression;
+                 }
+               else if (TYPE_P (parser->scope)
+                        && !COMPLETE_TYPE_P (parser->scope))
+                 error ("incomplete type `%T' used in nested name specifier",
+                        parser->scope);
+               else if (parser->scope != global_namespace)
+                 error ("`%D' is not a member of `%D'",
+                        id_expression, parser->scope);
+               else
+                 error ("`::%D' has not been declared", id_expression);
+             }
+           /* If DECL is a variable would be out of scope under
+              ANSI/ISO rules, but in scope in the ARM, name lookup
+              will succeed.  Issue a diagnostic here.  */
+           else
+             decl = check_for_out_of_scope_variable (decl);
+
+           /* Remember that the name was used in the definition of
+              the current class so that we can check later to see if
+              the meaning would have been different after the class
+              was entirely defined.  */
+           if (!parser->scope && decl != error_mark_node)
+             maybe_note_name_used_in_class (id_expression, decl);
+         }
+
+       /* If we didn't find anything, or what we found was a type,
+          then this wasn't really an id-expression.  */
+       if (TREE_CODE (decl) == TYPE_DECL
+           || TREE_CODE (decl) == NAMESPACE_DECL
+           || (TREE_CODE (decl) == TEMPLATE_DECL
+               && !DECL_FUNCTION_TEMPLATE_P (decl)))
+         {
+           cp_parser_error (parser, 
+                            "expected primary-expression");
+           return error_mark_node;
+         }
+
+       /* If the name resolved to a template parameter, there is no
+          need to look it up again later.  Similarly, we resolve
+          enumeration constants to their underlying values.  */
+       if (TREE_CODE (decl) == CONST_DECL)
+         {
+           *idk = CP_PARSER_ID_KIND_NONE;
+           if (DECL_TEMPLATE_PARM_P (decl) || !processing_template_decl)
+             return DECL_INITIAL (decl);
+           return decl;
+         }
+       else
+         {
+           bool dependent_p;
+           
+           /* If the declaration was explicitly qualified indicate
+              that.  The semantics of `A::f(3)' are different than
+              `f(3)' if `f' is virtual.  */
+           *idk = (parser->scope 
+                   ? CP_PARSER_ID_KIND_QUALIFIED
+                   : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+                      ? CP_PARSER_ID_KIND_TEMPLATE_ID
+                      : CP_PARSER_ID_KIND_UNQUALIFIED));
+
+
+           /* [temp.dep.expr]
+              
+              An id-expression is type-dependent if it contains an
+              identifier that was declared with a dependent type.
+              
+              As an optimization, we could choose not to create a
+              LOOKUP_EXPR for a name that resolved to a local
+              variable in the template function that we are currently
+              declaring; such a name cannot ever resolve to anything
+              else.  If we did that we would not have to look up
+              these names at instantiation time.
+              
+              The standard is not very specific about an
+              id-expression that names a set of overloaded functions.
+              What if some of them have dependent types and some of
+              them do not?  Presumably, such a name should be treated
+              as a dependent name.  */
+           /* Assume the name is not dependent.  */
+           dependent_p = false;
+           if (!processing_template_decl)
+             /* No names are dependent outside a template.  */
+             ;
+           /* A template-id where the name of the template was not
+              resolved is definitely dependent.  */
+           else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+                    && (TREE_CODE (TREE_OPERAND (decl, 0)) 
+                        == IDENTIFIER_NODE))
+             dependent_p = true;
+           /* For anything except an overloaded function, just check
+              its type.  */
+           else if (!is_overloaded_fn (decl))
+             dependent_p 
+               = cp_parser_dependent_type_p (TREE_TYPE (decl));
+           /* For a set of overloaded functions, check each of the
+              functions.  */
+           else
+             {
+               tree fns = decl;
+
+               if (BASELINK_P (fns))
+                 fns = BASELINK_FUNCTIONS (fns);
+                 
+               /* For a template-id, check to see if the template
+                  arguments are dependent.  */
+               if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+                 {
+                   tree args = TREE_OPERAND (fns, 1);
+
+                   if (args && TREE_CODE (args) == TREE_LIST)
+                     {
+                       while (args)
+                         {
+                           if (cp_parser_dependent_template_arg_p
+                               (TREE_VALUE (args)))
+                             {
+                               dependent_p = true;
+                               break;
+                             }
+                           args = TREE_CHAIN (args);
+                         }
+                     }
+                   else if (args && TREE_CODE (args) == TREE_VEC)
+                     {
+                       int i; 
+                       for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+                         if (cp_parser_dependent_template_arg_p
+                             (TREE_VEC_ELT (args, i)))
+                           {
+                             dependent_p = true;
+                             break;
+                           }
+                     }
+
+                   /* The functions are those referred to by the
+                      template-id.  */
+                   fns = TREE_OPERAND (fns, 0);
+                 }
+
+               /* If there are no dependent template arguments, go
+                  through the overlaoded functions.  */
+               while (fns && !dependent_p)
+                 {
+                   tree fn = OVL_CURRENT (fns);
+                   
+                   /* Member functions of dependent classes are
+                      dependent.  */
+                   if (TREE_CODE (fn) == FUNCTION_DECL
+                       && cp_parser_type_dependent_expression_p (fn))
+                     dependent_p = true;
+                   else if (TREE_CODE (fn) == TEMPLATE_DECL
+                            && cp_parser_dependent_template_p (fn))
+                     dependent_p = true;
+                   
+                   fns = OVL_NEXT (fns);
+                 }
+             }
+
+           /* If the name was dependent on a template parameter,
+              we will resolve the name at instantiation time.  */
+           if (dependent_p)
+             {
+               /* Create a SCOPE_REF for qualified names.  */
+               if (parser->scope)
+                 {
+                   if (TYPE_P (parser->scope))
+                     *qualifying_class = parser->scope;
+                   return build_nt (SCOPE_REF, 
+                                    parser->scope, 
+                                    id_expression);
+                 }
+               /* A TEMPLATE_ID already contains all the information
+                  we need.  */
+               if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
+                 return id_expression;
+               /* Create a LOOKUP_EXPR for other unqualified names.  */
+               return build_min_nt (LOOKUP_EXPR, id_expression);
+             }
+
+           if (parser->scope)
+             {
+               decl = (adjust_result_of_qualified_name_lookup 
+                       (decl, parser->scope, current_class_type));
+               if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
+                 *qualifying_class = parser->scope;
+             }
+           /* Resolve references to variables of anonymous unions
+              into COMPONENT_REFs.  */
+           else if (TREE_CODE (decl) == ALIAS_DECL)
+             decl = DECL_INITIAL (decl);
+           else
+             /* Transform references to non-static data members into
+                COMPONENT_REFs.  */
+             decl = hack_identifier (decl, id_expression);
+         }
+
+       if (TREE_DEPRECATED (decl))
+         warn_deprecated_use (decl);
+
+       return decl;
+      }
+
+      /* Anything else is an error.  */
+    default:
+      cp_parser_error (parser, "expected primary-expression");
+      return error_mark_node;
+    }
+}
+
+/* Parse an id-expression.
+
+   id-expression:
+     unqualified-id
+     qualified-id
+
+   qualified-id:
+     :: [opt] nested-name-specifier template [opt] unqualified-id
+     :: identifier
+     :: operator-function-id
+     :: template-id
+
+   Return a representation of the unqualified portion of the
+   identifier.  Sets PARSER->SCOPE to the qualifying scope if there is
+   a `::' or nested-name-specifier.
+
+   Often, if the id-expression was a qualified-id, the caller will
+   want to make a SCOPE_REF to represent the qualified-id.  This
+   function does not do this in order to avoid wastefully creating
+   SCOPE_REFs when they are not required.
+
+   If ASSUME_TYPENAME_P is true then we assume that qualified names
+   are typenames.  This flag is set when parsing a declarator-id;
+   for something like:
+
+     template <class T>
+     int S<T>::R::i = 3;
+
+   we are supposed to assume that `S<T>::R' is a class.
+
+   If TEMPLATE_KEYWORD_P is true, then we have just seen the
+   `template' keyword.
+
+   If CHECK_DEPENDENCY_P is false, then names are looked up inside
+   uninstantiated templates.  
+
+   If *TEMPLATE_KEYWORD_P is non-NULL, it is set to true iff the
+   `template' keyword is used to explicitly indicate that the entity
+   named is a template.  */
+
+static tree
+cp_parser_id_expression (cp_parser *parser,
+                        bool template_keyword_p,
+                        bool check_dependency_p,
+                        bool *template_p)
+{
+  bool global_scope_p;
+  bool nested_name_specifier_p;
+
+  /* Assume the `template' keyword was not used.  */
+  if (template_p)
+    *template_p = false;
+
+  /* Look for the optional `::' operator.  */
+  global_scope_p 
+    = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false) 
+       != NULL_TREE);
+  /* Look for the optional nested-name-specifier.  */
+  nested_name_specifier_p 
+    = (cp_parser_nested_name_specifier_opt (parser,
+                                           /*typename_keyword_p=*/false,
+                                           check_dependency_p,
+                                           /*type_p=*/false)
+       != NULL_TREE);
+  /* If there is a nested-name-specifier, then we are looking at
+     the first qualified-id production.  */
+  if (nested_name_specifier_p)
+    {
+      tree saved_scope;
+      tree saved_object_scope;
+      tree saved_qualifying_scope;
+      tree unqualified_id;
+      bool is_template;
+
+      /* See if the next token is the `template' keyword.  */
+      if (!template_p)
+       template_p = &is_template;
+      *template_p = cp_parser_optional_template_keyword (parser);
+      /* Name lookup we do during the processing of the
+        unqualified-id might obliterate SCOPE.  */
+      saved_scope = parser->scope;
+      saved_object_scope = parser->object_scope;
+      saved_qualifying_scope = parser->qualifying_scope;
+      /* Process the final unqualified-id.  */
+      unqualified_id = cp_parser_unqualified_id (parser, *template_p,
+                                                check_dependency_p);
+      /* Restore the SAVED_SCOPE for our caller.  */
+      parser->scope = saved_scope;
+      parser->object_scope = saved_object_scope;
+      parser->qualifying_scope = saved_qualifying_scope;
+
+      return unqualified_id;
+    }
+  /* Otherwise, if we are in global scope, then we are looking at one
+     of the other qualified-id productions.  */
+  else if (global_scope_p)
+    {
+      cp_token *token;
+      tree id;
+
+      /* We don't know yet whether or not this will be a 
+        template-id.  */
+      cp_parser_parse_tentatively (parser);
+      /* Try a template-id.  */
+      id = cp_parser_template_id (parser, 
+                                 /*template_keyword_p=*/false,
+                                 /*check_dependency_p=*/true);
+      /* If that worked, we're done.  */
+      if (cp_parser_parse_definitely (parser))
+       return id;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+
+      switch (token->type)
+       {
+       case CPP_NAME:
+         return cp_parser_identifier (parser);
+
+       case CPP_KEYWORD:
+         if (token->keyword == RID_OPERATOR)
+           return cp_parser_operator_function_id (parser);
+         /* Fall through.  */
+         
+       default:
+         cp_parser_error (parser, "expected id-expression");
+         return error_mark_node;
+       }
+    }
+  else
+    return cp_parser_unqualified_id (parser, template_keyword_p,
+                                    /*check_dependency_p=*/true);
+}
+
+/* Parse an unqualified-id.
+
+   unqualified-id:
+     identifier
+     operator-function-id
+     conversion-function-id
+     ~ class-name
+     template-id
+
+   If TEMPLATE_KEYWORD_P is TRUE, we have just seen the `template'
+   keyword, in a construct like `A::template ...'.
+
+   Returns a representation of unqualified-id.  For the `identifier'
+   production, an IDENTIFIER_NODE is returned.  For the `~ class-name'
+   production a BIT_NOT_EXPR is returned; the operand of the
+   BIT_NOT_EXPR is an IDENTIFIER_NODE for the class-name.  For the
+   other productions, see the documentation accompanying the
+   corresponding parsing functions.  If CHECK_DEPENDENCY_P is false,
+   names are looked up in uninstantiated templates.  */
+
+static tree
+cp_parser_unqualified_id (parser, template_keyword_p,
+                         check_dependency_p)
+     cp_parser *parser;
+     bool template_keyword_p;
+     bool check_dependency_p;
+{
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  
+  switch (token->type)
+    {
+    case CPP_NAME:
+      {
+       tree id;
+
+       /* We don't know yet whether or not this will be a
+          template-id.  */
+       cp_parser_parse_tentatively (parser);
+       /* Try a template-id.  */
+       id = cp_parser_template_id (parser, template_keyword_p,
+                                   check_dependency_p);
+       /* If it worked, we're done.  */
+       if (cp_parser_parse_definitely (parser))
+         return id;
+       /* Otherwise, it's an ordinary identifier.  */
+       return cp_parser_identifier (parser);
+      }
+
+    case CPP_TEMPLATE_ID:
+      return cp_parser_template_id (parser, template_keyword_p,
+                                   check_dependency_p);
+
+    case CPP_COMPL:
+      {
+       tree type_decl;
+       tree qualifying_scope;
+       tree object_scope;
+       tree scope;
+
+       /* Consume the `~' token.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Parse the class-name.  The standard, as written, seems to
+          say that:
+
+            template <typename T> struct S { ~S (); };
+            template <typename T> S<T>::~S() {}
+
+           is invalid, since `~' must be followed by a class-name, but
+          `S<T>' is dependent, and so not known to be a class.
+          That's not right; we need to look in uninstantiated
+          templates.  A further complication arises from:
+
+            template <typename T> void f(T t) {
+              t.T::~T();
+            } 
+
+          Here, it is not possible to look up `T' in the scope of `T'
+          itself.  We must look in both the current scope, and the
+          scope of the containing complete expression.  
+
+          Yet another issue is:
+
+             struct S {
+               int S;
+               ~S();
+             };
+
+             S::~S() {}
+
+           The standard does not seem to say that the `S' in `~S'
+          should refer to the type `S' and not the data member
+          `S::S'.  */
+
+       /* DR 244 says that we look up the name after the "~" in the
+          same scope as we looked up the qualifying name.  That idea
+          isn't fully worked out; it's more complicated than that.  */
+       scope = parser->scope;
+       object_scope = parser->object_scope;
+       qualifying_scope = parser->qualifying_scope;
+
+       /* If the name is of the form "X::~X" it's OK.  */
+       if (scope && TYPE_P (scope)
+           && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+           && (cp_lexer_peek_nth_token (parser->lexer, 2)->type 
+               == CPP_OPEN_PAREN)
+           && (cp_lexer_peek_token (parser->lexer)->value 
+               == TYPE_IDENTIFIER (scope)))
+         {
+           cp_lexer_consume_token (parser->lexer);
+           return build_nt (BIT_NOT_EXPR, scope);
+         }
+
+       /* If there was an explicit qualification (S::~T), first look
+          in the scope given by the qualification (i.e., S).  */
+       if (scope)
+         {
+           cp_parser_parse_tentatively (parser);
+           type_decl = cp_parser_class_name (parser, 
+                                             /*typename_keyword_p=*/false,
+                                             /*template_keyword_p=*/false,
+                                             /*type_p=*/false,
+                                             /*check_access_p=*/true,
+                                             /*check_dependency=*/false,
+                                             /*class_head_p=*/false);
+           if (cp_parser_parse_definitely (parser))
+             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+         }
+       /* In "N::S::~S", look in "N" as well.  */
+       if (scope && qualifying_scope)
+         {
+           cp_parser_parse_tentatively (parser);
+           parser->scope = qualifying_scope;
+           parser->object_scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           type_decl 
+             = cp_parser_class_name (parser, 
+                                     /*typename_keyword_p=*/false,
+                                     /*template_keyword_p=*/false,
+                                     /*type_p=*/false,
+                                     /*check_access_p=*/true,
+                                     /*check_dependency=*/false,
+                                     /*class_head_p=*/false);
+           if (cp_parser_parse_definitely (parser))
+             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+         }
+       /* In "p->S::~T", look in the scope given by "*p" as well.  */
+       else if (object_scope)
+         {
+           cp_parser_parse_tentatively (parser);
+           parser->scope = object_scope;
+           parser->object_scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           type_decl 
+             = cp_parser_class_name (parser, 
+                                     /*typename_keyword_p=*/false,
+                                     /*template_keyword_p=*/false,
+                                     /*type_p=*/false,
+                                     /*check_access_p=*/true,
+                                     /*check_dependency=*/false,
+                                     /*class_head_p=*/false);
+           if (cp_parser_parse_definitely (parser))
+             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+         }
+       /* Look in the surrounding context.  */
+       parser->scope = NULL_TREE;
+       parser->object_scope = NULL_TREE;
+       parser->qualifying_scope = NULL_TREE;
+       type_decl 
+         = cp_parser_class_name (parser, 
+                                 /*typename_keyword_p=*/false,
+                                 /*template_keyword_p=*/false,
+                                 /*type_p=*/false,
+                                 /*check_access_p=*/true,
+                                 /*check_dependency=*/false,
+                                 /*class_head_p=*/false);
+       /* If an error occurred, assume that the name of the
+          destructor is the same as the name of the qualifying
+          class.  That allows us to keep parsing after running
+          into ill-formed destructor names.  */
+       if (type_decl == error_mark_node && scope && TYPE_P (scope))
+         return build_nt (BIT_NOT_EXPR, scope);
+       else if (type_decl == error_mark_node)
+         return error_mark_node;
+
+       return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+      }
+
+    case CPP_KEYWORD:
+      if (token->keyword == RID_OPERATOR)
+       {
+         tree id;
+
+         /* This could be a template-id, so we try that first.  */
+         cp_parser_parse_tentatively (parser);
+         /* Try a template-id.  */
+         id = cp_parser_template_id (parser, template_keyword_p,
+                                     /*check_dependency_p=*/true);
+         /* If that worked, we're done.  */
+         if (cp_parser_parse_definitely (parser))
+           return id;
+         /* We still don't know whether we're looking at an
+            operator-function-id or a conversion-function-id.  */
+         cp_parser_parse_tentatively (parser);
+         /* Try an operator-function-id.  */
+         id = cp_parser_operator_function_id (parser);
+         /* If that didn't work, try a conversion-function-id.  */
+         if (!cp_parser_parse_definitely (parser))
+           id = cp_parser_conversion_function_id (parser);
+
+         return id;
+       }
+      /* Fall through.  */
+
+    default:
+      cp_parser_error (parser, "expected unqualified-id");
+      return error_mark_node;
+    }
+}
+
+/* Parse an (optional) nested-name-specifier.
+
+   nested-name-specifier:
+     class-or-namespace-name :: nested-name-specifier [opt]
+     class-or-namespace-name :: template nested-name-specifier [opt]
+
+   PARSER->SCOPE should be set appropriately before this function is
+   called.  TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in
+   effect.  TYPE_P is TRUE if we non-type bindings should be ignored
+   in name lookups.
+
+   Sets PARSER->SCOPE to the class (TYPE) or namespace
+   (NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
+   it unchanged if there is no nested-name-specifier.  Returns the new
+   scope iff there is a nested-name-specifier, or NULL_TREE otherwise.  */
+
+static tree
+cp_parser_nested_name_specifier_opt (cp_parser *parser, 
+                                    bool typename_keyword_p, 
+                                    bool check_dependency_p,
+                                    bool type_p)
+{
+  bool success = false;
+  tree access_check = NULL_TREE;
+  ptrdiff_t start;
+
+  /* If the next token corresponds to a nested name specifier, there
+     is no need to reparse it.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
+    {
+      tree value;
+      tree check;
+
+      /* Get the stored value.  */
+      value = cp_lexer_consume_token (parser->lexer)->value;
+      /* Perform any access checks that were deferred.  */
+      for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
+       cp_parser_defer_access_check (parser, 
+                                     TREE_PURPOSE (check),
+                                     TREE_VALUE (check));
+      /* Set the scope from the stored value.  */
+      parser->scope = TREE_VALUE (value);
+      parser->qualifying_scope = TREE_TYPE (value);
+      parser->object_scope = NULL_TREE;
+      return parser->scope;
+    }
+
+  /* Remember where the nested-name-specifier starts.  */
+  if (cp_parser_parsing_tentatively (parser)
+      && !cp_parser_committed_to_tentative_parse (parser))
+    {
+      cp_token *next_token = cp_lexer_peek_token (parser->lexer);
+      start = cp_lexer_token_difference (parser->lexer,
+                                        parser->lexer->first_token,
+                                        next_token);
+      access_check = parser->context->deferred_access_checks;
+    }
+  else
+    start = -1;
+
+  while (true)
+    {
+      tree new_scope;
+      tree old_scope;
+      tree saved_qualifying_scope;
+      cp_token *token;
+      bool template_keyword_p;
+
+      /* Spot cases that cannot be the beginning of a
+        nested-name-specifier.  On the second and subsequent times
+        through the loop, we look for the `template' keyword.  */
+      if (success 
+         && cp_lexer_next_token_is_keyword (parser->lexer,
+                                            RID_TEMPLATE))
+       ;
+      /* A template-id can start a nested-name-specifier.  */
+      else if (cp_lexer_next_token_is (parser->lexer, CPP_TEMPLATE_ID))
+       ;
+      else
+       {
+         /* If the next token is not an identifier, then it is
+            definitely not a class-or-namespace-name.  */
+         if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+           break;
+         /* If the following token is neither a `<' (to begin a
+            template-id), nor a `::', then we are not looking at a
+            nested-name-specifier.  */
+         token = cp_lexer_peek_nth_token (parser->lexer, 2);
+         if (token->type != CPP_LESS && token->type != CPP_SCOPE)
+           break;
+       }
+
+      /* The nested-name-specifier is optional, so we parse
+        tentatively.  */
+      cp_parser_parse_tentatively (parser);
+
+      /* Look for the optional `template' keyword, if this isn't the
+        first time through the loop.  */
+      if (success)
+       template_keyword_p = cp_parser_optional_template_keyword (parser);
+      else
+       template_keyword_p = false;
+
+      /* Save the old scope since the name lookup we are about to do
+        might destroy it.  */
+      old_scope = parser->scope;
+      saved_qualifying_scope = parser->qualifying_scope;
+      /* Parse the qualifying entity.  */
+      new_scope 
+       = cp_parser_class_or_namespace_name (parser,
+                                            typename_keyword_p,
+                                            template_keyword_p,
+                                            check_dependency_p,
+                                            type_p);
+      /* Look for the `::' token.  */
+      cp_parser_require (parser, CPP_SCOPE, "`::'");
+
+      /* If we found what we wanted, we keep going; otherwise, we're
+        done.  */
+      if (!cp_parser_parse_definitely (parser))
+       {
+         bool error_p = false;
+
+         /* Restore the OLD_SCOPE since it was valid before the
+            failed attempt at finding the last
+            class-or-namespace-name.  */
+         parser->scope = old_scope;
+         parser->qualifying_scope = saved_qualifying_scope;
+         /* If the next token is an identifier, and the one after
+            that is a `::', then any valid interpretation would have
+            found a class-or-namespace-name.  */
+         while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+                && (cp_lexer_peek_nth_token (parser->lexer, 2)->type 
+                    == CPP_SCOPE)
+                && (cp_lexer_peek_nth_token (parser->lexer, 3)->type 
+                    != CPP_COMPL))
+           {
+             token = cp_lexer_consume_token (parser->lexer);
+             if (!error_p) 
+               {
+                 tree decl;
+
+                 decl = cp_parser_lookup_name_simple (parser, token->value);
+                 if (TREE_CODE (decl) == TEMPLATE_DECL)
+                   error ("`%D' used without template parameters",
+                          decl);
+                 else if (parser->scope)
+                   {
+                     if (TYPE_P (parser->scope))
+                       error ("`%T::%D' is not a class-name or "
+                              "namespace-name",
+                              parser->scope, token->value);
+                     else
+                       error ("`%D::%D' is not a class-name or "
+                              "namespace-name",
+                              parser->scope, token->value);
+                   }
+                 else
+                   error ("`%D' is not a class-name or namespace-name",
+                          token->value);
+                 parser->scope = NULL_TREE;
+                 error_p = true;
+               }
+             cp_lexer_consume_token (parser->lexer);
+           }
+         break;
+       }
+
+      /* We've found one valid nested-name-specifier.  */
+      success = true;
+      /* Make sure we look in the right scope the next time through
+        the loop.  */
+      parser->scope = (TREE_CODE (new_scope) == TYPE_DECL 
+                      ? TREE_TYPE (new_scope)
+                      : new_scope);
+      /* If it is a class scope, try to complete it; we are about to
+        be looking up names inside the class.  */
+      if (TYPE_P (parser->scope))
+       complete_type (parser->scope);
+    }
+
+  /* If parsing tentatively, replace the sequence of tokens that makes
+     up the nested-name-specifier with a CPP_NESTED_NAME_SPECIFIER
+     token.  That way, should we re-parse the token stream, we will
+     not have to repeat the effort required to do the parse, nor will
+     we issue duplicate error messages.  */
+  if (success && start >= 0)
+    {
+      cp_token *token;
+      tree c;
+
+      /* Find the token that corresponds to the start of the
+        template-id.  */
+      token = cp_lexer_advance_token (parser->lexer, 
+                                     parser->lexer->first_token,
+                                     start);
+
+      /* Remember the access checks associated with this
+        nested-name-specifier.  */
+      c = parser->context->deferred_access_checks;
+      if (c == access_check)
+       access_check = NULL_TREE;
+      else
+       {
+         while (TREE_CHAIN (c) != access_check)
+           c = TREE_CHAIN (c);
+         access_check = parser->context->deferred_access_checks;
+         parser->context->deferred_access_checks = TREE_CHAIN (c);
+         TREE_CHAIN (c) = NULL_TREE;
+       }
+
+      /* Reset the contents of the START token.  */
+      token->type = CPP_NESTED_NAME_SPECIFIER;
+      token->value = build_tree_list (access_check, parser->scope);
+      TREE_TYPE (token->value) = parser->qualifying_scope;
+      token->keyword = RID_MAX;
+      /* Purge all subsequent tokens.  */
+      cp_lexer_purge_tokens_after (parser->lexer, token);
+    }
+
+  return success ? parser->scope : NULL_TREE;
+}
+
+/* Parse a nested-name-specifier.  See
+   cp_parser_nested_name_specifier_opt for details.  This function
+   behaves identically, except that it will an issue an error if no
+   nested-name-specifier is present, and it will return
+   ERROR_MARK_NODE, rather than NULL_TREE, if no nested-name-specifier
+   is present.  */
+
+static tree
+cp_parser_nested_name_specifier (cp_parser *parser, 
+                                bool typename_keyword_p, 
+                                bool check_dependency_p,
+                                bool type_p)
+{
+  tree scope;
+
+  /* Look for the nested-name-specifier.  */
+  scope = cp_parser_nested_name_specifier_opt (parser,
+                                              typename_keyword_p,
+                                              check_dependency_p,
+                                              type_p);
+  /* If it was not present, issue an error message.  */
+  if (!scope)
+    {
+      cp_parser_error (parser, "expected nested-name-specifier");
+      return error_mark_node;
+    }
+
+  return scope;
+}
+
+/* Parse a class-or-namespace-name.
+
+   class-or-namespace-name:
+     class-name
+     namespace-name
+
+   TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect.
+   TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect.
+   CHECK_DEPENDENCY_P is FALSE iff dependent names should be looked up.
+   TYPE_P is TRUE iff the next name should be taken as a class-name,
+   even the same name is declared to be another entity in the same
+   scope.
+
+   Returns the class (TYPE_DECL) or namespace (NAMESPACE_DECL)
+   specified by the class-or-namespace-name.  */
+
+static tree
+cp_parser_class_or_namespace_name (cp_parser *parser, 
+                                  bool typename_keyword_p,
+                                  bool template_keyword_p,
+                                  bool check_dependency_p,
+                                  bool type_p)
+{
+  tree saved_scope;
+  tree saved_qualifying_scope;
+  tree saved_object_scope;
+  tree scope;
+
+  /* If the next token is the `template' keyword, we know that we are
+     looking at a class-name.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    return cp_parser_class_name (parser, 
+                                typename_keyword_p,
+                                template_keyword_p,
+                                type_p,
+                                /*check_access_p=*/true,
+                                check_dependency_p,
+                                /*class_head_p=*/false);
+  /* Before we try to parse the class-name, we must save away the
+     current PARSER->SCOPE since cp_parser_class_name will destroy
+     it.  */
+  saved_scope = parser->scope;
+  saved_qualifying_scope = parser->qualifying_scope;
+  saved_object_scope = parser->object_scope;
+  /* Try for a class-name first.  */
+  cp_parser_parse_tentatively (parser);
+  scope = cp_parser_class_name (parser, 
+                               typename_keyword_p,
+                               template_keyword_p,
+                               type_p,
+                               /*check_access_p=*/true,
+                               check_dependency_p,
+                               /*class_head_p=*/false);
+  /* If that didn't work, try for a namespace-name.  */
+  if (!cp_parser_parse_definitely (parser))
+    {
+      /* Restore the saved scope.  */
+      parser->scope = saved_scope;
+      parser->qualifying_scope = saved_qualifying_scope;
+      parser->object_scope = saved_object_scope;
+      /* Now look for a namespace-name.  */
+      scope = cp_parser_namespace_name (parser);
+    }
+
+  return scope;
+}
+
+/* Parse a postfix-expression.
+
+   postfix-expression:
+     primary-expression
+     postfix-expression [ expression ]
+     postfix-expression ( expression-list [opt] )
+     simple-type-specifier ( expression-list [opt] )
+     typename :: [opt] nested-name-specifier identifier 
+       ( expression-list [opt] )
+     typename :: [opt] nested-name-specifier template [opt] template-id
+       ( expression-list [opt] )
+     postfix-expression . template [opt] id-expression
+     postfix-expression -> template [opt] id-expression
+     postfix-expression . pseudo-destructor-name
+     postfix-expression -> pseudo-destructor-name
+     postfix-expression ++
+     postfix-expression --
+     dynamic_cast < type-id > ( expression )
+     static_cast < type-id > ( expression )
+     reinterpret_cast < type-id > ( expression )
+     const_cast < type-id > ( expression )
+     typeid ( expression )
+     typeid ( type-id )
+
+   GNU Extension:
+     
+   postfix-expression:
+     ( type-id ) { initializer-list , [opt] }
+
+   This extension is a GNU version of the C99 compound-literal
+   construct.  (The C99 grammar uses `type-name' instead of `type-id',
+   but they are essentially the same concept.)
+
+   If ADDRESS_P is true, the postfix expression is the operand of the
+   `&' operator.
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_postfix_expression (cp_parser *parser, bool address_p)
+{
+  cp_token *token;
+  enum rid keyword;
+  cp_parser_id_kind idk = CP_PARSER_ID_KIND_NONE;
+  tree postfix_expression = NULL_TREE;
+  /* Non-NULL only if the current postfix-expression can be used to
+     form a pointer-to-member.  In that case, QUALIFYING_CLASS is the
+     class used to qualify the member.  */
+  tree qualifying_class = NULL_TREE;
+  bool done;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Some of the productions are determined by keywords.  */
+  keyword = token->keyword;
+  switch (keyword)
+    {
+    case RID_DYNCAST:
+    case RID_STATCAST:
+    case RID_REINTCAST:
+    case RID_CONSTCAST:
+      {
+       tree type;
+       tree expression;
+       const char *saved_message;
+
+       /* All of these can be handled in the same way from the point
+          of view of parsing.  Begin by consuming the token
+          identifying the cast.  */
+       cp_lexer_consume_token (parser->lexer);
+       
+       /* New types cannot be defined in the cast.  */
+       saved_message = parser->type_definition_forbidden_message;
+       parser->type_definition_forbidden_message
+         = "types may not be defined in casts";
+
+       /* Look for the opening `<'.  */
+       cp_parser_require (parser, CPP_LESS, "`<'");
+       /* Parse the type to which we are casting.  */
+       type = cp_parser_type_id (parser);
+       /* Look for the closing `>'.  */
+       cp_parser_require (parser, CPP_GREATER, "`>'");
+       /* Restore the old message.  */
+       parser->type_definition_forbidden_message = saved_message;
+
+       /* And the expression which is being cast.  */
+       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+       expression = cp_parser_expression (parser);
+       cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+       switch (keyword)
+         {
+         case RID_DYNCAST:
+           postfix_expression
+             = build_dynamic_cast (type, expression);
+           break;
+         case RID_STATCAST:
+           postfix_expression
+             = build_static_cast (type, expression);
+           break;
+         case RID_REINTCAST:
+           postfix_expression
+             = build_reinterpret_cast (type, expression);
+           break;
+         case RID_CONSTCAST:
+           postfix_expression
+             = build_const_cast (type, expression);
+           break;
+         default:
+           abort ();
+         }
+      }
+      break;
+
+    case RID_TYPEID:
+      {
+       tree type;
+       const char *saved_message;
+
+       /* Consume the `typeid' token.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Look for the `(' token.  */
+       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+       /* Types cannot be defined in a `typeid' expression.  */
+       saved_message = parser->type_definition_forbidden_message;
+       parser->type_definition_forbidden_message
+         = "types may not be defined in a `typeid\' expression";
+       /* We can't be sure yet whether we're looking at a type-id or an
+          expression.  */
+       cp_parser_parse_tentatively (parser);
+       /* Try a type-id first.  */
+       type = cp_parser_type_id (parser);
+       /* Look for the `)' token.  Otherwise, we can't be sure that
+          we're not looking at an expression: consider `typeid (int
+          (3))', for example.  */
+       cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+       /* If all went well, simply lookup the type-id.  */
+       if (cp_parser_parse_definitely (parser))
+         postfix_expression = get_typeid (type);
+       /* Otherwise, fall back to the expression variant.  */
+       else
+         {
+           tree expression;
+
+           /* Look for an expression.  */
+           expression = cp_parser_expression (parser);
+           /* Compute its typeid.  */
+           postfix_expression = build_typeid (expression);
+           /* Look for the `)' token.  */
+           cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+         }
+
+       /* Restore the saved message.  */
+       parser->type_definition_forbidden_message = saved_message;
+      }
+      break;
+      
+    case RID_TYPENAME:
+      {
+       bool template_p = false;
+       tree id;
+       tree type;
+
+       /* Consume the `typename' token.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Look for the optional `::' operator.  */
+       cp_parser_global_scope_opt (parser, 
+                                   /*current_scope_valid_p=*/false);
+       /* Look for the nested-name-specifier.  */
+       cp_parser_nested_name_specifier (parser,
+                                        /*typename_keyword_p=*/true,
+                                        /*check_dependency_p=*/true,
+                                        /*type_p=*/true);
+       /* Look for the optional `template' keyword.  */
+       template_p = cp_parser_optional_template_keyword (parser);
+       /* We don't know whether we're looking at a template-id or an
+          identifier.  */
+       cp_parser_parse_tentatively (parser);
+       /* Try a template-id.  */
+       id = cp_parser_template_id (parser, template_p,
+                                   /*check_dependency_p=*/true);
+       /* If that didn't work, try an identifier.  */
+       if (!cp_parser_parse_definitely (parser))
+         id = cp_parser_identifier (parser);
+       /* Create a TYPENAME_TYPE to represent the type to which the
+          functional cast is being performed.  */
+       type = make_typename_type (parser->scope, id, 
+                                  /*complain=*/1);
+
+       postfix_expression = cp_parser_functional_cast (parser, type);
+      }
+      break;
+
+    default:
+      {
+       tree type;
+
+       /* If the next thing is a simple-type-specifier, we may be
+          looking at a functional cast.  We could also be looking at
+          an id-expression.  So, we try the functional cast, and if
+          that doesn't work we fall back to the primary-expression.  */
+       cp_parser_parse_tentatively (parser);
+       /* Look for the simple-type-specifier.  */
+       type = cp_parser_simple_type_specifier (parser, 
+                                               CP_PARSER_FLAGS_NONE);
+       /* Parse the cast itself.  */
+       if (!cp_parser_error_occurred (parser))
+         postfix_expression 
+           = cp_parser_functional_cast (parser, type);
+       /* If that worked, we're done.  */
+       if (cp_parser_parse_definitely (parser))
+         break;
+
+       /* If the functional-cast didn't work out, try a
+          compound-literal.  */
+       if (cp_parser_allow_gnu_extensions_p (parser))
+         {
+           tree initializer_list = NULL_TREE;
+
+           cp_parser_parse_tentatively (parser);
+           /* Look for the `('.  */
+           if (cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+             {
+               type = cp_parser_type_id (parser);
+               /* Look for the `)'.  */
+               cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+               /* Look for the `{'.  */
+               cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
+               /* If things aren't going well, there's no need to
+                  keep going.  */
+               if (!cp_parser_error_occurred (parser))
+                 {
+                   /* Parse the initializer-list.  */
+                   initializer_list 
+                     = cp_parser_initializer_list (parser);
+                   /* Allow a trailing `,'.  */
+                   if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+                     cp_lexer_consume_token (parser->lexer);
+                   /* Look for the final `}'.  */
+                   cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+                 }
+             }
+           /* If that worked, we're definitely looking at a
+              compound-literal expression.  */
+           if (cp_parser_parse_definitely (parser))
+             {
+               /* Warn the user that a compound literal is not
+                  allowed in standard C++.  */
+               if (pedantic)
+                 pedwarn ("ISO C++ forbids compound-literals");
+               /* Form the representation of the compound-literal.  */
+               postfix_expression 
+                 = finish_compound_literal (type, initializer_list);
+               break;
+             }
+         }
+
+       /* It must be a primary-expression.  */
+       postfix_expression = cp_parser_primary_expression (parser, 
+                                                          &idk,
+                                                          &qualifying_class);
+      }
+      break;
+    }
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  done = (token->type != CPP_OPEN_SQUARE
+         && token->type != CPP_OPEN_PAREN
+         && token->type != CPP_DOT
+         && token->type != CPP_DEREF
+         && token->type != CPP_PLUS_PLUS
+         && token->type != CPP_MINUS_MINUS);
+
+  /* If the postfix expression is complete, finish up.  */
+  if (address_p && qualifying_class && done)
+    {
+      if (TREE_CODE (postfix_expression) == SCOPE_REF)
+       postfix_expression = TREE_OPERAND (postfix_expression, 1);
+      postfix_expression 
+       = build_offset_ref (qualifying_class, postfix_expression);
+      return postfix_expression;
+    }
+
+  /* Otherwise, if we were avoiding committing until we knew
+     whether or not we had a pointer-to-member, we now know that
+     the expression is an ordinary reference to a qualified name.  */
+  if (qualifying_class && !processing_template_decl)
+    {
+      if (TREE_CODE (postfix_expression) == FIELD_DECL)
+       postfix_expression 
+         = finish_non_static_data_member (postfix_expression,
+                                          qualifying_class);
+      else if (BASELINK_P (postfix_expression))
+       {
+         tree fn;
+         tree fns;
+
+         /* See if any of the functions are non-static members.  */
+         fns = BASELINK_FUNCTIONS (postfix_expression);
+         if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+           fns = TREE_OPERAND (fns, 0);
+         for (fn = fns; fn; fn = OVL_NEXT (fn))
+           if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+             break;
+         /* If so, the expression may be relative to the current
+            class.  */
+         if (fn && current_class_type 
+             && DERIVED_FROM_P (qualifying_class, current_class_type))
+           postfix_expression 
+             = (build_class_member_access_expr 
+                (maybe_dummy_object (qualifying_class, NULL),
+                 postfix_expression,
+                 BASELINK_ACCESS_BINFO (postfix_expression),
+                 /*preserve_reference=*/false));
+         else if (done)
+           return build_offset_ref (qualifying_class,
+                                    postfix_expression);
+       }
+    }
+
+  /* Remember that there was a reference to this entity.  */
+  if (DECL_P (postfix_expression))
+    mark_used (postfix_expression);
+
+  /* Keep looping until the postfix-expression is complete.  */
+  while (true)
+    {
+      if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
+       {
+         /* It is not a Koenig lookup function call.  */
+         unqualified_name_lookup_error (postfix_expression);
+         postfix_expression = error_mark_node;
+       }
+      
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+
+      switch (token->type)
+       {
+       case CPP_OPEN_SQUARE:
+         /* postfix-expression [ expression ] */
+         {
+           tree index;
+
+           /* Consume the `[' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the index expression.  */
+           index = cp_parser_expression (parser);
+           /* Look for the closing `]'.  */
+           cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+           /* Build the ARRAY_REF.  */
+           postfix_expression 
+             = grok_array_decl (postfix_expression, index);
+           idk = CP_PARSER_ID_KIND_NONE;
+         }
+         break;
+
+       case CPP_OPEN_PAREN:
+         /* postfix-expression ( expression-list [opt] ) */
+         {
+           tree args;
+
+           /* Consume the `(' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* If the next token is not a `)', then there are some
+               arguments.  */
+           if (cp_lexer_next_token_is_not (parser->lexer, 
+                                           CPP_CLOSE_PAREN))
+             args = cp_parser_expression_list (parser);
+           else
+             args = NULL_TREE;
+           /* Look for the closing `)'.  */
+           cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+           if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
+               && (is_overloaded_fn (postfix_expression)
+                   || DECL_P (postfix_expression)
+                   || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
+               && args)
+             {
+               tree arg;
+               tree identifier = NULL_TREE;
+               tree functions = NULL_TREE;
+
+               /* Find the name of the overloaded function.  */
+               if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
+                 identifier = postfix_expression;
+               else if (is_overloaded_fn (postfix_expression))
+                 {
+                   functions = postfix_expression;
+                   identifier = DECL_NAME (get_first_fn (functions));
+                 }
+               else if (DECL_P (postfix_expression))
+                 {
+                   functions = postfix_expression;
+                   identifier = DECL_NAME (postfix_expression);
+                 }
+
+               /* A call to a namespace-scope function using an
+                  unqualified name.
+
+                  Do Koenig lookup -- unless any of the arguments are
+                  type-dependent.  */
+               for (arg = args; arg; arg = TREE_CHAIN (arg))
+                 if (cp_parser_type_dependent_expression_p (TREE_VALUE (arg)))
+                     break;
+               if (!arg)
+                 {
+                   postfix_expression 
+                     = lookup_arg_dependent(identifier, functions, args);
+                   if (!postfix_expression)
+                     {
+                       /* The unqualified name could not be resolved.  */
+                       unqualified_name_lookup_error (identifier);
+                       postfix_expression = error_mark_node;
+                     }
+                   postfix_expression
+                     = build_call_from_tree (postfix_expression, args, 
+                                             /*diallow_virtual=*/false);
+                   break;
+                 }
+               postfix_expression = build_min_nt (LOOKUP_EXPR,
+                                                  identifier);
+             }
+           else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED 
+                    && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
+             {
+               /* The unqualified name could not be resolved.  */
+               unqualified_name_lookup_error (postfix_expression);
+               postfix_expression = error_mark_node;
+               break;
+             }
+
+           /* In the body of a template, no further processing is
+              required.  */
+           if (processing_template_decl)
+             {
+               postfix_expression = build_nt (CALL_EXPR,
+                                              postfix_expression, 
+                                              args);
+               break;
+             }
+
+           if (TREE_CODE (postfix_expression) == COMPONENT_REF)
+             postfix_expression
+               = (build_new_method_call 
+                  (TREE_OPERAND (postfix_expression, 0),
+                   TREE_OPERAND (postfix_expression, 1),
+                   args, NULL_TREE, 
+                   (idk == CP_PARSER_ID_KIND_QUALIFIED 
+                    ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
+           else if (TREE_CODE (postfix_expression) == OFFSET_REF)
+             postfix_expression = (build_offset_ref_call_from_tree
+                                   (postfix_expression, args));
+           else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
+             {
+               /* A call to a static class member, or a
+                  namespace-scope function.  */
+               postfix_expression
+                 = finish_call_expr (postfix_expression, args,
+                                     /*disallow_virtual=*/true);
+             }
+           else
+             {
+               /* All other function calls.  */
+               postfix_expression 
+                 = finish_call_expr (postfix_expression, args, 
+                                     /*disallow_virtual=*/false);
+             }
+
+           /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
+           idk = CP_PARSER_ID_KIND_NONE;
+         }
+         break;
+         
+       case CPP_DOT:
+       case CPP_DEREF:
+         /* postfix-expression . template [opt] id-expression  
+            postfix-expression . pseudo-destructor-name 
+            postfix-expression -> template [opt] id-expression
+            postfix-expression -> pseudo-destructor-name */
+         {
+           tree name;
+           bool dependent_p;
+           bool template_p;
+           tree scope = NULL_TREE;
+
+           /* If this is a `->' operator, dereference the pointer.  */
+           if (token->type == CPP_DEREF)
+             postfix_expression = build_x_arrow (postfix_expression);
+           /* Check to see whether or not the expression is
+              type-dependent.  */
+           dependent_p = (cp_parser_type_dependent_expression_p 
+                          (postfix_expression));
+           /* The identifier following the `->' or `.' is not
+              qualified.  */
+           parser->scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           parser->object_scope = NULL_TREE;
+           /* Enter the scope corresponding to the type of the object
+              given by the POSTFIX_EXPRESSION.  */
+           if (!dependent_p 
+               && TREE_TYPE (postfix_expression) != NULL_TREE)
+             {
+               scope = TREE_TYPE (postfix_expression);
+               /* According to the standard, no expression should
+                  ever have reference type.  Unfortunately, we do not
+                  currently match the standard in this respect in
+                  that our internal representation of an expression
+                  may have reference type even when the standard says
+                  it does not.  Therefore, we have to manually obtain
+                  the underlying type here.  */
+               if (TREE_CODE (scope) == REFERENCE_TYPE)
+                 scope = TREE_TYPE (scope);
+               /* If the SCOPE is an OFFSET_TYPE, then we grab the
+                  type of the field.  We get an OFFSET_TYPE for
+                  something like:
+
+                    S::T.a ...
+
+                  Probably, we should not get an OFFSET_TYPE here;
+                  that transformation should be made only if `&S::T'
+                  is written.  */
+               if (TREE_CODE (scope) == OFFSET_TYPE)
+                 scope = TREE_TYPE (scope);
+               /* The type of the POSTFIX_EXPRESSION must be
+                  complete.  */
+               scope = complete_type_or_else (scope, NULL_TREE);
+               /* Let the name lookup machinery know that we are
+                  processing a class member access expression.  */
+               parser->context->object_type = scope;
+               /* If something went wrong, we want to be able to
+                  discern that case, as opposed to the case where
+                  there was no SCOPE due to the type of expression
+                  being dependent.  */
+               if (!scope)
+                 scope = error_mark_node;
+             }
+
+           /* Consume the `.' or `->' operator.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* If the SCOPE is not a scalar type, we are looking at an
+              ordinary class member access expression, rather than a
+              pseudo-destructor-name.  */
+           if (!scope || !SCALAR_TYPE_P (scope))
+             {
+               template_p = cp_parser_optional_template_keyword (parser);
+               /* Parse the id-expression.  */
+               name = cp_parser_id_expression (parser,
+                                               template_p,
+                                               /*check_dependency_p=*/true,
+                                               /*template_p=*/NULL);
+               /* In general, build a SCOPE_REF if the member name is
+                  qualified.  However, if the name was not dependent
+                  and has already been resolved; there is no need to
+                  build the SCOPE_REF.  For example;
+
+                     struct X { void f(); };
+                     template <typename T> void f(T* t) { t->X::f(); }
+                   Even though "t" is dependent, "X::f" is not and has 
+                  except that for a BASELINK there is no need to
+                  include scope information.  */
+               if (name != error_mark_node 
+                   && !BASELINK_P (name)
+                   && parser->scope)
+                 {
+                   name = build_nt (SCOPE_REF, parser->scope, name);
+                   parser->scope = NULL_TREE;
+                   parser->qualifying_scope = NULL_TREE;
+                   parser->object_scope = NULL_TREE;
+                 }
+               postfix_expression 
+                 = finish_class_member_access_expr (postfix_expression, name);
+             }
+           /* Otherwise, try the pseudo-destructor-name production.  */
+           else
+             {
+               tree s;
+               tree type;
+
+               /* Parse the pseudo-destructor-name.  */
+               cp_parser_pseudo_destructor_name (parser, &s, &type);
+               /* Form the call.  */
+               postfix_expression 
+                 = finish_pseudo_destructor_expr (postfix_expression,
+                                                  s, TREE_TYPE (type));
+             }
+
+           /* We no longer need to look up names in the scope of the
+              object on the left-hand side of the `.' or `->'
+              operator.  */
+           parser->context->object_type = NULL_TREE;
+           idk = CP_PARSER_ID_KIND_NONE;
+         }
+         break;
+
+       case CPP_PLUS_PLUS:
+         /* postfix-expression ++  */
+         /* Consume the `++' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Generate a reprsentation for the complete expression.  */
+         postfix_expression 
+           = finish_increment_expr (postfix_expression, 
+                                    POSTINCREMENT_EXPR);
+         idk = CP_PARSER_ID_KIND_NONE;
+         break;
+
+       case CPP_MINUS_MINUS:
+         /* postfix-expression -- */
+         /* Consume the `--' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Generate a reprsentation for the complete expression.  */
+         postfix_expression 
+           = finish_increment_expr (postfix_expression, 
+                                    POSTDECREMENT_EXPR);
+         idk = CP_PARSER_ID_KIND_NONE;
+         break;
+
+       default:
+         return postfix_expression;
+       }
+    }
+
+  /* We should never get here.  */
+  abort ();
+  return error_mark_node;
+}
+
+/* Parse an expression-list.
+
+   expression-list:
+     assignment-expression
+     expression-list, assignment-expression
+
+   Returns a TREE_LIST.  The TREE_VALUE of each node is a
+   representation of an assignment-expression.  Note that a TREE_LIST
+   is returned even if there is only a single expression in the list.  */
+
+static tree
+cp_parser_expression_list (parser)
+     cp_parser *parser;
+{
+  tree expression_list = NULL_TREE;
+
+  /* Consume expressions until there are no more.  */
+  while (true)
+    {
+      tree expr;
+
+      /* Parse the next assignment-expression.  */
+      expr = cp_parser_assignment_expression (parser);
+      /* Add it to the list.  */
+      expression_list = tree_cons (NULL_TREE, expr, expression_list);
+
+      /* If the next token isn't a `,', then we are done.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       {
+         /* All uses of expression-list in the grammar are followed
+            by a `)'.  Therefore, if the next token is not a `)' an
+            error will be issued, unless we are parsing tentatively.
+            Skip ahead to see if there is another `,' before the `)';
+            if so, we can go there and recover.  */
+         if (cp_parser_parsing_tentatively (parser)
+             || cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
+             || !cp_parser_skip_to_closing_parenthesis_or_comma (parser))
+           break;
+       }
+
+      /* Otherwise, consume the `,' and keep going.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* We built up the list in reverse order so we must reverse it now.  */
+  return nreverse (expression_list);
+}
+
+/* Parse a pseudo-destructor-name.
+
+   pseudo-destructor-name:
+     :: [opt] nested-name-specifier [opt] type-name :: ~ type-name
+     :: [opt] nested-name-specifier template template-id :: ~ type-name
+     :: [opt] nested-name-specifier [opt] ~ type-name
+
+   If either of the first two productions is used, sets *SCOPE to the
+   TYPE specified before the final `::'.  Otherwise, *SCOPE is set to
+   NULL_TREE.  *TYPE is set to the TYPE_DECL for the final type-name,
+   or ERROR_MARK_NODE if no type-name is present.  */
+
+static void
+cp_parser_pseudo_destructor_name (parser, scope, type)
+     cp_parser *parser;
+     tree *scope;
+     tree *type;
+{
+  bool nested_name_specifier_p;
+
+  /* Look for the optional `::' operator.  */
+  cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true);
+  /* Look for the optional nested-name-specifier.  */
+  nested_name_specifier_p 
+    = (cp_parser_nested_name_specifier_opt (parser,
+                                           /*typename_keyword_p=*/false,
+                                           /*check_dependency_p=*/true,
+                                           /*type_p=*/false) 
+       != NULL_TREE);
+  /* Now, if we saw a nested-name-specifier, we might be doing the
+     second production.  */
+  if (nested_name_specifier_p 
+      && cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    {
+      /* Consume the `template' keyword.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the template-id.  */
+      cp_parser_template_id (parser, 
+                            /*template_keyword_p=*/true,
+                            /*check_dependency_p=*/false);
+      /* Look for the `::' token.  */
+      cp_parser_require (parser, CPP_SCOPE, "`::'");
+    }
+  /* If the next token is not a `~', then there might be some
+     additional qualification. */
+  else if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMPL))
+    {
+      /* Look for the type-name.  */
+      *scope = TREE_TYPE (cp_parser_type_name (parser));
+      /* Look for the `::' token.  */
+      cp_parser_require (parser, CPP_SCOPE, "`::'");
+    }
+  else
+    *scope = NULL_TREE;
+
+  /* Look for the `~'.  */
+  cp_parser_require (parser, CPP_COMPL, "`~'");
+  /* Look for the type-name again.  We are not responsible for
+     checking that it matches the first type-name.  */
+  *type = cp_parser_type_name (parser);
+}
+
+/* Parse a unary-expression.
+
+   unary-expression:
+     postfix-expression
+     ++ cast-expression
+     -- cast-expression
+     unary-operator cast-expression
+     sizeof unary-expression
+     sizeof ( type-id )
+     new-expression
+     delete-expression
+
+   GNU Extensions:
+
+   unary-expression:
+     __extension__ cast-expression
+     __alignof__ unary-expression
+     __alignof__ ( type-id )
+     __real__ cast-expression
+     __imag__ cast-expression
+     && identifier
+
+   ADDRESS_P is true iff the unary-expression is appearing as the
+   operand of the `&' operator.
+
+   Returns a representation of the expresion.  */
+
+static tree
+cp_parser_unary_expression (cp_parser *parser, bool address_p)
+{
+  cp_token *token;
+  enum tree_code unary_operator;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Some keywords give away the kind of expression.  */
+  if (token->type == CPP_KEYWORD)
+    {
+      enum rid keyword = token->keyword;
+
+      switch (keyword)
+       {
+       case RID_ALIGNOF:
+         {
+           /* Consume the `alignof' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the operand.  */
+           return finish_alignof (cp_parser_sizeof_operand 
+                                  (parser, keyword));
+         }
+
+       case RID_SIZEOF:
+         {
+           tree operand;
+           
+           /* Consume the `sizeof' token.   */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the operand.  */
+           operand = cp_parser_sizeof_operand (parser, keyword);
+
+           /* If the type of the operand cannot be determined build a
+              SIZEOF_EXPR.  */
+           if (TYPE_P (operand)
+               ? cp_parser_dependent_type_p (operand)
+               : cp_parser_type_dependent_expression_p (operand))
+             return build_min (SIZEOF_EXPR, size_type_node, operand);
+           /* Otherwise, compute the constant value.  */
+           else
+             return finish_sizeof (operand);
+         }
+
+       case RID_NEW:
+         return cp_parser_new_expression (parser);
+
+       case RID_DELETE:
+         return cp_parser_delete_expression (parser);
+         
+       case RID_EXTENSION:
+         {
+           /* The saved value of the PEDANTIC flag.  */
+           int saved_pedantic;
+           tree expr;
+
+           /* Save away the PEDANTIC flag.  */
+           cp_parser_extension_opt (parser, &saved_pedantic);
+           /* Parse the cast-expression.  */
+           expr = cp_parser_cast_expression (parser, /*address_p=*/false);
+           /* Restore the PEDANTIC flag.  */
+           pedantic = saved_pedantic;
+
+           return expr;
+         }
+
+       case RID_REALPART:
+       case RID_IMAGPART:
+         {
+           tree expression;
+
+           /* Consume the `__real__' or `__imag__' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the cast-expression.  */
+           expression = cp_parser_cast_expression (parser,
+                                                   /*address_p=*/false);
+           /* Create the complete representation.  */
+           return build_x_unary_op ((keyword == RID_REALPART
+                                     ? REALPART_EXPR : IMAGPART_EXPR),
+                                    expression);
+         }
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  /* Look for the `:: new' and `:: delete', which also signal the
+     beginning of a new-expression, or delete-expression,
+     respectively.  If the next token is `::', then it might be one of
+     these.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+    {
+      enum rid keyword;
+
+      /* See if the token after the `::' is one of the keywords in
+        which we're interested.  */
+      keyword = cp_lexer_peek_nth_token (parser->lexer, 2)->keyword;
+      /* If it's `new', we have a new-expression.  */
+      if (keyword == RID_NEW)
+       return cp_parser_new_expression (parser);
+      /* Similarly, for `delete'.  */
+      else if (keyword == RID_DELETE)
+       return cp_parser_delete_expression (parser);
+    }
+
+  /* Look for a unary operator.  */
+  unary_operator = cp_parser_unary_operator (token);
+  /* The `++' and `--' operators can be handled similarly, even though
+     they are not technically unary-operators in the grammar.  */
+  if (unary_operator == ERROR_MARK)
+    {
+      if (token->type == CPP_PLUS_PLUS)
+       unary_operator = PREINCREMENT_EXPR;
+      else if (token->type == CPP_MINUS_MINUS)
+       unary_operator = PREDECREMENT_EXPR;
+      /* Handle the GNU address-of-label extension.  */
+      else if (cp_parser_allow_gnu_extensions_p (parser)
+              && token->type == CPP_AND_AND)
+       {
+         tree identifier;
+
+         /* Consume the '&&' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Look for the identifier.  */
+         identifier = cp_parser_identifier (parser);
+         /* Create an expression representing the address.  */
+         return finish_label_address_expr (identifier);
+       }
+    }
+  if (unary_operator != ERROR_MARK)
+    {
+      tree cast_expression;
+
+      /* Consume the operator token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+      /* Parse the cast-expression.  */
+      cast_expression 
+       = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
+      /* Now, build an appropriate representation.  */
+      switch (unary_operator)
+       {
+       case INDIRECT_REF:
+         return build_x_indirect_ref (cast_expression, "unary *");
+         
+       case ADDR_EXPR:
+         return build_x_unary_op (ADDR_EXPR, cast_expression);
+         
+       case CONVERT_EXPR:
+       case NEGATE_EXPR:
+       case TRUTH_NOT_EXPR:
+       case PREINCREMENT_EXPR:
+       case PREDECREMENT_EXPR:
+         return finish_unary_op_expr (unary_operator, cast_expression);
+
+       case BIT_NOT_EXPR:
+         return build_x_unary_op (BIT_NOT_EXPR, cast_expression);
+
+       default:
+         abort ();
+         return error_mark_node;
+       }
+    }
+
+  return cp_parser_postfix_expression (parser, address_p);
+}
+
+/* Returns ERROR_MARK if TOKEN is not a unary-operator.  If TOKEN is a
+   unary-operator, the corresponding tree code is returned.  */
+
+static enum tree_code
+cp_parser_unary_operator (token)
+     cp_token *token;
+{
+  switch (token->type)
+    {
+    case CPP_MULT:
+      return INDIRECT_REF;
+
+    case CPP_AND:
+      return ADDR_EXPR;
+
+    case CPP_PLUS:
+      return CONVERT_EXPR;
+
+    case CPP_MINUS:
+      return NEGATE_EXPR;
+
+    case CPP_NOT:
+      return TRUTH_NOT_EXPR;
+      
+    case CPP_COMPL:
+      return BIT_NOT_EXPR;
+
+    default:
+      return ERROR_MARK;
+    }
+}
+
+/* Parse a new-expression.
+
+     :: [opt] new new-placement [opt] new-type-id new-initializer [opt]
+     :: [opt] new new-placement [opt] ( type-id ) new-initializer [opt]
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_new_expression (parser)
+     cp_parser *parser;
+{
+  bool global_scope_p;
+  tree placement;
+  tree type;
+  tree initializer;
+
+  /* Look for the optional `::' operator.  */
+  global_scope_p 
+    = (cp_parser_global_scope_opt (parser,
+                                  /*current_scope_valid_p=*/false)
+       != NULL_TREE);
+  /* Look for the `new' operator.  */
+  cp_parser_require_keyword (parser, RID_NEW, "`new'");
+  /* There's no easy way to tell a new-placement from the
+     `( type-id )' construct.  */
+  cp_parser_parse_tentatively (parser);
+  /* Look for a new-placement.  */
+  placement = cp_parser_new_placement (parser);
+  /* If that didn't work out, there's no new-placement.  */
+  if (!cp_parser_parse_definitely (parser))
+    placement = NULL_TREE;
+
+  /* If the next token is a `(', then we have a parenthesized
+     type-id.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the type-id.  */
+      type = cp_parser_type_id (parser);
+      /* Look for the closing `)'.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+    }
+  /* Otherwise, there must be a new-type-id.  */
+  else
+    type = cp_parser_new_type_id (parser);
+
+  /* If the next token is a `(', then we have a new-initializer.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    initializer = cp_parser_new_initializer (parser);
+  else
+    initializer = NULL_TREE;
+
+  /* Create a representation of the new-expression.  */
+  return build_new (placement, type, initializer, global_scope_p);
+}
+
+/* Parse a new-placement.
+
+   new-placement:
+     ( expression-list )
+
+   Returns the same representation as for an expression-list.  */
+
+static tree
+cp_parser_new_placement (parser)
+     cp_parser *parser;
+{
+  tree expression_list;
+
+  /* Look for the opening `('.  */
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+    return error_mark_node;
+  /* Parse the expression-list.  */
+  expression_list = cp_parser_expression_list (parser);
+  /* Look for the closing `)'.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return expression_list;
+}
+
+/* Parse a new-type-id.
+
+   new-type-id:
+     type-specifier-seq new-declarator [opt]
+
+   Returns a TREE_LIST whose TREE_PURPOSE is the type-specifier-seq,
+   and whose TREE_VALUE is the new-declarator.  */
+
+static tree
+cp_parser_new_type_id (parser)
+     cp_parser *parser;
+{
+  tree type_specifier_seq;
+  tree declarator;
+  const char *saved_message;
+
+  /* The type-specifier sequence must not contain type definitions.
+     (It cannot contain declarations of new types either, but if they
+     are not definitions we will catch that because they are not
+     complete.)  */
+  saved_message = parser->type_definition_forbidden_message;
+  parser->type_definition_forbidden_message
+    = "types may not be defined in a new-type-id";
+  /* Parse the type-specifier-seq.  */
+  type_specifier_seq = cp_parser_type_specifier_seq (parser);
+  /* Restore the old message.  */
+  parser->type_definition_forbidden_message = saved_message;
+  /* Parse the new-declarator.  */
+  declarator = cp_parser_new_declarator_opt (parser);
+
+  return build_tree_list (type_specifier_seq, declarator);
+}
+
+/* Parse an (optional) new-declarator.
+
+   new-declarator:
+     ptr-operator new-declarator [opt]
+     direct-new-declarator
+
+   Returns a representation of the declarator.  See
+   cp_parser_declarator for the representations used.  */
+
+static tree
+cp_parser_new_declarator_opt (parser)
+     cp_parser *parser;
+{
+  enum tree_code code;
+  tree type;
+  tree cv_qualifier_seq;
+
+  /* We don't know if there's a ptr-operator next, or not.  */
+  cp_parser_parse_tentatively (parser);
+  /* Look for a ptr-operator.  */
+  code = cp_parser_ptr_operator (parser, &type, &cv_qualifier_seq);
+  /* If that worked, look for more new-declarators.  */
+  if (cp_parser_parse_definitely (parser))
+    {
+      tree declarator;
+
+      /* Parse another optional declarator.  */
+      declarator = cp_parser_new_declarator_opt (parser);
+
+      /* Create the representation of the declarator.  */
+      if (code == INDIRECT_REF)
+       declarator = make_pointer_declarator (cv_qualifier_seq,
+                                             declarator);
+      else
+       declarator = make_reference_declarator (cv_qualifier_seq,
+                                               declarator);
+
+     /* Handle the pointer-to-member case.  */
+     if (type)
+       declarator = build_nt (SCOPE_REF, type, declarator);
+
+      return declarator;
+    }
+
+  /* If the next token is a `[', there is a direct-new-declarator.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
+    return cp_parser_direct_new_declarator (parser);
+
+  return NULL_TREE;
+}
+
+/* Parse a direct-new-declarator.
+
+   direct-new-declarator:
+     [ expression ]
+     direct-new-declarator [constant-expression]  
+
+   Returns an ARRAY_REF, following the same conventions as are
+   documented for cp_parser_direct_declarator.  */
+
+static tree
+cp_parser_direct_new_declarator (parser)
+     cp_parser *parser;
+{
+  tree declarator = NULL_TREE;
+
+  while (true)
+    {
+      tree expression;
+
+      /* Look for the opening `['.  */
+      cp_parser_require (parser, CPP_OPEN_SQUARE, "`['");
+      /* The first expression is not required to be constant.  */
+      if (!declarator)
+       {
+         expression = cp_parser_expression (parser);
+         /* The standard requires that the expression have integral
+            type.  DR 74 adds enumeration types.  We believe that the
+            real intent is that these expressions be handled like the
+            expression in a `switch' condition, which also allows
+            classes with a single conversion to integral or
+            enumeration type.  */
+         if (!processing_template_decl)
+           {
+             expression 
+               = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+                                             expression,
+                                             /*complain=*/1);
+             if (!expression)
+               {
+                 error ("expression in new-declarator must have integral or enumeration type");
+                 expression = error_mark_node;
+               }
+           }
+       }
+      /* But all the other expressions must be.  */
+      else
+       expression = cp_parser_constant_expression (parser);
+      /* Look for the closing `]'.  */
+      cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+      /* Add this bound to the declarator.  */
+      declarator = build_nt (ARRAY_REF, declarator, expression);
+
+      /* If the next token is not a `[', then there are no more
+        bounds.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
+       break;
+    }
+
+  return declarator;
+}
+
+/* Parse a new-initializer.
+
+   new-initializer:
+     ( expression-list [opt] )
+
+   Returns a reprsentation of the expression-list.  If there is no
+   expression-list, VOID_ZERO_NODE is returned.  */
+
+static tree
+cp_parser_new_initializer (parser)
+     cp_parser *parser;
+{
+  tree expression_list;
+
+  /* Look for the opening parenthesis.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  /* If the next token is not a `)', then there is an
+     expression-list.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+    expression_list = cp_parser_expression_list (parser);
+  else
+    expression_list = void_zero_node;
+  /* Look for the closing parenthesis.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return expression_list;
+}
+
+/* Parse a delete-expression.
+
+   delete-expression:
+     :: [opt] delete cast-expression
+     :: [opt] delete [ ] cast-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_delete_expression (parser)
+     cp_parser *parser;
+{
+  bool global_scope_p;
+  bool array_p;
+  tree expression;
+
+  /* Look for the optional `::' operator.  */
+  global_scope_p
+    = (cp_parser_global_scope_opt (parser,
+                                  /*current_scope_valid_p=*/false)
+       != NULL_TREE);
+  /* Look for the `delete' keyword.  */
+  cp_parser_require_keyword (parser, RID_DELETE, "`delete'");
+  /* See if the array syntax is in use.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
+    {
+      /* Consume the `[' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the `]' token.  */
+      cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+      /* Remember that this is the `[]' construct.  */
+      array_p = true;
+    }
+  else
+    array_p = false;
+
+  /* Parse the cast-expression.  */
+  expression = cp_parser_cast_expression (parser, /*address_p=*/false);
+
+  return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
+}
+
+/* Parse a cast-expression.
+
+   cast-expression:
+     unary-expression
+     ( type-id ) cast-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_cast_expression (cp_parser *parser, bool address_p)
+{
+  /* If it's a `(', then we might be looking at a cast.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      tree type = NULL_TREE;
+      tree expr = NULL_TREE;
+      bool compound_literal_p;
+      const char *saved_message;
+
+      /* There's no way to know yet whether or not this is a cast.
+        For example, `(int (3))' is a unary-expression, while `(int)
+        3' is a cast.  So, we resort to parsing tentatively.  */
+      cp_parser_parse_tentatively (parser);
+      /* Types may not be defined in a cast.  */
+      saved_message = parser->type_definition_forbidden_message;
+      parser->type_definition_forbidden_message
+       = "types may not be defined in casts";
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* A very tricky bit is that `(struct S) { 3 }' is a
+        compound-literal (which we permit in C++ as an extension).
+        But, that construct is not a cast-expression -- it is a
+        postfix-expression.  (The reason is that `(struct S) { 3 }.i'
+        is legal; if the compound-literal were a cast-expression,
+        you'd need an extra set of parentheses.)  But, if we parse
+        the type-id, and it happens to be a class-specifier, then we
+        will commit to the parse at that point, because we cannot
+        undo the action that is done when creating a new class.  So,
+        then we cannot back up and do a postfix-expression.  
+
+        Therefore, we scan ahead to the closing `)', and check to see
+        if the token after the `)' is a `{'.  If so, we are not
+        looking at a cast-expression.  
+
+        Save tokens so that we can put them back.  */
+      cp_lexer_save_tokens (parser->lexer);
+      /* Skip tokens until the next token is a closing parenthesis.
+        If we find the closing `)', and the next token is a `{', then
+        we are looking at a compound-literal.  */
+      compound_literal_p 
+       = (cp_parser_skip_to_closing_parenthesis (parser)
+          && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
+      /* Roll back the tokens we skipped.  */
+      cp_lexer_rollback_tokens (parser->lexer);
+      /* If we were looking at a compound-literal, simulate an error
+        so that the call to cp_parser_parse_definitely below will
+        fail.  */
+      if (compound_literal_p)
+       cp_parser_simulate_error (parser);
+      else
+       {
+         /* Look for the type-id.  */
+         type = cp_parser_type_id (parser);
+         /* Look for the closing `)'.  */
+         cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+       }
+
+      /* Restore the saved message.  */
+      parser->type_definition_forbidden_message = saved_message;
+
+      /* If all went well, this is a cast.  */
+      if (cp_parser_parse_definitely (parser))
+       {
+         /* Parse the dependent expression.  */
+         expr = cp_parser_cast_expression (parser, /*address_p=*/false);
+         /* Warn about old-style casts, if so requested.  */
+         if (warn_old_style_cast 
+             && !in_system_header 
+             && !VOID_TYPE_P (type) 
+             && current_lang_name != lang_name_c)
+           warning ("use of old-style cast");
+         /* Perform the cast.  */
+         expr = build_c_cast (type, expr);
+       }
+
+      if (expr)
+       return expr;
+    }
+
+  /* If we get here, then it's not a cast, so it must be a
+     unary-expression.  */
+  return cp_parser_unary_expression (parser, address_p);
+}
+
+/* Parse a pm-expression.
+
+   pm-expression:
+     cast-expression
+     pm-expression .* cast-expression
+     pm-expression ->* cast-expression
+
+     Returns a representation of the expression.  */
+
+static tree
+cp_parser_pm_expression (parser)
+     cp_parser *parser;
+{
+  tree cast_expr;
+  tree pm_expr;
+
+  /* Parse the cast-expresion.  */
+  cast_expr = cp_parser_cast_expression (parser, /*address_p=*/false);
+  pm_expr = cast_expr;
+  /* Now look for pointer-to-member operators.  */
+  while (true)
+    {
+      cp_token *token;
+      enum cpp_ttype token_type;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      token_type = token->type;
+      /* If it's not `.*' or `->*' there's no pointer-to-member
+        operation.  */
+      if (token_type != CPP_DOT_STAR 
+         && token_type != CPP_DEREF_STAR)
+       break;
+
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      /* Parse another cast-expression.  */
+      cast_expr = cp_parser_cast_expression (parser, /*address_p=*/false);
+
+      /* Build the representation of the pointer-to-member 
+        operation.  */
+      if (token_type == CPP_DEREF_STAR)
+       pm_expr = build_x_binary_op (MEMBER_REF, pm_expr, cast_expr);
+      else
+       pm_expr = build_m_component_ref (pm_expr, cast_expr);
+    }
+
+  return pm_expr;
+}
+
+/* Parse a multiplicative-expression.
+
+   mulitplicative-expression:
+     pm-expression
+     multiplicative-expression * pm-expression
+     multiplicative-expression / pm-expression
+     multiplicative-expression % pm-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_multiplicative_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_MULT, MULT_EXPR },
+    { CPP_DIV, TRUNC_DIV_EXPR },
+    { CPP_MOD, TRUNC_MOD_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_pm_expression);
+}
+
+/* Parse an additive-expression.
+
+   additive-expression:
+     multiplicative-expression
+     additive-expression + multiplicative-expression
+     additive-expression - multiplicative-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_additive_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_PLUS, PLUS_EXPR },
+    { CPP_MINUS, MINUS_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_multiplicative_expression);
+}
+
+/* Parse a shift-expression.
+
+   shift-expression:
+     additive-expression
+     shift-expression << additive-expression
+     shift-expression >> additive-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_shift_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_LSHIFT, LSHIFT_EXPR },
+    { CPP_RSHIFT, RSHIFT_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_additive_expression);
+}
+
+/* Parse a relational-expression.
+
+   relational-expression:
+     shift-expression
+     relational-expression < shift-expression
+     relational-expression > shift-expression
+     relational-expression <= shift-expression
+     relational-expression >= shift-expression
+
+   GNU Extension:
+
+   relational-expression:
+     relational-expression <? shift-expression
+     relational-expression >? shift-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_relational_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_LESS, LT_EXPR },
+    { CPP_GREATER, GT_EXPR },
+    { CPP_LESS_EQ, LE_EXPR },
+    { CPP_GREATER_EQ, GE_EXPR },
+    { CPP_MIN, MIN_EXPR },
+    { CPP_MAX, MAX_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_shift_expression);
+}
+
+/* Parse an equality-expression.
+
+   equality-expression:
+     relational-expression
+     equality-expression == relational-expression
+     equality-expression != relational-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_equality_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_EQ_EQ, EQ_EXPR },
+    { CPP_NOT_EQ, NE_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_relational_expression);
+}
+
+/* Parse an and-expression.
+
+   and-expression:
+     equality-expression
+     and-expression & equality-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_and_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_AND, BIT_AND_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_equality_expression);
+}
+
+/* Parse an exclusive-or-expression.
+
+   exclusive-or-expression:
+     and-expression
+     exclusive-or-expression ^ and-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_exclusive_or_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_XOR, BIT_XOR_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_and_expression);
+}
+
+
+/* Parse an inclusive-or-expression.
+
+   inclusive-or-expression:
+     exclusive-or-expression
+     inclusive-or-expression | exclusive-or-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_inclusive_or_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_OR, BIT_IOR_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_exclusive_or_expression);
+}
+
+/* Parse a logical-and-expression.
+
+   logical-and-expression:
+     inclusive-or-expression
+     logical-and-expression && inclusive-or-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_logical_and_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_AND_AND, TRUTH_ANDIF_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_inclusive_or_expression);
+}
+
+/* Parse a logical-or-expression.
+
+   logical-or-expression:
+     logical-and-expresion
+     logical-or-expression || logical-and-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_logical_or_expression (parser)
+     cp_parser *parser;
+{
+  static cp_parser_token_tree_map map = {
+    { CPP_OR_OR, TRUTH_ORIF_EXPR },
+    { CPP_EOF, ERROR_MARK }
+  };
+
+  return cp_parser_binary_expression (parser,
+                                     map,
+                                     cp_parser_logical_and_expression);
+}
+
+/* Parse a conditional-expression.
+
+   conditional-expression:
+     logical-or-expression
+     logical-or-expression ? expression : assignment-expression
+     
+   GNU Extensions:
+   
+   conditional-expression:
+     logical-or-expression ?  : assignment-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_conditional_expression (parser)
+     cp_parser *parser;
+{
+  tree logical_or_expr;
+
+  /* Parse the logical-or-expression.  */
+  logical_or_expr = cp_parser_logical_or_expression (parser);
+  /* If the next token is a `?', then we have a real conditional
+     expression.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+    return cp_parser_question_colon_clause (parser, logical_or_expr);
+  /* Otherwise, the value is simply the logical-or-expression.  */
+  else
+    return logical_or_expr;
+}
+
+/* Parse the `? expression : assignment-expression' part of a
+   conditional-expression.  The LOGICAL_OR_EXPR is the
+   logical-or-expression that started the conditional-expression.
+   Returns a representation of the entire conditional-expression.
+
+   This routine exists only so that it can be shared between
+   cp_parser_conditional_expression and
+   cp_parser_assignment_expression.
+
+     ? expression : assignment-expression
+   
+   GNU Extensions:
+   
+     ? : assignment-expression */
+
+static tree
+cp_parser_question_colon_clause (parser, logical_or_expr)
+     cp_parser *parser;
+     tree logical_or_expr;
+{
+  tree expr;
+  tree assignment_expr;
+
+  /* Consume the `?' token.  */
+  cp_lexer_consume_token (parser->lexer);
+  if (cp_parser_allow_gnu_extensions_p (parser)
+      && cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+    /* Implicit true clause.  */
+    expr = NULL_TREE;
+  else
+    /* Parse the expression.  */
+    expr = cp_parser_expression (parser);
+  
+  /* The next token should be a `:'.  */
+  cp_parser_require (parser, CPP_COLON, "`:'");
+  /* Parse the assignment-expression.  */
+  assignment_expr = cp_parser_assignment_expression (parser);
+
+  /* Build the conditional-expression.  */
+  return build_x_conditional_expr (logical_or_expr,
+                                  expr,
+                                  assignment_expr);
+}
+
+/* Parse an assignment-expression.
+
+   assignment-expression:
+     conditional-expression
+     logical-or-expression assignment-operator assignment_expression
+     throw-expression
+
+   Returns a representation for the expression.  */
+
+static tree
+cp_parser_assignment_expression (parser)
+     cp_parser *parser;
+{
+  tree expr;
+
+  /* If the next token is the `throw' keyword, then we're looking at
+     a throw-expression.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THROW))
+    expr = cp_parser_throw_expression (parser);
+  /* Otherwise, it must be that we are looking at a
+     logical-or-expression.  */
+  else
+    {
+      /* Parse the logical-or-expression.  */
+      expr = cp_parser_logical_or_expression (parser);
+      /* If the next token is a `?' then we're actually looking at a
+        conditional-expression.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+       return cp_parser_question_colon_clause (parser, expr);
+      else 
+       {
+         enum tree_code assignment_operator;
+
+         /* If it's an assignment-operator, we're using the second
+            production.  */
+         assignment_operator 
+           = cp_parser_assignment_operator_opt (parser);
+         if (assignment_operator != ERROR_MARK)
+           {
+             tree rhs;
+
+             /* Parse the right-hand side of the assignment.  */
+             rhs = cp_parser_assignment_expression (parser);
+             /* Build the asignment expression.  */
+             expr = build_x_modify_expr (expr, 
+                                         assignment_operator, 
+                                         rhs);
+           }
+       }
+    }
+
+  return expr;
+}
+
+/* Parse an (optional) assignment-operator.
+
+   assignment-operator: one of 
+     = *= /= %= += -= >>= <<= &= ^= |=  
+
+   GNU Extension:
+   
+   assignment-operator: one of
+     <?= >?=
+
+   If the next token is an assignment operator, the corresponding tree
+   code is returned, and the token is consumed.  For example, for
+   `+=', PLUS_EXPR is returned.  For `=' itself, the code returned is
+   NOP_EXPR.  For `/', TRUNC_DIV_EXPR is returned; for `%',
+   TRUNC_MOD_EXPR is returned.  If TOKEN is not an assignment
+   operator, ERROR_MARK is returned.  */
+
+static enum tree_code
+cp_parser_assignment_operator_opt (parser)
+     cp_parser *parser;
+{
+  enum tree_code op;
+  cp_token *token;
+
+  /* Peek at the next toen.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  switch (token->type)
+    {
+    case CPP_EQ:
+      op = NOP_EXPR;
+      break;
+
+    case CPP_MULT_EQ:
+      op = MULT_EXPR;
+      break;
+
+    case CPP_DIV_EQ:
+      op = TRUNC_DIV_EXPR;
+      break;
+
+    case CPP_MOD_EQ:
+      op = TRUNC_MOD_EXPR;
+      break;
+
+    case CPP_PLUS_EQ:
+      op = PLUS_EXPR;
+      break;
+
+    case CPP_MINUS_EQ:
+      op = MINUS_EXPR;
+      break;
+
+    case CPP_RSHIFT_EQ:
+      op = RSHIFT_EXPR;
+      break;
+
+    case CPP_LSHIFT_EQ:
+      op = LSHIFT_EXPR;
+      break;
+
+    case CPP_AND_EQ:
+      op = BIT_AND_EXPR;
+      break;
+
+    case CPP_XOR_EQ:
+      op = BIT_XOR_EXPR;
+      break;
+
+    case CPP_OR_EQ:
+      op = BIT_IOR_EXPR;
+      break;
+
+    case CPP_MIN_EQ:
+      op = MIN_EXPR;
+      break;
+
+    case CPP_MAX_EQ:
+      op = MAX_EXPR;
+      break;
+
+    default: 
+      /* Nothing else is an assignment operator.  */
+      op = ERROR_MARK;
+    }
+
+  /* If it was an assignment operator, consume it.  */
+  if (op != ERROR_MARK)
+    cp_lexer_consume_token (parser->lexer);
+
+  return op;
+}
+
+/* Parse an expression.
+
+   expression:
+     assignment-expression
+     expression , assignment-expression
+
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_expression (parser)
+     cp_parser *parser;
+{
+  tree expression = NULL_TREE;
+  bool saw_comma_p = false;
+
+  while (true)
+    {
+      tree assignment_expression;
+
+      /* Parse the next assignment-expression.  */
+      assignment_expression 
+       = cp_parser_assignment_expression (parser);
+      /* If this is the first assignment-expression, we can just
+        save it away.  */
+      if (!expression)
+       expression = assignment_expression;
+      /* Otherwise, chain the expressions together.  It is unclear why
+        we do not simply build COMPOUND_EXPRs as we go.  */
+      else
+       expression = tree_cons (NULL_TREE, 
+                               assignment_expression,
+                               expression);
+      /* If the next token is not a comma, then we are done with the
+        expression.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+      /* Consume the `,'.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* The first time we see a `,', we must take special action
+        because the representation used for a single expression is
+        different from that used for a list containing the single
+        expression.  */
+      if (!saw_comma_p)
+       {
+         /* Remember that this expression has a `,' in it.  */
+         saw_comma_p = true;
+         /* Turn the EXPRESSION into a TREE_LIST so that we can link
+            additional expressions to it.  */
+         expression = build_tree_list (NULL_TREE, expression);
+       }
+    }
+
+  /* Build a COMPOUND_EXPR to represent the entire expression, if
+     necessary.  We built up the list in reverse order, so we must
+     straighten it out here.  */
+  if (saw_comma_p)
+    expression = build_x_compound_expr (nreverse (expression));
+
+  return expression;
+}
+
+/* Parse a constant-expression. 
+
+   constant-expression:
+     conditional-expression  */
+
+static tree
+cp_parser_constant_expression (parser)
+     cp_parser *parser;
+{
+  bool saved_constant_expression_p;
+  tree expression;
+
+  /* It might seem that we could simply parse the
+     conditional-expression, and then check to see if it were
+     TREE_CONSTANT.  However, an expression that is TREE_CONSTANT is
+     one that the compiler can figure out is constant, possibly after
+     doing some simplifications or optimizations.  The standard has a
+     precise definition of constant-expression, and we must honor
+     that, even though it is somewhat more restrictive.
+
+     For example:
+
+       int i[(2, 3)];
+
+     is not a legal declaration, because `(2, 3)' is not a
+     constant-expression.  The `,' operator is forbidden in a
+     constant-expression.  However, GCC's constant-folding machinery
+     will fold this operation to an INTEGER_CST for `3'.  */
+
+  /* Save the old setting of CONSTANT_EXPRESSION_P.  */
+  saved_constant_expression_p = parser->constant_expression_p;
+  /* We are now parsing a constant-expression.  */
+  parser->constant_expression_p = true;
+  /* Parse the conditional-expression.  */
+  expression = cp_parser_conditional_expression (parser);
+  /* Restore the old setting of CONSTANT_EXPRESSION_P.  */
+  parser->constant_expression_p = saved_constant_expression_p;
+
+  return expression;
+}
+
+/* Statements [gram.stmt.stmt]  */
+
+/* Parse a statement.  
+
+   statement:
+     labeled-statement
+     expression-statement
+     compound-statement
+     selection-statement
+     iteration-statement
+     jump-statement
+     declaration-statement
+     try-block  */
+
+static void
+cp_parser_statement (parser)
+     cp_parser *parser;
+{
+  tree statement;
+  cp_token *token;
+  int statement_line_number;
+
+  /* There is no statement yet.  */
+  statement = NULL_TREE;
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Remember the line number of the first token in the statement.  */
+  statement_line_number = token->line_number;
+  /* If this is a keyword, then that will often determine what kind of
+     statement we have.  */
+  if (token->type == CPP_KEYWORD)
+    {
+      enum rid keyword = token->keyword;
+
+      switch (keyword)
+       {
+       case RID_CASE:
+       case RID_DEFAULT:
+         statement = cp_parser_labeled_statement (parser);
+         break;
+
+       case RID_IF:
+       case RID_SWITCH:
+         statement = cp_parser_selection_statement (parser);
+         break;
+
+       case RID_WHILE:
+       case RID_DO:
+       case RID_FOR:
+         statement = cp_parser_iteration_statement (parser);
+         break;
+
+       case RID_BREAK:
+       case RID_CONTINUE:
+       case RID_RETURN:
+       case RID_GOTO:
+         statement = cp_parser_jump_statement (parser);
+         break;
+
+       case RID_TRY:
+         statement = cp_parser_try_block (parser);
+         break;
+
+       default:
+         /* It might be a keyword like `int' that can start a
+            declaration-statement.  */
+         break;
+       }
+    }
+  else if (token->type == CPP_NAME)
+    {
+      /* If the next token is a `:', then we are looking at a
+        labeled-statement.  */
+      token = cp_lexer_peek_nth_token (parser->lexer, 2);
+      if (token->type == CPP_COLON)
+       statement = cp_parser_labeled_statement (parser);
+    }
+  /* Anything that starts with a `{' must be a compound-statement.  */
+  else if (token->type == CPP_OPEN_BRACE)
+    statement = cp_parser_compound_statement (parser);
+
+  /* Everything else must be a declaration-statement or an
+     expression-statement.  Try for the declaration-statement 
+     first, unless we are looking at a `;', in which case we know that
+     we have an expression-statement.  */
+  if (!statement)
+    {
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+       {
+         cp_parser_parse_tentatively (parser);
+         /* Try to parse the declaration-statement.  */
+         cp_parser_declaration_statement (parser);
+         /* If that worked, we're done.  */
+         if (cp_parser_parse_definitely (parser))
+           return;
+       }
+      /* Look for an expression-statement instead.  */
+      statement = cp_parser_expression_statement (parser);
+    }
+
+  /* Set the line number for the statement.  */
+  if (statement && statement_code_p (TREE_CODE (statement)))
+    STMT_LINENO (statement) = statement_line_number;
+}
+
+/* Parse a labeled-statement.
+
+   labeled-statement:
+     identifier : statement
+     case constant-expression : statement
+     default : statement  
+
+   Returns the new CASE_LABEL, for a `case' or `default' label.  For
+   an ordinary label, returns a LABEL_STMT.  */
+
+static tree
+cp_parser_labeled_statement (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree statement = NULL_TREE;
+
+  /* The next token should be an identifier.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  if (token->type != CPP_NAME
+      && token->type != CPP_KEYWORD)
+    {
+      cp_parser_error (parser, "expected labeled-statement");
+      return error_mark_node;
+    }
+
+  switch (token->keyword)
+    {
+    case RID_CASE:
+      {
+       tree expr;
+
+       /* Consume the `case' token.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Parse the constant-expression.  */
+       expr = cp_parser_constant_expression (parser);
+       /* Create the label.  */
+       statement = finish_case_label (expr, NULL_TREE);
+      }
+      break;
+
+    case RID_DEFAULT:
+      /* Consume the `default' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Create the label.  */
+      statement = finish_case_label (NULL_TREE, NULL_TREE);
+      break;
+
+    default:
+      /* Anything else must be an ordinary label.  */
+      statement = finish_label_stmt (cp_parser_identifier (parser));
+      break;
+    }
+
+  /* Require the `:' token.  */
+  cp_parser_require (parser, CPP_COLON, "`:'");
+  /* Parse the labeled statement.  */
+  cp_parser_statement (parser);
+
+  /* Return the label, in the case of a `case' or `default' label.  */
+  return statement;
+}
+
+/* Parse an expression-statement.
+
+   expression-statement:
+     expression [opt] ;
+
+   Returns the new EXPR_STMT -- or NULL_TREE if the expression
+   statement consists of nothing more than an `;'.  */
+
+static tree
+cp_parser_expression_statement (parser)
+     cp_parser *parser;
+{
+  tree statement;
+
+  /* If the next token is not a `;', then there is an expression to parse.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    statement = finish_expr_stmt (cp_parser_expression (parser));
+  /* Otherwise, we do not even bother to build an EXPR_STMT.  */
+  else
+    {
+      finish_stmt ();
+      statement = NULL_TREE;
+    }
+  /* Consume the final `;'.  */
+  if (!cp_parser_require (parser, CPP_SEMICOLON, "`;'"))
+    {
+      /* If there is additional (erroneous) input, skip to the end of
+        the statement.  */
+      cp_parser_skip_to_end_of_statement (parser);
+      /* If the next token is now a `;', consume it.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       cp_lexer_consume_token (parser->lexer);
+    }
+
+  return statement;
+}
+
+/* Parse a compound-statement.
+
+   compound-statement:
+     { statement-seq [opt] }
+     
+   Returns a COMPOUND_STMT representing the statement.  */
+
+static tree
+cp_parser_compound_statement (cp_parser *parser)
+{
+  tree compound_stmt;
+
+  /* Consume the `{'.  */
+  if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
+    return error_mark_node;
+  /* Begin the compound-statement.  */
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+  /* Parse an (optional) statement-seq.  */
+  cp_parser_statement_seq_opt (parser);
+  /* Finish the compound-statement.  */
+  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+  /* Consume the `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+
+  return compound_stmt;
+}
+
+/* Parse an (optional) statement-seq.
+
+   statement-seq:
+     statement
+     statement-seq [opt] statement  */
+
+static void
+cp_parser_statement_seq_opt (parser)
+     cp_parser *parser;
+{
+  /* Scan statements until there aren't any more.  */
+  while (true)
+    {
+      /* If we're looking at a `}', then we've run out of statements.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
+         || cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+       break;
+
+      /* Parse the statement.  */
+      cp_parser_statement (parser);
+    }
+}
+
+/* Parse a selection-statement.
+
+   selection-statement:
+     if ( condition ) statement
+     if ( condition ) statement else statement
+     switch ( condition ) statement  
+
+   Returns the new IF_STMT or SWITCH_STMT.  */
+
+static tree
+cp_parser_selection_statement (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  enum rid keyword;
+
+  /* Peek at the next token.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, "selection-statement");
+
+  /* See what kind of keyword it is.  */
+  keyword = token->keyword;
+  switch (keyword)
+    {
+    case RID_IF:
+    case RID_SWITCH:
+      {
+       tree statement;
+       tree condition;
+
+       /* Look for the `('.  */
+       if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+         {
+           cp_parser_skip_to_end_of_statement (parser);
+           return error_mark_node;
+         }
+
+       /* Begin the selection-statement.  */
+       if (keyword == RID_IF)
+         statement = begin_if_stmt ();
+       else
+         statement = begin_switch_stmt ();
+
+       /* Parse the condition.  */
+       condition = cp_parser_condition (parser);
+       /* Look for the `)'.  */
+       if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+         cp_parser_skip_to_closing_parenthesis (parser);
+
+       if (keyword == RID_IF)
+         {
+           tree then_stmt;
+
+           /* Add the condition.  */
+           finish_if_stmt_cond (condition, statement);
+
+           /* Parse the then-clause.  */
+           then_stmt = cp_parser_implicitly_scoped_statement (parser);
+           finish_then_clause (statement);
+
+           /* If the next token is `else', parse the else-clause.  */
+           if (cp_lexer_next_token_is_keyword (parser->lexer,
+                                               RID_ELSE))
+             {
+               tree else_stmt;
+
+               /* Consume the `else' keyword.  */
+               cp_lexer_consume_token (parser->lexer);
+               /* Parse the else-clause.  */
+               else_stmt 
+                 = cp_parser_implicitly_scoped_statement (parser);
+               finish_else_clause (statement);
+             }
+
+           /* Now we're all done with the if-statement.  */
+           finish_if_stmt ();
+         }
+       else
+         {
+           tree body;
+
+           /* Add the condition.  */
+           finish_switch_cond (condition, statement);
+
+           /* Parse the body of the switch-statement.  */
+           body = cp_parser_implicitly_scoped_statement (parser);
+
+           /* Now we're all done with the switch-statement.  */
+           finish_switch_stmt (statement);
+         }
+
+       return statement;
+      }
+      break;
+
+    default:
+      cp_parser_error (parser, "expected selection-statement");
+      return error_mark_node;
+    }
+}
+
+/* Parse a condition. 
+
+   condition:
+     expression
+     type-specifier-seq declarator = assignment-expression  
+
+   GNU Extension:
+   
+   condition:
+     type-specifier-seq declarator asm-specification [opt] 
+       attributes [opt] = assignment-expression
+   Returns the expression that should be tested.  */
+
+static tree
+cp_parser_condition (parser)
+     cp_parser *parser;
+{
+  tree type_specifiers;
+  const char *saved_message;
+
+  /* Try the declaration first.  */
+  cp_parser_parse_tentatively (parser);
+  /* New types are not allowed in the type-specifier-seq for a
+     condition.  */
+  saved_message = parser->type_definition_forbidden_message;
+  parser->type_definition_forbidden_message
+    = "types may not be defined in conditions";
+  /* Parse the type-specifier-seq.  */
+  type_specifiers = cp_parser_type_specifier_seq (parser);
+  /* Restore the saved message.  */
+  parser->type_definition_forbidden_message = saved_message;
+  /* If all is well, we might be looking at a declaration.  */
+  if (!cp_parser_error_occurred (parser))
+    {
+      tree decl;
+      tree asm_specification;
+      tree attributes;
+      tree declarator;
+      tree initializer = NULL_TREE;
+      
+      /* Parse the declarator.  */
+      declarator = cp_parser_declarator (parser, 
+                                        /*abstract_p=*/false,
+                                        /*ctor_dtor_or_conv_p=*/NULL);
+      /* Parse the attributes.  */
+      attributes = cp_parser_attributes_opt (parser);
+      /* Parse the asm-specification.  */
+      asm_specification = cp_parser_asm_specification_opt (parser);
+      /* If the next token is not an `=', then we might still be
+        looking at an expression.  For example:
+        
+          if (A(a).x)
+         
+        looks like a decl-specifier-seq and a declarator -- but then
+        there is no `=', so this is an expression.  */
+      cp_parser_require (parser, CPP_EQ, "`='");
+      /* If we did see an `=', then we are looking at a declaration
+        for sure.  */
+      if (cp_parser_parse_definitely (parser))
+       {
+         /* Create the declaration.  */
+         decl = start_decl (declarator, type_specifiers, 
+                            /*initialized_p=*/true,
+                            attributes, /*prefix_attributes=*/NULL_TREE);
+         /* Parse the assignment-expression.  */
+         initializer = cp_parser_assignment_expression (parser);
+         
+         /* Process the initializer.  */
+         cp_finish_decl (decl, 
+                         initializer, 
+                         asm_specification, 
+                         LOOKUP_ONLYCONVERTING);
+         
+         return convert_from_reference (decl);
+       }
+    }
+  /* If we didn't even get past the declarator successfully, we are
+     definitely not looking at a declaration.  */
+  else
+    cp_parser_abort_tentative_parse (parser);
+
+  /* Otherwise, we are looking at an expression.  */
+  return cp_parser_expression (parser);
+}
+
+/* Parse an iteration-statement.
+
+   iteration-statement:
+     while ( condition ) statement
+     do statement while ( expression ) ;
+     for ( for-init-statement condition [opt] ; expression [opt] )
+       statement
+
+   Returns the new WHILE_STMT, DO_STMT, or FOR_STMT.  */
+
+static tree
+cp_parser_iteration_statement (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  enum rid keyword;
+  tree statement;
+
+  /* Peek at the next token.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement");
+  if (!token)
+    return error_mark_node;
+
+  /* See what kind of keyword it is.  */
+  keyword = token->keyword;
+  switch (keyword)
+    {
+    case RID_WHILE:
+      {
+       tree condition;
+
+       /* Begin the while-statement.  */
+       statement = begin_while_stmt ();
+       /* Look for the `('.  */
+       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+       /* Parse the condition.  */
+       condition = cp_parser_condition (parser);
+       finish_while_stmt_cond (condition, statement);
+       /* Look for the `)'.  */
+       cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+       /* Parse the dependent statement.  */
+       cp_parser_already_scoped_statement (parser);
+       /* We're done with the while-statement.  */
+       finish_while_stmt (statement);
+      }
+      break;
+
+    case RID_DO:
+      {
+       tree expression;
+
+       /* Begin the do-statement.  */
+       statement = begin_do_stmt ();
+       /* Parse the body of the do-statement.  */
+       cp_parser_implicitly_scoped_statement (parser);
+       finish_do_body (statement);
+       /* Look for the `while' keyword.  */
+       cp_parser_require_keyword (parser, RID_WHILE, "`while'");
+       /* Look for the `('.  */
+       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+       /* Parse the expression.  */
+       expression = cp_parser_expression (parser);
+       /* We're done with the do-statement.  */
+       finish_do_stmt (expression, statement);
+       /* Look for the `)'.  */
+       cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+       /* Look for the `;'.  */
+       cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      }
+      break;
+
+    case RID_FOR:
+      {
+       tree condition = NULL_TREE;
+       tree expression = NULL_TREE;
+
+       /* Begin the for-statement.  */
+       statement = begin_for_stmt ();
+       /* Look for the `('.  */
+       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+       /* Parse the initialization.  */
+       cp_parser_for_init_statement (parser);
+       finish_for_init_stmt (statement);
+
+       /* If there's a condition, process it.  */
+       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+         condition = cp_parser_condition (parser);
+       finish_for_cond (condition, statement);
+       /* Look for the `;'.  */
+       cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+       /* If there's an expression, process it.  */
+       if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+         expression = cp_parser_expression (parser);
+       finish_for_expr (expression, statement);
+       /* Look for the `)'.  */
+       cp_parser_require (parser, CPP_CLOSE_PAREN, "`;'");
+
+       /* Parse the body of the for-statement.  */
+       cp_parser_already_scoped_statement (parser);
+
+       /* We're done with the for-statement.  */
+       finish_for_stmt (statement);
+      }
+      break;
+
+    default:
+      cp_parser_error (parser, "expected iteration-statement");
+      statement = error_mark_node;
+      break;
+    }
+
+  return statement;
+}
+
+/* Parse a for-init-statement.
+
+   for-init-statement:
+     expression-statement
+     simple-declaration  */
+
+static void
+cp_parser_for_init_statement (parser)
+     cp_parser *parser;
+{
+  /* If the next token is a `;', then we have an empty
+     expression-statement.  Gramatically, this is also a
+     simple-declaration, but an invalid one, because it does not
+     declare anything.  Therefore, if we did not handle this case
+     specially, we would issue an error message about an invalid
+     declaration.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    {
+      /* We're going to speculatively look for a declaration, falling back
+        to an expression, if necessary.  */
+      cp_parser_parse_tentatively (parser);
+      /* Parse the declaration.  */
+      cp_parser_simple_declaration (parser,
+                                   /*function_definition_allowed_p=*/false);
+      /* If the tentative parse failed, then we shall need to look for an
+        expression-statement.  */
+      if (cp_parser_parse_definitely (parser))
+       return;
+    }
+
+  cp_parser_expression_statement (parser);
+}
+
+/* Parse a jump-statement.
+
+   jump-statement:
+     break ;
+     continue ;
+     return expression [opt] ;
+     goto identifier ;  
+
+   GNU extension:
+
+   jump-statement:
+     goto * expression ;
+
+   Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_STMT, or
+   GOTO_STMT.  */
+
+static tree
+cp_parser_jump_statement (parser)
+     cp_parser *parser;
+{
+  tree statement = error_mark_node;
+  cp_token *token;
+  enum rid keyword;
+
+  /* Peek at the next token.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, "jump-statement");
+  if (!token)
+    return error_mark_node;
+
+  /* See what kind of keyword it is.  */
+  keyword = token->keyword;
+  switch (keyword)
+    {
+    case RID_BREAK:
+      statement = finish_break_stmt ();
+      cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      break;
+
+    case RID_CONTINUE:
+      statement = finish_continue_stmt ();
+      cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      break;
+
+    case RID_RETURN:
+      {
+       tree expr;
+
+       /* If the next token is a `;', then there is no 
+          expression.  */
+       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+         expr = cp_parser_expression (parser);
+       else
+         expr = NULL_TREE;
+       /* Build the return-statement.  */
+       statement = finish_return_stmt (expr);
+       /* Look for the final `;'.  */
+       cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      }
+      break;
+
+    case RID_GOTO:
+      /* Create the goto-statement.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_MULT))
+       {
+         /* Issue a warning about this use of a GNU extension.  */
+         if (pedantic)
+           pedwarn ("ISO C++ forbids computed gotos");
+         /* Consume the '*' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Parse the dependent expression.  */
+         finish_goto_stmt (cp_parser_expression (parser));
+       }
+      else
+       finish_goto_stmt (cp_parser_identifier (parser));
+      /* Look for the final `;'.  */
+      cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      break;
+
+    default:
+      cp_parser_error (parser, "expected jump-statement");
+      break;
+    }
+
+  return statement;
+}
+
+/* Parse a declaration-statement.
+
+   declaration-statement:
+     block-declaration  */
+
+static void
+cp_parser_declaration_statement (parser)
+     cp_parser *parser;
+{
+  /* Parse the block-declaration.  */
+  cp_parser_block_declaration (parser, /*statement_p=*/true);
+
+  /* Finish off the statement.  */
+  finish_stmt ();
+}
+
+/* Some dependent statements (like `if (cond) statement'), are
+   implicitly in their own scope.  In other words, if the statement is
+   a single statement (as opposed to a compound-statement), it is
+   none-the-less treated as if it were enclosed in braces.  Any
+   declarations appearing in the dependent statement are out of scope
+   after control passes that point.  This function parses a statement,
+   but ensures that is in its own scope, even if it is not a
+   compound-statement.  
+
+   Returns the new statement.  */
+
+static tree
+cp_parser_implicitly_scoped_statement (parser)
+     cp_parser *parser;
+{
+  tree statement;
+
+  /* If the token is not a `{', then we must take special action.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+    {
+      /* Create a compound-statement.  */
+      statement = begin_compound_stmt (/*has_no_scope=*/0);
+      /* Parse the dependent-statement.  */
+      cp_parser_statement (parser);
+      /* Finish the dummy compound-statement.  */
+      finish_compound_stmt (/*has_no_scope=*/0, statement);
+    }
+  /* Otherwise, we simply parse the statement directly.  */
+  else
+    statement = cp_parser_compound_statement (parser);
+
+  /* Return the statement.  */
+  return statement;
+}
+
+/* For some dependent statements (like `while (cond) statement'), we
+   have already created a scope.  Therefore, even if the dependent
+   statement is a compound-statement, we do not want to create another
+   scope.  */
+
+static void
+cp_parser_already_scoped_statement (parser)
+     cp_parser *parser;
+{
+  /* If the token is not a `{', then we must take special action.  */
+  if (cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_BRACE))
+    {
+      tree statement;
+
+      /* Create a compound-statement.  */
+      statement = begin_compound_stmt (/*has_no_scope=*/1);
+      /* Parse the dependent-statement.  */
+      cp_parser_statement (parser);
+      /* Finish the dummy compound-statement.  */
+      finish_compound_stmt (/*has_no_scope=*/1, statement);
+    }
+  /* Otherwise, we simply parse the statement directly.  */
+  else
+    cp_parser_statement (parser);
+}
+
+/* Declarations [gram.dcl.dcl] */
+
+/* Parse an optional declaration-sequence.
+
+   declaration-seq:
+     declaration
+     declaration-seq declaration  */
+
+static void
+cp_parser_declaration_seq_opt (parser)
+     cp_parser *parser;
+{
+  while (true)
+    {
+      cp_token *token;
+
+      token = cp_lexer_peek_token (parser->lexer);
+
+      if (token->type == CPP_CLOSE_BRACE
+         || token->type == CPP_EOF)
+       break;
+
+      if (token->type == CPP_SEMICOLON) 
+       {
+         /* A declaration consisting of a single semicolon is
+            invalid.  Allow it unless we're being pedantic.  */
+         if (pedantic)
+           pedwarn ("extra `;'");
+         cp_lexer_consume_token (parser->lexer);
+         continue;
+       }
+
+      cp_parser_declaration (parser);
+    }
+}
+
+/* Parse a declaration.
+
+   declaration:
+     block-declaration
+     function-definition
+     template-declaration
+     explicit-instantiation
+     explicit-specialization
+     linkage-specification
+     namespace-definition    */
+
+static void
+cp_parser_declaration (parser)
+     cp_parser *parser;
+{
+  cp_token token1;
+  cp_token token2;
+
+  /* Try to figure out what kind of declaration is present.  */
+  token1 = *cp_lexer_peek_token (parser->lexer);
+  if (token1.type != CPP_EOF)
+    token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
+
+  /* If the next token is `extern' and the following token is a string
+     literal, then we have a linkage specification.  */
+  if (token1.keyword == RID_EXTERN
+      && cp_parser_is_string_literal (&token2))
+    cp_parser_linkage_specification (parser);
+  /* If the next token is `template', then we have either a template
+     declaration, an explicit instantiation, or an explicit
+     specialization.  */
+  else if (token1.keyword == RID_TEMPLATE)
+    {
+      /* `template <>' indicates a template specialization.  */
+      if (token2.type == CPP_LESS
+         && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
+       cp_parser_explicit_specialization (parser);
+      /* `template <' indicates a template declaration.  */
+      else if (token2.type == CPP_LESS)
+       cp_parser_template_declaration (parser, /*member_p=*/false);
+      /* Anything else must be an explicit instantiation.  */
+      else
+       cp_parser_explicit_instantiation (parser);
+    }
+  /* If the next token is `export', then we have a template
+     declaration.  */
+  else if (token1.keyword == RID_EXPORT)
+    cp_parser_template_declaration (parser, /*member_p=*/false);
+  /* If the next token is `extern', 'static' or 'inline' and the one
+     after that is `template', we have a GNU extended explicit
+     instantiation directive.  */
+  else if (cp_parser_allow_gnu_extensions_p (parser)
+          && (token1.keyword == RID_EXTERN
+              || token1.keyword == RID_STATIC
+              || token1.keyword == RID_INLINE)
+          && token2.keyword == RID_TEMPLATE)
+    cp_parser_explicit_instantiation (parser);
+  /* If the next token is `namespace', check for a named or unnamed
+     namespace definition.  */
+  else if (token1.keyword == RID_NAMESPACE
+          && (/* A named namespace definition.  */
+              (token2.type == CPP_NAME
+               && (cp_lexer_peek_nth_token (parser->lexer, 3)->type 
+                   == CPP_OPEN_BRACE))
+              /* An unnamed namespace definition.  */
+              || token2.type == CPP_OPEN_BRACE))
+    cp_parser_namespace_definition (parser);
+  /* We must have either a block declaration or a function
+     definition.  */
+  else
+    /* Try to parse a block-declaration, or a function-definition.  */
+    cp_parser_block_declaration (parser, /*statement_p=*/false);
+}
+
+/* Parse a block-declaration.  
+
+   block-declaration:
+     simple-declaration
+     asm-definition
+     namespace-alias-definition
+     using-declaration
+     using-directive  
+
+   GNU Extension:
+
+   block-declaration:
+     __extension__ block-declaration 
+     label-declaration
+
+   If STATEMENT_P is TRUE, then this block-declaration is ocurring as
+   part of a declaration-statement.  */
+
+static void
+cp_parser_block_declaration (cp_parser *parser, 
+                            bool      statement_p)
+{
+  cp_token *token1;
+  int saved_pedantic;
+
+  /* Check for the `__extension__' keyword.  */
+  if (cp_parser_extension_opt (parser, &saved_pedantic))
+    {
+      /* Parse the qualified declaration.  */
+      cp_parser_block_declaration (parser, statement_p);
+      /* Restore the PEDANTIC flag.  */
+      pedantic = saved_pedantic;
+
+      return;
+    }
+
+  /* Peek at the next token to figure out which kind of declaration is
+     present.  */
+  token1 = cp_lexer_peek_token (parser->lexer);
+
+  /* If the next keyword is `asm', we have an asm-definition.  */
+  if (token1->keyword == RID_ASM)
+    {
+      if (statement_p)
+       cp_parser_commit_to_tentative_parse (parser);
+      cp_parser_asm_definition (parser);
+    }
+  /* If the next keyword is `namespace', we have a
+     namespace-alias-definition.  */
+  else if (token1->keyword == RID_NAMESPACE)
+    cp_parser_namespace_alias_definition (parser);
+  /* If the next keyword is `using', we have either a
+     using-declaration or a using-directive.  */
+  else if (token1->keyword == RID_USING)
+    {
+      cp_token *token2;
+
+      if (statement_p)
+       cp_parser_commit_to_tentative_parse (parser);
+      /* If the token after `using' is `namespace', then we have a
+        using-directive.  */
+      token2 = cp_lexer_peek_nth_token (parser->lexer, 2);
+      if (token2->keyword == RID_NAMESPACE)
+       cp_parser_using_directive (parser);
+      /* Otherwise, it's a using-declaration.  */
+      else
+       cp_parser_using_declaration (parser);
+    }
+  /* If the next keyword is `__label__' we have a label declaration.  */
+  else if (token1->keyword == RID_LABEL)
+    {
+      if (statement_p)
+       cp_parser_commit_to_tentative_parse (parser);
+      cp_parser_label_declaration (parser);
+    }
+  /* Anything else must be a simple-declaration.  */
+  else
+    cp_parser_simple_declaration (parser, !statement_p);
+}
+
+/* Parse a simple-declaration.
+
+   simple-declaration:
+     decl-specifier-seq [opt] init-declarator-list [opt] ;  
+
+   init-declarator-list:
+     init-declarator
+     init-declarator-list , init-declarator 
+
+   If FUNCTION_DEFINTION_ALLOWED_P is TRUE, then we also recognize a
+   function-definition as a simple-declaration.   */
+
+static void
+cp_parser_simple_declaration (parser, function_definition_allowed_p)
+     cp_parser *parser;
+     bool function_definition_allowed_p;
+{
+  tree decl_specifiers;
+  tree attributes;
+  tree access_checks;
+  bool declares_class_or_enum;
+  bool saw_declarator;
+
+  /* Defer access checks until we know what is being declared; the
+     checks for names appearing in the decl-specifier-seq should be
+     done as if we were in the scope of the thing being declared.  */
+  cp_parser_start_deferring_access_checks (parser);
+  /* Parse the decl-specifier-seq.  We have to keep track of whether
+     or not the decl-specifier-seq declares a named class or
+     enumeration type, since that is the only case in which the
+     init-declarator-list is allowed to be empty.  
+
+     [dcl.dcl]
+
+     In a simple-declaration, the optional init-declarator-list can be
+     omitted only when declaring a class or enumeration, that is when
+     the decl-specifier-seq contains either a class-specifier, an
+     elaborated-type-specifier, or an enum-specifier.  */
+  decl_specifiers
+    = cp_parser_decl_specifier_seq (parser, 
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &attributes,
+                                   &declares_class_or_enum);
+  /* We no longer need to defer access checks.  */
+  access_checks = cp_parser_stop_deferring_access_checks (parser);
+
+  /* Keep going until we hit the `;' at the end of the simple
+     declaration.  */
+  saw_declarator = false;
+  while (cp_lexer_next_token_is_not (parser->lexer, 
+                                    CPP_SEMICOLON))
+    {
+      cp_token *token;
+      bool function_definition_p;
+
+      saw_declarator = true;
+      /* Parse the init-declarator.  */
+      cp_parser_init_declarator (parser, decl_specifiers, attributes,
+                                access_checks,
+                                function_definition_allowed_p,
+                                /*member_p=*/false,
+                                &function_definition_p);
+      /* Handle function definitions specially.  */
+      if (function_definition_p)
+       {
+         /* If the next token is a `,', then we are probably
+            processing something like:
+
+              void f() {}, *p;
+
+            which is erroneous.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+           error ("mixing declarations and function-definitions is forbidden");
+         /* Otherwise, we're done with the list of declarators.  */
+         else
+           return;
+       }
+      /* The next token should be either a `,' or a `;'.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's a `,', there are more declarators to come.  */
+      if (token->type == CPP_COMMA)
+       cp_lexer_consume_token (parser->lexer);
+      /* If it's a `;', we are done.  */
+      else if (token->type == CPP_SEMICOLON)
+       break;
+      /* Anything else is an error.  */
+      else
+       {
+         cp_parser_error (parser, "expected `,' or `;'");
+         /* Skip tokens until we reach the end of the statement.  */
+         cp_parser_skip_to_end_of_statement (parser);
+         return;
+       }
+      /* After the first time around, a function-definition is not
+        allowed -- even if it was OK at first.  For example:
+
+           int i, f() {}
+
+         is not valid.  */
+      function_definition_allowed_p = false;
+    }
+
+  /* Issue an error message if no declarators are present, and the
+     decl-specifier-seq does not itself declare a class or
+     enumeration.  */
+  if (!saw_declarator)
+    {
+      if (cp_parser_declares_only_class_p (parser))
+       shadow_tag (decl_specifiers);
+      /* Perform any deferred access checks.  */
+      cp_parser_perform_deferred_access_checks (access_checks);
+    }
+
+  /* Consume the `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+  /* Mark all the classes that appeared in the decl-specifier-seq as
+     having received a `;'.  */
+  note_list_got_semicolon (decl_specifiers);
+}
+
+/* Parse a decl-specifier-seq.
+
+   decl-specifier-seq:
+     decl-specifier-seq [opt] decl-specifier
+
+   decl-specifier:
+     storage-class-specifier
+     type-specifier
+     function-specifier
+     friend
+     typedef  
+
+   GNU Extension:
+
+   decl-specifier-seq:
+     decl-specifier-seq [opt] attributes
+
+   Returns a TREE_LIST, giving the decl-specifiers in the order they
+   appear in the source code.  The TREE_VALUE of each node is the
+   decl-specifier.  For a keyword (such as `auto' or `friend'), the
+   TREE_VALUE is simply the correspoding TREE_IDENTIFIER.  For the
+   representation of a type-specifier, see cp_parser_type_specifier.  
+
+   If there are attributes, they will be stored in *ATTRIBUTES,
+   represented as described above cp_parser_attributes.  
+
+   If FRIEND_IS_NOT_CLASS_P is non-NULL, and the `friend' specifier
+   appears, and the entity that will be a friend is not going to be a
+   class, then *FRIEND_IS_NOT_CLASS_P will be set to TRUE.  Note that
+   even if *FRIEND_IS_NOT_CLASS_P is FALSE, the entity to which
+   friendship is granted might not be a class.  */
+
+static tree
+cp_parser_decl_specifier_seq (parser, flags, attributes,
+                             declares_class_or_enum)
+     cp_parser *parser;
+     cp_parser_flags flags;
+     tree *attributes;
+     bool *declares_class_or_enum;
+{
+  tree decl_specs = NULL_TREE;
+  bool friend_p = false;
+
+  /* Assume no class or enumeration type is declared.  */
+  *declares_class_or_enum = false;
+
+  /* Assume there are no attributes.  */
+  *attributes = NULL_TREE;
+
+  /* Keep reading specifiers until there are no more to read.  */
+  while (true)
+    {
+      tree decl_spec = NULL_TREE;
+      bool constructor_p;
+      cp_token *token;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* Handle attributes.  */
+      if (token->keyword == RID_ATTRIBUTE)
+       {
+         /* Parse the attributes.  */
+         decl_spec = cp_parser_attributes_opt (parser);
+         /* Add them to the list.  */
+         *attributes = chainon (*attributes, decl_spec);
+         continue;
+       }
+      /* If the next token is an appropriate keyword, we can simply
+        add it to the list.  */
+      switch (token->keyword)
+       {
+       case RID_FRIEND:
+         /* decl-specifier:
+              friend  */
+         friend_p = true;
+         /* The representation of the specifier is simply the
+            appropriate TREE_IDENTIFIER node.  */
+         decl_spec = token->value;
+         /* Consume the token.  */
+         cp_lexer_consume_token (parser->lexer);
+         break;
+
+         /* function-specifier:
+              inline
+              virtual
+              explicit  */
+       case RID_INLINE:
+       case RID_VIRTUAL:
+       case RID_EXPLICIT:
+         decl_spec = cp_parser_function_specifier_opt (parser);
+         break;
+         
+         /* decl-specifier:
+              typedef  */
+       case RID_TYPEDEF:
+         /* The representation of the specifier is simply the
+            appropriate TREE_IDENTIFIER node.  */
+         decl_spec = token->value;
+         /* Consume the token.  */
+         cp_lexer_consume_token (parser->lexer);
+         break;
+
+         /* storage-class-specifier:
+              auto
+              register
+              static
+              extern
+              mutable  
+
+             GNU Extension:
+              thread  */
+       case RID_AUTO:
+       case RID_REGISTER:
+       case RID_STATIC:
+       case RID_EXTERN:
+       case RID_MUTABLE:
+       case RID_THREAD:
+         decl_spec = cp_parser_storage_class_specifier_opt (parser);
+         break;
+         
+       default:
+         break;
+       }
+
+      /* Constructors are a special case.  The `S' in `S()' is not a
+        decl-specifier; it is the beginning of the declarator.  */
+      constructor_p = (!decl_spec 
+                      && cp_parser_constructor_declarator_p (parser,
+                                                             friend_p));
+
+      /* If we don't have a DECL_SPEC yet, then we must be looking at
+        a type-specifier.  */
+      if (!decl_spec && !constructor_p)
+       {
+         bool decl_spec_declares_class_or_enum;
+         bool is_cv_qualifier;
+
+         decl_spec
+           = cp_parser_type_specifier (parser, flags,
+                                       friend_p,
+                                       /*is_declaration=*/true,
+                                       &decl_spec_declares_class_or_enum,
+                                       &is_cv_qualifier);
+
+         *declares_class_or_enum |= decl_spec_declares_class_or_enum;
+
+         /* If this type-specifier referenced a user-defined type
+            (a typedef, class-name, etc.), then we can't allow any
+            more such type-specifiers henceforth.
+
+            [dcl.spec]
+
+            The longest sequence of decl-specifiers that could
+            possibly be a type name is taken as the
+            decl-specifier-seq of a declaration.  The sequence shall
+            be self-consistent as described below.
+
+            [dcl.type]
+
+            As a general rule, at most one type-specifier is allowed
+            in the complete decl-specifier-seq of a declaration.  The
+            only exceptions are the following:
+
+            -- const or volatile can be combined with any other
+               type-specifier. 
+
+            -- signed or unsigned can be combined with char, long,
+               short, or int.
+
+            -- ..
+
+            Example:
+
+              typedef char* Pc;
+              void g (const int Pc);
+
+            Here, Pc is *not* part of the decl-specifier seq; it's
+            the declarator.  Therefore, once we see a type-specifier
+            (other than a cv-qualifier), we forbid any additional
+            user-defined types.  We *do* still allow things like `int
+            int' to be considered a decl-specifier-seq, and issue the
+            error message later.  */
+         if (decl_spec && !is_cv_qualifier)
+           flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
+       }
+
+      /* If we still do not have a DECL_SPEC, then there are no more
+        decl-specifiers.  */
+      if (!decl_spec)
+       {
+         /* Issue an error message, unless the entire construct was
+             optional.  */
+         if (!(flags & CP_PARSER_FLAGS_OPTIONAL))
+           {
+             cp_parser_error (parser, "expected decl specifier");
+             return error_mark_node;
+           }
+
+         break;
+       }
+
+      /* Add the DECL_SPEC to the list of specifiers.  */
+      decl_specs = tree_cons (NULL_TREE, decl_spec, decl_specs);
+
+      /* After we see one decl-specifier, further decl-specifiers are
+        always optional.  */
+      flags |= CP_PARSER_FLAGS_OPTIONAL;
+    }
+
+  /* We have built up the DECL_SPECS in reverse order.  Return them in
+     the correct order.  */
+  return nreverse (decl_specs);
+}
+
+/* Parse an (optional) storage-class-specifier. 
+
+   storage-class-specifier:
+     auto
+     register
+     static
+     extern
+     mutable  
+
+   GNU Extension:
+
+   storage-class-specifier:
+     thread
+
+   Returns an IDENTIFIER_NODE corresponding to the keyword used.  */
+   
+static tree
+cp_parser_storage_class_specifier_opt (parser)
+     cp_parser *parser;
+{
+  switch (cp_lexer_peek_token (parser->lexer)->keyword)
+    {
+    case RID_AUTO:
+    case RID_REGISTER:
+    case RID_STATIC:
+    case RID_EXTERN:
+    case RID_MUTABLE:
+    case RID_THREAD:
+      /* Consume the token.  */
+      return cp_lexer_consume_token (parser->lexer)->value;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Parse an (optional) function-specifier. 
+
+   function-specifier:
+     inline
+     virtual
+     explicit
+
+   Returns an IDENTIFIER_NODE corresponding to the keyword used.  */
+   
+static tree
+cp_parser_function_specifier_opt (parser)
+     cp_parser *parser;
+{
+  switch (cp_lexer_peek_token (parser->lexer)->keyword)
+    {
+    case RID_INLINE:
+    case RID_VIRTUAL:
+    case RID_EXPLICIT:
+      /* Consume the token.  */
+      return cp_lexer_consume_token (parser->lexer)->value;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Parse a linkage-specification.
+
+   linkage-specification:
+     extern string-literal { declaration-seq [opt] }
+     extern string-literal declaration  */
+
+static void
+cp_parser_linkage_specification (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree linkage;
+
+  /* Look for the `extern' keyword.  */
+  cp_parser_require_keyword (parser, RID_EXTERN, "`extern'");
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's not a string-literal, then there's a problem.  */
+  if (!cp_parser_is_string_literal (token))
+    {
+      cp_parser_error (parser, "expected language-name");
+      return;
+    }
+  /* Consume the token.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Transform the literal into an identifier.  If the literal is a
+     wide-character string, or contains embedded NULs, then we can't
+     handle it as the user wants.  */
+  if (token->type == CPP_WSTRING
+      || (strlen (TREE_STRING_POINTER (token->value))
+         != (size_t) (TREE_STRING_LENGTH (token->value) - 1)))
+    {
+      cp_parser_error (parser, "invalid linkage-specification");
+      /* Assume C++ linkage.  */
+      linkage = get_identifier ("c++");
+    }
+  /* If it's a simple string constant, things are easier.  */
+  else
+    linkage = get_identifier (TREE_STRING_POINTER (token->value));
+
+  /* We're now using the new linkage.  */
+  push_lang_context (linkage);
+
+  /* If the next token is a `{', then we're using the first
+     production.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+    {
+      /* Consume the `{' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the declarations.  */
+      cp_parser_declaration_seq_opt (parser);
+      /* Look for the closing `}'.  */
+      cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+    }
+  /* Otherwise, there's just one declaration.  */
+  else
+    {
+      bool saved_in_unbraced_linkage_specification_p;
+
+      saved_in_unbraced_linkage_specification_p 
+       = parser->in_unbraced_linkage_specification_p;
+      parser->in_unbraced_linkage_specification_p = true;
+      have_extern_spec = true;
+      cp_parser_declaration (parser);
+      have_extern_spec = false;
+      parser->in_unbraced_linkage_specification_p 
+       = saved_in_unbraced_linkage_specification_p;
+    }
+
+  /* We're done with the linkage-specification.  */
+  pop_lang_context ();
+}
+
+/* Special member functions [gram.special] */
+
+/* Parse a conversion-function-id.
+
+   conversion-function-id:
+     operator conversion-type-id  
+
+   Returns an IDENTIFIER_NODE representing the operator.  */
+
+static tree 
+cp_parser_conversion_function_id (parser)
+     cp_parser *parser;
+{
+  tree type;
+  tree saved_scope;
+  tree saved_qualifying_scope;
+  tree saved_object_scope;
+
+  /* Look for the `operator' token.  */
+  if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
+    return error_mark_node;
+  /* When we parse the conversion-type-id, the current scope will be
+     reset.  However, we need that information in able to look up the
+     conversion function later, so we save it here.  */
+  saved_scope = parser->scope;
+  saved_qualifying_scope = parser->qualifying_scope;
+  saved_object_scope = parser->object_scope;
+  /* We must enter the scope of the class so that the names of
+     entities declared within the class are available in the
+     conversion-type-id.  For example, consider:
+
+       struct S { 
+         typedef int I;
+        operator I();
+       };
+
+       S::operator I() { ... }
+
+     In order to see that `I' is a type-name in the definition, we
+     must be in the scope of `S'.  */
+  if (saved_scope)
+    push_scope (saved_scope);
+  /* Parse the conversion-type-id.  */
+  type = cp_parser_conversion_type_id (parser);
+  /* Leave the scope of the class, if any.  */
+  if (saved_scope)
+    pop_scope (saved_scope);
+  /* Restore the saved scope.  */
+  parser->scope = saved_scope;
+  parser->qualifying_scope = saved_qualifying_scope;
+  parser->object_scope = saved_object_scope;
+  /* If the TYPE is invalid, indicate failure.  */
+  if (type == error_mark_node)
+    return error_mark_node;
+  return mangle_conv_op_name_for_type (type);
+}
+
+/* Parse a conversion-type-id:
+
+   conversion-type-id:
+     type-specifier-seq conversion-declarator [opt]
+
+   Returns the TYPE specified.  */
+
+static tree
+cp_parser_conversion_type_id (parser)
+     cp_parser *parser;
+{
+  tree attributes;
+  tree type_specifiers;
+  tree declarator;
+
+  /* Parse the attributes.  */
+  attributes = cp_parser_attributes_opt (parser);
+  /* Parse the type-specifiers.  */
+  type_specifiers = cp_parser_type_specifier_seq (parser);
+  /* If that didn't work, stop.  */
+  if (type_specifiers == error_mark_node)
+    return error_mark_node;
+  /* Parse the conversion-declarator.  */
+  declarator = cp_parser_conversion_declarator_opt (parser);
+
+  return grokdeclarator (declarator, type_specifiers, TYPENAME,
+                        /*initialized=*/0, &attributes);
+}
+
+/* Parse an (optional) conversion-declarator.
+
+   conversion-declarator:
+     ptr-operator conversion-declarator [opt]  
+
+   Returns a representation of the declarator.  See
+   cp_parser_declarator for details.  */
+
+static tree
+cp_parser_conversion_declarator_opt (parser)
+     cp_parser *parser;
+{
+  enum tree_code code;
+  tree class_type;
+  tree cv_qualifier_seq;
+
+  /* We don't know if there's a ptr-operator next, or not.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try the ptr-operator.  */
+  code = cp_parser_ptr_operator (parser, &class_type, 
+                                &cv_qualifier_seq);
+  /* If it worked, look for more conversion-declarators.  */
+  if (cp_parser_parse_definitely (parser))
+    {
+     tree declarator;
+
+     /* Parse another optional declarator.  */
+     declarator = cp_parser_conversion_declarator_opt (parser);
+
+     /* Create the representation of the declarator.  */
+     if (code == INDIRECT_REF)
+       declarator = make_pointer_declarator (cv_qualifier_seq,
+                                            declarator);
+     else
+       declarator =  make_reference_declarator (cv_qualifier_seq,
+                                               declarator);
+
+     /* Handle the pointer-to-member case.  */
+     if (class_type)
+       declarator = build_nt (SCOPE_REF, class_type, declarator);
+
+     return declarator;
+   }
+
+  return NULL_TREE;
+}
+
+/* Parse an (optional) ctor-initializer.
+
+   ctor-initializer:
+     : mem-initializer-list  
+
+   Returns TRUE iff the ctor-initializer was actually present.  */
+
+static bool
+cp_parser_ctor_initializer_opt (parser)
+     cp_parser *parser;
+{
+  /* If the next token is not a `:', then there is no
+     ctor-initializer.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+    {
+      /* Do default initialization of any bases and members.  */
+      if (DECL_CONSTRUCTOR_P (current_function_decl))
+       finish_mem_initializers (NULL_TREE);
+
+      return false;
+    }
+
+  /* Consume the `:' token.  */
+  cp_lexer_consume_token (parser->lexer);
+  /* And the mem-initializer-list.  */
+  cp_parser_mem_initializer_list (parser);
+
+  return true;
+}
+
+/* Parse a mem-initializer-list.
+
+   mem-initializer-list:
+     mem-initializer
+     mem-initializer , mem-initializer-list  */
+
+static void
+cp_parser_mem_initializer_list (parser)
+     cp_parser *parser;
+{
+  tree mem_initializer_list = NULL_TREE;
+
+  /* Let the semantic analysis code know that we are starting the
+     mem-initializer-list.  */
+  begin_mem_initializers ();
+
+  /* Loop through the list.  */
+  while (true)
+    {
+      tree mem_initializer;
+
+      /* Parse the mem-initializer.  */
+      mem_initializer = cp_parser_mem_initializer (parser);
+      /* Add it to the list, unless it was erroneous.  */
+      if (mem_initializer)
+       {
+         TREE_CHAIN (mem_initializer) = mem_initializer_list;
+         mem_initializer_list = mem_initializer;
+       }
+      /* If the next token is not a `,', we're done.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+      /* Consume the `,' token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* Perform semantic analysis.  */
+  finish_mem_initializers (mem_initializer_list);
+}
+
+/* Parse a mem-initializer.
+
+   mem-initializer:
+     mem-initializer-id ( expression-list [opt] )  
+
+   GNU extension:
+  
+   mem-initializer:
+     ( expresion-list [opt] )
+
+   Returns a TREE_LIST.  The TREE_PURPOSE is the TYPE (for a base
+   class) or FIELD_DECL (for a non-static data member) to initialize;
+   the TREE_VALUE is the expression-list.  */
+
+static tree
+cp_parser_mem_initializer (parser)
+     cp_parser *parser;
+{
+  tree mem_initializer_id;
+  tree expression_list;
+
+  /* Find out what is being initialized.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      pedwarn ("anachronistic old-style base class initializer");
+      mem_initializer_id = NULL_TREE;
+    }
+  else
+    mem_initializer_id = cp_parser_mem_initializer_id (parser);
+  /* Look for the opening `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  /* Parse the expression-list.  */
+  if (cp_lexer_next_token_is_not (parser->lexer,
+                                 CPP_CLOSE_PAREN))
+    expression_list = cp_parser_expression_list (parser);
+  else
+    expression_list = void_type_node;
+  /* Look for the closing `)'.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return expand_member_init (mem_initializer_id,
+                            expression_list);
+}
+
+/* Parse a mem-initializer-id.
+
+   mem-initializer-id:
+     :: [opt] nested-name-specifier [opt] class-name
+     identifier  
+
+   Returns a TYPE indicating the class to be initializer for the first
+   production.  Returns an IDENTIFIER_NODE indicating the data member
+   to be initialized for the second production.  */
+
+static tree
+cp_parser_mem_initializer_id (parser)
+     cp_parser *parser;
+{
+  bool global_scope_p;
+  bool nested_name_specifier_p;
+  tree id;
+
+  /* Look for the optional `::' operator.  */
+  global_scope_p 
+    = (cp_parser_global_scope_opt (parser, 
+                                  /*current_scope_valid_p=*/false) 
+       != NULL_TREE);
+  /* Look for the optional nested-name-specifier.  The simplest way to
+     implement:
+
+       [temp.res]
+
+       The keyword `typename' is not permitted in a base-specifier or
+       mem-initializer; in these contexts a qualified name that
+       depends on a template-parameter is implicitly assumed to be a
+       type name.
+
+     is to assume that we have seen the `typename' keyword at this
+     point.  */
+  nested_name_specifier_p 
+    = (cp_parser_nested_name_specifier_opt (parser,
+                                           /*typename_keyword_p=*/true,
+                                           /*check_dependency_p=*/true,
+                                           /*type_p=*/true)
+       != NULL_TREE);
+  /* If there is a `::' operator or a nested-name-specifier, then we
+     are definitely looking for a class-name.  */
+  if (global_scope_p || nested_name_specifier_p)
+    return cp_parser_class_name (parser,
+                                /*typename_keyword_p=*/true,
+                                /*template_keyword_p=*/false,
+                                /*type_p=*/false,
+                                /*check_access_p=*/true,
+                                /*check_dependency_p=*/true,
+                                /*class_head_p=*/false);
+  /* Otherwise, we could also be looking for an ordinary identifier.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try a class-name.  */
+  id = cp_parser_class_name (parser, 
+                            /*typename_keyword_p=*/true,
+                            /*template_keyword_p=*/false,
+                            /*type_p=*/false,
+                            /*check_access_p=*/true,
+                            /*check_dependency_p=*/true,
+                            /*class_head_p=*/false);
+  /* If we found one, we're done.  */
+  if (cp_parser_parse_definitely (parser))
+    return id;
+  /* Otherwise, look for an ordinary identifier.  */
+  return cp_parser_identifier (parser);
+}
+
+/* Overloading [gram.over] */
+
+/* Parse an operator-function-id.
+
+   operator-function-id:
+     operator operator  
+
+   Returns an IDENTIFIER_NODE for the operator which is a
+   human-readable spelling of the identifier, e.g., `operator +'.  */
+
+static tree 
+cp_parser_operator_function_id (parser)
+     cp_parser *parser;
+{
+  /* Look for the `operator' keyword.  */
+  if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
+    return error_mark_node;
+  /* And then the name of the operator itself.  */
+  return cp_parser_operator (parser);
+}
+
+/* Parse an operator.
+
+   operator:
+     new delete new[] delete[] + - * / % ^ & | ~ ! = < >
+     += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= &&
+     || ++ -- , ->* -> () []
+
+   GNU Extensions:
+   
+   operator:
+     <? >? <?= >?=
+
+   Returns an IDENTIFIER_NODE for the operator which is a
+   human-readable spelling of the identifier, e.g., `operator +'.  */
+   
+static tree
+cp_parser_operator (parser)
+     cp_parser *parser;
+{
+  tree id = NULL_TREE;
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Figure out which operator we have.  */
+  switch (token->type)
+    {
+    case CPP_KEYWORD:
+      {
+       enum tree_code op;
+
+       /* The keyword should be either `new' or `delete'.  */
+       if (token->keyword == RID_NEW)
+         op = NEW_EXPR;
+       else if (token->keyword == RID_DELETE)
+         op = DELETE_EXPR;
+       else
+         break;
+
+       /* Consume the `new' or `delete' token.  */
+       cp_lexer_consume_token (parser->lexer);
+
+       /* Peek at the next token.  */
+       token = cp_lexer_peek_token (parser->lexer);
+       /* If it's a `[' token then this is the array variant of the
+          operator.  */
+       if (token->type == CPP_OPEN_SQUARE)
+         {
+           /* Consume the `[' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Look for the `]' token.  */
+           cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+           id = ansi_opname (op == NEW_EXPR 
+                             ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
+         }
+       /* Otherwise, we have the non-array variant.  */
+       else
+         id = ansi_opname (op);
+
+       return id;
+      }
+
+    case CPP_PLUS:
+      id = ansi_opname (PLUS_EXPR);
+      break;
+
+    case CPP_MINUS:
+      id = ansi_opname (MINUS_EXPR);
+      break;
+
+    case CPP_MULT:
+      id = ansi_opname (MULT_EXPR);
+      break;
+
+    case CPP_DIV:
+      id = ansi_opname (TRUNC_DIV_EXPR);
+      break;
+
+    case CPP_MOD:
+      id = ansi_opname (TRUNC_MOD_EXPR);
+      break;
+
+    case CPP_XOR:
+      id = ansi_opname (BIT_XOR_EXPR);
+      break;
+
+    case CPP_AND:
+      id = ansi_opname (BIT_AND_EXPR);
+      break;
+
+    case CPP_OR:
+      id = ansi_opname (BIT_IOR_EXPR);
+      break;
+
+    case CPP_COMPL:
+      id = ansi_opname (BIT_NOT_EXPR);
+      break;
+      
+    case CPP_NOT:
+      id = ansi_opname (TRUTH_NOT_EXPR);
+      break;
+
+    case CPP_EQ:
+      id = ansi_assopname (NOP_EXPR);
+      break;
+
+    case CPP_LESS:
+      id = ansi_opname (LT_EXPR);
+      break;
+
+    case CPP_GREATER:
+      id = ansi_opname (GT_EXPR);
+      break;
+
+    case CPP_PLUS_EQ:
+      id = ansi_assopname (PLUS_EXPR);
+      break;
+
+    case CPP_MINUS_EQ:
+      id = ansi_assopname (MINUS_EXPR);
+      break;
+
+    case CPP_MULT_EQ:
+      id = ansi_assopname (MULT_EXPR);
+      break;
+
+    case CPP_DIV_EQ:
+      id = ansi_assopname (TRUNC_DIV_EXPR);
+      break;
+
+    case CPP_MOD_EQ:
+      id = ansi_assopname (TRUNC_MOD_EXPR);
+      break;
+
+    case CPP_XOR_EQ:
+      id = ansi_assopname (BIT_XOR_EXPR);
+      break;
+
+    case CPP_AND_EQ:
+      id = ansi_assopname (BIT_AND_EXPR);
+      break;
+
+    case CPP_OR_EQ:
+      id = ansi_assopname (BIT_IOR_EXPR);
+      break;
+
+    case CPP_LSHIFT:
+      id = ansi_opname (LSHIFT_EXPR);
+      break;
+
+    case CPP_RSHIFT:
+      id = ansi_opname (RSHIFT_EXPR);
+      break;
+
+    case CPP_LSHIFT_EQ:
+      id = ansi_assopname (LSHIFT_EXPR);
+      break;
+
+    case CPP_RSHIFT_EQ:
+      id = ansi_assopname (RSHIFT_EXPR);
+      break;
+
+    case CPP_EQ_EQ:
+      id = ansi_opname (EQ_EXPR);
+      break;
+
+    case CPP_NOT_EQ:
+      id = ansi_opname (NE_EXPR);
+      break;
+
+    case CPP_LESS_EQ:
+      id = ansi_opname (LE_EXPR);
+      break;
+
+    case CPP_GREATER_EQ:
+      id = ansi_opname (GE_EXPR);
+      break;
+
+    case CPP_AND_AND:
+      id = ansi_opname (TRUTH_ANDIF_EXPR);
+      break;
+
+    case CPP_OR_OR:
+      id = ansi_opname (TRUTH_ORIF_EXPR);
+      break;
+      
+    case CPP_PLUS_PLUS:
+      id = ansi_opname (POSTINCREMENT_EXPR);
+      break;
+
+    case CPP_MINUS_MINUS:
+      id = ansi_opname (PREDECREMENT_EXPR);
+      break;
+
+    case CPP_COMMA:
+      id = ansi_opname (COMPOUND_EXPR);
+      break;
+
+    case CPP_DEREF_STAR:
+      id = ansi_opname (MEMBER_REF);
+      break;
+
+    case CPP_DEREF:
+      id = ansi_opname (COMPONENT_REF);
+      break;
+
+    case CPP_OPEN_PAREN:
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the matching `)'.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+      return ansi_opname (CALL_EXPR);
+
+    case CPP_OPEN_SQUARE:
+      /* Consume the `['.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the matching `]'.  */
+      cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+      return ansi_opname (ARRAY_REF);
+
+      /* Extensions.  */
+    case CPP_MIN:
+      id = ansi_opname (MIN_EXPR);
+      break;
+
+    case CPP_MAX:
+      id = ansi_opname (MAX_EXPR);
+      break;
+
+    case CPP_MIN_EQ:
+      id = ansi_assopname (MIN_EXPR);
+      break;
+
+    case CPP_MAX_EQ:
+      id = ansi_assopname (MAX_EXPR);
+      break;
+
+    default:
+      /* Anything else is an error.  */
+      break;
+    }
+
+  /* If we have selected an identifier, we need to consume the
+     operator token.  */
+  if (id)
+    cp_lexer_consume_token (parser->lexer);
+  /* Otherwise, no valid operator name was present.  */
+  else
+    {
+      cp_parser_error (parser, "expected operator");
+      id = error_mark_node;
+    }
+
+  return id;
+}
+
+/* Parse a template-declaration.
+
+   template-declaration:
+     export [opt] template < template-parameter-list > declaration  
+
+   If MEMBER_P is TRUE, this template-declaration occurs within a
+   class-specifier.  
+
+   The grammar rule given by the standard isn't correct.  What
+   is really meant is:
+
+   template-declaration:
+     export [opt] template-parameter-list-seq 
+       decl-specifier-seq [opt] init-declarator [opt] ;
+     export [opt] template-parameter-list-seq 
+       function-definition
+
+   template-parameter-list-seq:
+     template-parameter-list-seq [opt]
+     template < template-parameter-list >  */
+
+static void
+cp_parser_template_declaration (parser, member_p)
+     cp_parser *parser;
+     bool member_p;
+{
+  /* Check for `export'.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))
+    {
+      /* Consume the `export' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Warn that we do not support `export'.  */
+      warning ("keyword `export' not implemented, and will be ignored");
+    }
+
+  cp_parser_template_declaration_after_export (parser, member_p);
+}
+
+/* Parse a template-parameter-list.
+
+   template-parameter-list:
+     template-parameter
+     template-parameter-list , template-parameter
+
+   Returns a TREE_LIST.  Each node represents a template parameter.
+   The nodes are connected via their TREE_CHAINs.  */
+
+static tree
+cp_parser_template_parameter_list (parser)
+     cp_parser *parser;
+{
+  tree parameter_list = NULL_TREE;
+
+  while (true)
+    {
+      tree parameter;
+      cp_token *token;
+
+      /* Parse the template-parameter.  */
+      parameter = cp_parser_template_parameter (parser);
+      /* Add it to the list.  */
+      parameter_list = process_template_parm (parameter_list,
+                                             parameter);
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's not a `,', we're done.  */
+      if (token->type != CPP_COMMA)
+       break;
+      /* Otherwise, consume the `,' token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  return parameter_list;
+}
+
+/* Parse a template-parameter.
+
+   template-parameter:
+     type-parameter
+     parameter-declaration
+
+   Returns a TREE_LIST.  The TREE_VALUE represents the parameter.  The
+   TREE_PURPOSE is the default value, if any.  */
+
+static tree
+cp_parser_template_parameter (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it is `class' or `template', we have a type-parameter.  */
+  if (token->keyword == RID_TEMPLATE)
+    return cp_parser_type_parameter (parser);
+  /* If it is `class' or `typename' we do not know yet whether it is a
+     type parameter or a non-type parameter.  Consider:
+
+       template <typename T, typename T::X X> ...
+
+     or:
+     
+       template <class C, class D*> ...
+
+     Here, the first parameter is a type parameter, and the second is
+     a non-type parameter.  We can tell by looking at the token after
+     the identifier -- if it is a `,', `=', or `>' then we have a type
+     parameter.  */
+  if (token->keyword == RID_TYPENAME || token->keyword == RID_CLASS)
+    {
+      /* Peek at the token after `class' or `typename'.  */
+      token = cp_lexer_peek_nth_token (parser->lexer, 2);
+      /* If it's an identifier, skip it.  */
+      if (token->type == CPP_NAME)
+       token = cp_lexer_peek_nth_token (parser->lexer, 3);
+      /* Now, see if the token looks like the end of a template
+        parameter.  */
+      if (token->type == CPP_COMMA 
+         || token->type == CPP_EQ
+         || token->type == CPP_GREATER)
+       return cp_parser_type_parameter (parser);
+    }
+
+  /* Otherwise, it is a non-type parameter.  
+
+     [temp.param]
+
+     When parsing a default template-argument for a non-type
+     template-parameter, the first non-nested `>' is taken as the end
+     of the template parameter-list rather than a greater-than
+     operator.  */
+  return 
+    cp_parser_parameter_declaration (parser,
+                                    /*greater_than_is_operator_p=*/false);
+}
+
+/* Parse a type-parameter.
+
+   type-parameter:
+     class identifier [opt]
+     class identifier [opt] = type-id
+     typename identifier [opt]
+     typename identifier [opt] = type-id
+     template < template-parameter-list > class identifier [opt]
+     template < template-parameter-list > class identifier [opt] 
+       = id-expression  
+
+   Returns a TREE_LIST.  The TREE_VALUE is itself a TREE_LIST.  The
+   TREE_PURPOSE is the default-argument, if any.  The TREE_VALUE is
+   the declaration of the parameter.  */
+
+static tree
+cp_parser_type_parameter (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree parameter;
+
+  /* Look for a keyword to tell us what kind of parameter this is.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, 
+                            "expected `class', `typename', or `template'");
+  if (!token)
+    return error_mark_node;
+
+  switch (token->keyword)
+    {
+    case RID_CLASS:
+    case RID_TYPENAME:
+      {
+       tree identifier;
+       tree default_argument;
+
+       /* If the next token is an identifier, then it names the
+           parameter.  */
+       if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+         identifier = cp_parser_identifier (parser);
+       else
+         identifier = NULL_TREE;
+
+       /* Create the parameter.  */
+       parameter = finish_template_type_parm (class_type_node, identifier);
+
+       /* If the next token is an `=', we have a default argument.  */
+       if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+         {
+           /* Consume the `=' token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the default-argumen.  */
+           default_argument = cp_parser_type_id (parser);
+         }
+       else
+         default_argument = NULL_TREE;
+
+       /* Create the combined representation of the parameter and the
+          default argument.  */
+       parameter = build_tree_list (default_argument, 
+                                    parameter);
+      }
+      break;
+
+    case RID_TEMPLATE:
+      {
+       tree parameter_list;
+       tree identifier;
+       tree default_argument;
+
+       /* Look for the `<'.  */
+       cp_parser_require (parser, CPP_LESS, "`<'");
+       /* Parse the template-parameter-list.  */
+       begin_template_parm_list ();
+       parameter_list 
+         = cp_parser_template_parameter_list (parser);
+       parameter_list = end_template_parm_list (parameter_list);
+       /* Look for the `>'.  */
+       cp_parser_require (parser, CPP_GREATER, "`>'");
+       /* Look for the `class' keyword.  */
+       cp_parser_require_keyword (parser, RID_CLASS, "`class'");
+       /* If the next token is an `=', then there is a
+          default-argument.  If the next token is a `>', we are at
+          the end of the parameter-list.  If the next token is a `,',
+          then we are at the end of this parameter.  */
+       if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
+           && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)
+           && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+         identifier = cp_parser_identifier (parser);
+       else
+         identifier = NULL_TREE;
+       /* Create the template parameter.  */
+       parameter = finish_template_template_parm (class_type_node,
+                                                  identifier);
+                                                  
+       /* If the next token is an `=', then there is a
+          default-argument.  */
+       if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+         {
+           /* Consume the `='.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the id-expression.  */
+           default_argument 
+             = cp_parser_id_expression (parser,
+                                        /*template_keyword_p=*/false,
+                                        /*check_dependency_p=*/true,
+                                        /*template_p=*/NULL);
+           /* Look up the name.  */
+           default_argument 
+             = cp_parser_lookup_name_simple (parser, default_argument);
+           /* See if the default argument is valid.  */
+           default_argument
+             = check_template_template_default_arg (default_argument);
+         }
+       else
+         default_argument = NULL_TREE;
+
+       /* Create the combined representation of the parameter and the
+          default argument.  */
+       parameter =  build_tree_list (default_argument, 
+                                     parameter);
+      }
+      break;
+
+    default:
+      /* Anything else is an error.  */
+      cp_parser_error (parser,
+                      "expected `class', `typename', or `template'");
+      parameter = error_mark_node;
+    }
+  
+  return parameter;
+}
+
+/* Parse a template-id.
+
+   template-id:
+     template-name < template-argument-list [opt] >
+
+   If TEMPLATE_KEYWORD_P is TRUE, then we have just seen the
+   `template' keyword.  In this case, a TEMPLATE_ID_EXPR will be
+   returned.  Otherwise, if the template-name names a function, or set
+   of functions, returns a TEMPLATE_ID_EXPR.  If the template-name
+   names a class, returns a TYPE_DECL for the specialization.  
+
+   If CHECK_DEPENDENCY_P is FALSE, names are looked up in
+   uninstantiated templates.  */
+
+static tree
+cp_parser_template_id (cp_parser *parser, 
+                      bool template_keyword_p, 
+                      bool check_dependency_p)
+{
+  tree template;
+  tree arguments;
+  tree saved_scope;
+  tree saved_qualifying_scope;
+  tree saved_object_scope;
+  tree template_id;
+  bool saved_greater_than_is_operator_p;
+  ptrdiff_t start_of_id;
+  tree access_check = NULL_TREE;
+
+  /* If the next token corresponds to a template-id, there is no need
+     to reparse it.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_TEMPLATE_ID))
+    {
+      tree value;
+      tree check;
+
+      /* Get the stored value.  */
+      value = cp_lexer_consume_token (parser->lexer)->value;
+      /* Perform any access checks that were deferred.  */
+      for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
+       cp_parser_defer_access_check (parser, 
+                                     TREE_PURPOSE (check),
+                                     TREE_VALUE (check));
+      /* Return the stored value.  */
+      return TREE_VALUE (value);
+    }
+
+  /* Remember where the template-id starts.  */
+  if (cp_parser_parsing_tentatively (parser)
+      && !cp_parser_committed_to_tentative_parse (parser))
+    {
+      cp_token *next_token = cp_lexer_peek_token (parser->lexer);
+      start_of_id = cp_lexer_token_difference (parser->lexer,
+                                              parser->lexer->first_token,
+                                              next_token);
+      access_check = parser->context->deferred_access_checks;
+    }
+  else
+    start_of_id = -1;
+
+  /* Parse the template-name.  */
+  template = cp_parser_template_name (parser, template_keyword_p,
+                                     check_dependency_p);
+  if (template == error_mark_node)
+    return error_mark_node;
+
+  /* Look for the `<' that starts the template-argument-list.  */
+  if (!cp_parser_require (parser, CPP_LESS, "`<'"))
+    return error_mark_node;
+
+  /* [temp.names]
+
+     When parsing a template-id, the first non-nested `>' is taken as
+     the end of the template-argument-list rather than a greater-than
+     operator.  */
+  saved_greater_than_is_operator_p 
+    = parser->greater_than_is_operator_p;
+  parser->greater_than_is_operator_p = false;
+  /* Parsing the argument list may modify SCOPE, so we save it
+     here.  */
+  saved_scope = parser->scope;
+  saved_qualifying_scope = parser->qualifying_scope;
+  saved_object_scope = parser->object_scope;
+  /* Parse the template-argument-list itself.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
+    arguments = NULL_TREE;
+  else
+    arguments = cp_parser_template_argument_list (parser);
+  /* Look for the `>' that ends the template-argument-list.  */
+  cp_parser_require (parser, CPP_GREATER, "`>'");
+  /* The `>' token might be a greater-than operator again now.  */
+  parser->greater_than_is_operator_p 
+    = saved_greater_than_is_operator_p;
+  /* Restore the SAVED_SCOPE.  */
+  parser->scope = saved_scope;
+  parser->qualifying_scope = saved_qualifying_scope;
+  parser->object_scope = saved_object_scope;
+
+  /* Build a representation of the specialization.  */
+  if (TREE_CODE (template) == IDENTIFIER_NODE)
+    template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);
+  else if (DECL_CLASS_TEMPLATE_P (template)
+          || DECL_TEMPLATE_TEMPLATE_PARM_P (template))
+    template_id 
+      = finish_template_type (template, arguments, 
+                             cp_lexer_next_token_is (parser->lexer, 
+                                                     CPP_SCOPE));
+  else
+    {
+      /* If it's not a class-template or a template-template, it should be
+        a function-template.  */
+      my_friendly_assert ((DECL_FUNCTION_TEMPLATE_P (template)
+                          || TREE_CODE (template) == OVERLOAD
+                          || BASELINK_P (template)),
+                         20010716);
+      
+      template_id = lookup_template_function (template, arguments);
+    }
+  
+  /* If parsing tentatively, replace the sequence of tokens that makes
+     up the template-id with a CPP_TEMPLATE_ID token.  That way,
+     should we re-parse the token stream, we will not have to repeat
+     the effort required to do the parse, nor will we issue duplicate
+     error messages about problems during instantiation of the
+     template.  */
+  if (start_of_id >= 0)
+    {
+      cp_token *token;
+      tree c;
+
+      /* Find the token that corresponds to the start of the
+        template-id.  */
+      token = cp_lexer_advance_token (parser->lexer, 
+                                     parser->lexer->first_token,
+                                     start_of_id);
+
+      /* Remember the access checks associated with this
+        nested-name-specifier.  */
+      c = parser->context->deferred_access_checks;
+      if (c == access_check)
+       access_check = NULL_TREE;
+      else
+       {
+         while (TREE_CHAIN (c) != access_check)
+           c = TREE_CHAIN (c);
+         access_check = parser->context->deferred_access_checks;
+         parser->context->deferred_access_checks = TREE_CHAIN (c);
+         TREE_CHAIN (c) = NULL_TREE;
+       }
+
+      /* Reset the contents of the START_OF_ID token.  */
+      token->type = CPP_TEMPLATE_ID;
+      token->value = build_tree_list (access_check, template_id);
+      token->keyword = RID_MAX;
+      /* Purge all subsequent tokens.  */
+      cp_lexer_purge_tokens_after (parser->lexer, token);
+    }
+
+  return template_id;
+}
+
+/* Parse a template-name.
+
+   template-name:
+     identifier
+   The standard should actually say:
+
+   template-name:
+     identifier
+     operator-function-id
+     conversion-function-id
+
+   A defect report has been filed about this issue.
+
+   If TEMPLATE_KEYWORD_P is true, then we have just seen the
+   `template' keyword, in a construction like:
+
+     T::template f<3>()
+
+   In that case `f' is taken to be a template-name, even though there
+   is no way of knowing for sure.
+
+   Returns the TEMPLATE_DECL for the template, or an OVERLOAD if the
+   name refers to a set of overloaded functions, at least one of which
+   is a template, or an IDENTIFIER_NODE with the name of the template,
+   if TEMPLATE_KEYWORD_P is true.  If CHECK_DEPENDENCY_P is FALSE,
+   names are looked up inside uninstantiated templates.  */
+
+static tree
+cp_parser_template_name (parser, template_keyword_p, check_dependency_p)
+     cp_parser *parser;
+     bool template_keyword_p;
+     bool check_dependency_p;
+{
+  tree identifier;
+  tree decl;
+  tree fns;
+
+  /* If the next token is `operator', then we have either an
+     operator-function-id or a conversion-function-id.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_OPERATOR))
+    {
+      /* We don't know whether we're looking at an
+        operator-function-id or a conversion-function-id.  */
+      cp_parser_parse_tentatively (parser);
+      /* Try an operator-function-id.  */
+      identifier = cp_parser_operator_function_id (parser);
+      /* If that didn't work, try a conversion-function-id.  */
+      if (!cp_parser_parse_definitely (parser))
+       identifier = cp_parser_conversion_function_id (parser);
+    }
+  /* Look for the identifier.  */
+  else
+    identifier = cp_parser_identifier (parser);
+  
+  /* If we didn't find an identifier, we don't have a template-id.  */
+  if (identifier == error_mark_node)
+    return error_mark_node;
+
+  /* If the name immediately followed the `template' keyword, then it
+     is a template-name.  However, if the next token is not `<', then
+     we do not treat it as a template-name, since it is not being used
+     as part of a template-id.  This enables us to handle constructs
+     like:
+
+       template <typename T> struct S { S(); };
+       template <typename T> S<T>::S();
+
+     correctly.  We would treat `S' as a template -- if it were `S<T>'
+     -- but we do not if there is no `<'.  */
+  if (template_keyword_p && processing_template_decl
+      && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    return identifier;
+
+  /* Look up the name.  */
+  decl = cp_parser_lookup_name (parser, identifier,
+                               /*check_access=*/true,
+                               /*is_type=*/false,
+                               check_dependency_p);
+  decl = maybe_get_template_decl_from_type_decl (decl);
+
+  /* If DECL is a template, then the name was a template-name.  */
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    ;
+  else 
+    {
+      /* The standard does not explicitly indicate whether a name that
+        names a set of overloaded declarations, some of which are
+        templates, is a template-name.  However, such a name should
+        be a template-name; otherwise, there is no way to form a
+        template-id for the overloaded templates.  */
+      fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
+      if (TREE_CODE (fns) == OVERLOAD)
+       {
+         tree fn;
+         
+         for (fn = fns; fn; fn = OVL_NEXT (fn))
+           if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
+             break;
+       }
+      else
+       {
+         /* Otherwise, the name does not name a template.  */
+         cp_parser_error (parser, "expected template-name");
+         return error_mark_node;
+       }
+    }
+
+  /* If DECL is dependent, and refers to a function, then just return
+     its name; we will look it up again during template instantiation.  */
+  if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
+    {
+      tree scope = CP_DECL_CONTEXT (get_first_fn (decl));
+      if (TYPE_P (scope) && cp_parser_dependent_type_p (scope))
+       return identifier;
+    }
+
+  return decl;
+}
+
+/* Parse a template-argument-list.
+
+   template-argument-list:
+     template-argument
+     template-argument-list , template-argument
+
+   Returns a TREE_LIST representing the arguments, in the order they
+   appeared.  The TREE_VALUE of each node is a representation of the
+   argument.  */
+
+static tree
+cp_parser_template_argument_list (parser)
+     cp_parser *parser;
+{
+  tree arguments = NULL_TREE;
+
+  while (true)
+    {
+      tree argument;
+
+      /* Parse the template-argument.  */
+      argument = cp_parser_template_argument (parser);
+      /* Add it to the list.  */
+      arguments = tree_cons (NULL_TREE, argument, arguments);
+      /* If it is not a `,', then there are no more arguments.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+      /* Otherwise, consume the ','.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* We built up the arguments in reverse order.  */
+  return nreverse (arguments);
+}
+
+/* Parse a template-argument.
+
+   template-argument:
+     assignment-expression
+     type-id
+     id-expression
+
+   The representation is that of an assignment-expression, type-id, or
+   id-expression -- except that the qualified id-expression is
+   evaluated, so that the value returned is either a DECL or an
+   OVERLOAD.  */
+
+static tree
+cp_parser_template_argument (parser)
+     cp_parser *parser;
+{
+  tree argument;
+  bool template_p;
+
+  /* There's really no way to know what we're looking at, so we just
+     try each alternative in order.  
+
+       [temp.arg]
+
+       In a template-argument, an ambiguity between a type-id and an
+       expression is resolved to a type-id, regardless of the form of
+       the corresponding template-parameter.  
+
+     Therefore, we try a type-id first.  */
+  cp_parser_parse_tentatively (parser);
+  /* Otherwise, try a type-id.  */
+  argument = cp_parser_type_id (parser);
+  /* If the next token isn't a `,' or a `>', then this argument wasn't
+     really finished.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
+      && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
+    cp_parser_error (parser, "expected template-argument");
+  /* If that worked, we're done.  */
+  if (cp_parser_parse_definitely (parser))
+    return argument;
+  /* We're still not sure what the argument will be.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try a template.  */
+  argument = cp_parser_id_expression (parser, 
+                                     /*template_keyword_p=*/false,
+                                     /*check_dependency_p=*/true,
+                                     &template_p);
+  /* If the next token isn't a `,' or a `>', then this argument wasn't
+     really finished.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
+      && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
+    cp_parser_error (parser, "expected template-argument");
+  if (!cp_parser_error_occurred (parser))
+    {
+      /* Figure out what is being referred to.  */
+      argument = cp_parser_lookup_name_simple (parser, argument);
+      if (template_p)
+       argument = make_unbound_class_template (TREE_OPERAND (argument, 0),
+                                               TREE_OPERAND (argument, 1),
+                                               tf_error | tf_parsing);
+      else if (TREE_CODE (argument) != TEMPLATE_DECL)
+       cp_parser_error (parser, "expected template-name");
+    }
+  if (cp_parser_parse_definitely (parser))
+    return argument;
+  /* It must be an assignment-expression.  */
+  return cp_parser_assignment_expression (parser);
+}
+
+/* Parse an explicit-instantiation.
+
+   explicit-instantiation:
+     template declaration  
+
+   Although the standard says `declaration', what it really means is:
+
+   explicit-instantiation:
+     template decl-specifier-seq [opt] declarator [opt] ; 
+
+   Things like `template int S<int>::i = 5, int S<double>::j;' are not
+   supposed to be allowed.  A defect report has been filed about this
+   issue.  
+
+   GNU Extension:
+  
+   explicit-instantiation:
+     storage-class-specifier template 
+       decl-specifier-seq [opt] declarator [opt] ;
+     function-specifier template 
+       decl-specifier-seq [opt] declarator [opt] ;  */
+
+static void
+cp_parser_explicit_instantiation (parser)
+     cp_parser *parser;
+{
+  bool declares_class_or_enum;
+  tree decl_specifiers;
+  tree attributes;
+  tree extension_specifier = NULL_TREE;
+
+  /* Look for an (optional) storage-class-specifier or
+     function-specifier.  */
+  if (cp_parser_allow_gnu_extensions_p (parser))
+    {
+      extension_specifier 
+       = cp_parser_storage_class_specifier_opt (parser);
+      if (!extension_specifier)
+       extension_specifier = cp_parser_function_specifier_opt (parser);
+    }
+
+  /* Look for the `template' keyword.  */
+  cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
+  /* Let the front end know that we are processing an explicit
+     instantiation.  */
+  begin_explicit_instantiation ();
+  /* [temp.explicit] says that we are supposed to ignore access
+     control while processing explicit instantiation directives.  */
+  scope_chain->check_access = 0;
+  /* Parse a decl-specifier-seq.  */
+  decl_specifiers 
+    = cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &attributes,
+                                   &declares_class_or_enum);
+  /* If there was exactly one decl-specifier, and it declared a class,
+     and there's no declarator, then we have an explicit type
+     instantiation.  */
+  if (declares_class_or_enum && cp_parser_declares_only_class_p (parser))
+    {
+      tree type;
+
+      type = check_tag_decl (decl_specifiers);
+      if (type)
+       do_type_instantiation (type, extension_specifier, /*complain=*/1);
+    }
+  else
+    {
+      tree declarator;
+      tree decl;
+
+      /* Parse the declarator.  */
+      declarator 
+       = cp_parser_declarator (parser, 
+                               /*abstract_p=*/false, 
+                               /*ctor_dtor_or_conv_p=*/NULL);
+      decl = grokdeclarator (declarator, decl_specifiers, 
+                            NORMAL, 0, NULL);
+      /* Do the explicit instantiation.  */
+      do_decl_instantiation (decl, extension_specifier);
+    }
+  /* We're done with the instantiation.  */
+  end_explicit_instantiation ();
+  /* Trun access control back on.  */
+  scope_chain->check_access = flag_access_control;
+
+  /* Look for the trailing `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+}
+
+/* Parse an explicit-specialization.
+
+   explicit-specialization:
+     template < > declaration  
+
+   Although the standard says `declaration', what it really means is:
+
+   explicit-specialization:
+     template <> decl-specifier [opt] init-declarator [opt] ;
+     template <> function-definition 
+     template <> explicit-specialization
+     template <> template-declaration  */
+
+static void
+cp_parser_explicit_specialization (parser)
+     cp_parser *parser;
+{
+  /* Look for the `template' keyword.  */
+  cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
+  /* Look for the `<'.  */
+  cp_parser_require (parser, CPP_LESS, "`<'");
+  /* Look for the `>'.  */
+  cp_parser_require (parser, CPP_GREATER, "`>'");
+  /* We have processed another parameter list.  */
+  ++parser->num_template_parameter_lists;
+  /* Let the front end know that we are beginning a specialization.  */
+  begin_specialization ();
+
+  /* If the next keyword is `template', we need to figure out whether
+     or not we're looking a template-declaration.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    {
+      if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS
+         && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER)
+       cp_parser_template_declaration_after_export (parser,
+                                                    /*member_p=*/false);
+      else
+       cp_parser_explicit_specialization (parser);
+    }
+  else
+    /* Parse the dependent declaration.  */
+    cp_parser_single_declaration (parser, 
+                                 /*member_p=*/false,
+                                 /*friend_p=*/NULL);
+
+  /* We're done with the specialization.  */
+  end_specialization ();
+  /* We're done with this parameter list.  */
+  --parser->num_template_parameter_lists;
+}
+
+/* Parse a type-specifier.
+
+   type-specifier:
+     simple-type-specifier
+     class-specifier
+     enum-specifier
+     elaborated-type-specifier
+     cv-qualifier
+
+   GNU Extension:
+
+   type-specifier:
+     __complex__
+
+   Returns a representation of the type-specifier.  If the
+   type-specifier is a keyword (like `int' or `const', or
+   `__complex__') then the correspoding IDENTIFIER_NODE is returned.
+   For a class-specifier, enum-specifier, or elaborated-type-specifier
+   a TREE_TYPE is returned; otherwise, a TYPE_DECL is returned.
+
+   If IS_FRIEND is TRUE then this type-specifier is being declared a
+   `friend'.  If IS_DECLARATION is TRUE, then this type-specifier is
+   appearing in a decl-specifier-seq.
+
+   If DECLARES_CLASS_OR_ENUM is non-NULL, and the type-specifier is a
+   class-specifier, enum-specifier, or elaborated-type-specifier, then
+   *DECLARES_CLASS_OR_ENUM is set to TRUE.  Otherwise, it is set to
+   FALSE.
+
+   If IS_CV_QUALIFIER is non-NULL, and the type-specifier is a
+   cv-qualifier, then IS_CV_QUALIFIER is set to TRUE.  Otherwise, it
+   is set to FALSE.  */
+
+static tree
+cp_parser_type_specifier (parser, 
+                         flags, 
+                         is_friend,
+                         is_declaration,
+                         declares_class_or_enum,
+                         is_cv_qualifier)
+     cp_parser *parser;
+     cp_parser_flags flags;
+     bool is_friend;
+     bool is_declaration;
+     bool *declares_class_or_enum;
+     bool *is_cv_qualifier;
+{
+  tree type_spec = NULL_TREE;
+  cp_token *token;
+  enum rid keyword;
+
+  /* Assume this type-specifier does not declare a new type.  */
+  if (declares_class_or_enum)
+    *declares_class_or_enum = false;
+  /* And that it does not specify a cv-qualifier.  */
+  if (is_cv_qualifier)
+    *is_cv_qualifier = false;
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  /* If we're looking at a keyword, we can use that to guide the
+     production we choose.  */
+  keyword = token->keyword;
+  switch (keyword)
+    {
+      /* Any of these indicate either a class-specifier, or an
+        elaborated-type-specifier.  */
+    case RID_CLASS:
+    case RID_STRUCT:
+    case RID_UNION:
+    case RID_ENUM:
+      /* Parse tentatively so that we can back up if we don't find a
+        class-specifier or enum-specifier.  */
+      cp_parser_parse_tentatively (parser);
+      /* Look for the class-specifier or enum-specifier.  */
+      if (keyword == RID_ENUM)
+       type_spec = cp_parser_enum_specifier (parser);
+      else
+       type_spec = cp_parser_class_specifier (parser);
+
+      /* If that worked, we're done.  */
+      if (cp_parser_parse_definitely (parser))
+       {
+         if (declares_class_or_enum)
+           *declares_class_or_enum = true;
+         return type_spec;
+       }
+
+      /* Fall through.  */
+
+    case RID_TYPENAME:
+      /* Look for an elaborated-type-specifier.  */
+      type_spec = cp_parser_elaborated_type_specifier (parser,
+                                                      is_friend,
+                                                      is_declaration);
+      /* We're declaring a class or enum -- unless we're using
+        `typename'.  */
+      if (declares_class_or_enum && keyword != RID_TYPENAME)
+       *declares_class_or_enum = true;
+      return type_spec;
+
+    case RID_CONST:
+    case RID_VOLATILE:
+    case RID_RESTRICT:
+      type_spec = cp_parser_cv_qualifier_opt (parser);
+      /* Even though we call a routine that looks for an optional
+        qualifier, we know that there should be one.  */
+      my_friendly_assert (type_spec != NULL, 20000328);
+      /* This type-specifier was a cv-qualified.  */
+      if (is_cv_qualifier)
+       *is_cv_qualifier = true;
+
+      return type_spec;
+
+    case RID_COMPLEX:
+      /* The `__complex__' keyword is a GNU extension.  */
+      return cp_lexer_consume_token (parser->lexer)->value;
+
+    default:
+      break;
+    }
+
+  /* If we do not already have a type-specifier, assume we are looking
+     at a simple-type-specifier.  */
+  type_spec = cp_parser_simple_type_specifier (parser, flags);
+
+  /* If we didn't find a type-specifier, and a type-specifier was not
+     optional in this context, issue an error message.  */
+  if (!type_spec && !(flags & CP_PARSER_FLAGS_OPTIONAL))
+    {
+      cp_parser_error (parser, "expected type specifier");
+      return error_mark_node;
+    }
+
+  return type_spec;
+}
+
+/* Parse a simple-type-specifier.
+
+   simple-type-specifier:
+     :: [opt] nested-name-specifier [opt] type-name
+     :: [opt] nested-name-specifier template template-id
+     char
+     wchar_t
+     bool
+     short
+     int
+     long
+     signed
+     unsigned
+     float
+     double
+     void  
+
+   GNU Extension:
+
+   simple-type-specifier:
+     __typeof__ unary-expression
+     __typeof__ ( type-id )
+
+   For the various keywords, the value returned is simply the
+   TREE_IDENTIFIER representing the keyword.  For the first two
+   productions, the value returned is the indicated TYPE_DECL.  */
+
+static tree
+cp_parser_simple_type_specifier (parser, flags)
+     cp_parser *parser;
+     cp_parser_flags flags;
+{
+  tree type = NULL_TREE;
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  /* If we're looking at a keyword, things are easy.  */
+  switch (token->keyword)
+    {
+    case RID_CHAR:
+    case RID_WCHAR:
+    case RID_BOOL:
+    case RID_SHORT:
+    case RID_INT:
+    case RID_LONG:
+    case RID_SIGNED:
+    case RID_UNSIGNED:
+    case RID_FLOAT:
+    case RID_DOUBLE:
+    case RID_VOID:
+      /* Consume the token.  */
+      return cp_lexer_consume_token (parser->lexer)->value;
+
+    case RID_TYPEOF:
+      {
+       tree operand;
+
+       /* Consume the `typeof' token.  */
+       cp_lexer_consume_token (parser->lexer);
+       /* Parse the operand to `typeof'  */
+       operand = cp_parser_sizeof_operand (parser, RID_TYPEOF);
+       /* If it is not already a TYPE, take its type.  */
+       if (!TYPE_P (operand))
+         operand = finish_typeof (operand);
+
+       return operand;
+      }
+
+    default:
+      break;
+    }
+
+  /* The type-specifier must be a user-defined type.  */
+  if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES)) 
+    {
+      /* Don't gobble tokens or issue error messages if this is an
+        optional type-specifier.  */
+      if (flags & CP_PARSER_FLAGS_OPTIONAL)
+       cp_parser_parse_tentatively (parser);
+
+      /* Look for the optional `::' operator.  */
+      cp_parser_global_scope_opt (parser,
+                                 /*current_scope_valid_p=*/false);
+      /* Look for the nested-name specifier.  */
+      cp_parser_nested_name_specifier_opt (parser,
+                                          /*typename_keyword_p=*/false,
+                                          /*check_dependency_p=*/true,
+                                          /*type_p=*/false);
+      /* If we have seen a nested-name-specifier, and the next token
+        is `template', then we are using the template-id production.  */
+      if (parser->scope 
+         && cp_parser_optional_template_keyword (parser))
+       {
+         /* Look for the template-id.  */
+         type = cp_parser_template_id (parser, 
+                                       /*template_keyword_p=*/true,
+                                       /*check_dependency_p=*/true);
+         /* If the template-id did not name a type, we are out of
+            luck.  */
+         if (TREE_CODE (type) != TYPE_DECL)
+           {
+             cp_parser_error (parser, "expected template-id for type");
+             type = NULL_TREE;
+           }
+       }
+      /* Otherwise, look for a type-name.  */
+      else
+       {
+         type = cp_parser_type_name (parser);
+         if (type == error_mark_node)
+           type = NULL_TREE;
+       }
+
+      /* If it didn't work out, we don't have a TYPE.  */
+      if ((flags & CP_PARSER_FLAGS_OPTIONAL) 
+         && !cp_parser_parse_definitely (parser))
+       type = NULL_TREE;
+    }
+
+  /* If we didn't get a type-name, issue an error message.  */
+  if (!type && !(flags & CP_PARSER_FLAGS_OPTIONAL))
+    {
+      cp_parser_error (parser, "expected type-name");
+      return error_mark_node;
+    }
+
+  return type;
+}
+
+/* Parse a type-name.
+
+   type-name:
+     class-name
+     enum-name
+     typedef-name  
+
+   enum-name:
+     identifier
+
+   typedef-name:
+     identifier 
+
+   Returns a TYPE_DECL for the the type.  */
+
+static tree
+cp_parser_type_name (parser)
+     cp_parser *parser;
+{
+  tree type_decl;
+  tree identifier;
+
+  /* We can't know yet whether it is a class-name or not.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try a class-name.  */
+  type_decl = cp_parser_class_name (parser, 
+                                   /*typename_keyword_p=*/false,
+                                   /*template_keyword_p=*/false,
+                                   /*type_p=*/false,
+                                   /*check_access_p=*/true,
+                                   /*check_dependency_p=*/true,
+                                   /*class_head_p=*/false);
+  /* If it's not a class-name, keep looking.  */
+  if (!cp_parser_parse_definitely (parser))
+    {
+      /* It must be a typedef-name or an enum-name.  */
+      identifier = cp_parser_identifier (parser);
+      if (identifier == error_mark_node)
+       return error_mark_node;
+      
+      /* Look up the type-name.  */
+      type_decl = cp_parser_lookup_name_simple (parser, identifier);
+      /* Issue an error if we did not find a type-name.  */
+      if (TREE_CODE (type_decl) != TYPE_DECL)
+       {
+         cp_parser_error (parser, "expected type-name");
+         type_decl = error_mark_node;
+       }
+      /* Remember that the name was used in the definition of the
+        current class so that we can check later to see if the
+        meaning would have been different after the class was
+        entirely defined.  */
+      else if (type_decl != error_mark_node
+              && !parser->scope)
+       maybe_note_name_used_in_class (identifier, type_decl);
+    }
+  
+  return type_decl;
+}
+
+
+/* Parse an elaborated-type-specifier.  Note that the grammar given
+   here incorporates the resolution to DR68.
+
+   elaborated-type-specifier:
+     class-key :: [opt] nested-name-specifier [opt] identifier
+     class-key :: [opt] nested-name-specifier [opt] template [opt] template-id
+     enum :: [opt] nested-name-specifier [opt] identifier
+     typename :: [opt] nested-name-specifier identifier
+     typename :: [opt] nested-name-specifier template [opt] 
+       template-id 
+
+   If IS_FRIEND is TRUE, then this elaborated-type-specifier is being
+   declared `friend'.  If IS_DECLARATION is TRUE, then this
+   elaborated-type-specifier appears in a decl-specifiers-seq, i.e.,
+   something is being declared.
+
+   Returns the TYPE specified.  */
+
+static tree
+cp_parser_elaborated_type_specifier (parser, is_friend, is_declaration)
+     cp_parser *parser;
+     bool is_friend;
+     bool is_declaration;
+{
+  enum tag_types tag_type;
+  tree identifier;
+  tree type = NULL_TREE;
+
+  /* See if we're looking at the `enum' keyword.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ENUM))
+    {
+      /* Consume the `enum' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Remember that it's an enumeration type.  */
+      tag_type = enum_type;
+    }
+  /* Or, it might be `typename'.  */
+  else if (cp_lexer_next_token_is_keyword (parser->lexer,
+                                          RID_TYPENAME))
+    {
+      /* Consume the `typename' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Remember that it's a `typename' type.  */
+      tag_type = typename_type;
+      /* The `typename' keyword is only allowed in templates.  */
+      if (!processing_template_decl)
+       pedwarn ("using `typename' outside of template");
+    }
+  /* Otherwise it must be a class-key.  */
+  else
+    {
+      tag_type = cp_parser_class_key (parser);
+      if (tag_type == none_type)
+       return error_mark_node;
+    }
+
+  /* Look for the `::' operator.  */
+  cp_parser_global_scope_opt (parser, 
+                             /*current_scope_valid_p=*/false);
+  /* Look for the nested-name-specifier.  */
+  if (tag_type == typename_type)
+    cp_parser_nested_name_specifier (parser,
+                                    /*typename_keyword_p=*/true,
+                                    /*check_dependency_p=*/true,
+                                    /*type_p=*/true);
+  else
+    /* Even though `typename' is not present, the proposed resolution
+       to Core Issue 180 says that in `class A<T>::B', `B' should be
+       considered a type-name, even if `A<T>' is dependent.  */
+    cp_parser_nested_name_specifier_opt (parser,
+                                        /*typename_keyword_p=*/true,
+                                        /*check_dependency_p=*/true,
+                                        /*type_p=*/true);
+  /* For everything but enumeration types, consider a template-id.  */
+  if (tag_type != enum_type)
+    {
+      bool template_p = false;
+      tree decl;
+
+      /* Allow the `template' keyword.  */
+      template_p = cp_parser_optional_template_keyword (parser);
+      /* If we didn't see `template', we don't know if there's a
+         template-id or not.  */
+      if (!template_p)
+       cp_parser_parse_tentatively (parser);
+      /* Parse the template-id.  */
+      decl = cp_parser_template_id (parser, template_p,
+                                   /*check_dependency_p=*/true);
+      /* If we didn't find a template-id, look for an ordinary
+         identifier.  */
+      if (!template_p && !cp_parser_parse_definitely (parser))
+       ;
+      /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is
+        in effect, then we must assume that, upon instantiation, the
+        template will correspond to a class.  */
+      else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+              && tag_type == typename_type)
+       type = make_typename_type (parser->scope, decl,
+                                  /*complain=*/1);
+      else 
+       type = TREE_TYPE (decl);
+    }
+
+  /* For an enumeration type, consider only a plain identifier.  */
+  if (!type)
+    {
+      identifier = cp_parser_identifier (parser);
+
+      if (identifier == error_mark_node)
+       return error_mark_node;
+
+      /* For a `typename', we needn't call xref_tag.  */
+      if (tag_type == typename_type)
+       return make_typename_type (parser->scope, identifier, 
+                                  /*complain=*/1);
+      /* Look up a qualified name in the usual way.  */
+      if (parser->scope)
+       {
+         tree decl;
+
+         /* In an elaborated-type-specifier, names are assumed to name
+            types, so we set IS_TYPE to TRUE when calling
+            cp_parser_lookup_name.  */
+         decl = cp_parser_lookup_name (parser, identifier, 
+                                       /*check_access=*/true,
+                                       /*is_type=*/true,
+                                       /*check_dependency=*/true);
+         decl = (cp_parser_maybe_treat_template_as_class 
+                 (decl, /*tag_name_p=*/is_friend));
+
+         if (TREE_CODE (decl) != TYPE_DECL)
+           {
+             error ("expected type-name");
+             return error_mark_node;
+           }
+         else if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
+                  && tag_type != enum_type)
+           error ("`%T' referred to as `%s'", TREE_TYPE (decl),
+                  tag_type == record_type ? "struct" : "class");
+         else if (TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
+                  && tag_type == enum_type)
+           error ("`%T' referred to as enum", TREE_TYPE (decl));
+
+         type = TREE_TYPE (decl);
+       }
+      else 
+       {
+         /* An elaborated-type-specifier sometimes introduces a new type and
+            sometimes names an existing type.  Normally, the rule is that it
+            introduces a new type only if there is not an existing type of
+            the same name already in scope.  For example, given:
+
+              struct S {};
+              void f() { struct S s; }
+
+            the `struct S' in the body of `f' is the same `struct S' as in
+            the global scope; the existing definition is used.  However, if
+            there were no global declaration, this would introduce a new 
+            local class named `S'.
+
+            An exception to this rule applies to the following code:
+
+              namespace N { struct S; }
+
+            Here, the elaborated-type-specifier names a new type
+            unconditionally; even if there is already an `S' in the
+            containing scope this declaration names a new type.
+            This exception only applies if the elaborated-type-specifier
+            forms the complete declaration:
+
+              [class.name] 
+
+              A declaration consisting solely of `class-key identifier ;' is
+              either a redeclaration of the name in the current scope or a
+              forward declaration of the identifier as a class name.  It
+              introduces the name into the current scope.
+
+            We are in this situation precisely when the next token is a `;'.
+
+            An exception to the exception is that a `friend' declaration does
+            *not* name a new type; i.e., given:
+
+              struct S { friend struct T; };
+
+            `T' is not a new type in the scope of `S'.  
+
+            Also, `new struct S' or `sizeof (struct S)' never results in the
+            definition of a new type; a new type can only be declared in a
+            declaration context.   */
+
+         type = xref_tag (tag_type, identifier, 
+                          /*attributes=*/NULL_TREE,
+                          (is_friend 
+                           || !is_declaration
+                           || cp_lexer_next_token_is_not (parser->lexer, 
+                                                          CPP_SEMICOLON)));
+       }
+    }
+  if (tag_type != enum_type)
+    cp_parser_check_class_key (tag_type, type);
+  return type;
+}
+
+/* Parse an enum-specifier.
+
+   enum-specifier:
+     enum identifier [opt] { enumerator-list [opt] }
+
+   Returns an ENUM_TYPE representing the enumeration.  */
+
+static tree
+cp_parser_enum_specifier (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree identifier = NULL_TREE;
+  tree type;
+
+  /* Look for the `enum' keyword.  */
+  if (!cp_parser_require_keyword (parser, RID_ENUM, "`enum'"))
+    return error_mark_node;
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  /* See if it is an identifier.  */
+  if (token->type == CPP_NAME)
+    identifier = cp_parser_identifier (parser);
+
+  /* Look for the `{'.  */
+  if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
+    return error_mark_node;
+
+  /* At this point, we're going ahead with the enum-specifier, even
+     if some other problem occurs.  */
+  cp_parser_commit_to_tentative_parse (parser);
+
+  /* Issue an error message if type-definitions are forbidden here.  */
+  cp_parser_check_type_definition (parser);
+
+  /* Create the new type.  */
+  type = start_enum (identifier ? identifier : make_anon_name ());
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's not a `}', then there are some enumerators.  */
+  if (token->type != CPP_CLOSE_BRACE)
+    cp_parser_enumerator_list (parser, type);
+  /* Look for the `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+
+  /* Finish up the enumeration.  */
+  finish_enum (type);
+
+  return type;
+}
+
+/* Parse an enumerator-list.  The enumerators all have the indicated
+   TYPE.  
+
+   enumerator-list:
+     enumerator-definition
+     enumerator-list , enumerator-definition  */
+
+static void
+cp_parser_enumerator_list (parser, type)
+     cp_parser *parser;
+     tree type;
+{
+  while (true)
+    {
+      cp_token *token;
+
+      /* Parse an enumerator-definition.  */
+      cp_parser_enumerator_definition (parser, type);
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's not a `,', then we've reached the end of the 
+        list.  */
+      if (token->type != CPP_COMMA)
+       break;
+      /* Otherwise, consume the `,' and keep going.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* If the next token is a `}', there is a trailing comma.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+       {
+         if (pedantic && !in_system_header)
+           pedwarn ("comma at end of enumerator list");
+         break;
+       }
+    }
+}
+
+/* Parse an enumerator-definition.  The enumerator has the indicated
+   TYPE.
+
+   enumerator-definition:
+     enumerator
+     enumerator = constant-expression
+    
+   enumerator:
+     identifier  */
+
+static void
+cp_parser_enumerator_definition (parser, type)
+     cp_parser *parser;
+     tree type;
+{
+  cp_token *token;
+  tree identifier;
+  tree value;
+
+  /* Look for the identifier.  */
+  identifier = cp_parser_identifier (parser);
+  if (identifier == error_mark_node)
+    return;
+  
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's an `=', then there's an explicit value.  */
+  if (token->type == CPP_EQ)
+    {
+      /* Consume the `=' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the value.  */
+      value = cp_parser_constant_expression (parser);
+    }
+  else
+    value = NULL_TREE;
+
+  /* Create the enumerator.  */
+  build_enumerator (identifier, value, type);
+}
+
+/* Parse a namespace-name.
+
+   namespace-name:
+     original-namespace-name
+     namespace-alias
+
+   Returns the NAMESPACE_DECL for the namespace.  */
+
+static tree
+cp_parser_namespace_name (parser)
+     cp_parser *parser;
+{
+  tree identifier;
+  tree namespace_decl;
+
+  /* Get the name of the namespace.  */
+  identifier = cp_parser_identifier (parser);
+  if (identifier == error_mark_node)
+    return error_mark_node;
+
+  /* Look up the identifier in the currently active scope.  */
+  namespace_decl = cp_parser_lookup_name_simple (parser, identifier);
+  /* If it's not a namespace, issue an error.  */
+  if (namespace_decl == error_mark_node
+      || TREE_CODE (namespace_decl) != NAMESPACE_DECL)
+    {
+      cp_parser_error (parser, "expected namespace-name");
+      namespace_decl = error_mark_node;
+    }
+  
+  return namespace_decl;
+}
+
+/* Parse a namespace-definition.
+
+   namespace-definition:
+     named-namespace-definition
+     unnamed-namespace-definition  
+
+   named-namespace-definition:
+     original-namespace-definition
+     extension-namespace-definition
+
+   original-namespace-definition:
+     namespace identifier { namespace-body }
+   
+   extension-namespace-definition:
+     namespace original-namespace-name { namespace-body }
+   unnamed-namespace-definition:
+     namespace { namespace-body } */
+
+static void
+cp_parser_namespace_definition (parser)
+     cp_parser *parser;
+{
+  tree identifier;
+
+  /* Look for the `namespace' keyword.  */
+  cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
+
+  /* Get the name of the namespace.  We do not attempt to distinguish
+     between an original-namespace-definition and an
+     extension-namespace-definition at this point.  The semantic
+     analysis routines are responsible for that.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    identifier = cp_parser_identifier (parser);
+  else
+    identifier = NULL_TREE;
+
+  /* Look for the `{' to start the namespace.  */
+  cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
+  /* Start the namespace.  */
+  push_namespace (identifier);
+  /* Parse the body of the namespace.  */
+  cp_parser_namespace_body (parser);
+  /* Finish the namespace.  */
+  pop_namespace ();
+  /* Look for the final `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+}
+
+/* Parse a namespace-body.
+
+   namespace-body:
+     declaration-seq [opt]  */
+
+static void
+cp_parser_namespace_body (parser)
+     cp_parser *parser;
+{
+  cp_parser_declaration_seq_opt (parser);
+}
+
+/* Parse a namespace-alias-definition.
+
+   namespace-alias-definition:
+     namespace identifier = qualified-namespace-specifier ;  */
+
+static void
+cp_parser_namespace_alias_definition (parser)
+     cp_parser *parser;
+{
+  tree identifier;
+  tree namespace_specifier;
+
+  /* Look for the `namespace' keyword.  */
+  cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
+  /* Look for the identifier.  */
+  identifier = cp_parser_identifier (parser);
+  if (identifier == error_mark_node)
+    return;
+  /* Look for the `=' token.  */
+  cp_parser_require (parser, CPP_EQ, "`='");
+  /* Look for the qualified-namespace-specifier.  */
+  namespace_specifier 
+    = cp_parser_qualified_namespace_specifier (parser);
+  /* Look for the `;' token.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+  /* Register the alias in the symbol table.  */
+  do_namespace_alias (identifier, namespace_specifier);
+}
+
+/* Parse a qualified-namespace-specifier.
+
+   qualified-namespace-specifier:
+     :: [opt] nested-name-specifier [opt] namespace-name
+
+   Returns a NAMESPACE_DECL corresponding to the specified
+   namespace.  */
+
+static tree
+cp_parser_qualified_namespace_specifier (parser)
+     cp_parser *parser;
+{
+  /* Look for the optional `::'.  */
+  cp_parser_global_scope_opt (parser, 
+                             /*current_scope_valid_p=*/false);
+
+  /* Look for the optional nested-name-specifier.  */
+  cp_parser_nested_name_specifier_opt (parser,
+                                      /*typename_keyword_p=*/false,
+                                      /*check_dependency_p=*/true,
+                                      /*type_p=*/false);
+
+  return cp_parser_namespace_name (parser);
+}
+
+/* Parse a using-declaration.
+
+   using-declaration:
+     using typename [opt] :: [opt] nested-name-specifier unqualified-id ;
+     using :: unqualified-id ;  */
+
+static void
+cp_parser_using_declaration (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  bool typename_p = false;
+  bool global_scope_p;
+  tree decl;
+  tree identifier;
+  tree scope;
+
+  /* Look for the `using' keyword.  */
+  cp_parser_require_keyword (parser, RID_USING, "`using'");
+  
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* See if it's `typename'.  */
+  if (token->keyword == RID_TYPENAME)
+    {
+      /* Remember that we've seen it.  */
+      typename_p = true;
+      /* Consume the `typename' token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* Look for the optional global scope qualification.  */
+  global_scope_p 
+    = (cp_parser_global_scope_opt (parser,
+                                  /*current_scope_valid_p=*/false) 
+       != NULL_TREE);
+
+  /* If we saw `typename', or didn't see `::', then there must be a
+     nested-name-specifier present.  */
+  if (typename_p || !global_scope_p)
+    cp_parser_nested_name_specifier (parser, typename_p, 
+                                    /*check_dependency_p=*/true,
+                                    /*type_p=*/false);
+  /* Otherwise, we could be in either of the two productions.  In that
+     case, treat the nested-name-specifier as optional.  */
+  else
+    cp_parser_nested_name_specifier_opt (parser,
+                                        /*typename_keyword_p=*/false,
+                                        /*check_dependency_p=*/true,
+                                        /*type_p=*/false);
+
+  /* Parse the unqualified-id.  */
+  identifier = cp_parser_unqualified_id (parser, 
+                                        /*template_keyword_p=*/false,
+                                        /*check_dependency_p=*/true);
+
+  /* The function we call to handle a using-declaration is different
+     depending on what scope we are in.  */
+  scope = current_scope ();
+  if (scope && TYPE_P (scope))
+    {
+      /* Create the USING_DECL.  */
+      decl = do_class_using_decl (build_nt (SCOPE_REF,
+                                           parser->scope,
+                                           identifier));
+      /* Add it to the list of members in this class.  */
+      finish_member_declaration (decl);
+    }
+  else
+    {
+      decl = cp_parser_lookup_name_simple (parser, identifier);
+      if (scope)
+       do_local_using_decl (decl);
+      else
+       do_toplevel_using_decl (decl);
+    }
+
+  /* Look for the final `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+}
+
+/* Parse a using-directive.  
+   using-directive:
+     using namespace :: [opt] nested-name-specifier [opt]
+       namespace-name ;  */
+
+static void
+cp_parser_using_directive (parser)
+     cp_parser *parser;
+{
+  tree namespace_decl;
+
+  /* Look for the `using' keyword.  */
+  cp_parser_require_keyword (parser, RID_USING, "`using'");
+  /* And the `namespace' keyword.  */
+  cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
+  /* Look for the optional `::' operator.  */
+  cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
+  /* And the optional nested-name-sepcifier.  */
+  cp_parser_nested_name_specifier_opt (parser,
+                                      /*typename_keyword_p=*/false,
+                                      /*check_dependency_p=*/true,
+                                      /*type_p=*/false);
+  /* Get the namespace being used.  */
+  namespace_decl = cp_parser_namespace_name (parser);
+  /* Update the symbol table.  */
+  do_using_directive (namespace_decl);
+  /* Look for the final `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+}
+
+/* Parse an asm-definition.
+
+   asm-definition:
+     asm ( string-literal ) ;  
+
+   GNU Extension:
+
+   asm-definition:
+     asm volatile [opt] ( string-literal ) ;
+     asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
+     asm volatile [opt] ( string-literal : asm-operand-list [opt]
+                          : asm-operand-list [opt] ) ;
+     asm volatile [opt] ( string-literal : asm-operand-list [opt] 
+                          : asm-operand-list [opt] 
+                          : asm-operand-list [opt] ) ;  */
+
+static void
+cp_parser_asm_definition (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree string;
+  tree outputs = NULL_TREE;
+  tree inputs = NULL_TREE;
+  tree clobbers = NULL_TREE;
+  tree asm_stmt;
+  bool volatile_p = false;
+  bool extended_p = false;
+
+  /* Look for the `asm' keyword.  */
+  cp_parser_require_keyword (parser, RID_ASM, "`asm'");
+  /* See if the next token is `volatile'.  */
+  if (cp_parser_allow_gnu_extensions_p (parser)
+      && cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE))
+    {
+      /* Remember that we saw the `volatile' keyword.  */
+      volatile_p = true;
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+  /* Look for the opening `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  /* Look for the string.  */
+  token = cp_parser_require (parser, CPP_STRING, "asm body");
+  if (!token)
+    return;
+  string = token->value;
+  /* If we're allowing GNU extensions, check for the extended assembly
+     syntax.  Unfortunately, the `:' tokens need not be separated by 
+     a space in C, and so, for compatibility, we tolerate that here
+     too.  Doing that means that we have to treat the `::' operator as
+     two `:' tokens.  */
+  if (cp_parser_allow_gnu_extensions_p (parser)
+      && at_function_scope_p ()
+      && (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
+         || cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)))
+    {
+      bool inputs_p = false;
+      bool clobbers_p = false;
+
+      /* The extended syntax was used.  */
+      extended_p = true;
+
+      /* Look for outputs.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+       {
+         /* Consume the `:'.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Parse the output-operands.  */
+         if (cp_lexer_next_token_is_not (parser->lexer, 
+                                         CPP_COLON)
+             && cp_lexer_next_token_is_not (parser->lexer,
+                                            CPP_SCOPE))
+           outputs = cp_parser_asm_operand_list (parser);
+       }
+      /* If the next token is `::', there are no outputs, and the
+        next token is the beginning of the inputs.  */
+      else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+       {
+         /* Consume the `::' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* The inputs are coming next.  */
+         inputs_p = true;
+       }
+
+      /* Look for inputs.  */
+      if (inputs_p
+         || cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+       {
+         if (!inputs_p)
+           /* Consume the `:'.  */
+           cp_lexer_consume_token (parser->lexer);
+         /* Parse the output-operands.  */
+         if (cp_lexer_next_token_is_not (parser->lexer, 
+                                         CPP_COLON)
+             && cp_lexer_next_token_is_not (parser->lexer,
+                                            CPP_SCOPE))
+           inputs = cp_parser_asm_operand_list (parser);
+       }
+      else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+       /* The clobbers are coming next.  */
+       clobbers_p = true;
+
+      /* Look for clobbers.  */
+      if (clobbers_p 
+         || cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+       {
+         if (!clobbers_p)
+           /* Consume the `:'.  */
+           cp_lexer_consume_token (parser->lexer);
+         /* Parse the clobbers.  */
+         clobbers = cp_parser_asm_clobber_list (parser);
+       }
+    }
+  /* Look for the closing `)'.  */
+  if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+    cp_parser_skip_to_closing_parenthesis (parser);
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+  /* Create the ASM_STMT.  */
+  if (at_function_scope_p ())
+    {
+      asm_stmt = 
+       finish_asm_stmt (volatile_p 
+                        ? ridpointers[(int) RID_VOLATILE] : NULL_TREE,
+                        string, outputs, inputs, clobbers);
+      /* If the extended syntax was not used, mark the ASM_STMT.  */
+      if (!extended_p)
+       ASM_INPUT_P (asm_stmt) = 1;
+    }
+  else
+    assemble_asm (string);
+}
+
+/* Declarators [gram.dcl.decl] */
+
+/* Parse an init-declarator.
+
+   init-declarator:
+     declarator initializer [opt]
+
+   GNU Extension:
+
+   init-declarator:
+     declarator asm-specification [opt] attributes [opt] initializer [opt]
+
+   The DECL_SPECIFIERS and PREFIX_ATTRIBUTES apply to this declarator.
+   Returns a reprsentation of the entity declared.  The ACCESS_CHECKS
+   represent deferred access checks from the decl-specifier-seq.  If
+   MEMBER_P is TRUE, then this declarator appears in a class scope.
+   The new DECL created by this declarator is returned.
+
+   If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and
+   for a function-definition here as well.  If the declarator is a
+   declarator for a function-definition, *FUNCTION_DEFINITION_P will
+   be TRUE upon return.  By that point, the function-definition will
+   have been completely parsed.
+
+   FUNCTION_DEFINITION_P may be NULL if FUNCTION_DEFINITION_ALLOWED_P
+   is FALSE.  */
+
+static tree
+cp_parser_init_declarator (parser, 
+                          decl_specifiers, 
+                          prefix_attributes,
+                          access_checks,
+                          function_definition_allowed_p,
+                          member_p,
+                          function_definition_p)
+     cp_parser *parser;
+     tree decl_specifiers;
+     tree prefix_attributes;
+     tree access_checks;
+     bool function_definition_allowed_p;
+     bool member_p;
+     bool *function_definition_p;
+{
+  cp_token *token;
+  tree declarator;
+  tree attributes;
+  tree asm_specification;
+  tree initializer;
+  tree decl = NULL_TREE;
+  tree scope;
+  tree declarator_access_checks;
+  bool is_initialized;
+  bool is_parenthesized_init;
+  bool ctor_dtor_or_conv_p;
+  bool friend_p;
+
+  /* Assume that this is not the declarator for a function
+     definition.  */
+  if (function_definition_p)
+    *function_definition_p = false;
+
+  /* Defer access checks while parsing the declarator; we cannot know
+     what names are accessible until we know what is being 
+     declared.  */
+  cp_parser_start_deferring_access_checks (parser);
+  /* Parse the declarator.  */
+  declarator 
+    = cp_parser_declarator (parser,
+                           /*abstract_p=*/false,
+                           &ctor_dtor_or_conv_p);
+  /* Gather up the deferred checks.  */
+  declarator_access_checks 
+    = cp_parser_stop_deferring_access_checks (parser);
+
+  /* If the DECLARATOR was erroneous, there's no need to go
+     further.  */
+  if (declarator == error_mark_node)
+    return error_mark_node;
+
+  /* Figure out what scope the entity declared by the DECLARATOR is
+     located in.  `grokdeclarator' sometimes changes the scope, so
+     we compute it now.  */
+  scope = get_scope_of_declarator (declarator);
+
+  /* If we're allowing GNU extensions, look for an asm-specification
+     and attributes.  */
+  if (cp_parser_allow_gnu_extensions_p (parser))
+    {
+      /* Look for an asm-specification.  */
+      asm_specification = cp_parser_asm_specification_opt (parser);
+      /* And attributes.  */
+      attributes = cp_parser_attributes_opt (parser);
+    }
+  else
+    {
+      asm_specification = NULL_TREE;
+      attributes = NULL_TREE;
+    }
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Check to see if the token indicates the start of a
+     function-definition.  */
+  if (cp_parser_token_starts_function_definition_p (token))
+    {
+      if (!function_definition_allowed_p)
+       {
+         /* If a function-definition should not appear here, issue an
+            error message.  */
+         cp_parser_error (parser,
+                          "a function-definition is not allowed here");
+         return error_mark_node;
+       }
+      else
+       {
+         tree *ac;
+
+         /* Neither attributes nor an asm-specification are allowed
+            on a function-definition.  */
+         if (asm_specification)
+           error ("an asm-specification is not allowed on a function-definition");
+         if (attributes)
+           error ("attributes are not allowed on a function-definition");
+         /* This is a function-definition.  */
+         *function_definition_p = true;
+
+         /* Thread the access checks together.  */
+         ac = &access_checks;
+         while (*ac)
+           ac = &TREE_CHAIN (*ac);
+         *ac = declarator_access_checks;
+
+         /* Parse the function definition.  */
+         decl = (cp_parser_function_definition_from_specifiers_and_declarator
+                 (parser, decl_specifiers, prefix_attributes, declarator,
+                  access_checks));
+
+         /* Pull the access-checks apart again.  */
+         *ac = NULL_TREE;
+
+         return decl;
+       }
+    }
+
+  /* [dcl.dcl]
+
+     Only in function declarations for constructors, destructors, and
+     type conversions can the decl-specifier-seq be omitted.  
+
+     We explicitly postpone this check past the point where we handle
+     function-definitions because we tolerate function-definitions
+     that are missing their return types in some modes.  */
+  if (!decl_specifiers && !ctor_dtor_or_conv_p)
+    {
+      cp_parser_error (parser, 
+                      "expected constructor, destructor, or type conversion");
+      return error_mark_node;
+    }
+
+  /* An `=' or an `(' indicates an initializer.  */
+  is_initialized = (token->type == CPP_EQ 
+                    || token->type == CPP_OPEN_PAREN);
+  /* If the init-declarator isn't initialized and isn't followed by a
+     `,' or `;', it's not a valid init-declarator.  */
+  if (!is_initialized 
+      && token->type != CPP_COMMA
+      && token->type != CPP_SEMICOLON)
+    {
+      cp_parser_error (parser, "expected init-declarator");
+      return error_mark_node;
+    }
+
+  /* Because start_decl has side-effects, we should only call it if we
+     know we're going ahead.  By this point, we know that we cannot
+     possibly be looking at any other construct.  */
+  cp_parser_commit_to_tentative_parse (parser);
+
+  /* Check to see whether or not this declaration is a friend.  */
+  friend_p = cp_parser_friend_p (decl_specifiers);
+
+  /* Check that the number of template-parameter-lists is OK.  */
+  if (!cp_parser_check_declarator_template_parameters (parser, 
+                                                      declarator))
+    return error_mark_node;
+
+  /* Enter the newly declared entry in the symbol table.  If we're
+     processing a declaration in a class-specifier, we wait until
+     after processing the initializer.  */
+  if (!member_p)
+    {
+      if (parser->in_unbraced_linkage_specification_p)
+       {
+         decl_specifiers = tree_cons (error_mark_node,
+                                      get_identifier ("extern"),
+                                      decl_specifiers);
+         have_extern_spec = false;
+       }
+      decl = start_decl (declarator,
+                        decl_specifiers,
+                        is_initialized,
+                        attributes,
+                        prefix_attributes);
+    }
+
+  /* Enter the SCOPE.  That way unqualified names appearing in the
+     initializer will be looked up in SCOPE.  */
+  if (scope)
+    push_scope (scope);
+
+  /* Perform deferred access control checks, now that we know in which
+     SCOPE the declared entity resides.  */
+  if (!member_p && decl) 
+    {
+      tree saved_current_function_decl = NULL_TREE;
+
+      /* If the entity being declared is a function, pretend that we
+        are in its scope.  If it is a `friend', it may have access to
+        things that would not otherwise be accessible. */
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       {
+         saved_current_function_decl = current_function_decl;
+         current_function_decl = decl;
+       }
+       
+      /* Perform the access control checks for the decl-specifiers.  */
+      cp_parser_perform_deferred_access_checks (access_checks);
+      /* And for the declarator.  */
+      cp_parser_perform_deferred_access_checks (declarator_access_checks);
+
+      /* Restore the saved value.  */
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       current_function_decl = saved_current_function_decl;
+    }
+
+  /* Parse the initializer.  */
+  if (is_initialized)
+    initializer = cp_parser_initializer (parser, 
+                                        &is_parenthesized_init);
+  else
+    {
+      initializer = NULL_TREE;
+      is_parenthesized_init = false;
+    }
+
+  /* The old parser allows attributes to appear after a parenthesized
+     initializer.  Mark Mitchell proposed removing this functionality
+     on the GCC mailing lists on 2002-08-13.  This parser accepts the
+     attributes -- but ignores them.  */
+  if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init)
+    if (cp_parser_attributes_opt (parser))
+      warning ("attributes after parenthesized initializer ignored");
+
+  /* Leave the SCOPE, now that we have processed the initializer.  It
+     is important to do this before calling cp_finish_decl because it
+     makes decisions about whether to create DECL_STMTs or not based
+     on the current scope.  */
+  if (scope)
+    pop_scope (scope);
+
+  /* For an in-class declaration, use `grokfield' to create the
+     declaration.  */
+  if (member_p)
+    decl = grokfield (declarator, decl_specifiers,
+                     initializer, /*asmspec=*/NULL_TREE,
+                       /*attributes=*/NULL_TREE);
+
+  /* Finish processing the declaration.  But, skip friend
+     declarations.  */
+  if (!friend_p && decl)
+    cp_finish_decl (decl, 
+                   initializer, 
+                   asm_specification,
+                   /* If the initializer is in parentheses, then this is
+                      a direct-initialization, which means that an
+                      `explicit' constructor is OK.  Otherwise, an
+                      `explicit' constructor cannot be used.  */
+                   ((is_parenthesized_init || !is_initialized)
+                    ? 0 : LOOKUP_ONLYCONVERTING));
+
+  return decl;
+}
+
+/* Parse a declarator.
+   
+   declarator:
+     direct-declarator
+     ptr-operator declarator  
+
+   abstract-declarator:
+     ptr-operator abstract-declarator [opt]
+     direct-abstract-declarator
+
+   GNU Extensions:
+
+   declarator:
+     attributes [opt] direct-declarator
+     attributes [opt] ptr-operator declarator  
+
+   abstract-declarator:
+     attributes [opt] ptr-operator abstract-declarator [opt]
+     attributes [opt] direct-abstract-declarator
+     
+   Returns a representation of the declarator.  If the declarator has
+   the form `* declarator', then an INDIRECT_REF is returned, whose
+   only operand is the sub-declarator.  Analagously, `& declarator' is
+   represented as an ADDR_EXPR.  For `X::* declarator', a SCOPE_REF is
+   used.  The first operand is the TYPE for `X'.  The second operand
+   is an INDIRECT_REF whose operand is the sub-declarator.
+
+   Otherwise, the reprsentation is as for a direct-declarator.
+
+   (It would be better to define a structure type to represent
+   declarators, rather than abusing `tree' nodes to represent
+   declarators.  That would be much clearer and save some memory.
+   There is no reason for declarators to be garbage-collected, for
+   example; they are created during parser and no longer needed after
+   `grokdeclarator' has been called.)
+
+   For a ptr-operator that has the optional cv-qualifier-seq,
+   cv-qualifiers will be stored in the TREE_TYPE of the INDIRECT_REF
+   node.
+
+   If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is set to
+   true if this declarator represents a constructor, destructor, or
+   type conversion operator.  Otherwise, it is set to false.  
+
+   (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have
+   a decl-specifier-seq unless it declares a constructor, destructor,
+   or conversion.  It might seem that we could check this condition in
+   semantic analysis, rather than parsing, but that makes it difficult
+   to handle something like `f()'.  We want to notice that there are
+   no decl-specifiers, and therefore realize that this is an
+   expression, not a declaration.)  */
+
+static tree
+cp_parser_declarator (parser, abstract_p, ctor_dtor_or_conv_p)
+     cp_parser *parser;
+     bool abstract_p;
+     bool *ctor_dtor_or_conv_p;
+{
+  cp_token *token;
+  tree declarator;
+  enum tree_code code;
+  tree cv_qualifier_seq;
+  tree class_type;
+  tree attributes = NULL_TREE;
+
+  /* Assume this is not a constructor, destructor, or type-conversion
+     operator.  */
+  if (ctor_dtor_or_conv_p)
+    *ctor_dtor_or_conv_p = false;
+
+  if (cp_parser_allow_gnu_extensions_p (parser))
+    attributes = cp_parser_attributes_opt (parser);
+  
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  
+  /* Check for the ptr-operator production.  */
+  cp_parser_parse_tentatively (parser);
+  /* Parse the ptr-operator.  */
+  code = cp_parser_ptr_operator (parser, 
+                                &class_type, 
+                                &cv_qualifier_seq);
+  /* If that worked, then we have a ptr-operator.  */
+  if (cp_parser_parse_definitely (parser))
+    {
+      /* The dependent declarator is optional if we are parsing an
+        abstract-declarator.  */
+      if (abstract_p)
+       cp_parser_parse_tentatively (parser);
+
+      /* Parse the dependent declarator.  */
+      declarator = cp_parser_declarator (parser, abstract_p,
+                                        /*ctor_dtor_or_conv_p=*/NULL);
+
+      /* If we are parsing an abstract-declarator, we must handle the
+        case where the dependent declarator is absent.  */
+      if (abstract_p && !cp_parser_parse_definitely (parser))
+       declarator = NULL_TREE;
+       
+      /* Build the representation of the ptr-operator.  */
+      if (code == INDIRECT_REF)
+       declarator = make_pointer_declarator (cv_qualifier_seq, 
+                                             declarator);
+      else
+       declarator = make_reference_declarator (cv_qualifier_seq,
+                                               declarator);
+      /* Handle the pointer-to-member case.  */
+      if (class_type)
+       declarator = build_nt (SCOPE_REF, class_type, declarator);
+    }
+  /* Everything else is a direct-declarator.  */
+  else
+    declarator = cp_parser_direct_declarator (parser, 
+                                             abstract_p,
+                                             ctor_dtor_or_conv_p);
+
+  if (attributes && declarator != error_mark_node)
+    declarator = tree_cons (attributes, declarator, NULL_TREE);
+  
+  return declarator;
+}
+
+/* Parse a direct-declarator or direct-abstract-declarator.
+
+   direct-declarator:
+     declarator-id
+     direct-declarator ( parameter-declaration-clause )
+       cv-qualifier-seq [opt] 
+       exception-specification [opt]
+     direct-declarator [ constant-expression [opt] ]
+     ( declarator )  
+
+   direct-abstract-declarator:
+     direct-abstract-declarator [opt]
+       ( parameter-declaration-clause ) 
+       cv-qualifier-seq [opt]
+       exception-specification [opt]
+     direct-abstract-declarator [opt] [ constant-expression [opt] ]
+     ( abstract-declarator )
+
+   Returns a representation of the declarator.  ABSTRACT_P is TRUE if
+   we are parsing a direct-abstract-declarator; FALSE if we are
+   parsing a direct-declarator.  CTOR_DTOR_OR_CONV_P is as for 
+   cp_parser_declarator.
+
+   For the declarator-id production, the representation is as for an
+   id-expression, except that a qualified name is represented as a
+   SCOPE_REF.  A function-declarator is represented as a CALL_EXPR;
+   see the documentation of the FUNCTION_DECLARATOR_* macros for
+   information about how to find the various declarator components.
+   An array-declarator is represented as an ARRAY_REF.  The
+   direct-declarator is the first operand; the constant-expression
+   indicating the size of the array is the second operand.  */
+
+static tree
+cp_parser_direct_declarator (parser, abstract_p, ctor_dtor_or_conv_p)
+     cp_parser *parser;
+     bool abstract_p;
+     bool *ctor_dtor_or_conv_p;
+{
+  cp_token *token;
+  tree declarator;
+  tree scope = NULL_TREE;
+  bool saved_default_arg_ok_p = parser->default_arg_ok_p;
+  bool saved_in_declarator_p = parser->in_declarator_p;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Find the initial direct-declarator.  It might be a parenthesized
+     declarator.  */
+  if (token->type == CPP_OPEN_PAREN)
+    {
+      /* For an abstract declarator we do not know whether we are
+        looking at the beginning of a parameter-declaration-clause,
+        or at a parenthesized abstract declarator.  For example, if
+        we see `(int)', we are looking at a
+        parameter-declaration-clause, and the
+        direct-abstract-declarator has been omitted.  If, on the
+        other hand we are looking at `((*))' then we are looking at a
+        parenthesized abstract-declarator.  There is no easy way to
+        tell which situation we are in.  */
+      if (abstract_p)
+       cp_parser_parse_tentatively (parser);
+
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the nested declarator.  */
+      declarator 
+       = cp_parser_declarator (parser, abstract_p, ctor_dtor_or_conv_p);
+      /* Expect a `)'.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+      /* If parsing a parenthesized abstract declarator didn't work,
+        try a parameter-declaration-clause.  */
+      if (abstract_p && !cp_parser_parse_definitely (parser))
+       declarator = NULL_TREE;
+      /* If we were not parsing an abstract declarator, but failed to
+        find a satisfactory nested declarator, then an error has
+        occurred.  */
+      else if (!abstract_p && declarator == error_mark_node)
+       return error_mark_node;
+      /* Default args cannot appear in an abstract decl.  */
+      parser->default_arg_ok_p = false;
+    }
+  /* Otherwise, for a non-abstract declarator, there should be a
+     declarator-id.  */
+  else if (!abstract_p)
+    {
+      declarator = cp_parser_declarator_id (parser);
+      
+      if (TREE_CODE (declarator) == SCOPE_REF)
+       {
+         scope = TREE_OPERAND (declarator, 0);
+         
+         /* In the declaration of a member of a template class
+            outside of the class itself, the SCOPE will sometimes be
+            a TYPENAME_TYPE.  For example, given:
+            
+               template <typename T>
+              int S<T>::R::i = 3;
+
+             the SCOPE will be a TYPENAME_TYPE for `S<T>::R'.  In this
+            context, we must resolve S<T>::R to an ordinary type,
+            rather than a typename type.
+
+            The reason we normally avoid resolving TYPENAME_TYPEs is
+            that a specialization of `S' might render `S<T>::R' not a
+            type.  However, if `S' is specialized, then this `i' will
+            not be used, so there is no harm in resolving the types
+            here.  */
+         if (TREE_CODE (scope) == TYPENAME_TYPE)
+           {
+             /* Resolve the TYPENAME_TYPE.  */
+             scope = cp_parser_resolve_typename_type (parser, scope);
+             /* If that failed, the declarator is invalid.  */
+             if (scope == error_mark_node)
+               return error_mark_node;
+             /* Build a new DECLARATOR.  */
+             declarator = build_nt (SCOPE_REF, 
+                                    scope,
+                                    TREE_OPERAND (declarator, 1));
+           }
+       }
+      else if (TREE_CODE (declarator) != IDENTIFIER_NODE)
+       /* Default args can only appear for a function decl.  */
+       parser->default_arg_ok_p = false;
+      
+      /* Check to see whether the declarator-id names a constructor, 
+        destructor, or conversion.  */
+      if (ctor_dtor_or_conv_p 
+         && ((TREE_CODE (declarator) == SCOPE_REF 
+              && CLASS_TYPE_P (TREE_OPERAND (declarator, 0)))
+             || (TREE_CODE (declarator) != SCOPE_REF
+                 && at_class_scope_p ())))
+       {
+         tree unqualified_name;
+         tree class_type;
+
+         /* Get the unqualified part of the name.  */
+         if (TREE_CODE (declarator) == SCOPE_REF)
+           {
+             class_type = TREE_OPERAND (declarator, 0);
+             unqualified_name = TREE_OPERAND (declarator, 1);
+           }
+         else
+           {
+             class_type = current_class_type;
+             unqualified_name = declarator;
+           }
+
+         /* See if it names ctor, dtor or conv.  */
+         if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR
+             || IDENTIFIER_TYPENAME_P (unqualified_name)
+             || constructor_name_p (unqualified_name, class_type))
+           {
+             *ctor_dtor_or_conv_p = true;
+             /* We would have cleared the default arg flag above, but
+                they are ok.  */
+             parser->default_arg_ok_p = saved_default_arg_ok_p;
+           }
+       }
+    }
+  /* But for an abstract declarator, the initial direct-declarator can
+     be omitted.  */
+  else
+    {
+      declarator = NULL_TREE;
+      parser->default_arg_ok_p = false;
+    }
+
+  scope = get_scope_of_declarator (declarator);
+  if (scope)
+    /* Any names that appear after the declarator-id for a member
+       are looked up in the containing scope.  */
+    push_scope (scope);
+  else
+    scope = NULL_TREE;
+  parser->in_declarator_p = true;
+
+  /* Now, parse function-declarators and array-declarators until there
+     are no more.  */
+  while (true)
+    {
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's a `[', we're looking at an array-declarator.  */
+      if (token->type == CPP_OPEN_SQUARE)
+       {
+         tree bounds;
+
+         /* Consume the `['.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_token (parser->lexer);
+         /* If the next token is `]', then there is no
+            constant-expression.  */
+         if (token->type != CPP_CLOSE_SQUARE)
+           bounds = cp_parser_constant_expression (parser);
+         else
+           bounds = NULL_TREE;
+         /* Look for the closing `]'.  */
+         cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+         declarator = build_nt (ARRAY_REF, declarator, bounds);
+       }
+      /* If it's a `(', we're looking at a function-declarator.  */
+      else if (token->type == CPP_OPEN_PAREN)
+       {
+         /* A function-declarator.  Or maybe not.  Consider, for
+            example:
+
+              int i (int);
+              int i (3);
+
+            The first is the declaration of a function while the
+            second is a the definition of a variable, including its
+            initializer.
+
+            Having seen only the parenthesis, we cannot know which of
+            these two alternatives should be selected.  Even more
+            complex are examples like:
+
+               int i (int (a));
+              int i (int (3));
+
+            The former is a function-declaration; the latter is a
+            variable initialization.  
+
+            First, we attempt to parse a parameter-declaration
+            clause.  If this works, then we continue; otherwise, we
+            replace the tokens consumed in the process and continue.  */
+         tree params;
+
+         /* We are now parsing tentatively.  */
+         cp_parser_parse_tentatively (parser);
+         
+         /* Consume the `('.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Parse the parameter-declaration-clause.  */
+         params = cp_parser_parameter_declaration_clause (parser);
+         
+         /* If all went well, parse the cv-qualifier-seq and the
+            exception-specification.  */
+         if (cp_parser_parse_definitely (parser))
+           {
+             tree cv_qualifiers;
+             tree exception_specification;
+
+             /* Consume the `)'.  */
+             cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+             /* Parse the cv-qualifier-seq.  */
+             cv_qualifiers = cp_parser_cv_qualifier_seq_opt (parser);
+             /* And the exception-specification.  */
+             exception_specification 
+               = cp_parser_exception_specification_opt (parser);
+
+             /* Create the function-declarator.  */
+             declarator = make_call_declarator (declarator,
+                                                params,
+                                                cv_qualifiers,
+                                                exception_specification);
+           }
+         /* Otherwise, we must be done with the declarator.  */
+         else
+           break;
+       }
+      /* Otherwise, we're done with the declarator.  */
+      else
+       break;
+      /* Any subsequent parameter lists are to do with return type, so
+        are not those of the declared function.  */
+      parser->default_arg_ok_p = false;
+    }
+
+  /* For an abstract declarator, we might wind up with nothing at this
+     point.  That's an error; the declarator is not optional.  */
+  if (!declarator)
+    cp_parser_error (parser, "expected declarator");
+
+  /* If we entered a scope, we must exit it now.  */
+  if (scope)
+    pop_scope (scope);
+
+  parser->default_arg_ok_p = saved_default_arg_ok_p;
+  parser->in_declarator_p = saved_in_declarator_p;
+  
+  return declarator;
+}
+
+/* Parse a ptr-operator.  
+
+   ptr-operator:
+     * cv-qualifier-seq [opt]
+     &
+     :: [opt] nested-name-specifier * cv-qualifier-seq [opt]
+
+   GNU Extension:
+
+   ptr-operator:
+     & cv-qualifier-seq [opt]
+
+   Returns INDIRECT_REF if a pointer, or pointer-to-member, was
+   used.  Returns ADDR_EXPR if a reference was used.  In the
+   case of a pointer-to-member, *TYPE is filled in with the 
+   TYPE containing the member.  *CV_QUALIFIER_SEQ is filled in
+   with the cv-qualifier-seq, or NULL_TREE, if there are no
+   cv-qualifiers.  Returns ERROR_MARK if an error occurred.  */
+   
+static enum tree_code
+cp_parser_ptr_operator (parser, type, cv_qualifier_seq)
+     cp_parser *parser;
+     tree *type;
+     tree *cv_qualifier_seq;
+{
+  enum tree_code code = ERROR_MARK;
+  cp_token *token;
+
+  /* Assume that it's not a pointer-to-member.  */
+  *type = NULL_TREE;
+  /* And that there are no cv-qualifiers.  */
+  *cv_qualifier_seq = NULL_TREE;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's a `*' or `&' we have a pointer or reference.  */
+  if (token->type == CPP_MULT || token->type == CPP_AND)
+    {
+      /* Remember which ptr-operator we were processing.  */
+      code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
+
+      /* Consume the `*' or `&'.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      /* A `*' can be followed by a cv-qualifier-seq, and so can a
+        `&', if we are allowing GNU extensions.  (The only qualifier
+        that can legally appear after `&' is `restrict', but that is
+        enforced during semantic analysis.  */
+      if (code == INDIRECT_REF 
+         || cp_parser_allow_gnu_extensions_p (parser))
+       *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+    }
+  else
+    {
+      /* Try the pointer-to-member case.  */
+      cp_parser_parse_tentatively (parser);
+      /* Look for the optional `::' operator.  */
+      cp_parser_global_scope_opt (parser,
+                                 /*current_scope_valid_p=*/false);
+      /* Look for the nested-name specifier.  */
+      cp_parser_nested_name_specifier (parser,
+                                      /*typename_keyword_p=*/false,
+                                      /*check_dependency_p=*/true,
+                                      /*type_p=*/false);
+      /* If we found it, and the next token is a `*', then we are
+        indeed looking at a pointer-to-member operator.  */
+      if (!cp_parser_error_occurred (parser)
+         && cp_parser_require (parser, CPP_MULT, "`*'"))
+       {
+         /* The type of which the member is a member is given by the
+            current SCOPE.  */
+         *type = parser->scope;
+         /* The next name will not be qualified.  */
+         parser->scope = NULL_TREE;
+         parser->qualifying_scope = NULL_TREE;
+         parser->object_scope = NULL_TREE;
+         /* Indicate that the `*' operator was used.  */
+         code = INDIRECT_REF;
+         /* Look for the optional cv-qualifier-seq.  */
+         *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+       }
+      /* If that didn't work we don't have a ptr-operator.  */
+      if (!cp_parser_parse_definitely (parser))
+       cp_parser_error (parser, "expected ptr-operator");
+    }
+
+  return code;
+}
+
+/* Parse an (optional) cv-qualifier-seq.
+
+   cv-qualifier-seq:
+     cv-qualifier cv-qualifier-seq [opt]  
+
+   Returns a TREE_LIST.  The TREE_VALUE of each node is the
+   representation of a cv-qualifier.  */
+
+static tree
+cp_parser_cv_qualifier_seq_opt (parser)
+     cp_parser *parser;
+{
+  tree cv_qualifiers = NULL_TREE;
+  
+  while (true)
+    {
+      tree cv_qualifier;
+
+      /* Look for the next cv-qualifier.  */
+      cv_qualifier = cp_parser_cv_qualifier_opt (parser);
+      /* If we didn't find one, we're done.  */
+      if (!cv_qualifier)
+       break;
+
+      /* Add this cv-qualifier to the list.  */
+      cv_qualifiers 
+       = tree_cons (NULL_TREE, cv_qualifier, cv_qualifiers);
+    }
+
+  /* We built up the list in reverse order.  */
+  return nreverse (cv_qualifiers);
+}
+
+/* Parse an (optional) cv-qualifier.
+
+   cv-qualifier:
+     const
+     volatile  
+
+   GNU Extension:
+
+   cv-qualifier:
+     __restrict__ */
+
+static tree
+cp_parser_cv_qualifier_opt (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree cv_qualifier = NULL_TREE;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* See if it's a cv-qualifier.  */
+  switch (token->keyword)
+    {
+    case RID_CONST:
+    case RID_VOLATILE:
+    case RID_RESTRICT:
+      /* Save the value of the token.  */
+      cv_qualifier = token->value;
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+      break;
+
+    default:
+      break;
+    }
+
+  return cv_qualifier;
+}
+
+/* Parse a declarator-id.
+
+   declarator-id:
+     id-expression
+     :: [opt] nested-name-specifier [opt] type-name  
+
+   In the `id-expression' case, the value returned is as for
+   cp_parser_id_expression if the id-expression was an unqualified-id.
+   If the id-expression was a qualified-id, then a SCOPE_REF is
+   returned.  The first operand is the scope (either a NAMESPACE_DECL
+   or TREE_TYPE), but the second is still just a representation of an
+   unqualified-id.  */
+
+static tree
+cp_parser_declarator_id (parser)
+     cp_parser *parser;
+{
+  tree id_expression;
+
+  /* The expression must be an id-expression.  Assume that qualified
+     names are the names of types so that:
+
+       template <class T>
+       int S<T>::R::i = 3;
+
+     will work; we must treat `S<T>::R' as the name of a type.
+     Similarly, assume that qualified names are templates, where
+     required, so that:
+
+       template <class T>
+       int S<T>::R<T>::i = 3;
+
+     will work, too.  */
+  id_expression = cp_parser_id_expression (parser,
+                                          /*template_keyword_p=*/false,
+                                          /*check_dependency_p=*/false,
+                                          /*template_p=*/NULL);
+  /* If the name was qualified, create a SCOPE_REF to represent 
+     that.  */
+  if (parser->scope)
+    id_expression = build_nt (SCOPE_REF, parser->scope, id_expression);
+
+  return id_expression;
+}
+
+/* Parse a type-id.
+
+   type-id:
+     type-specifier-seq abstract-declarator [opt]
+
+   Returns the TYPE specified.  */
+
+static tree
+cp_parser_type_id (parser)
+     cp_parser *parser;
+{
+  tree type_specifier_seq;
+  tree abstract_declarator;
+
+  /* Parse the type-specifier-seq.  */
+  type_specifier_seq 
+    = cp_parser_type_specifier_seq (parser);
+  if (type_specifier_seq == error_mark_node)
+    return error_mark_node;
+
+  /* There might or might not be an abstract declarator.  */
+  cp_parser_parse_tentatively (parser);
+  /* Look for the declarator.  */
+  abstract_declarator 
+    = cp_parser_declarator (parser, /*abstract_p=*/true, NULL);
+  /* Check to see if there really was a declarator.  */
+  if (!cp_parser_parse_definitely (parser))
+    abstract_declarator = NULL_TREE;
+
+  return groktypename (build_tree_list (type_specifier_seq,
+                                       abstract_declarator));
+}
+
+/* Parse a type-specifier-seq.
+
+   type-specifier-seq:
+     type-specifier type-specifier-seq [opt]
+
+   GNU extension:
+
+   type-specifier-seq:
+     attributes type-specifier-seq [opt]
+
+   Returns a TREE_LIST.  Either the TREE_VALUE of each node is a
+   type-specifier, or the TREE_PURPOSE is a list of attributes.  */
+
+static tree
+cp_parser_type_specifier_seq (parser)
+     cp_parser *parser;
+{
+  bool seen_type_specifier = false;
+  tree type_specifier_seq = NULL_TREE;
+
+  /* Parse the type-specifiers and attributes.  */
+  while (true)
+    {
+      tree type_specifier;
+
+      /* Check for attributes first.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
+       {
+         type_specifier_seq = tree_cons (cp_parser_attributes_opt (parser),
+                                         NULL_TREE,
+                                         type_specifier_seq);
+         continue;
+       }
+
+      /* After the first type-specifier, others are optional.  */
+      if (seen_type_specifier)
+       cp_parser_parse_tentatively (parser);
+      /* Look for the type-specifier.  */
+      type_specifier = cp_parser_type_specifier (parser, 
+                                                CP_PARSER_FLAGS_NONE,
+                                                /*is_friend=*/false,
+                                                /*is_declaration=*/false,
+                                                NULL,
+                                                NULL);
+      /* If the first type-specifier could not be found, this is not a
+        type-specifier-seq at all.  */
+      if (!seen_type_specifier && type_specifier == error_mark_node)
+       return error_mark_node;
+      /* If subsequent type-specifiers could not be found, the
+        type-specifier-seq is complete.  */
+      else if (seen_type_specifier && !cp_parser_parse_definitely (parser))
+       break;
+
+      /* Add the new type-specifier to the list.  */
+      type_specifier_seq 
+       = tree_cons (NULL_TREE, type_specifier, type_specifier_seq);
+      seen_type_specifier = true;
+    }
+
+  /* We built up the list in reverse order.  */
+  return nreverse (type_specifier_seq);
+}
+
+/* Parse a parameter-declaration-clause.
+
+   parameter-declaration-clause:
+     parameter-declaration-list [opt] ... [opt]
+     parameter-declaration-list , ...
+
+   Returns a representation for the parameter declarations.  Each node
+   is a TREE_LIST.  (See cp_parser_parameter_declaration for the exact
+   representation.)  If the parameter-declaration-clause ends with an
+   ellipsis, PARMLIST_ELLIPSIS_P will hold of the first node in the
+   list.  A return value of NULL_TREE indicates a
+   parameter-declaration-clause consisting only of an ellipsis.  */
+
+static tree
+cp_parser_parameter_declaration_clause (parser)
+     cp_parser *parser;
+{
+  tree parameters;
+  cp_token *token;
+  bool ellipsis_p;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* Check for trivial parameter-declaration-clauses.  */
+  if (token->type == CPP_ELLIPSIS)
+    {
+      /* Consume the `...' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      return NULL_TREE;
+    }
+  else if (token->type == CPP_CLOSE_PAREN)
+    /* There are no parameters.  */
+    return void_list_node;
+  /* Check for `(void)', too, which is a special case.  */
+  else if (token->keyword == RID_VOID
+          && (cp_lexer_peek_nth_token (parser->lexer, 2)->type 
+              == CPP_CLOSE_PAREN))
+    {
+      /* Consume the `void' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* There are no parameters.  */
+      return void_list_node;
+    }
+  
+  /* Parse the parameter-declaration-list.  */
+  parameters = cp_parser_parameter_declaration_list (parser);
+  /* If a parse error occurred while parsing the
+     parameter-declaration-list, then the entire
+     parameter-declaration-clause is erroneous.  */
+  if (parameters == error_mark_node)
+    return error_mark_node;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's a `,', the clause should terminate with an ellipsis.  */
+  if (token->type == CPP_COMMA)
+    {
+      /* Consume the `,'.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Expect an ellipsis.  */
+      ellipsis_p 
+       = (cp_parser_require (parser, CPP_ELLIPSIS, "`...'") != NULL);
+    }
+  /* It might also be `...' if the optional trailing `,' was 
+     omitted.  */
+  else if (token->type == CPP_ELLIPSIS)
+    {
+      /* Consume the `...' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* And remember that we saw it.  */
+      ellipsis_p = true;
+    }
+  else
+    ellipsis_p = false;
+
+  /* Finish the parameter list.  */
+  return finish_parmlist (parameters, ellipsis_p);
+}
+
+/* Parse a parameter-declaration-list.
+
+   parameter-declaration-list:
+     parameter-declaration
+     parameter-declaration-list , parameter-declaration
+
+   Returns a representation of the parameter-declaration-list, as for
+   cp_parser_parameter_declaration_clause.  However, the
+   `void_list_node' is never appended to the list.  */
+
+static tree
+cp_parser_parameter_declaration_list (parser)
+     cp_parser *parser;
+{
+  tree parameters = NULL_TREE;
+
+  /* Look for more parameters.  */
+  while (true)
+    {
+      tree parameter;
+      /* Parse the parameter.  */
+      parameter 
+       = cp_parser_parameter_declaration (parser,
+                                          /*greater_than_is_operator_p=*/true);
+      /* If a parse error ocurred parsing the parameter declaration,
+        then the entire parameter-declaration-list is erroneous.  */
+      if (parameter == error_mark_node)
+       {
+         parameters = error_mark_node;
+         break;
+       }
+      /* Add the new parameter to the list.  */
+      TREE_CHAIN (parameter) = parameters;
+      parameters = parameter;
+
+      /* Peek at the next token.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
+         || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+       /* The parameter-declaration-list is complete.  */
+       break;
+      else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       {
+         cp_token *token;
+
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_nth_token (parser->lexer, 2);
+         /* If it's an ellipsis, then the list is complete.  */
+         if (token->type == CPP_ELLIPSIS)
+           break;
+         /* Otherwise, there must be more parameters.  Consume the
+            `,'.  */
+         cp_lexer_consume_token (parser->lexer);
+       }
+      else
+       {
+         cp_parser_error (parser, "expected `,' or `...'");
+         break;
+       }
+    }
+
+  /* We built up the list in reverse order; straighten it out now.  */
+  return nreverse (parameters);
+}
+
+/* Parse a parameter declaration.
+
+   parameter-declaration:
+     decl-specifier-seq declarator
+     decl-specifier-seq declarator = assignment-expression
+     decl-specifier-seq abstract-declarator [opt]
+     decl-specifier-seq abstract-declarator [opt] = assignment-expression
+
+   If GREATER_THAN_IS_OPERATOR_P is FALSE, then a non-nested `>' token
+   encountered during the parsing of the assignment-expression is not
+   interpreted as a greater-than operator.
+
+   Returns a TREE_LIST representing the parameter-declaration.  The
+   TREE_VALUE is a representation of the decl-specifier-seq and
+   declarator.  In particular, the TREE_VALUE will be a TREE_LIST
+   whose TREE_PURPOSE represents the decl-specifier-seq and whose
+   TREE_VALUE represents the declarator.  */
+
+static tree
+cp_parser_parameter_declaration (parser, greater_than_is_operator_p)
+     cp_parser *parser;
+     bool greater_than_is_operator_p;
+{
+  bool declares_class_or_enum;
+  tree decl_specifiers;
+  tree attributes;
+  tree declarator;
+  tree default_argument;
+  tree parameter;
+  cp_token *token;
+  const char *saved_message;
+
+  /* Type definitions may not appear in parameter types.  */
+  saved_message = parser->type_definition_forbidden_message;
+  parser->type_definition_forbidden_message 
+    = "types may not be defined in parameter types";
+
+  /* Parse the declaration-specifiers.  */
+  decl_specifiers 
+    = cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_NONE,
+                                   &attributes,
+                                   &declares_class_or_enum);
+  /* If an error occurred, there's no reason to attempt to parse the
+     rest of the declaration.  */
+  if (cp_parser_error_occurred (parser))
+    {
+      parser->type_definition_forbidden_message = saved_message;
+      return error_mark_node;
+    }
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If the next token is a `)', `,', `=', `>', or `...', then there
+     is no declarator.  */
+  if (token->type == CPP_CLOSE_PAREN 
+      || token->type == CPP_COMMA
+      || token->type == CPP_EQ
+      || token->type == CPP_ELLIPSIS
+      || token->type == CPP_GREATER)
+    declarator = NULL_TREE;
+  /* Otherwise, there should be a declarator.  */
+  else
+    {
+      bool saved_default_arg_ok_p = parser->default_arg_ok_p;
+      parser->default_arg_ok_p = false;
+  
+      /* We don't know whether the declarator will be abstract or
+        not.  So, first we try an ordinary declarator.  */
+      cp_parser_parse_tentatively (parser);
+      declarator = cp_parser_declarator (parser,
+                                        /*abstract_p=*/false,
+                                        /*ctor_dtor_or_conv_p=*/NULL);
+      /* If that didn't work, look for an abstract declarator.  */
+      if (!cp_parser_parse_definitely (parser))
+       declarator = cp_parser_declarator (parser,
+                                          /*abstract_p=*/true,
+                                          /*ctor_dtor_or_conv_p=*/NULL);
+      parser->default_arg_ok_p = saved_default_arg_ok_p;
+    }
+
+  /* The restriction on definining new types applies only to the type
+     of the parameter, not to the default argument.  */
+  parser->type_definition_forbidden_message = saved_message;
+
+  /* If the next token is `=', then process a default argument.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+    {
+      bool saved_greater_than_is_operator_p;
+      /* Consume the `='.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      /* If we are defining a class, then the tokens that make up the
+        default argument must be saved and processed later.  */
+      if (at_class_scope_p () && TYPE_BEING_DEFINED (current_class_type))
+       {
+         unsigned depth = 0;
+
+         /* Create a DEFAULT_ARG to represented the unparsed default
+             argument.  */
+         default_argument = make_node (DEFAULT_ARG);
+         DEFARG_TOKENS (default_argument) = cp_token_cache_new ();
+
+         /* Add tokens until we have processed the entire default
+            argument.  */
+         while (true)
+           {
+             bool done = false;
+             cp_token *token;
+
+             /* Peek at the next token.  */
+             token = cp_lexer_peek_token (parser->lexer);
+             /* What we do depends on what token we have.  */
+             switch (token->type)
+               {
+                 /* In valid code, a default argument must be
+                    immediately followed by a `,' `)', or `...'.  */
+               case CPP_COMMA:
+               case CPP_CLOSE_PAREN:
+               case CPP_ELLIPSIS:
+                 /* If we run into a non-nested `;', `}', or `]',
+                    then the code is invalid -- but the default
+                    argument is certainly over.  */
+               case CPP_SEMICOLON:
+               case CPP_CLOSE_BRACE:
+               case CPP_CLOSE_SQUARE:
+                 if (depth == 0)
+                   done = true;
+                 /* Update DEPTH, if necessary.  */
+                 else if (token->type == CPP_CLOSE_PAREN
+                          || token->type == CPP_CLOSE_BRACE
+                          || token->type == CPP_CLOSE_SQUARE)
+                   --depth;
+                 break;
+
+               case CPP_OPEN_PAREN:
+               case CPP_OPEN_SQUARE:
+               case CPP_OPEN_BRACE:
+                 ++depth;
+                 break;
+
+               case CPP_GREATER:
+                 /* If we see a non-nested `>', and `>' is not an
+                    operator, then it marks the end of the default
+                    argument.  */
+                 if (!depth && !greater_than_is_operator_p)
+                   done = true;
+                 break;
+
+                 /* If we run out of tokens, issue an error message.  */
+               case CPP_EOF:
+                 error ("file ends in default argument");
+                 done = true;
+                 break;
+
+               case CPP_NAME:
+               case CPP_SCOPE:
+                 /* In these cases, we should look for template-ids.
+                    For example, if the default argument is 
+                    `X<int, double>()', we need to do name lookup to
+                    figure out whether or not `X' is a template; if
+                    so, the `,' does not end the deault argument.
+
+                    That is not yet done.  */
+                 break;
+
+               default:
+                 break;
+               }
+
+             /* If we've reached the end, stop.  */
+             if (done)
+               break;
+             
+             /* Add the token to the token block.  */
+             token = cp_lexer_consume_token (parser->lexer);
+             cp_token_cache_push_token (DEFARG_TOKENS (default_argument),
+                                        token);
+           }
+       }
+      /* Outside of a class definition, we can just parse the
+         assignment-expression.  */
+      else
+       {
+         bool saved_local_variables_forbidden_p;
+
+         /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
+            set correctly.  */
+         saved_greater_than_is_operator_p 
+           = parser->greater_than_is_operator_p;
+         parser->greater_than_is_operator_p = greater_than_is_operator_p;
+         /* Local variable names (and the `this' keyword) may not
+            appear in a default argument.  */
+         saved_local_variables_forbidden_p 
+           = parser->local_variables_forbidden_p;
+         parser->local_variables_forbidden_p = true;
+         /* Parse the assignment-expression.  */
+         default_argument = cp_parser_assignment_expression (parser);
+         /* Restore saved state.  */
+         parser->greater_than_is_operator_p 
+           = saved_greater_than_is_operator_p;
+         parser->local_variables_forbidden_p 
+           = saved_local_variables_forbidden_p; 
+       }
+      if (!parser->default_arg_ok_p)
+       {
+         pedwarn ("default arguments are only permitted on functions");
+         if (flag_pedantic_errors)
+           default_argument = NULL_TREE;
+       }
+    }
+  else
+    default_argument = NULL_TREE;
+  
+  /* Create the representation of the parameter.  */
+  if (attributes)
+    decl_specifiers = tree_cons (attributes, NULL_TREE, decl_specifiers);
+  parameter = build_tree_list (default_argument, 
+                              build_tree_list (decl_specifiers,
+                                               declarator));
+
+  return parameter;
+}
+
+/* Parse a function-definition.  
+
+   function-definition:
+     decl-specifier-seq [opt] declarator ctor-initializer [opt]
+       function-body 
+     decl-specifier-seq [opt] declarator function-try-block  
+
+   GNU Extension:
+
+   function-definition:
+     __extension__ function-definition 
+
+   Returns the FUNCTION_DECL for the function.  If FRIEND_P is
+   non-NULL, *FRIEND_P is set to TRUE iff the function was declared to
+   be a `friend'.  */
+
+static tree
+cp_parser_function_definition (parser, friend_p)
+     cp_parser *parser;
+     bool *friend_p;
+{
+  tree decl_specifiers;
+  tree attributes;
+  tree declarator;
+  tree fn;
+  tree access_checks;
+  cp_token *token;
+  bool declares_class_or_enum;
+  bool member_p;
+  /* The saved value of the PEDANTIC flag.  */
+  int saved_pedantic;
+
+  /* Any pending qualification must be cleared by our caller.  It is
+     more robust to force the callers to clear PARSER->SCOPE than to
+     do it here since if the qualification is in effect here, it might
+     also end up in effect elsewhere that it is not intended.  */
+  my_friendly_assert (!parser->scope, 20010821);
+
+  /* Handle `__extension__'.  */
+  if (cp_parser_extension_opt (parser, &saved_pedantic))
+    {
+      /* Parse the function-definition.  */
+      fn = cp_parser_function_definition (parser, friend_p);
+      /* Restore the PEDANTIC flag.  */
+      pedantic = saved_pedantic;
+
+      return fn;
+    }
+
+  /* Check to see if this definition appears in a class-specifier.  */
+  member_p = (at_class_scope_p () 
+             && TYPE_BEING_DEFINED (current_class_type));
+  /* Defer access checks in the decl-specifier-seq until we know what
+     function is being defined.  There is no need to do this for the
+     definition of member functions; we cannot be defining a member
+     from another class.  */
+  if (!member_p)
+    cp_parser_start_deferring_access_checks (parser);
+  /* Parse the decl-specifier-seq.  */
+  decl_specifiers 
+    = cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &attributes,
+                                   &declares_class_or_enum);
+  /* Figure out whether this declaration is a `friend'.  */
+  if (friend_p)
+    *friend_p = cp_parser_friend_p (decl_specifiers);
+
+  /* Parse the declarator.  */
+  declarator = cp_parser_declarator (parser, 
+                                    /*abstract_p=*/false,
+                                    /*ctor_dtor_or_conv_p=*/NULL);
+
+  /* Gather up any access checks that occurred.  */
+  if (!member_p)
+    access_checks = cp_parser_stop_deferring_access_checks (parser);
+  else
+    access_checks = NULL_TREE;
+
+  /* If something has already gone wrong, we may as well stop now.  */
+  if (declarator == error_mark_node)
+    {
+      /* Skip to the end of the function, or if this wasn't anything
+        like a function-definition, to a `;' in the hopes of finding
+        a sensible place from which to continue parsing.  */
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return error_mark_node;
+    }
+
+  /* The next character should be a `{' (for a simple function
+     definition), a `:' (for a ctor-initializer), or `try' (for a
+     function-try block).  */
+  token = cp_lexer_peek_token (parser->lexer);
+  if (!cp_parser_token_starts_function_definition_p (token))
+    {
+      /* Issue the error-message.  */
+      cp_parser_error (parser, "expected function-definition");
+      /* Skip to the next `;'.  */
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+
+      return error_mark_node;
+    }
+
+  /* If we are in a class scope, then we must handle
+     function-definitions specially.  In particular, we save away the
+     tokens that make up the function body, and parse them again
+     later, in order to handle code like:
+
+       struct S {
+         int f () { return i; }
+        int i;
+       }; 
+     Here, we cannot parse the body of `f' until after we have seen
+     the declaration of `i'.  */
+  if (member_p)
+    {
+      cp_token_cache *cache;
+
+      /* Create the function-declaration.  */
+      fn = start_method (decl_specifiers, declarator, attributes);
+      /* If something went badly wrong, bail out now.  */
+      if (fn == error_mark_node)
+       {
+         /* If there's a function-body, skip it.  */
+         if (cp_parser_token_starts_function_definition_p 
+             (cp_lexer_peek_token (parser->lexer)))
+           cp_parser_skip_to_end_of_block_or_statement (parser);
+         return error_mark_node;
+       }
+
+      /* Create a token cache.  */
+      cache = cp_token_cache_new ();
+      /* Save away the tokens that make up the body of the 
+        function.  */
+      cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0);
+      /* Handle function try blocks.  */
+      while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
+       cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0);
+
+      /* Save away the inline definition; we will process it when the
+        class is complete.  */
+      DECL_PENDING_INLINE_INFO (fn) = cache;
+      DECL_PENDING_INLINE_P (fn) = 1;
+
+      /* We're done with the inline definition.  */
+      finish_method (fn);
+
+      /* Add FN to the queue of functions to be parsed later.  */
+      TREE_VALUE (parser->unparsed_functions_queues)
+       = tree_cons (current_class_type, fn, 
+                    TREE_VALUE (parser->unparsed_functions_queues));
+
+      return fn;
+    }
+
+  /* Check that the number of template-parameter-lists is OK.  */
+  if (!cp_parser_check_declarator_template_parameters (parser, 
+                                                      declarator))
+    {
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return error_mark_node;
+    }
+
+  return (cp_parser_function_definition_from_specifiers_and_declarator
+         (parser, decl_specifiers, attributes, declarator, access_checks));
+}
+
+/* Parse a function-body.
+
+   function-body:
+     compound_statement  */
+
+static void
+cp_parser_function_body (cp_parser *parser)
+{
+  cp_parser_compound_statement (parser);
+}
+
+/* Parse a ctor-initializer-opt followed by a function-body.  Return
+   true if a ctor-initializer was present.  */
+
+static bool
+cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
+{
+  tree body;
+  bool ctor_initializer_p;
+
+  /* Begin the function body.  */
+  body = begin_function_body ();
+  /* Parse the optional ctor-initializer.  */
+  ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+  /* Parse the function-body.  */
+  cp_parser_function_body (parser);
+  /* Finish the function body.  */
+  finish_function_body (body);
+
+  return ctor_initializer_p;
+}
+
+/* Parse an initializer.
+
+   initializer:
+     = initializer-clause
+     ( expression-list )  
+
+   Returns a expression representing the initializer.  If no
+   initializer is present, NULL_TREE is returned.  
+
+   *IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )'
+   production is used, and zero otherwise.  *IS_PARENTHESIZED_INIT is
+   set to FALSE if there is no initializer present.  */
+
+static tree
+cp_parser_initializer (parser, is_parenthesized_init)
+     cp_parser *parser;
+     bool *is_parenthesized_init;
+{
+  cp_token *token;
+  tree init;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  /* Let our caller know whether or not this initializer was
+     parenthesized.  */
+  *is_parenthesized_init = (token->type == CPP_OPEN_PAREN);
+
+  if (token->type == CPP_EQ)
+    {
+      /* Consume the `='.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the initializer-clause.  */
+      init = cp_parser_initializer_clause (parser);
+    }
+  else if (token->type == CPP_OPEN_PAREN)
+    {
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the expression-list.  */
+      init = cp_parser_expression_list (parser);
+      /* Consume the `)' token.  */
+      if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+       cp_parser_skip_to_closing_parenthesis (parser);
+    }
+  else
+    {
+      /* Anything else is an error.  */
+      cp_parser_error (parser, "expected initializer");
+      init = error_mark_node;
+    }
+
+  return init;
+}
+
+/* Parse an initializer-clause.  
+
+   initializer-clause:
+     assignment-expression
+     { initializer-list , [opt] }
+     { }
+
+   Returns an expression representing the initializer.  
+
+   If the `assignment-expression' production is used the value
+   returned is simply a reprsentation for the expression.  
+
+   Otherwise, a CONSTRUCTOR is returned.  The CONSTRUCTOR_ELTS will be
+   the elements of the initializer-list (or NULL_TREE, if the last
+   production is used).  The TREE_TYPE for the CONSTRUCTOR will be
+   NULL_TREE.  There is no way to detect whether or not the optional
+   trailing `,' was provided.  */
+
+static tree
+cp_parser_initializer_clause (parser)
+     cp_parser *parser;
+{
+  tree initializer;
+
+  /* If it is not a `{', then we are looking at an
+     assignment-expression.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+    initializer = cp_parser_assignment_expression (parser);
+  else
+    {
+      /* Consume the `{' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Create a CONSTRUCTOR to represent the braced-initializer.  */
+      initializer = make_node (CONSTRUCTOR);
+      /* Mark it with TREE_HAS_CONSTRUCTOR.  This should not be
+        necessary, but check_initializer depends upon it, for 
+        now.  */
+      TREE_HAS_CONSTRUCTOR (initializer) = 1;
+      /* If it's not a `}', then there is a non-trivial initializer.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
+       {
+         /* Parse the initializer list.  */
+         CONSTRUCTOR_ELTS (initializer)
+           = cp_parser_initializer_list (parser);
+         /* A trailing `,' token is allowed.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+           cp_lexer_consume_token (parser->lexer);
+       }
+
+      /* Now, there should be a trailing `}'.  */
+      cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+    }
+
+  return initializer;
+}
+
+/* Parse an initializer-list.
+
+   initializer-list:
+     initializer-clause
+     initializer-list , initializer-clause
+
+   GNU Extension:
+   
+   initializer-list:
+     identifier : initializer-clause
+     initializer-list, identifier : initializer-clause
+
+   Returns a TREE_LIST.  The TREE_VALUE of each node is an expression
+   for the initializer.  If the TREE_PURPOSE is non-NULL, it is the
+   IDENTIFIER_NODE naming the field to initialize.   */
+
+static tree
+cp_parser_initializer_list (parser)
+     cp_parser *parser;
+{
+  tree initializers = NULL_TREE;
+
+  /* Parse the rest of the list.  */
+  while (true)
+    {
+      cp_token *token;
+      tree identifier;
+      tree initializer;
+      
+      /* If the next token is an identifier and the following one is a
+        colon, we are looking at the GNU designated-initializer
+        syntax.  */
+      if (cp_parser_allow_gnu_extensions_p (parser)
+         && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+         && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON)
+       {
+         /* Consume the identifier.  */
+         identifier = cp_lexer_consume_token (parser->lexer)->value;
+         /* Consume the `:'.  */
+         cp_lexer_consume_token (parser->lexer);
+       }
+      else
+       identifier = NULL_TREE;
+
+      /* Parse the initializer.  */
+      initializer = cp_parser_initializer_clause (parser);
+
+      /* Add it to the list.  */
+      initializers = tree_cons (identifier, initializer, initializers);
+
+      /* If the next token is not a comma, we have reached the end of
+        the list.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_nth_token (parser->lexer, 2);
+      /* If the next token is a `}', then we're still done.  An
+        initializer-clause can have a trailing `,' after the
+        initializer-list and before the closing `}'.  */
+      if (token->type == CPP_CLOSE_BRACE)
+       break;
+
+      /* Consume the `,' token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* The initializers were built up in reverse order, so we need to
+     reverse them now.  */
+  return nreverse (initializers);
+}
+
+/* Classes [gram.class] */
+
+/* Parse a class-name.
+
+   class-name:
+     identifier
+     template-id
+
+   TYPENAME_KEYWORD_P is true iff the `typename' keyword has been used
+   to indicate that names looked up in dependent types should be
+   assumed to be types.  TEMPLATE_KEYWORD_P is true iff the `template'
+   keyword has been used to indicate that the name that appears next
+   is a template.  TYPE_P is true iff the next name should be treated
+   as class-name, even if it is declared to be some other kind of name
+   as well.  The accessibility of the class-name is checked iff
+   CHECK_ACCESS_P is true.  If CHECK_DEPENDENCY_P is FALSE, names are
+   looked up in dependent scopes.  If CLASS_HEAD_P is TRUE, this class
+   is the class being defined in a class-head.
+
+   Returns the TYPE_DECL representing the class.  */
+
+static tree
+cp_parser_class_name (cp_parser *parser, 
+                     bool typename_keyword_p, 
+                     bool template_keyword_p, 
+                     bool type_p,
+                     bool check_access_p,
+                     bool check_dependency_p,
+                     bool class_head_p)
+{
+  tree decl;
+  tree scope;
+  bool typename_p;
+  
+  /* PARSER->SCOPE can be cleared when parsing the template-arguments
+     to a template-id, so we save it here.  */
+  scope = parser->scope;
+  /* Any name names a type if we're following the `typename' keyword
+     in a qualified name where the enclosing scope is type-dependent.  */
+  typename_p = (typename_keyword_p && scope && TYPE_P (scope)
+               && cp_parser_dependent_type_p (scope));
+
+  /* We don't know whether what comes next is a template-id or 
+     not.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try a template-id.  */
+  decl = cp_parser_template_id (parser, template_keyword_p,
+                               check_dependency_p);
+  if (cp_parser_parse_definitely (parser))
+    {
+      if (decl == error_mark_node)
+       return error_mark_node;
+    }
+  else
+    {
+      /* If it wasn't a template-id, try a simple identifier.  */
+      tree identifier;
+
+      /* Look for the identifier.  */
+      identifier = cp_parser_identifier (parser);
+      /* If the next token isn't an identifier, we are certainly not
+        looking at a class-name.  */
+      if (identifier == error_mark_node)
+       decl = error_mark_node;
+      /* If we know this is a type-name, there's no need to look it
+        up.  */
+      else if (typename_p)
+       decl = identifier;
+      else
+       {
+         /* If the next token is a `::', then the name must be a type
+            name.
+
+            [basic.lookup.qual]
+
+            During the lookup for a name preceding the :: scope
+            resolution operator, object, function, and enumerator
+            names are ignored.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+           type_p = true;
+         /* Look up the name.  */
+         decl = cp_parser_lookup_name (parser, identifier, 
+                                       check_access_p,
+                                       type_p,
+                                       check_dependency_p);
+       }
+    }
+
+  decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
+
+  /* If this is a typename, create a TYPENAME_TYPE.  */
+  if (typename_p && decl != error_mark_node)
+    decl = TYPE_NAME (make_typename_type (scope, decl,
+                                         /*complain=*/1));
+
+  /* Check to see that it is really the name of a class.  */
+  if (TREE_CODE (decl) == TEMPLATE_ID_EXPR 
+      && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
+      && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+    /* Situations like this:
+
+        template <typename T> struct A {
+          typename T::template X<int>::I i; 
+        };
+
+       are problematic.  Is `T::template X<int>' a class-name?  The
+       standard does not seem to be definitive, but there is no other
+       valid interpretation of the following `::'.  Therefore, those
+       names are considered class-names.  */
+    decl = TYPE_NAME (make_typename_type (scope, decl, 
+                                         tf_error | tf_parsing));
+  else if (decl == error_mark_node
+          || TREE_CODE (decl) != TYPE_DECL
+          || !IS_AGGR_TYPE (TREE_TYPE (decl)))
+    {
+      cp_parser_error (parser, "expected class-name");
+      return error_mark_node;
+    }
+
+  return decl;
+}
+
+/* Parse a class-specifier.
+
+   class-specifier:
+     class-head { member-specification [opt] }
+
+   Returns the TREE_TYPE representing the class.  */
+
+static tree
+cp_parser_class_specifier (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree type;
+  tree attributes = NULL_TREE;
+  int has_trailing_semicolon;
+  bool nested_name_specifier_p;
+  bool deferring_access_checks_p;
+  tree saved_access_checks;
+  unsigned saved_num_template_parameter_lists;
+
+  /* Parse the class-head.  */
+  type = cp_parser_class_head (parser,
+                              &nested_name_specifier_p,
+                              &deferring_access_checks_p,
+                              &saved_access_checks);
+  /* If the class-head was a semantic disaster, skip the entire body
+     of the class.  */
+  if (!type)
+    {
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return error_mark_node;
+    }
+  /* Look for the `{'.  */
+  if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
+    return error_mark_node;
+  /* Issue an error message if type-definitions are forbidden here.  */
+  cp_parser_check_type_definition (parser);
+  /* Remember that we are defining one more class.  */
+  ++parser->num_classes_being_defined;
+  /* Inside the class, surrounding template-parameter-lists do not
+     apply.  */
+  saved_num_template_parameter_lists 
+    = parser->num_template_parameter_lists; 
+  parser->num_template_parameter_lists = 0;
+  /* Start the class.  */
+  type = begin_class_definition (type);
+  if (type == error_mark_node)
+    /* If the type is erroneous, skip the entire body of the class. */
+    cp_parser_skip_to_closing_brace (parser);
+  else
+    /* Parse the member-specification.  */
+    cp_parser_member_specification_opt (parser);
+  /* Look for the trailing `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+  /* We get better error messages by noticing a common problem: a
+     missing trailing `;'.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  has_trailing_semicolon = (token->type == CPP_SEMICOLON);
+  /* Look for attributes to apply to this class.  */
+  if (cp_parser_allow_gnu_extensions_p (parser))
+    attributes = cp_parser_attributes_opt (parser);
+  /* Finish the class definition.  */
+  type = finish_class_definition (type, 
+                                 attributes,
+                                 has_trailing_semicolon,
+                                 nested_name_specifier_p);
+  /* If this class is not itself within the scope of another class,
+     then we need to parse the bodies of all of the queued function
+     definitions.  Note that the queued functions defined in a class
+     are not always processed immediately following the
+     class-specifier for that class.  Consider:
+
+       struct A {
+         struct B { void f() { sizeof (A); } };
+       };
+
+     If `f' were processed before the processing of `A' were
+     completed, there would be no way to compute the size of `A'.
+     Note that the nesting we are interested in here is lexical --
+     not the semantic nesting given by TYPE_CONTEXT.  In particular,
+     for:
+
+       struct A { struct B; };
+       struct A::B { void f() { } };
+
+     there is no need to delay the parsing of `A::B::f'.  */
+  if (--parser->num_classes_being_defined == 0) 
+    {
+      tree last_scope = NULL_TREE;
+
+      /* Process non FUNCTION_DECL related DEFAULT_ARGs.  */
+      for (parser->default_arg_types = nreverse (parser->default_arg_types);
+          parser->default_arg_types;
+          parser->default_arg_types = TREE_CHAIN (parser->default_arg_types))
+       cp_parser_late_parsing_default_args
+         (parser, TREE_PURPOSE (parser->default_arg_types));
+      
+      /* Reverse the queue, so that we process it in the order the
+        functions were declared.  */
+      TREE_VALUE (parser->unparsed_functions_queues)
+       = nreverse (TREE_VALUE (parser->unparsed_functions_queues));
+      /* Loop through all of the functions.  */
+      while (TREE_VALUE (parser->unparsed_functions_queues))
+
+       {
+         tree fn;
+         tree fn_scope;
+         tree queue_entry;
+
+         /* Figure out which function we need to process.  */
+         queue_entry = TREE_VALUE (parser->unparsed_functions_queues);
+         fn_scope = TREE_PURPOSE (queue_entry);
+         fn = TREE_VALUE (queue_entry);
+
+         /* Parse the function.  */
+         cp_parser_late_parsing_for_member (parser, fn);
+
+         TREE_VALUE (parser->unparsed_functions_queues)
+           = TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues));
+       }
+
+      /* If LAST_SCOPE is non-NULL, then we have pushed scopes one
+        more time than we have popped, so me must pop here.  */
+      if (last_scope)
+       pop_scope (last_scope);
+    }
+
+  /* Put back any saved access checks.  */
+  if (deferring_access_checks_p)
+    {
+      cp_parser_start_deferring_access_checks (parser);
+      parser->context->deferred_access_checks = saved_access_checks;
+    }
+
+  /* Restore the count of active template-parameter-lists.  */
+  parser->num_template_parameter_lists
+    = saved_num_template_parameter_lists;
+
+  return type;
+}
+
+/* Parse a class-head.
+
+   class-head:
+     class-key identifier [opt] base-clause [opt]
+     class-key nested-name-specifier identifier base-clause [opt]
+     class-key nested-name-specifier [opt] template-id 
+       base-clause [opt]  
+
+   GNU Extensions:
+     class-key attributes identifier [opt] base-clause [opt]
+     class-key attributes nested-name-specifier identifier base-clause [opt]
+     class-key attributes nested-name-specifier [opt] template-id 
+       base-clause [opt]  
+
+   Returns the TYPE of the indicated class.  Sets
+   *NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
+   involving a nested-name-specifier was used, and FALSE otherwise.
+   Sets *DEFERRING_ACCESS_CHECKS_P to TRUE iff we were deferring
+   access checks before this class-head.  In that case,
+   *SAVED_ACCESS_CHECKS is set to the current list of deferred access
+   checks.  
+
+   Returns NULL_TREE if the class-head is syntactically valid, but
+   semantically invalid in a way that means we should skip the entire
+   body of the class.  */
+
+static tree
+cp_parser_class_head (parser, 
+                     nested_name_specifier_p,
+                     deferring_access_checks_p,
+                     saved_access_checks)
+     cp_parser *parser;
+     bool *nested_name_specifier_p;
+     bool *deferring_access_checks_p;
+     tree *saved_access_checks;
+{
+  cp_token *token;
+  tree nested_name_specifier;
+  enum tag_types class_key;
+  tree id = NULL_TREE;
+  tree type = NULL_TREE;
+  tree attributes;
+  bool template_id_p = false;
+  bool qualified_p = false;
+  bool invalid_nested_name_p = false;
+  unsigned num_templates;
+
+  /* Assume no nested-name-specifier will be present.  */
+  *nested_name_specifier_p = false;
+  /* Assume no template parameter lists will be used in defining the
+     type.  */
+  num_templates = 0;
+
+  /* Look for the class-key.  */
+  class_key = cp_parser_class_key (parser);
+  if (class_key == none_type)
+    return error_mark_node;
+
+  /* Parse the attributes.  */
+  attributes = cp_parser_attributes_opt (parser);
+
+  /* If the next token is `::', that is invalid -- but sometimes
+     people do try to write:
+
+       struct ::S {};  
+
+     Handle this gracefully by accepting the extra qualifier, and then
+     issuing an error about it later if this really is a
+     class-header.  If it turns out just to be an elaborated type
+     specifier, remain silent.  */
+  if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false))
+    qualified_p = true;
+
+  /* Determine the name of the class.  Begin by looking for an
+     optional nested-name-specifier.  */
+  nested_name_specifier 
+    = cp_parser_nested_name_specifier_opt (parser,
+                                          /*typename_keyword_p=*/false,
+                                          /*check_dependency_p=*/true,
+                                          /*type_p=*/false);
+  /* If there was a nested-name-specifier, then there *must* be an
+     identifier.  */
+  if (nested_name_specifier)
+    {
+      /* Although the grammar says `identifier', it really means
+        `class-name' or `template-name'.  You are only allowed to
+        define a class that has already been declared with this
+        syntax.  
+
+        The proposed resolution for Core Issue 180 says that whever
+        you see `class T::X' you should treat `X' as a type-name.
+        
+        It is OK to define an inaccessible class; for example:
+        
+           class A { class B; };
+           class A::B {};
+        
+        So, we ask cp_parser_class_name not to check accessibility.  
+
+         We do not know if we will see a class-name, or a
+        template-name.  We look for a class-name first, in case the
+        class-name is a template-id; if we looked for the
+        template-name first we would stop after the template-name.  */
+      cp_parser_parse_tentatively (parser);
+      type = cp_parser_class_name (parser,
+                                  /*typename_keyword_p=*/false,
+                                  /*template_keyword_p=*/false,
+                                  /*type_p=*/true,
+                                  /*check_access_p=*/false,
+                                  /*check_dependency_p=*/false,
+                                  /*class_head_p=*/true);
+      /* If that didn't work, ignore the nested-name-specifier.  */
+      if (!cp_parser_parse_definitely (parser))
+       {
+         invalid_nested_name_p = true;
+         id = cp_parser_identifier (parser);
+         if (id == error_mark_node)
+           id = NULL_TREE;
+       }
+      /* If we could not find a corresponding TYPE, treat this
+        declaration like an unqualified declaration.  */
+      if (type == error_mark_node)
+       nested_name_specifier = NULL_TREE;
+      /* Otherwise, count the number of templates used in TYPE and its
+        containing scopes.  */
+      else 
+       {
+         tree scope;
+
+         for (scope = TREE_TYPE (type); 
+              scope && TREE_CODE (scope) != NAMESPACE_DECL;
+              scope = (TYPE_P (scope) 
+                       ? TYPE_CONTEXT (scope)
+                       : DECL_CONTEXT (scope))) 
+           if (TYPE_P (scope) 
+               && CLASS_TYPE_P (scope)
+               && CLASSTYPE_TEMPLATE_INFO (scope)
+               && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
+             ++num_templates;
+       }
+    }
+  /* Otherwise, the identifier is optional.  */
+  else
+    {
+      /* We don't know whether what comes next is a template-id,
+        an identifier, or nothing at all.  */
+      cp_parser_parse_tentatively (parser);
+      /* Check for a template-id.  */
+      id = cp_parser_template_id (parser, 
+                                 /*template_keyword_p=*/false,
+                                 /*check_dependency_p=*/true);
+      /* If that didn't work, it could still be an identifier.  */
+      if (!cp_parser_parse_definitely (parser))
+       {
+         if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+           id = cp_parser_identifier (parser);
+         else
+           id = NULL_TREE;
+       }
+      else
+       {
+         template_id_p = true;
+         ++num_templates;
+       }
+    }
+
+  /* If it's not a `:' or a `{' then we can't really be looking at a
+     class-head, since a class-head only appears as part of a
+     class-specifier.  We have to detect this situation before calling
+     xref_tag, since that has irreversible side-effects.  */
+  if (!cp_parser_next_token_starts_class_definition_p (parser))
+    {
+      cp_parser_error (parser, "expected `{' or `:'");
+      return error_mark_node;
+    }
+
+  /* At this point, we're going ahead with the class-specifier, even
+     if some other problem occurs.  */
+  cp_parser_commit_to_tentative_parse (parser);
+  /* Issue the error about the overly-qualified name now.  */
+  if (qualified_p)
+    cp_parser_error (parser,
+                    "global qualification of class name is invalid");
+  else if (invalid_nested_name_p)
+    cp_parser_error (parser,
+                    "qualified name does not name a class");
+  /* Make sure that the right number of template parameters were
+     present.  */
+  if (!cp_parser_check_template_parameters (parser, num_templates))
+    /* If something went wrong, there is no point in even trying to
+       process the class-definition.  */
+    return NULL_TREE;
+
+  /* We do not need to defer access checks for entities declared
+     within the class.  But, we do need to save any access checks that
+     are currently deferred and restore them later, in case we are in
+     the middle of something else.  */
+  *deferring_access_checks_p = parser->context->deferring_access_checks_p;
+  if (*deferring_access_checks_p)
+    *saved_access_checks = cp_parser_stop_deferring_access_checks (parser);
+
+  /* Look up the type.  */
+  if (template_id_p)
+    {
+      type = TREE_TYPE (id);
+      maybe_process_partial_specialization (type);
+    }
+  else if (!nested_name_specifier)
+    {
+      /* If the class was unnamed, create a dummy name.  */
+      if (!id)
+       id = make_anon_name ();
+      type = xref_tag (class_key, id, attributes, /*globalize=*/0);
+    }
+  else
+    {
+      int new_type_p;
+      tree class_type;
+
+      /* Given:
+
+           template <typename T> struct S { struct T };
+           template <typename T> struct S::T { };
+
+        we will get a TYPENAME_TYPE when processing the definition of
+        `S::T'.  We need to resolve it to the actual type before we
+        try to define it.  */
+      if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
+       {
+         type = cp_parser_resolve_typename_type (parser, TREE_TYPE (type));
+         if (type != error_mark_node)
+           type = TYPE_NAME (type);
+       }
+
+      maybe_process_partial_specialization (TREE_TYPE (type));
+      class_type = current_class_type;
+      type = TREE_TYPE (handle_class_head (class_key, 
+                                          nested_name_specifier,
+                                          type,
+                                          attributes,
+                                          /*defn_p=*/1,
+                                          &new_type_p));
+      if (type != error_mark_node)
+       {
+         if (!class_type && TYPE_CONTEXT (type))
+           *nested_name_specifier_p = true;
+         else if (class_type && !same_type_p (TYPE_CONTEXT (type),
+                                              class_type))
+           *nested_name_specifier_p = true;
+       }
+    }
+  /* Indicate whether this class was declared as a `class' or as a
+     `struct'.  */
+  if (TREE_CODE (type) == RECORD_TYPE)
+    CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
+  cp_parser_check_class_key (class_key, type);
+
+  /* Enter the scope containing the class; the names of base classes
+     should be looked up in that context.  For example, given:
+
+       struct A { struct B {}; struct C; };
+       struct A::C : B {};
+
+     is valid.  */
+  if (nested_name_specifier)
+    push_scope (nested_name_specifier);
+  /* Now, look for the base-clause.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  if (token->type == CPP_COLON)
+    {
+      tree bases;
+
+      /* Get the list of base-classes.  */
+      bases = cp_parser_base_clause (parser);
+      /* Process them.  */
+      xref_basetypes (type, bases);
+    }
+  /* Leave the scope given by the nested-name-specifier.  We will
+     enter the class scope itself while processing the members.  */
+  if (nested_name_specifier)
+    pop_scope (nested_name_specifier);
+
+  return type;
+}
+
+/* Parse a class-key.
+
+   class-key:
+     class
+     struct
+     union
+
+   Returns the kind of class-key specified, or none_type to indicate
+   error.  */
+
+static enum tag_types
+cp_parser_class_key (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  enum tag_types tag_type;
+
+  /* Look for the class-key.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, "class-key");
+  if (!token)
+    return none_type;
+
+  /* Check to see if the TOKEN is a class-key.  */
+  tag_type = cp_parser_token_is_class_key (token);
+  if (!tag_type)
+    cp_parser_error (parser, "expected class-key");
+  return tag_type;
+}
+
+/* Parse an (optional) member-specification.
+
+   member-specification:
+     member-declaration member-specification [opt]
+     access-specifier : member-specification [opt]  */
+
+static void
+cp_parser_member_specification_opt (parser)
+     cp_parser *parser;
+{
+  while (true)
+    {
+      cp_token *token;
+      enum rid keyword;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's a `}', or EOF then we've seen all the members.  */
+      if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF)
+       break;
+
+      /* See if this token is a keyword.  */
+      keyword = token->keyword;
+      switch (keyword)
+       {
+       case RID_PUBLIC:
+       case RID_PROTECTED:
+       case RID_PRIVATE:
+         /* Consume the access-specifier.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Remember which access-specifier is active.  */
+         current_access_specifier = token->value;
+         /* Look for the `:'.  */
+         cp_parser_require (parser, CPP_COLON, "`:'");
+         break;
+
+       default:
+         /* Otherwise, the next construction must be a
+            member-declaration.  */
+         cp_parser_member_declaration (parser);
+         reset_type_access_control ();
+       }
+    }
+}
+
+/* Parse a member-declaration.  
+
+   member-declaration:
+     decl-specifier-seq [opt] member-declarator-list [opt] ;
+     function-definition ; [opt]
+     :: [opt] nested-name-specifier template [opt] unqualified-id ;
+     using-declaration
+     template-declaration 
+
+   member-declarator-list:
+     member-declarator
+     member-declarator-list , member-declarator
+
+   member-declarator:
+     declarator pure-specifier [opt] 
+     declarator constant-initializer [opt]
+     identifier [opt] : constant-expression 
+
+   GNU Extensions:
+
+   member-declaration:
+     __extension__ member-declaration
+
+   member-declarator:
+     declarator attributes [opt] pure-specifier [opt]
+     declarator attributes [opt] constant-initializer [opt]
+     identifier [opt] attributes [opt] : constant-expression  */
+
+static void
+cp_parser_member_declaration (parser)
+     cp_parser *parser;
+{
+  tree decl_specifiers;
+  tree prefix_attributes;
+  tree decl;
+  bool declares_class_or_enum;
+  bool friend_p;
+  cp_token *token;
+  int saved_pedantic;
+
+  /* Check for the `__extension__' keyword.  */
+  if (cp_parser_extension_opt (parser, &saved_pedantic))
+    {
+      /* Recurse.  */
+      cp_parser_member_declaration (parser);
+      /* Restore the old value of the PEDANTIC flag.  */
+      pedantic = saved_pedantic;
+
+      return;
+    }
+
+  /* Check for a template-declaration.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    {
+      /* Parse the template-declaration.  */
+      cp_parser_template_declaration (parser, /*member_p=*/true);
+
+      return;
+    }
+
+  /* Check for a using-declaration.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+    {
+      /* Parse the using-declaration.  */
+      cp_parser_using_declaration (parser);
+
+      return;
+    }
+  
+  /* We can't tell whether we're looking at a declaration or a
+     function-definition.  */
+  cp_parser_parse_tentatively (parser);
+
+  /* Parse the decl-specifier-seq.  */
+  decl_specifiers 
+    = cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &prefix_attributes,
+                                   &declares_class_or_enum);
+  /* If there is no declarator, then the decl-specifier-seq should
+     specify a type.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+    {
+      /* If there was no decl-specifier-seq, and the next token is a
+        `;', then we have something like:
+
+          struct S { ; };
+
+        [class.mem]
+
+        Each member-declaration shall declare at least one member
+        name of the class.  */
+      if (!decl_specifiers)
+       {
+         if (pedantic)
+           pedwarn ("extra semicolon");
+       }
+      else 
+       {
+         tree type;
+         
+         /* See if this declaration is a friend.  */
+         friend_p = cp_parser_friend_p (decl_specifiers);
+         /* If there were decl-specifiers, check to see if there was
+            a class-declaration.  */
+         type = check_tag_decl (decl_specifiers);
+         /* Nested classes have already been added to the class, but
+            a `friend' needs to be explicitly registered.  */
+         if (friend_p)
+           {
+             /* If the `friend' keyword was present, the friend must
+                be introduced with a class-key.  */
+              if (!declares_class_or_enum)
+                error ("a class-key must be used when declaring a friend");
+              /* In this case:
+
+                   template <typename T> struct A { 
+                      friend struct A<T>::B; 
+                    };
+                 A<T>::B will be represented by a TYPENAME_TYPE, and
+                 therefore not recognized by check_tag_decl.  */
+              if (!type)
+                {
+                  tree specifier;
+
+                  for (specifier = decl_specifiers; 
+                       specifier;
+                       specifier = TREE_CHAIN (specifier))
+                    {
+                      tree s = TREE_VALUE (specifier);
+
+                      if (TREE_CODE (s) == IDENTIFIER_NODE
+                          && IDENTIFIER_GLOBAL_VALUE (s))
+                        type = IDENTIFIER_GLOBAL_VALUE (s);
+                      if (TREE_CODE (s) == TYPE_DECL)
+                        s = TREE_TYPE (s);
+                      if (TYPE_P (s))
+                        {
+                          type = s;
+                          break;
+                        }
+                    }
+                }
+              if (!type)
+                error ("friend declaration does not name a class or "
+                       "function");
+              else
+                make_friend_class (current_class_type, type);
+           }
+         /* If there is no TYPE, an error message will already have
+            been issued.  */
+         else if (!type)
+           ;
+         /* An anonymous aggregate has to be handled specially; such
+            a declaration really declares a data member (with a
+            particular type), as opposed to a nested class.  */
+         else if (ANON_AGGR_TYPE_P (type))
+           {
+             /* Remove constructors and such from TYPE, now that we
+                know it is an anoymous aggregate.  */
+             fixup_anonymous_aggr (type);
+             /* And make the corresponding data member.  */
+             decl = build_decl (FIELD_DECL, NULL_TREE, type);
+             /* Add it to the class.  */
+             finish_member_declaration (decl);
+           }
+       }
+    }
+  else
+    {
+      /* See if these declarations will be friends.  */
+      friend_p = cp_parser_friend_p (decl_specifiers);
+
+      /* Keep going until we hit the `;' at the end of the 
+        declaration.  */
+      while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+       {
+         tree attributes = NULL_TREE;
+         tree first_attribute;
+
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_token (parser->lexer);
+
+         /* Check for a bitfield declaration.  */
+         if (token->type == CPP_COLON
+             || (token->type == CPP_NAME
+                 && cp_lexer_peek_nth_token (parser->lexer, 2)->type 
+                 == CPP_COLON))
+           {
+             tree identifier;
+             tree width;
+
+             /* Get the name of the bitfield.  Note that we cannot just
+                check TOKEN here because it may have been invalidated by
+                the call to cp_lexer_peek_nth_token above.  */
+             if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
+               identifier = cp_parser_identifier (parser);
+             else
+               identifier = NULL_TREE;
+
+             /* Consume the `:' token.  */
+             cp_lexer_consume_token (parser->lexer);
+             /* Get the width of the bitfield.  */
+             width = cp_parser_constant_expression (parser);
+
+             /* Look for attributes that apply to the bitfield.  */
+             attributes = cp_parser_attributes_opt (parser);
+             /* Remember which attributes are prefix attributes and
+                which are not.  */
+             first_attribute = attributes;
+             /* Combine the attributes.  */
+             attributes = chainon (prefix_attributes, attributes);
+
+             /* Create the bitfield declaration.  */
+             decl = grokbitfield (identifier, 
+                                  decl_specifiers,
+                                  width);
+             /* Apply the attributes.  */
+             cplus_decl_attributes (&decl, attributes, /*flags=*/0);
+           }
+         else
+           {
+             tree declarator;
+             tree initializer;
+             tree asm_specification;
+             bool ctor_dtor_or_conv_p;
+
+             /* Parse the declarator.  */
+             declarator 
+               = cp_parser_declarator (parser,
+                                       /*abstract_p=*/false,
+                                       &ctor_dtor_or_conv_p);
+
+             /* If something went wrong parsing the declarator, make sure
+                that we at least consume some tokens.  */
+             if (declarator == error_mark_node)
+               {
+                 /* Skip to the end of the statement.  */
+                 cp_parser_skip_to_end_of_statement (parser);
+                 break;
+               }
+
+             /* Look for an asm-specification.  */
+             asm_specification = cp_parser_asm_specification_opt (parser);
+             /* Look for attributes that apply to the declaration.  */
+             attributes = cp_parser_attributes_opt (parser);
+             /* Remember which attributes are prefix attributes and
+                which are not.  */
+             first_attribute = attributes;
+             /* Combine the attributes.  */
+             attributes = chainon (prefix_attributes, attributes);
+
+             /* If it's an `=', then we have a constant-initializer or a
+                pure-specifier.  It is not correct to parse the
+                initializer before registering the member declaration
+                since the member declaration should be in scope while
+                its initializer is processed.  However, the rest of the
+                front end does not yet provide an interface that allows
+                us to handle this correctly.  */
+             if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+               {
+                 /* In [class.mem]:
+
+                    A pure-specifier shall be used only in the declaration of
+                    a virtual function.  
+
+                    A member-declarator can contain a constant-initializer
+                    only if it declares a static member of integral or
+                    enumeration type.  
+
+                    Therefore, if the DECLARATOR is for a function, we look
+                    for a pure-specifier; otherwise, we look for a
+                    constant-initializer.  When we call `grokfield', it will
+                    perform more stringent semantics checks.  */
+                 if (TREE_CODE (declarator) == CALL_EXPR)
+                   initializer = cp_parser_pure_specifier (parser);
+                 else
+                   {
+                     /* This declaration cannot be a function
+                        definition.  */
+                     cp_parser_commit_to_tentative_parse (parser);
+                     /* Parse the initializer.  */
+                     initializer = cp_parser_constant_initializer (parser);
+                   }
+               }
+             /* Otherwise, there is no initializer.  */
+             else
+               initializer = NULL_TREE;
+
+             /* See if we are probably looking at a function
+                definition.  We are certainly not looking at at a
+                member-declarator.  Calling `grokfield' has
+                side-effects, so we must not do it unless we are sure
+                that we are looking at a member-declarator.  */
+             if (cp_parser_token_starts_function_definition_p 
+                 (cp_lexer_peek_token (parser->lexer)))
+               decl = error_mark_node;
+             else
+               /* Create the declaration.  */
+               decl = grokfield (declarator, 
+                                 decl_specifiers, 
+                                 initializer,
+                                 asm_specification,
+                                 attributes);
+           }
+
+         /* Reset PREFIX_ATTRIBUTES.  */
+         while (attributes && TREE_CHAIN (attributes) != first_attribute)
+           attributes = TREE_CHAIN (attributes);
+         if (attributes)
+           TREE_CHAIN (attributes) = NULL_TREE;
+
+         /* If there is any qualification still in effect, clear it
+            now; we will be starting fresh with the next declarator.  */
+         parser->scope = NULL_TREE;
+         parser->qualifying_scope = NULL_TREE;
+         parser->object_scope = NULL_TREE;
+         /* If it's a `,', then there are more declarators.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+           cp_lexer_consume_token (parser->lexer);
+         /* If the next token isn't a `;', then we have a parse error.  */
+         else if (cp_lexer_next_token_is_not (parser->lexer,
+                                              CPP_SEMICOLON))
+           {
+             cp_parser_error (parser, "expected `;'");
+             /* Skip tokens until we find a `;'  */
+             cp_parser_skip_to_end_of_statement (parser);
+
+             break;
+           }
+
+         if (decl)
+           {
+             /* Add DECL to the list of members.  */
+             if (!friend_p)
+               finish_member_declaration (decl);
+
+             /* If DECL is a function, we must return
+                to parse it later.  (Even though there is no definition,
+                there might be default arguments that need handling.)  */
+             if (TREE_CODE (decl) == FUNCTION_DECL)
+               TREE_VALUE (parser->unparsed_functions_queues)
+                 = tree_cons (current_class_type, decl, 
+                              TREE_VALUE (parser->unparsed_functions_queues));
+           }
+       }
+    }
+
+  /* If everything went well, look for the `;'.  */
+  if (cp_parser_parse_definitely (parser))
+    {
+      cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+      return;
+    }
+
+  /* Parse the function-definition.  */
+  decl = cp_parser_function_definition (parser,        &friend_p);
+  /* If the member was not a friend, declare it here.  */
+  if (!friend_p)
+    finish_member_declaration (decl);
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If the next token is a semicolon, consume it.  */
+  if (token->type == CPP_SEMICOLON)
+    cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse a pure-specifier.
+
+   pure-specifier:
+     = 0
+
+   Returns INTEGER_ZERO_NODE if a pure specifier is found.
+   Otherwiser, ERROR_MARK_NODE is returned.  */
+
+static tree
+cp_parser_pure_specifier (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+
+  /* Look for the `=' token.  */
+  if (!cp_parser_require (parser, CPP_EQ, "`='"))
+    return error_mark_node;
+  /* Look for the `0' token.  */
+  token = cp_parser_require (parser, CPP_NUMBER, "`0'");
+  /* Unfortunately, this will accept `0L' and `0x00' as well.  We need
+     to get information from the lexer about how the number was
+     spelled in order to fix this problem.  */
+  if (!token || !integer_zerop (token->value))
+    return error_mark_node;
+
+  return integer_zero_node;
+}
+
+/* Parse a constant-initializer.
+
+   constant-initializer:
+     = constant-expression
+
+   Returns a representation of the constant-expression.  */
+
+static tree
+cp_parser_constant_initializer (parser)
+     cp_parser *parser;
+{
+  /* Look for the `=' token.  */
+  if (!cp_parser_require (parser, CPP_EQ, "`='"))
+    return error_mark_node;
+
+  /* It is invalid to write:
+
+       struct S { static const int i = { 7 }; };
+
+     */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+    {
+      cp_parser_error (parser,
+                      "a brace-enclosed initializer is not allowed here");
+      /* Consume the opening brace.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Skip the initializer.  */
+      cp_parser_skip_to_closing_brace (parser);
+      /* Look for the trailing `}'.  */
+      cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
+      
+      return error_mark_node;
+    }
+
+  return cp_parser_constant_expression (parser);
+}
+
+/* Derived classes [gram.class.derived] */
+
+/* Parse a base-clause.
+
+   base-clause:
+     : base-specifier-list  
+
+   base-specifier-list:
+     base-specifier
+     base-specifier-list , base-specifier
+
+   Returns a TREE_LIST representing the base-classes, in the order in
+   which they were declared.  The representation of each node is as
+   described by cp_parser_base_specifier.  
+
+   In the case that no bases are specified, this function will return
+   NULL_TREE, not ERROR_MARK_NODE.  */
+
+static tree
+cp_parser_base_clause (parser)
+     cp_parser *parser;
+{
+  tree bases = NULL_TREE;
+
+  /* Look for the `:' that begins the list.  */
+  cp_parser_require (parser, CPP_COLON, "`:'");
+
+  /* Scan the base-specifier-list.  */
+  while (true)
+    {
+      cp_token *token;
+      tree base;
+
+      /* Look for the base-specifier.  */
+      base = cp_parser_base_specifier (parser);
+      /* Add BASE to the front of the list.  */
+      if (base != error_mark_node)
+       {
+         TREE_CHAIN (base) = bases;
+         bases = base;
+       }
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's not a comma, then the list is complete.  */
+      if (token->type != CPP_COMMA)
+       break;
+      /* Consume the `,'.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* PARSER->SCOPE may still be non-NULL at this point, if the last
+     base class had a qualified name.  However, the next name that
+     appears is certainly not qualified.  */
+  parser->scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+
+  return nreverse (bases);
+}
+
+/* Parse a base-specifier.
+
+   base-specifier:
+     :: [opt] nested-name-specifier [opt] class-name
+     virtual access-specifier [opt] :: [opt] nested-name-specifier
+       [opt] class-name
+     access-specifier virtual [opt] :: [opt] nested-name-specifier
+       [opt] class-name
+
+   Returns a TREE_LIST.  The TREE_PURPOSE will be one of
+   ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to
+   indicate the specifiers provided.  The TREE_VALUE will be a TYPE
+   (or the ERROR_MARK_NODE) indicating the type that was specified.  */
+       
+static tree
+cp_parser_base_specifier (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  bool done = false;
+  bool virtual_p = false;
+  bool duplicate_virtual_error_issued_p = false;
+  bool duplicate_access_error_issued_p = false;
+  bool class_scope_p;
+  access_kind access = ak_none;
+  tree access_node;
+  tree type;
+
+  /* Process the optional `virtual' and `access-specifier'.  */
+  while (!done)
+    {
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* Process `virtual'.  */
+      switch (token->keyword)
+       {
+       case RID_VIRTUAL:
+         /* If `virtual' appears more than once, issue an error.  */
+         if (virtual_p && !duplicate_virtual_error_issued_p)
+           {
+             cp_parser_error (parser,
+                              "`virtual' specified more than once in base-specified");
+             duplicate_virtual_error_issued_p = true;
+           }
+
+         virtual_p = true;
+
+         /* Consume the `virtual' token.  */
+         cp_lexer_consume_token (parser->lexer);
+
+         break;
+
+       case RID_PUBLIC:
+       case RID_PROTECTED:
+       case RID_PRIVATE:
+         /* If more than one access specifier appears, issue an
+            error.  */
+         if (access != ak_none && !duplicate_access_error_issued_p)
+           {
+             cp_parser_error (parser,
+                              "more than one access specifier in base-specified");
+             duplicate_access_error_issued_p = true;
+           }
+
+         access = ((access_kind) 
+                   tree_low_cst (ridpointers[(int) token->keyword],
+                                 /*pos=*/1));
+
+         /* Consume the access-specifier.  */
+         cp_lexer_consume_token (parser->lexer);
+
+         break;
+
+       default:
+         done = true;
+         break;
+       }
+    }
+
+  /* Map `virtual_p' and `access' onto one of the access 
+     tree-nodes.  */
+  if (!virtual_p)
+    switch (access)
+      {
+      case ak_none:
+       access_node = access_default_node;
+       break;
+      case ak_public:
+       access_node = access_public_node;
+       break;
+      case ak_protected:
+       access_node = access_protected_node;
+       break;
+      case ak_private:
+       access_node = access_private_node;
+       break;
+      default:
+       abort ();
+      }
+  else
+    switch (access)
+      {
+      case ak_none:
+       access_node = access_default_virtual_node;
+       break;
+      case ak_public:
+       access_node = access_public_virtual_node;
+       break;
+      case ak_protected:
+       access_node = access_protected_virtual_node;
+       break;
+      case ak_private:
+       access_node = access_private_virtual_node;
+       break;
+      default:
+       abort ();
+      }
+
+  /* Look for the optional `::' operator.  */
+  cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
+  /* Look for the nested-name-specifier.  The simplest way to
+     implement:
+
+       [temp.res]
+
+       The keyword `typename' is not permitted in a base-specifier or
+       mem-initializer; in these contexts a qualified name that
+       depends on a template-parameter is implicitly assumed to be a
+       type name.
+
+     is to pretend that we have seen the `typename' keyword at this
+     point.  */ 
+  cp_parser_nested_name_specifier_opt (parser,
+                                      /*typename_keyword_p=*/true,
+                                      /*check_dependency_p=*/true,
+                                      /*type_p=*/true);
+  /* If the base class is given by a qualified name, assume that names
+     we see are type names or templates, as appropriate.  */
+  class_scope_p = (parser->scope && TYPE_P (parser->scope));
+  /* Finally, look for the class-name.  */
+  type = cp_parser_class_name (parser, 
+                              class_scope_p,
+                              class_scope_p,
+                              /*type_p=*/true,
+                              /*check_access=*/true,
+                              /*check_dependency_p=*/true,
+                              /*class_head_p=*/false);
+
+  if (type == error_mark_node)
+    return error_mark_node;
+
+  return finish_base_specifier (access_node, TREE_TYPE (type));
+}
+
+/* Exception handling [gram.exception] */
+
+/* Parse an (optional) exception-specification.
+
+   exception-specification:
+     throw ( type-id-list [opt] )
+
+   Returns a TREE_LIST representing the exception-specification.  The
+   TREE_VALUE of each node is a type.  */
+
+static tree
+cp_parser_exception_specification_opt (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree type_id_list;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's not `throw', then there's no exception-specification.  */
+  if (!cp_parser_is_keyword (token, RID_THROW))
+    return NULL_TREE;
+
+  /* Consume the `throw'.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Look for the `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If it's not a `)', then there is a type-id-list.  */
+  if (token->type != CPP_CLOSE_PAREN)
+    {
+      const char *saved_message;
+
+      /* Types may not be defined in an exception-specification.  */
+      saved_message = parser->type_definition_forbidden_message;
+      parser->type_definition_forbidden_message
+       = "types may not be defined in an exception-specification";
+      /* Parse the type-id-list.  */
+      type_id_list = cp_parser_type_id_list (parser);
+      /* Restore the saved message.  */
+      parser->type_definition_forbidden_message = saved_message;
+    }
+  else
+    type_id_list = empty_except_spec;
+
+  /* Look for the `)'.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return type_id_list;
+}
+
+/* Parse an (optional) type-id-list.
+
+   type-id-list:
+     type-id
+     type-id-list , type-id
+
+   Returns a TREE_LIST.  The TREE_VALUE of each node is a TYPE,
+   in the order that the types were presented.  */
+
+static tree
+cp_parser_type_id_list (parser)
+     cp_parser *parser;
+{
+  tree types = NULL_TREE;
+
+  while (true)
+    {
+      cp_token *token;
+      tree type;
+
+      /* Get the next type-id.  */
+      type = cp_parser_type_id (parser);
+      /* Add it to the list.  */
+      types = add_exception_specifier (types, type, /*complain=*/1);
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it is not a `,', we are done.  */
+      if (token->type != CPP_COMMA)
+       break;
+      /* Consume the `,'.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  return nreverse (types);
+}
+
+/* Parse a try-block.
+
+   try-block:
+     try compound-statement handler-seq  */
+
+static tree
+cp_parser_try_block (parser)
+     cp_parser *parser;
+{
+  tree try_block;
+
+  cp_parser_require_keyword (parser, RID_TRY, "`try'");
+  try_block = begin_try_block ();
+  cp_parser_compound_statement (parser);
+  finish_try_block (try_block);
+  cp_parser_handler_seq (parser);
+  finish_handler_sequence (try_block);
+
+  return try_block;
+}
+
+/* Parse a function-try-block.
+
+   function-try-block:
+     try ctor-initializer [opt] function-body handler-seq  */
+
+static bool
+cp_parser_function_try_block (parser)
+     cp_parser *parser;
+{
+  tree try_block;
+  bool ctor_initializer_p;
+
+  /* Look for the `try' keyword.  */
+  if (!cp_parser_require_keyword (parser, RID_TRY, "`try'"))
+    return false;
+  /* Let the rest of the front-end know where we are.  */
+  try_block = begin_function_try_block ();
+  /* Parse the function-body.  */
+  ctor_initializer_p 
+    = cp_parser_ctor_initializer_opt_and_function_body (parser);
+  /* We're done with the `try' part.  */
+  finish_function_try_block (try_block);
+  /* Parse the handlers.  */
+  cp_parser_handler_seq (parser);
+  /* We're done with the handlers.  */
+  finish_function_handler_sequence (try_block);
+
+  return ctor_initializer_p;
+}
+
+/* Parse a handler-seq.
+
+   handler-seq:
+     handler handler-seq [opt]  */
+
+static void
+cp_parser_handler_seq (parser)
+     cp_parser *parser;
+{
+  while (true)
+    {
+      cp_token *token;
+
+      /* Parse the handler.  */
+      cp_parser_handler (parser);
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's not `catch' then there are no more handlers.  */
+      if (!cp_parser_is_keyword (token, RID_CATCH))
+       break;
+    }
+}
+
+/* Parse a handler.
+
+   handler:
+     catch ( exception-declaration ) compound-statement  */
+
+static void
+cp_parser_handler (parser)
+     cp_parser *parser;
+{
+  tree handler;
+  tree declaration;
+
+  cp_parser_require_keyword (parser, RID_CATCH, "`catch'");
+  handler = begin_handler ();
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  declaration = cp_parser_exception_declaration (parser);
+  finish_handler_parms (declaration, handler);
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+  cp_parser_compound_statement (parser);
+  finish_handler (handler);
+}
+
+/* Parse an exception-declaration.
+
+   exception-declaration:
+     type-specifier-seq declarator
+     type-specifier-seq abstract-declarator
+     type-specifier-seq
+     ...  
+
+   Returns a VAR_DECL for the declaration, or NULL_TREE if the
+   ellipsis variant is used.  */
+
+static tree
+cp_parser_exception_declaration (parser)
+     cp_parser *parser;
+{
+  tree type_specifiers;
+  tree declarator;
+  const char *saved_message;
+
+  /* If it's an ellipsis, it's easy to handle.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    {
+      /* Consume the `...' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      return NULL_TREE;
+    }
+
+  /* Types may not be defined in exception-declarations.  */
+  saved_message = parser->type_definition_forbidden_message;
+  parser->type_definition_forbidden_message
+    = "types may not be defined in exception-declarations";
+
+  /* Parse the type-specifier-seq.  */
+  type_specifiers = cp_parser_type_specifier_seq (parser);
+  /* If it's a `)', then there is no declarator.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+    declarator = NULL_TREE;
+  else
+    {
+      /* Otherwise, we can't be sure whether we are looking at a
+        direct, or an abstract, declarator.  */
+      cp_parser_parse_tentatively (parser);
+      /* Try an ordinary declarator.  */
+      declarator = cp_parser_declarator (parser,
+                                        /*abstract_p=*/false,
+                                        /*ctor_dtor_or_conv_p=*/NULL);
+      /* If that didn't work, try an abstract declarator.  */
+      if (!cp_parser_parse_definitely (parser))
+       declarator = cp_parser_declarator (parser,
+                                          /*abstract_p=*/true,
+                                          /*ctor_dtor_or_conv_p=*/NULL);
+    }
+
+  /* Restore the saved message.  */
+  parser->type_definition_forbidden_message = saved_message;
+
+  return start_handler_parms (type_specifiers, declarator);
+}
+
+/* Parse a throw-expression. 
+
+   throw-expression:
+     throw assignment-expresion [opt]
+
+   Returns a THROW_EXPR representing the throw-expression.  */
+
+static tree
+cp_parser_throw_expression (parser)
+     cp_parser *parser;
+{
+  tree expression;
+
+  cp_parser_require_keyword (parser, RID_THROW, "`throw'");
+  /* We can't be sure if there is an assignment-expression or not.  */
+  cp_parser_parse_tentatively (parser);
+  /* Try it.  */
+  expression = cp_parser_assignment_expression (parser);
+  /* If it didn't work, this is just a rethrow.  */
+  if (!cp_parser_parse_definitely (parser))
+    expression = NULL_TREE;
+
+  return build_throw (expression);
+}
+
+/* GNU Extensions */
+
+/* Parse an (optional) asm-specification.
+
+   asm-specification:
+     asm ( string-literal )
+
+   If the asm-specification is present, returns a STRING_CST
+   corresponding to the string-literal.  Otherwise, returns
+   NULL_TREE.  */
+
+static tree
+cp_parser_asm_specification_opt (parser)
+     cp_parser *parser;
+{
+  cp_token *token;
+  tree asm_specification;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If the next token isn't the `asm' keyword, then there's no 
+     asm-specification.  */
+  if (!cp_parser_is_keyword (token, RID_ASM))
+    return NULL_TREE;
+
+  /* Consume the `asm' token.  */
+  cp_lexer_consume_token (parser->lexer);
+  /* Look for the `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+  /* Look for the string-literal.  */
+  token = cp_parser_require (parser, CPP_STRING, "string-literal");
+  if (token)
+    asm_specification = token->value;
+  else
+    asm_specification = NULL_TREE;
+
+  /* Look for the `)'.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`('");
+
+  return asm_specification;
+}
+
+/* Parse an asm-operand-list.  
+
+   asm-operand-list:
+     asm-operand
+     asm-operand-list , asm-operand
+     
+   asm-operand:
+     string-literal ( expression )  
+     [ string-literal ] string-literal ( expression )
+
+   Returns a TREE_LIST representing the operands.  The TREE_VALUE of
+   each node is the expression.  The TREE_PURPOSE is itself a
+   TREE_LIST whose TREE_PURPOSE is a STRING_CST for the bracketed
+   string-literal (or NULL_TREE if not present) and whose TREE_VALUE
+   is a STRING_CST for the string literal before the parenthesis.  */
+
+static tree
+cp_parser_asm_operand_list (parser)
+     cp_parser *parser;
+{
+  tree asm_operands = NULL_TREE;
+
+  while (true)
+    {
+      tree string_literal;
+      tree expression;
+      tree name;
+      cp_token *token;
+      
+      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) 
+       {
+         /* Consume the `[' token.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Read the operand name.  */
+         name = cp_parser_identifier (parser);
+         if (name != error_mark_node) 
+           name = build_string (IDENTIFIER_LENGTH (name),
+                                IDENTIFIER_POINTER (name));
+         /* Look for the closing `]'.  */
+         cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+       }
+      else
+       name = NULL_TREE;
+      /* Look for the string-literal.  */
+      token = cp_parser_require (parser, CPP_STRING, "string-literal");
+      string_literal = token ? token->value : error_mark_node;
+      /* Look for the `('.  */
+      cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+      /* Parse the expression.  */
+      expression = cp_parser_expression (parser);
+      /* Look for the `)'.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+      /* Add this operand to the list.  */
+      asm_operands = tree_cons (build_tree_list (name, string_literal),
+                               expression, 
+                               asm_operands);
+      /* If the next token is not a `,', there are no more 
+        operands.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+      /* Consume the `,'.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  return nreverse (asm_operands);
+}
+
+/* Parse an asm-clobber-list.  
+
+   asm-clobber-list:
+     string-literal
+     asm-clobber-list , string-literal  
+
+   Returns a TREE_LIST, indicating the clobbers in the order that they
+   appeared.  The TREE_VALUE of each node is a STRING_CST.  */
+
+static tree
+cp_parser_asm_clobber_list (parser)
+     cp_parser *parser;
+{
+  tree clobbers = NULL_TREE;
+
+  while (true)
+    {
+      cp_token *token;
+      tree string_literal;
+
+      /* Look for the string literal.  */
+      token = cp_parser_require (parser, CPP_STRING, "string-literal");
+      string_literal = token ? token->value : error_mark_node;
+      /* Add it to the list.  */
+      clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
+      /* If the next token is not a `,', then the list is 
+        complete.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+       break;
+      /* Consume the `,' token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  return clobbers;
+}
+
+/* Parse an (optional) series of attributes.
+
+   attributes:
+     attributes attribute
+
+   attribute:
+     __attribute__ (( attribute-list [opt] ))  
+
+   The return value is as for cp_parser_attribute_list.  */
+     
+static tree
+cp_parser_attributes_opt (parser)
+     cp_parser *parser;
+{
+  tree attributes = NULL_TREE;
+
+  while (true)
+    {
+      cp_token *token;
+      tree attribute_list;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's not `__attribute__', then we're done.  */
+      if (token->keyword != RID_ATTRIBUTE)
+       break;
+
+      /* Consume the `__attribute__' keyword.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the two `(' tokens.  */
+      cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+      cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type != CPP_CLOSE_PAREN)
+       /* Parse the attribute-list.  */
+       attribute_list = cp_parser_attribute_list (parser);
+      else
+       /* If the next token is a `)', then there is no attribute
+          list.  */
+       attribute_list = NULL;
+
+      /* Look for the two `)' tokens.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+      /* Add these new attributes to the list.  */
+      attributes = chainon (attributes, attribute_list);
+    }
+
+  return attributes;
+}
+
+/* Parse an attribute-list.  
+
+   attribute-list:  
+     attribute 
+     attribute-list , attribute
+
+   attribute:
+     identifier     
+     identifier ( identifier )
+     identifier ( identifier , expression-list )
+     identifier ( expression-list ) 
+
+   Returns a TREE_LIST.  Each node corresponds to an attribute.  THe
+   TREE_PURPOSE of each node is the identifier indicating which
+   attribute is in use.  The TREE_VALUE represents the arguments, if
+   any.  */
+
+static tree
+cp_parser_attribute_list (parser)
+     cp_parser *parser;
+{
+  tree attribute_list = NULL_TREE;
+
+  while (true)
+    {
+      cp_token *token;
+      tree identifier;
+      tree attribute;
+
+      /* Look for the identifier.  We also allow keywords here; for
+        example `__attribute__ ((const))' is legal.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type != CPP_NAME 
+         && token->type != CPP_KEYWORD)
+       return error_mark_node;
+      /* Consume the token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+      
+      /* Save away the identifier that indicates which attribute this is.  */
+      identifier = token->value;
+      attribute = build_tree_list (identifier, NULL_TREE);
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If it's an `(', then parse the attribute arguments.  */
+      if (token->type == CPP_OPEN_PAREN)
+       {
+         tree arguments;
+         int arguments_allowed_p = 1;
+
+         /* Consume the `('.  */
+         cp_lexer_consume_token (parser->lexer);
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_token (parser->lexer);
+         /* Check to see if the next token is an identifier.  */
+         if (token->type == CPP_NAME)
+           {
+             /* Save the identifier.  */
+             identifier = token->value;
+             /* Consume the identifier.  */
+             cp_lexer_consume_token (parser->lexer);
+             /* Peek at the next token.  */
+             token = cp_lexer_peek_token (parser->lexer);
+             /* If the next token is a `,', then there are some other
+                expressions as well.  */
+             if (token->type == CPP_COMMA)
+               /* Consume the comma.  */
+               cp_lexer_consume_token (parser->lexer);
+             else
+               arguments_allowed_p = 0;
+           }
+         else
+           identifier = NULL_TREE;
+
+         /* If there are arguments, parse them too.  */
+         if (arguments_allowed_p)
+           arguments = cp_parser_expression_list (parser);
+         else
+           arguments = NULL_TREE;
+
+         /* Combine the identifier and the arguments.  */
+         if (identifier)
+           arguments = tree_cons (NULL_TREE, identifier, arguments);
+
+         /* Save the identifier and arguments away.  */
+         TREE_VALUE (attribute) = arguments;
+
+         /* Look for the closing `)'.  */
+         cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+       }
+
+      /* Add this attribute to the list.  */
+      TREE_CHAIN (attribute) = attribute_list;
+      attribute_list = attribute;
+
+      /* Now, look for more attributes.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If the next token isn't a `,', we're done.  */
+      if (token->type != CPP_COMMA)
+       break;
+
+      /* Consume the commma and keep going.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* We built up the list in reverse order.  */
+  return nreverse (attribute_list);
+}
+
+/* Parse an optional `__extension__' keyword.  Returns TRUE if it is
+   present, and FALSE otherwise.  *SAVED_PEDANTIC is set to the
+   current value of the PEDANTIC flag, regardless of whether or not
+   the `__extension__' keyword is present.  The caller is responsible
+   for restoring the value of the PEDANTIC flag.  */
+
+static bool
+cp_parser_extension_opt (parser, saved_pedantic)
+     cp_parser *parser;
+     int *saved_pedantic;
+{
+  /* Save the old value of the PEDANTIC flag.  */
+  *saved_pedantic = pedantic;
+
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION))
+    {
+      /* Consume the `__extension__' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* We're not being pedantic while the `__extension__' keyword is
+        in effect.  */
+      pedantic = 0;
+
+      return true;
+    }
+
+  return false;
+}
+
+/* Parse a label declaration.
+
+   label-declaration:
+     __label__ label-declarator-seq ;
+
+   label-declarator-seq:
+     identifier , label-declarator-seq
+     identifier  */
+
+static void
+cp_parser_label_declaration (parser)
+     cp_parser *parser;
+{
+  /* Look for the `__label__' keyword.  */
+  cp_parser_require_keyword (parser, RID_LABEL, "`__label__'");
+
+  while (true)
+    {
+      tree identifier;
+
+      /* Look for an identifier.  */
+      identifier = cp_parser_identifier (parser);
+      /* Declare it as a lobel.  */
+      finish_label_decl (identifier);
+      /* If the next token is a `;', stop.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       break;
+      /* Look for the `,' separating the label declarations.  */
+      cp_parser_require (parser, CPP_COMMA, "`,'");
+    }
+
+  /* Look for the final `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+}
+
+/* Support Functions */
+
+/* Looks up NAME in the current scope, as given by PARSER->SCOPE.
+   NAME should have one of the representations used for an
+   id-expression.  If NAME is the ERROR_MARK_NODE, the ERROR_MARK_NODE
+   is returned.  If PARSER->SCOPE is a dependent type, then a
+   SCOPE_REF is returned.
+
+   If NAME is a TEMPLATE_ID_EXPR, then it will be immediately
+   returned; the name was already resolved when the TEMPLATE_ID_EXPR
+   was formed.  Abstractly, such entities should not be passed to this
+   function, because they do not need to be looked up, but it is
+   simpler to check for this special case here, rather than at the
+   call-sites.
+
+   In cases not explicitly covered above, this function returns a
+   DECL, OVERLOAD, or baselink representing the result of the lookup.
+   If there was no entity with the indicated NAME, the ERROR_MARK_NODE
+   is returned.
+
+   If CHECK_ACCESS is TRUE, then access control is performed on the
+   declaration to which the name resolves, and an error message is
+   issued if the declaration is inaccessible.
+
+   If IS_TYPE is TRUE, bindings that do not refer to types are
+   ignored.
+
+   If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent
+   types.  */
+
+static tree
+cp_parser_lookup_name (parser, name, check_access, is_type, 
+                      check_dependency)
+     cp_parser *parser;
+     tree name;
+     bool check_access;
+     bool is_type;
+     bool check_dependency;
+{
+  tree decl;
+  tree object_type = parser->context->object_type;
+
+  /* Now that we have looked up the name, the OBJECT_TYPE (if any) is
+     no longer valid.  Note that if we are parsing tentatively, and
+     the parse fails, OBJECT_TYPE will be automatically restored.  */
+  parser->context->object_type = NULL_TREE;
+
+  if (name == error_mark_node)
+    return error_mark_node;
+
+  /* A template-id has already been resolved; there is no lookup to
+     do.  */
+  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+    return name;
+  if (BASELINK_P (name))
+    {
+      my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name))
+                          == TEMPLATE_ID_EXPR),
+                         20020909);
+      return name;
+    }
+
+  /* A BIT_NOT_EXPR is used to represent a destructor.  By this point,
+     it should already have been checked to make sure that the name
+     used matches the type being destroyed.  */
+  if (TREE_CODE (name) == BIT_NOT_EXPR)
+    {
+      tree type;
+
+      /* Figure out to which type this destructor applies.  */
+      if (parser->scope)
+       type = parser->scope;
+      else if (object_type)
+       type = object_type;
+      else
+       type = current_class_type;
+      /* If that's not a class type, there is no destructor.  */
+      if (!type || !CLASS_TYPE_P (type))
+       return error_mark_node;
+      /* If it was a class type, return the destructor.  */
+      return CLASSTYPE_DESTRUCTORS (type);
+    }
+
+  /* By this point, the NAME should be an ordinary identifier.  If
+     the id-expression was a qualified name, the qualifying scope is
+     stored in PARSER->SCOPE at this point.  */
+  my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
+                     20000619);
+  
+  /* Perform the lookup.  */
+  if (parser->scope)
+    { 
+      bool dependent_type_p;
+
+      if (parser->scope == error_mark_node)
+       return error_mark_node;
+
+      /* If the SCOPE is dependent, the lookup must be deferred until
+        the template is instantiated -- unless we are explicitly
+        looking up names in uninstantiated templates.  Even then, we
+        cannot look up the name if the scope is not a class type; it
+        might, for example, be a template type parameter.  */
+      dependent_type_p = (TYPE_P (parser->scope)
+                         && !(parser->in_declarator_p
+                              && currently_open_class (parser->scope))
+                         && cp_parser_dependent_type_p (parser->scope));
+      if ((check_dependency || !CLASS_TYPE_P (parser->scope))
+          && dependent_type_p)
+       {
+         if (!is_type)
+           decl = build_nt (SCOPE_REF, parser->scope, name);
+         else
+           /* The resolution to Core Issue 180 says that `struct A::B'
+              should be considered a type-name, even if `A' is
+              dependent.  */
+           decl = TYPE_NAME (make_typename_type (parser->scope,
+                                                 name,
+                                                 /*complain=*/1));
+       }
+      else
+       {
+         /* If PARSER->SCOPE is a dependent type, then it must be a
+            class type, and we must not be checking dependencies;
+            otherwise, we would have processed this lookup above.  So
+            that PARSER->SCOPE is not considered a dependent base by
+            lookup_member, we must enter the scope here.  */
+         if (dependent_type_p)
+           push_scope (parser->scope);
+         /* If the PARSER->SCOPE is a a template specialization, it
+            may be instantiated during name lookup.  In that case,
+            errors may be issued.  Even if we rollback the current
+            tentative parse, those errors are valid.  */
+         decl = lookup_qualified_name (parser->scope, name, is_type,
+                                       /*flags=*/0);
+         if (dependent_type_p)
+           pop_scope (parser->scope);
+       }
+      parser->qualifying_scope = parser->scope;
+      parser->object_scope = NULL_TREE;
+    }
+  else if (object_type)
+    {
+      tree object_decl = NULL_TREE;
+      /* Look up the name in the scope of the OBJECT_TYPE, unless the
+        OBJECT_TYPE is not a class.  */
+      if (CLASS_TYPE_P (object_type))
+       /* If the OBJECT_TYPE is a template specialization, it may
+          be instantiated during name lookup.  In that case, errors
+          may be issued.  Even if we rollback the current tentative
+          parse, those errors are valid.  */
+       object_decl = lookup_member (object_type,
+                                    name,
+                                    /*protect=*/0, is_type);
+      /* Look it up in the enclosing context, too.  */
+      decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
+                              /*namespaces_only=*/0, 
+                              /*flags=*/0);
+      parser->object_scope = object_type;
+      parser->qualifying_scope = NULL_TREE;
+      if (object_decl)
+       decl = object_decl;
+    }
+  else
+    {
+      decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
+                              /*namespaces_only=*/0, 
+                              /*flags=*/0);
+      parser->qualifying_scope = NULL_TREE;
+      parser->object_scope = NULL_TREE;
+    }
+
+  /* If the lookup failed, let our caller know.  */
+  if (!decl 
+      || decl == error_mark_node
+      || (TREE_CODE (decl) == FUNCTION_DECL 
+         && DECL_ANTICIPATED (decl)))
+    return error_mark_node;
+
+  /* If it's a TREE_LIST, the result of the lookup was ambiguous.  */
+  if (TREE_CODE (decl) == TREE_LIST)
+    {
+      /* The error message we have to print is too complicated for
+        cp_parser_error, so we incorporate its actions directly.  */
+      cp_parser_simulate_error (parser);
+      if (!cp_parser_parsing_tentatively (parser)
+         || cp_parser_committed_to_tentative_parse (parser))
+       {
+         error ("reference to `%D' is ambiguous", name);
+         print_candidates (decl);
+       }
+      return error_mark_node;
+    }
+
+  my_friendly_assert (DECL_P (decl) 
+                     || TREE_CODE (decl) == OVERLOAD
+                     || TREE_CODE (decl) == SCOPE_REF
+                     || BASELINK_P (decl),
+                     20000619);
+
+  /* If we have resolved the name of a member declaration, check to
+     see if the declaration is accessible.  When the name resolves to
+     set of overloaded functions, accesibility is checked when
+     overload resolution is done.  
+
+     During an explicit instantiation, access is not checked at all,
+     as per [temp.explicit].  */
+  if (check_access && scope_chain->check_access && DECL_P (decl))
+    {
+      tree qualifying_type;
+      
+      /* Figure out the type through which DECL is being
+        accessed.  */
+      qualifying_type 
+       = cp_parser_scope_through_which_access_occurs (decl,
+                                                      object_type,
+                                                      parser->scope);
+      if (qualifying_type)
+       {
+         /* If we are supposed to defer access checks, just record
+            the information for later.  */
+         if (parser->context->deferring_access_checks_p)
+           cp_parser_defer_access_check (parser, qualifying_type, decl);
+         /* Otherwise, check accessibility now.  */
+         else
+           enforce_access (qualifying_type, decl);
+       }
+    }
+
+  return decl;
+}
+
+/* Like cp_parser_lookup_name, but for use in the typical case where
+   CHECK_ACCESS is TRUE, IS_TYPE is FALSE, and CHECK_DEPENDENCY is
+   TRUE.  */
+
+static tree
+cp_parser_lookup_name_simple (parser, name)
+     cp_parser *parser;
+     tree name;
+{
+  return cp_parser_lookup_name (parser, name, 
+                               /*check_access=*/true,
+                               /*is_type=*/false, 
+                               /*check_dependency=*/true);
+}
+
+/* TYPE is a TYPENAME_TYPE.  Returns the ordinary TYPE to which the
+   TYPENAME_TYPE corresponds.  Note that this function peers inside
+   uninstantiated templates and therefore should be used only in
+   extremely limited situations.  */
+
+static tree
+cp_parser_resolve_typename_type (parser, type)
+     cp_parser *parser;
+     tree type;
+{
+  tree scope;
+  tree name;
+  tree decl;
+
+  my_friendly_assert (TREE_CODE (type) == TYPENAME_TYPE,
+                     20010702);
+
+  scope = TYPE_CONTEXT (type);
+  name = DECL_NAME (TYPE_NAME (type));
+
+  /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
+     it first before we can figure out what NAME refers to.  */
+  if (TREE_CODE (scope) == TYPENAME_TYPE)
+    scope = cp_parser_resolve_typename_type (parser, scope);
+  /* If we don't know what SCOPE refers to, then we cannot resolve the
+     TYPENAME_TYPE.  */
+  if (scope == error_mark_node)
+    return error_mark_node;
+  /* If the SCOPE is a template type parameter, we have no way of
+     resolving the name.  */
+  if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM)
+    return type;
+  /* Enter the SCOPE so that name lookup will be resolved as if we
+     were in the class definition.  In particular, SCOPE will no
+     longer be considered a dependent type.  */
+  push_scope (scope);
+  /* Look up the declaration.  */
+  decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/1);
+  /* If all went well, we got a TYPE_DECL for a non-typename.  */
+  if (!decl 
+      || TREE_CODE (decl) != TYPE_DECL 
+      || TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+    {
+      cp_parser_error (parser, "could not resolve typename type");
+      type = error_mark_node;
+    }
+  else
+    type = TREE_TYPE (decl);
+  /* Leave the SCOPE.  */
+  pop_scope (scope);
+
+  return type;
+}
+
+/* If DECL is a TEMPLATE_DECL that can be treated like a TYPE_DECL in
+   the current context, return the TYPE_DECL.  If TAG_NAME_P is
+   true, the DECL indicates the class being defined in a class-head,
+   or declared in an elaborated-type-specifier.
+
+   Otherwise, return DECL.  */
+
+static tree
+cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p)
+{
+  /* If the DECL is a TEMPLATE_DECL for a class type, and we are in
+     the scope of the class, then treat the TEMPLATE_DECL as a
+     class-name.  For example, in:
+
+       template <class T> struct S {
+         S s;
+       };
+
+     is OK.  
+
+     If the TEMPLATE_DECL is being declared as part of a class-head,
+     the same translation occurs:
+
+       struct A { 
+         template <typename T> struct B;
+       };
+
+       template <typename T> struct A::B {}; 
+   
+     Similarly, in a elaborated-type-specifier:
+
+       namespace N { struct X{}; }
+
+       struct A {
+         template <typename T> friend struct N::X;
+       };
+
+     */
+  if (DECL_CLASS_TEMPLATE_P (decl)
+      && (tag_name_p
+         || (current_class_type
+             && same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (decl)),
+                             current_class_type))))
+    return DECL_TEMPLATE_RESULT (decl);
+
+  return decl;
+}
+
+/* If too many, or too few, template-parameter lists apply to the
+   declarator, issue an error message.  Returns TRUE if all went well,
+   and FALSE otherwise.  */
+
+static bool
+cp_parser_check_declarator_template_parameters (parser, declarator)
+     cp_parser *parser;
+     tree declarator;
+{
+  unsigned num_templates;
+
+  /* We haven't seen any classes that involve template parameters yet.  */
+  num_templates = 0;
+
+  switch (TREE_CODE (declarator))
+    {
+    case CALL_EXPR:
+    case ARRAY_REF:
+    case INDIRECT_REF:
+    case ADDR_EXPR:
+      {
+       tree main_declarator = TREE_OPERAND (declarator, 0);
+       return
+         cp_parser_check_declarator_template_parameters (parser, 
+                                                         main_declarator);
+      }
+
+    case SCOPE_REF:
+      {
+       tree scope;
+       tree member;
+
+       scope = TREE_OPERAND (declarator, 0);
+       member = TREE_OPERAND (declarator, 1);
+
+       /* If this is a pointer-to-member, then we are not interested
+          in the SCOPE, because it does not qualify the thing that is
+          being declared.  */
+       if (TREE_CODE (member) == INDIRECT_REF)
+         return (cp_parser_check_declarator_template_parameters
+                 (parser, member));
+
+       while (scope && CLASS_TYPE_P (scope))
+         {
+           /* You're supposed to have one `template <...>'
+              for every template class, but you don't need one
+              for a full specialization.  For example:
+              
+              template <class T> struct S{};
+              template <> struct S<int> { void f(); };
+              void S<int>::f () {}
+              
+              is correct; there shouldn't be a `template <>' for
+              the definition of `S<int>::f'.  */
+           if (CLASSTYPE_TEMPLATE_INFO (scope)
+               && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope)
+                   || uses_template_parms (CLASSTYPE_TI_ARGS (scope)))
+               && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
+             ++num_templates;
+
+           scope = TYPE_CONTEXT (scope);
+         }
+      }
+
+      /* Fall through.  */
+
+    default:
+      /* If the DECLARATOR has the form `X<y>' then it uses one
+        additional level of template parameters.  */
+      if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+       ++num_templates;
+
+      return cp_parser_check_template_parameters (parser, 
+                                                 num_templates);
+    }
+}
+
+/* NUM_TEMPLATES were used in the current declaration.  If that is
+   invalid, return FALSE and issue an error messages.  Otherwise,
+   return TRUE.  */
+
+static bool
+cp_parser_check_template_parameters (parser, num_templates)
+     cp_parser *parser;
+     unsigned num_templates;
+{
+  /* If there are more template classes than parameter lists, we have
+     something like:
+     
+       template <class T> void S<T>::R<T>::f ();  */
+  if (parser->num_template_parameter_lists < num_templates)
+    {
+      error ("too few template-parameter-lists");
+      return false;
+    }
+  /* If there are the same number of template classes and parameter
+     lists, that's OK.  */
+  if (parser->num_template_parameter_lists == num_templates)
+    return true;
+  /* If there are more, but only one more, then we are referring to a
+     member template.  That's OK too.  */
+  if (parser->num_template_parameter_lists == num_templates + 1)
+      return true;
+  /* Otherwise, there are too many template parameter lists.  We have
+     something like:
+
+     template <class T> template <class U> void S::f();  */
+  error ("too many template-parameter-lists");
+  return false;
+}
+
+/* Parse a binary-expression of the general form:
+
+   binary-expression:
+     <expr>
+     binary-expression <token> <expr>
+
+   The TOKEN_TREE_MAP maps <token> types to <expr> codes.  FN is used
+   to parser the <expr>s.  If the first production is used, then the
+   value returned by FN is returned directly.  Otherwise, a node with
+   the indicated EXPR_TYPE is returned, with operands corresponding to
+   the two sub-expressions.  */
+
+static tree
+cp_parser_binary_expression (parser, token_tree_map, fn)
+     cp_parser *parser;
+     cp_parser_token_tree_map token_tree_map;
+     cp_parser_expression_fn fn;
+{
+  tree lhs;
+
+  /* Parse the first expression.  */
+  lhs = (*fn) (parser);
+  /* Now, look for more expressions.  */
+  while (true)
+    {
+      cp_token *token;
+      cp_parser_token_tree_map_node *map_node;
+      tree rhs;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If the token is `>', and that's not an operator at the
+        moment, then we're done.  */
+      if (token->type == CPP_GREATER
+         && !parser->greater_than_is_operator_p)
+       break;
+      /* If we find one of the tokens we want, build the correspoding
+        tree representation.  */
+      for (map_node = token_tree_map; 
+          map_node->token_type != CPP_EOF;
+          ++map_node)
+       if (map_node->token_type == token->type)
+         {
+           /* Consume the operator token.  */
+           cp_lexer_consume_token (parser->lexer);
+           /* Parse the right-hand side of the expression.  */
+           rhs = (*fn) (parser);
+           /* Build the binary tree node.  */
+           lhs = build_x_binary_op (map_node->tree_type, lhs, rhs);
+           break;
+         }
+
+      /* If the token wasn't one of the ones we want, we're done.  */
+      if (map_node->token_type == CPP_EOF)
+       break;
+    }
+
+  return lhs;
+}
+
+/* Parse an optional `::' token indicating that the following name is
+   from the global namespace.  If so, PARSER->SCOPE is set to the
+   GLOBAL_NAMESPACE. Otherwise, PARSER->SCOPE is set to NULL_TREE,
+   unless CURRENT_SCOPE_VALID_P is TRUE, in which case it is left alone.
+   Returns the new value of PARSER->SCOPE, if the `::' token is
+   present, and NULL_TREE otherwise.  */
+
+static tree
+cp_parser_global_scope_opt (parser, current_scope_valid_p)
+     cp_parser *parser;
+     bool current_scope_valid_p;
+{
+  cp_token *token;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  /* If we're looking at a `::' token then we're starting from the
+     global namespace, not our current location.  */
+  if (token->type == CPP_SCOPE)
+    {
+      /* Consume the `::' token.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Set the SCOPE so that we know where to start the lookup.  */
+      parser->scope = global_namespace;
+      parser->qualifying_scope = global_namespace;
+      parser->object_scope = NULL_TREE;
+
+      return parser->scope;
+    }
+  else if (!current_scope_valid_p)
+    {
+      parser->scope = NULL_TREE;
+      parser->qualifying_scope = NULL_TREE;
+      parser->object_scope = NULL_TREE;
+    }
+
+  return NULL_TREE;
+}
+
+/* Returns TRUE if the upcoming token sequence is the start of a
+   constructor declarator.  If FRIEND_P is true, the declarator is
+   preceded by the `friend' specifier.  */
+
+static bool
+cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
+{
+  bool constructor_p;
+  tree type_decl = NULL_TREE;
+  bool nested_name_p;
+
+  /* Parse tentatively; we are going to roll back all of the tokens
+     consumed here.  */
+  cp_parser_parse_tentatively (parser);
+  /* Assume that we are looking at a constructor declarator.  */
+  constructor_p = true;
+  /* Look for the optional `::' operator.  */
+  cp_parser_global_scope_opt (parser,
+                             /*current_scope_valid_p=*/false);
+  /* Look for the nested-name-specifier.  */
+  nested_name_p 
+    = (cp_parser_nested_name_specifier_opt (parser,
+                                           /*typename_keyword_p=*/false,
+                                           /*check_dependency_p=*/false,
+                                           /*type_p=*/false)
+       != NULL_TREE);
+  /* Outside of a class-specifier, there must be a
+     nested-name-specifier.  */
+  if (!nested_name_p && 
+      (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
+       || friend_p))
+    constructor_p = false;
+  /* If we still think that this might be a constructor-declarator,
+     look for a class-name.  */
+  if (constructor_p)
+    {
+      /* If we have:
+
+          template <typename T> struct S { S(); }
+          template <typename T> S<T>::S ();
+
+        we must recognize that the nested `S' names a class.
+        Similarly, for:
+
+          template <typename T> S<T>::S<T> ();
+
+        we must recognize that the nested `S' names a template.  */
+      type_decl = cp_parser_class_name (parser,
+                                       /*typename_keyword_p=*/false,
+                                       /*template_keyword_p=*/false,
+                                       /*type_p=*/false,
+                                       /*check_access_p=*/false,
+                                       /*check_dependency_p=*/false,
+                                       /*class_head_p=*/false);
+      /* If there was no class-name, then this is not a constructor.  */
+      constructor_p = !cp_parser_error_occurred (parser);
+    }
+  /* If we're still considering a constructor, we have to see a `(',
+     to begin the parameter-declaration-clause, followed by either a
+     `)', an `...', or a decl-specifier.  We need to check for a
+     type-specifier to avoid being fooled into thinking that:
+
+       S::S (f) (int);
+
+     is a constructor.  (It is actually a function named `f' that
+     takes one parameter (of type `int') and returns a value of type
+     `S::S'.  */
+  if (constructor_p 
+      && cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+    {
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS)
+         && !cp_parser_storage_class_specifier_opt (parser))
+       {
+         if (current_class_type 
+             && !same_type_p (current_class_type, TREE_TYPE (type_decl)))
+           /* The constructor for one class cannot be declared inside
+              another.  */
+           constructor_p = false;
+         else
+           {
+             tree type;
+
+             /* Names appearing in the type-specifier should be looked up
+                in the scope of the class.  */
+             if (current_class_type)
+               type = NULL_TREE;
+             else
+               {
+                 type = TREE_TYPE (type_decl);
+                 if (TREE_CODE (type) == TYPENAME_TYPE)
+                   type = cp_parser_resolve_typename_type (parser, type);
+                 push_scope (type);
+               }
+             /* Look for the type-specifier.  */
+             cp_parser_type_specifier (parser,
+                                       CP_PARSER_FLAGS_NONE,
+                                       /*is_friend=*/false,
+                                       /*is_declarator=*/true,
+                                       /*declares_class_or_enum=*/NULL,
+                                       /*is_cv_qualifier=*/NULL);
+             /* Leave the scope of the class.  */
+             if (type)
+               pop_scope (type);
+
+             constructor_p = !cp_parser_error_occurred (parser);
+           }
+       }
+    }
+  else
+    constructor_p = false;
+  /* We did not really want to consume any tokens.  */
+  cp_parser_abort_tentative_parse (parser);
+
+  return constructor_p;
+}
+
+/* Parse the definition of the function given by the DECL_SPECIFIERS,
+   ATTRIBUTES, and DECLARATOR.  The ACCESS_CHECKS have been deferred;
+   they must be performed once we are in the scope of the function.
+
+   Returns the function defined.  */
+
+static tree
+cp_parser_function_definition_from_specifiers_and_declarator
+  (parser, decl_specifiers, attributes, declarator, access_checks)
+     cp_parser *parser;
+     tree decl_specifiers;
+     tree attributes;
+     tree declarator;
+     tree access_checks;
+{
+  tree fn;
+  bool success_p;
+
+  /* Begin the function-definition.  */
+  success_p = begin_function_definition (decl_specifiers, 
+                                        attributes, 
+                                        declarator);
+
+  /* If there were names looked up in the decl-specifier-seq that we
+     did not check, check them now.  We must wait until we are in the
+     scope of the function to perform the checks, since the function
+     might be a friend.  */
+  cp_parser_perform_deferred_access_checks (access_checks);
+
+  if (!success_p)
+    {
+      /* If begin_function_definition didn't like the definition, skip
+        the entire function.  */
+      error ("invalid function declaration");
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      fn = error_mark_node;
+    }
+  else
+    fn = cp_parser_function_definition_after_declarator (parser,
+                                                        /*inline_p=*/false);
+
+  return fn;
+}
+
+/* Parse the part of a function-definition that follows the
+   declarator.  INLINE_P is TRUE iff this function is an inline
+   function defined with a class-specifier.
+
+   Returns the function defined.  */
+
+static tree 
+cp_parser_function_definition_after_declarator (parser, 
+                                               inline_p)
+     cp_parser *parser;
+     bool inline_p;
+{
+  tree fn;
+  bool ctor_initializer_p = false;
+  bool saved_in_unbraced_linkage_specification_p;
+  unsigned saved_num_template_parameter_lists;
+
+  /* If the next token is `return', then the code may be trying to
+     make use of the "named return value" extension that G++ used to
+     support.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_RETURN))
+    {
+      /* Consume the `return' keyword.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the identifier that indicates what value is to be
+        returned.  */
+      cp_parser_identifier (parser);
+      /* Issue an error message.  */
+      error ("named return values are no longer supported");
+      /* Skip tokens until we reach the start of the function body.  */
+      while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+       cp_lexer_consume_token (parser->lexer);
+    }
+  /* The `extern' in `extern "C" void f () { ... }' does not apply to
+     anything declared inside `f'.  */
+  saved_in_unbraced_linkage_specification_p 
+    = parser->in_unbraced_linkage_specification_p;
+  parser->in_unbraced_linkage_specification_p = false;
+  /* Inside the function, surrounding template-parameter-lists do not
+     apply.  */
+  saved_num_template_parameter_lists 
+    = parser->num_template_parameter_lists; 
+  parser->num_template_parameter_lists = 0;
+  /* If the next token is `try', then we are looking at a
+     function-try-block.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
+    ctor_initializer_p = cp_parser_function_try_block (parser);
+  /* A function-try-block includes the function-body, so we only do
+     this next part if we're not processing a function-try-block.  */
+  else
+    ctor_initializer_p 
+      = cp_parser_ctor_initializer_opt_and_function_body (parser);
+
+  /* Finish the function.  */
+  fn = finish_function ((ctor_initializer_p ? 1 : 0) | 
+                       (inline_p ? 2 : 0));
+  /* Generate code for it, if necessary.  */
+  expand_body (fn);
+  /* Restore the saved values.  */
+  parser->in_unbraced_linkage_specification_p 
+    = saved_in_unbraced_linkage_specification_p;
+  parser->num_template_parameter_lists 
+    = saved_num_template_parameter_lists;
+
+  return fn;
+}
+
+/* Parse a template-declaration, assuming that the `export' (and
+   `extern') keywords, if present, has already been scanned.  MEMBER_P
+   is as for cp_parser_template_declaration.  */
+
+static void
+cp_parser_template_declaration_after_export (parser, member_p)
+     cp_parser *parser;
+     bool member_p;
+{
+  tree decl = NULL_TREE;
+  tree parameter_list;
+  bool friend_p = false;
+
+  /* Look for the `template' keyword.  */
+  if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))
+    return;
+      
+  /* And the `<'.  */
+  if (!cp_parser_require (parser, CPP_LESS, "`<'"))
+    return;
+      
+  /* Parse the template parameters.  */
+  begin_template_parm_list ();
+  /* If the next token is `>', then we have an invalid
+     specialization.  Rather than complain about an invalid template
+     parameter, issue an error message here.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
+    {
+      cp_parser_error (parser, "invalid explicit specialization");
+      parameter_list = NULL_TREE;
+    }
+  else
+    parameter_list = cp_parser_template_parameter_list (parser);
+  parameter_list = end_template_parm_list (parameter_list);
+  /* Look for the `>'.  */
+  cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
+  /* We just processed one more parameter list.  */
+  ++parser->num_template_parameter_lists;
+  /* If the next token is `template', there are more template
+     parameters.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, 
+                                     RID_TEMPLATE))
+    cp_parser_template_declaration_after_export (parser, member_p);
+  else
+    {
+      decl = cp_parser_single_declaration (parser,
+                                          member_p,
+                                          &friend_p);
+
+      /* If this is a member template declaration, let the front
+        end know.  */
+      if (member_p && !friend_p && decl)
+       decl = finish_member_template_decl (decl);
+      else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
+       make_friend_class (current_class_type, TREE_TYPE (decl));
+    }
+  /* We are done with the current parameter list.  */
+  --parser->num_template_parameter_lists;
+
+  /* Finish up.  */
+  finish_template_decl (parameter_list);
+
+  /* Register member declarations.  */
+  if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
+    finish_member_declaration (decl);
+
+  /* If DECL is a function template, we must return to parse it later.
+     (Even though there is no definition, there might be default
+     arguments that need handling.)  */
+  if (member_p && decl 
+      && (TREE_CODE (decl) == FUNCTION_DECL
+         || DECL_FUNCTION_TEMPLATE_P (decl)))
+    TREE_VALUE (parser->unparsed_functions_queues)
+      = tree_cons (current_class_type, decl, 
+                  TREE_VALUE (parser->unparsed_functions_queues));
+}
+
+/* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or
+   `function-definition' sequence.  MEMBER_P is true, this declaration
+   appears in a class scope.
+
+   Returns the DECL for the declared entity.  If FRIEND_P is non-NULL,
+   *FRIEND_P is set to TRUE iff the declaration is a friend.  */
+
+static tree
+cp_parser_single_declaration (parser, 
+                             member_p,
+                             friend_p)
+     cp_parser *parser;
+     bool member_p;
+     bool *friend_p;
+{
+  bool declares_class_or_enum;
+  tree decl = NULL_TREE;
+  tree decl_specifiers;
+  tree attributes;
+  tree access_checks;
+
+  /* Parse the dependent declaration.  We don't know yet
+     whether it will be a function-definition.  */
+  cp_parser_parse_tentatively (parser);
+  /* Defer access checks until we know what is being declared.  */
+  cp_parser_start_deferring_access_checks (parser);
+  /* Try the `decl-specifier-seq [opt] init-declarator [opt]'
+     alternative.  */
+  decl_specifiers 
+    = cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &attributes,
+                                   &declares_class_or_enum);
+  /* Gather up the access checks that occurred the
+     decl-specifier-seq.  */
+  access_checks = cp_parser_stop_deferring_access_checks (parser);
+  /* Check for the declaration of a template class.  */
+  if (declares_class_or_enum)
+    {
+      if (cp_parser_declares_only_class_p (parser))
+       {
+         decl = shadow_tag (decl_specifiers);
+         if (decl)
+           decl = TYPE_NAME (decl);
+         else
+           decl = error_mark_node;
+       }
+    }
+  else
+    decl = NULL_TREE;
+  /* If it's not a template class, try for a template function.  If
+     the next token is a `;', then this declaration does not declare
+     anything.  But, if there were errors in the decl-specifiers, then
+     the error might well have come from an attempted class-specifier.
+     In that case, there's no need to warn about a missing declarator.  */
+  if (!decl
+      && (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
+         || !value_member (error_mark_node, decl_specifiers)))
+    decl = cp_parser_init_declarator (parser, 
+                                     decl_specifiers,
+                                     attributes,
+                                     access_checks,
+                                     /*function_definition_allowed_p=*/false,
+                                     member_p,
+                                     /*function_definition_p=*/NULL);
+  /* Clear any current qualification; whatever comes next is the start
+     of something new.  */
+  parser->scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+  /* Look for a trailing `;' after the declaration.  */
+  if (!cp_parser_require (parser, CPP_SEMICOLON, "expected `;'")
+      && cp_parser_committed_to_tentative_parse (parser))
+    cp_parser_skip_to_end_of_block_or_statement (parser);
+  /* If it worked, set *FRIEND_P based on the DECL_SPECIFIERS.  */
+  if (cp_parser_parse_definitely (parser))
+    {
+      if (friend_p)
+       *friend_p = cp_parser_friend_p (decl_specifiers);
+    }
+  /* Otherwise, try a function-definition.  */
+  else
+    decl = cp_parser_function_definition (parser, friend_p);
+
+  return decl;
+}
+
+/* Parse a functional cast to TYPE.  Returns an expression
+   representing the cast.  */
+
+static tree
+cp_parser_functional_cast (parser, type)
+     cp_parser *parser;
+     tree type;
+{
+  tree expression_list;
+
+  /* Look for the opening `('.  */
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+    return error_mark_node;
+  /* If the next token is not an `)', there are arguments to the
+     cast.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+    expression_list = cp_parser_expression_list (parser);
+  else
+    expression_list = NULL_TREE;
+  /* Look for the closing `)'.  */
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return build_functional_cast (type, expression_list);
+}
+
+/* MEMBER_FUNCTION is a member function, or a friend.  If default
+   arguments, or the body of the function have not yet been parsed,
+   parse them now.  */
+
+static void
+cp_parser_late_parsing_for_member (parser, member_function)
+     cp_parser *parser;
+     tree member_function;
+{
+  cp_lexer *saved_lexer;
+
+  /* If this member is a template, get the underlying
+     FUNCTION_DECL.  */
+  if (DECL_FUNCTION_TEMPLATE_P (member_function))
+    member_function = DECL_TEMPLATE_RESULT (member_function);
+
+  /* There should not be any class definitions in progress at this
+     point; the bodies of members are only parsed outside of all class
+     definitions.  */
+  my_friendly_assert (parser->num_classes_being_defined == 0, 20010816);
+  /* While we're parsing the member functions we might encounter more
+     classes.  We want to handle them right away, but we don't want
+     them getting mixed up with functions that are currently in the
+     queue.  */
+  parser->unparsed_functions_queues
+    = tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
+
+  /* Make sure that any template parameters are in scope.  */
+  maybe_begin_member_template_processing (member_function);
+
+  /* If there are default arguments that have not yet been processed,
+     take care of them now.  */
+  if (DECL_FUNCTION_MEMBER_P (member_function))
+    push_nested_class (DECL_CONTEXT (member_function), 1);
+  cp_parser_late_parsing_default_args (parser, TREE_TYPE (member_function));
+  if (DECL_FUNCTION_MEMBER_P (member_function))
+    pop_nested_class ();
+
+  /* If the body of the function has not yet been parsed, parse it
+     now.  */
+  if (DECL_PENDING_INLINE_P (member_function))
+    {
+      tree function_scope;
+      cp_token_cache *tokens;
+
+      /* The function is no longer pending; we are processing it.  */
+      tokens = DECL_PENDING_INLINE_INFO (member_function);
+      DECL_PENDING_INLINE_INFO (member_function) = NULL;
+      DECL_PENDING_INLINE_P (member_function) = 0;
+      /* If this was an inline function in a local class, enter the scope
+        of the containing function.  */
+      function_scope = decl_function_context (member_function);
+      if (function_scope)
+       push_function_context_to (function_scope);
+      
+      /* Save away the current lexer.  */
+      saved_lexer = parser->lexer;
+      /* Make a new lexer to feed us the tokens saved for this function.  */
+      parser->lexer = cp_lexer_new_from_tokens (tokens);
+      parser->lexer->next = saved_lexer;
+      
+      /* Set the current source position to be the location of the first
+        token in the saved inline body.  */
+      cp_lexer_set_source_position_from_token 
+       (parser->lexer,
+        cp_lexer_peek_token (parser->lexer));
+      
+      /* Let the front end know that we going to be defining this
+        function.  */
+      start_function (NULL_TREE, member_function, NULL_TREE,
+                     SF_PRE_PARSED | SF_INCLASS_INLINE);
+      
+      /* Now, parse the body of the function.  */
+      cp_parser_function_definition_after_declarator (parser,
+                                                     /*inline_p=*/true);
+      
+      /* Leave the scope of the containing function.  */
+      if (function_scope)
+       pop_function_context_from (function_scope);
+      /* Restore the lexer.  */
+      parser->lexer = saved_lexer;
+    }
+
+  /* Remove any template parameters from the symbol table.  */
+  maybe_end_member_template_processing ();
+
+  /* Restore the queue.  */
+  parser->unparsed_functions_queues 
+    = TREE_CHAIN (parser->unparsed_functions_queues);
+}
+
+/* TYPE is a FUNCTION_TYPE or METHOD_TYPE which contains a parameter
+   with an unparsed DEFAULT_ARG.  Parse those default args now.  */
+
+static void
+cp_parser_late_parsing_default_args (parser, type)
+     cp_parser *parser;
+     tree type;
+{
+  cp_lexer *saved_lexer;
+  cp_token_cache *tokens;
+  bool saved_local_variables_forbidden_p;
+  tree parameters;
+  
+  for (parameters = TYPE_ARG_TYPES (type);
+       parameters;
+       parameters = TREE_CHAIN (parameters))
+    {
+      if (!TREE_PURPOSE (parameters)
+         || TREE_CODE (TREE_PURPOSE (parameters)) != DEFAULT_ARG)
+       continue;
+  
+       /* Save away the current lexer.  */
+      saved_lexer = parser->lexer;
+       /* Create a new one, using the tokens we have saved.  */
+      tokens =  DEFARG_TOKENS (TREE_PURPOSE (parameters));
+      parser->lexer = cp_lexer_new_from_tokens (tokens);
+
+       /* Set the current source position to be the location of the
+         first token in the default argument.  */
+      cp_lexer_set_source_position_from_token 
+       (parser->lexer, cp_lexer_peek_token (parser->lexer));
+
+       /* Local variable names (and the `this' keyword) may not appear
+         in a default argument.  */
+      saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
+      parser->local_variables_forbidden_p = true;
+       /* Parse the assignment-expression.  */
+      TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser);
+
+       /* Restore saved state.  */
+      parser->lexer = saved_lexer;
+      parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
+    }
+}
+
+/* Parse the operand of `sizeof' (or a similar operator).  Returns
+   either a TYPE or an expression, depending on the form of the
+   input.  The KEYWORD indicates which kind of expression we have
+   encountered.  */
+
+static tree
+cp_parser_sizeof_operand (parser, keyword)
+     cp_parser *parser;
+     enum rid keyword;
+{
+  static const char *format;
+  tree expr = NULL_TREE;
+  const char *saved_message;
+  bool saved_constant_expression_p;
+
+  /* Initialize FORMAT the first time we get here.  */
+  if (!format)
+    format = "types may not be defined in `%s' expressions";
+
+  /* Types cannot be defined in a `sizeof' expression.  Save away the
+     old message.  */
+  saved_message = parser->type_definition_forbidden_message;
+  /* And create the new one.  */
+  parser->type_definition_forbidden_message 
+    = ((const char *) 
+       xmalloc (strlen (format) 
+               + strlen (IDENTIFIER_POINTER (ridpointers[keyword]))
+               + 1 /* `\0' */));
+  sprintf ((char *) parser->type_definition_forbidden_message,
+          format, IDENTIFIER_POINTER (ridpointers[keyword]));
+
+  /* The restrictions on constant-expressions do not apply inside
+     sizeof expressions.  */
+  saved_constant_expression_p = parser->constant_expression_p;
+  parser->constant_expression_p = false;
+
+  /* If it's a `(', then we might be looking at the type-id
+     construction.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      tree type;
+
+      /* We can't be sure yet whether we're looking at a type-id or an
+        expression.  */
+      cp_parser_parse_tentatively (parser);
+      /* Consume the `('.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Parse the type-id.  */
+      type = cp_parser_type_id (parser);
+      /* Now, look for the trailing `)'.  */
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+      /* If all went well, then we're done.  */
+      if (cp_parser_parse_definitely (parser))
+       {
+         /* Build a list of decl-specifiers; right now, we have only
+            a single type-specifier.  */
+         type = build_tree_list (NULL_TREE,
+                                 type);
+
+         /* Call grokdeclarator to figure out what type this is.  */
+         expr = grokdeclarator (NULL_TREE,
+                                type,
+                                TYPENAME,
+                                /*initialized=*/0,
+                                /*attrlist=*/NULL);
+       }
+    }
+
+  /* If the type-id production did not work out, then we must be
+     looking at the unary-expression production.  */
+  if (!expr)
+    expr = cp_parser_unary_expression (parser, /*address_p=*/false);
+
+  /* Free the message we created.  */
+  free ((char *) parser->type_definition_forbidden_message);
+  /* And restore the old one.  */
+  parser->type_definition_forbidden_message = saved_message;
+  parser->constant_expression_p = saved_constant_expression_p;
+
+  return expr;
+}
+
+/* If the current declaration has no declarator, return true.  */
+
+static bool
+cp_parser_declares_only_class_p (cp_parser *parser)
+{
+  /* If the next token is a `;' or a `,' then there is no 
+     declarator.  */
+  return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+         || cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
+}
+
+/* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
+   Returns TRUE iff `friend' appears among the DECL_SPECIFIERS.  */
+
+static bool
+cp_parser_friend_p (decl_specifiers)
+     tree decl_specifiers;
+{
+  while (decl_specifiers)
+    {
+      /* See if this decl-specifier is `friend'.  */
+      if (TREE_CODE (TREE_VALUE (decl_specifiers)) == IDENTIFIER_NODE
+         && C_RID_CODE (TREE_VALUE (decl_specifiers)) == RID_FRIEND)
+       return true;
+
+      /* Go on to the next decl-specifier.  */
+      decl_specifiers = TREE_CHAIN (decl_specifiers);
+    }
+
+  return false;
+}
+
+/* If the next token is of the indicated TYPE, consume it.  Otherwise,
+   issue an error message indicating that TOKEN_DESC was expected.
+   
+   Returns the token consumed, if the token had the appropriate type.
+   Otherwise, returns NULL.  */
+
+static cp_token *
+cp_parser_require (parser, type, token_desc)
+     cp_parser *parser;
+     enum cpp_ttype type;
+     const char *token_desc;
+{
+  if (cp_lexer_next_token_is (parser->lexer, type))
+    return cp_lexer_consume_token (parser->lexer);
+  else
+    {
+      dyn_string_t error_msg;
+
+      /* Format the error message.  */
+      error_msg = dyn_string_new (0);
+      dyn_string_append_cstr (error_msg, "expected ");
+      dyn_string_append_cstr (error_msg, token_desc);
+      cp_parser_error (parser, error_msg->s);
+      dyn_string_delete (error_msg);
+      return NULL;
+    }
+}
+
+/* Like cp_parser_require, except that tokens will be skipped until
+   the desired token is found.  An error message is still produced if
+   the next token is not as expected.  */
+
+static void
+cp_parser_skip_until_found (parser, type, token_desc)
+     cp_parser *parser;
+     enum cpp_ttype type;
+     const char *token_desc;
+{
+  cp_token *token;
+  unsigned nesting_depth = 0;
+
+  if (cp_parser_require (parser, type, token_desc))
+    return;
+
+  /* Skip tokens until the desired token is found.  */
+  while (true)
+    {
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* If we've reached the token we want, consume it and 
+        stop.  */
+      if (token->type == type && !nesting_depth)
+       {
+         cp_lexer_consume_token (parser->lexer);
+         return;
+       }
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      if (token->type == CPP_OPEN_BRACE 
+         || token->type == CPP_OPEN_PAREN
+         || token->type == CPP_OPEN_SQUARE)
+       ++nesting_depth;
+      else if (token->type == CPP_CLOSE_BRACE 
+              || token->type == CPP_CLOSE_PAREN
+              || token->type == CPP_CLOSE_SQUARE)
+       {
+         if (nesting_depth-- == 0)
+           return;
+       }
+      /* Consume this token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+}
+
+/* If the next token is the indicated keyword, consume it.  Otherwise,
+   issue an error message indicating that TOKEN_DESC was expected.
+   
+   Returns the token consumed, if the token had the appropriate type.
+   Otherwise, returns NULL.  */
+
+static cp_token *
+cp_parser_require_keyword (parser, keyword, token_desc)
+     cp_parser *parser;
+     enum rid keyword;
+     const char *token_desc;
+{
+  cp_token *token = cp_parser_require (parser, CPP_KEYWORD, token_desc);
+
+  if (token && token->keyword != keyword)
+    {
+      dyn_string_t error_msg;
+
+      /* Format the error message.  */
+      error_msg = dyn_string_new (0);
+      dyn_string_append_cstr (error_msg, "expected ");
+      dyn_string_append_cstr (error_msg, token_desc);
+      cp_parser_error (parser, error_msg->s);
+      dyn_string_delete (error_msg);
+      return NULL;
+    }
+
+  return token;
+}
+
+/* Returns TRUE iff TOKEN is a token that can begin the body of a
+   function-definition.  */
+
+static bool 
+cp_parser_token_starts_function_definition_p (token)
+     cp_token *token;
+{
+  return (/* An ordinary function-body begins with an `{'.  */
+         token->type == CPP_OPEN_BRACE
+         /* A ctor-initializer begins with a `:'.  */
+         || token->type == CPP_COLON
+         /* A function-try-block begins with `try'.  */
+         || token->keyword == RID_TRY
+         /* The named return value extension begins with `return'.  */
+         || token->keyword == RID_RETURN);
+}
+
+/* Returns TRUE iff the next token is the ":" or "{" beginning a class
+   definition.  */
+
+static bool
+cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
+{
+  cp_token *token;
+
+  token = cp_lexer_peek_token (parser->lexer);
+  return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
+}
+
+/* Returns the kind of tag indicated by TOKEN, if it is a class-key,
+   or none_type otherwise.  */
+
+static enum tag_types
+cp_parser_token_is_class_key (token)
+     cp_token *token;
+{
+  switch (token->keyword)
+    {
+    case RID_CLASS:
+      return class_type;
+    case RID_STRUCT:
+      return record_type;
+    case RID_UNION:
+      return union_type;
+      
+    default:
+      return none_type;
+    }
+}
+
+/* Issue an error message if the CLASS_KEY does not match the TYPE.  */
+
+static void
+cp_parser_check_class_key (enum tag_types class_key, tree type)
+{
+  if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
+    pedwarn ("`%s' tag used in naming `%#T'",
+           class_key == union_type ? "union"
+            : class_key == record_type ? "struct" : "class", 
+            type);
+}
+                          
+/* Look for the `template' keyword, as a syntactic disambiguator.
+   Return TRUE iff it is present, in which case it will be 
+   consumed.  */
+
+static bool
+cp_parser_optional_template_keyword (cp_parser *parser)
+{
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    {
+      /* The `template' keyword can only be used within templates;
+        outside templates the parser can always figure out what is a
+        template and what is not.  */
+      if (!processing_template_decl)
+       {
+         error ("`template' (as a disambiguator) is only allowed "
+                "within templates");
+         /* If this part of the token stream is rescanned, the same
+            error message would be generated.  So, we purge the token
+            from the stream.  */
+         cp_lexer_purge_token (parser->lexer);
+         return false;
+       }
+      else
+       {
+         /* Consume the `template' keyword.  */
+         cp_lexer_consume_token (parser->lexer);
+         return true;
+       }
+    }
+
+  return false;
+}
+
+/* Add tokens to CACHE until an non-nested END token appears.  */
+
+static void
+cp_parser_cache_group (cp_parser *parser, 
+                      cp_token_cache *cache,
+                      enum cpp_ttype end,
+                      unsigned depth)
+{
+  while (true)
+    {
+      cp_token *token;
+
+      /* Abort a parenthesized expression if we encounter a brace.  */
+      if ((end == CPP_CLOSE_PAREN || depth == 0)
+         && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       return;
+      /* Consume the next token.  */
+      token = cp_lexer_consume_token (parser->lexer);
+      /* If we've reached the end of the file, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      /* Add this token to the tokens we are saving.  */
+      cp_token_cache_push_token (cache, token);
+      /* See if it starts a new group.  */
+      if (token->type == CPP_OPEN_BRACE)
+       {
+         cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, depth + 1);
+         if (depth == 0)
+           return;
+       }
+      else if (token->type == CPP_OPEN_PAREN)
+       cp_parser_cache_group (parser, cache, CPP_CLOSE_PAREN, depth + 1);
+      else if (token->type == end)
+       return;
+    }
+}
+
+/* Begin parsing tentatively.  We always save tokens while parsing
+   tentatively so that if the tentative parsing fails we can restore the
+   tokens.  */
+
+static void
+cp_parser_parse_tentatively (parser)
+     cp_parser *parser;
+{
+  /* Enter a new parsing context.  */
+  parser->context = cp_parser_context_new (parser->context);
+  /* Begin saving tokens.  */
+  cp_lexer_save_tokens (parser->lexer);
+  /* In order to avoid repetitive access control error messages,
+     access checks are queued up until we are no longer parsing
+     tentatively.  */
+  cp_parser_start_deferring_access_checks (parser);
+}
+
+/* Commit to the currently active tentative parse.  */
+
+static void
+cp_parser_commit_to_tentative_parse (parser)
+     cp_parser *parser;
+{
+  cp_parser_context *context;
+  cp_lexer *lexer;
+
+  /* Mark all of the levels as committed.  */
+  lexer = parser->lexer;
+  for (context = parser->context; context->next; context = context->next)
+    {
+      if (context->status == CP_PARSER_STATUS_KIND_COMMITTED)
+       break;
+      context->status = CP_PARSER_STATUS_KIND_COMMITTED;
+      while (!cp_lexer_saving_tokens (lexer))
+       lexer = lexer->next;
+      cp_lexer_commit_tokens (lexer);
+    }
+}
+
+/* Abort the currently active tentative parse.  All consumed tokens
+   will be rolled back, and no diagnostics will be issued.  */
+
+static void
+cp_parser_abort_tentative_parse (parser)
+     cp_parser *parser;
+{
+  cp_parser_simulate_error (parser);
+  /* Now, pretend that we want to see if the construct was
+     successfully parsed.  */
+  cp_parser_parse_definitely (parser);
+}
+
+/* Stop parsing tentatively.  If a parse error has ocurred, restore the
+   token stream.  Otherwise, commit to the tokens we have consumed.
+   Returns true if no error occurred; false otherwise.  */
+
+static bool
+cp_parser_parse_definitely (parser)
+     cp_parser *parser;
+{
+  bool error_occurred;
+  cp_parser_context *context;
+
+  /* Remember whether or not an error ocurred, since we are about to
+     destroy that information.  */
+  error_occurred = cp_parser_error_occurred (parser);
+  /* Remove the topmost context from the stack.  */
+  context = parser->context;
+  parser->context = context->next;
+  /* If no parse errors occurred, commit to the tentative parse.  */
+  if (!error_occurred)
+    {
+      /* Commit to the tokens read tentatively, unless that was
+        already done.  */
+      if (context->status != CP_PARSER_STATUS_KIND_COMMITTED)
+       cp_lexer_commit_tokens (parser->lexer);
+      if (!parser->context->deferring_access_checks_p)
+       /* If in the parent context we are not deferring checks, then
+          these perform these checks now.  */
+       (cp_parser_perform_deferred_access_checks 
+        (context->deferred_access_checks));
+      else
+       /* Any lookups that were deferred during the tentative parse are
+          still deferred.  */
+       parser->context->deferred_access_checks 
+         = chainon (parser->context->deferred_access_checks,
+                    context->deferred_access_checks);
+      return true;
+    }
+  /* Otherwise, if errors occurred, roll back our state so that things
+     are just as they were before we began the tentative parse.  */
+  else
+    {
+      cp_lexer_rollback_tokens (parser->lexer);
+      return false;
+    }
+}
+
+/* Returns non-zero if we are parsing tentatively.  */
+
+static bool
+cp_parser_parsing_tentatively (parser)
+     cp_parser *parser;
+{
+  return parser->context->next != NULL;
+}
+
+/* Returns true if we are parsing tentatively -- but have decided that
+   we will stick with this tentative parse, even if errors occur.  */
+
+static bool
+cp_parser_committed_to_tentative_parse (parser)
+     cp_parser *parser;
+{
+  return (cp_parser_parsing_tentatively (parser)
+         && parser->context->status == CP_PARSER_STATUS_KIND_COMMITTED);
+}
+
+/* Returns non-zero iff an error has occurred during the most recent
+   tentative parse.  */
+   
+static bool
+cp_parser_error_occurred (parser)
+     cp_parser *parser;
+{
+  return (cp_parser_parsing_tentatively (parser)
+         && parser->context->status == CP_PARSER_STATUS_KIND_ERROR);
+}
+
+/* Returns non-zero if GNU extensions are allowed.  */
+
+static bool
+cp_parser_allow_gnu_extensions_p (parser)
+     cp_parser *parser;
+{
+  return parser->allow_gnu_extensions_p;
+}
+
+\f
+
+/* The parser.  */
+
+static GTY (()) cp_parser *the_parser;
+
+/* External interface.  */
+
+/* Parse the entire translation unit.  */
+
+int
+yyparse ()
+{
+  bool error_occurred;
+
+  the_parser = cp_parser_new ();
+  error_occurred = cp_parser_translation_unit (the_parser);
+  the_parser = NULL;
+
+  return error_occurred;
+}
+
+/* Clean up after parsing the entire translation unit.  */
+
+void
+free_parser_stacks ()
+{
+  /* Nothing to do.  */
+}
+
+/* This variable must be provided by every front end.  */
+
+int yydebug;
+
+#include "gt-cp-parser.h"
index eb574548e777132abda9ea64f198cbbdd8ae6e08..a7d1af13ff73a2e13cc90769ad3c7090ea1e58f5 100644 (file)
@@ -36,7 +36,6 @@ Boston, MA 02111-1307, USA.  */
 #include "cp-tree.h"
 #include "tree-inline.h"
 #include "decl.h"
-#include "parse.h"
 #include "lex.h"
 #include "output.h"
 #include "except.h"
@@ -135,7 +134,6 @@ static tree tsubst_friend_class PARAMS ((tree, tree));
 static int can_complete_type_without_circularity PARAMS ((tree));
 static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int));
 static int template_decl_level PARAMS ((tree));
-static tree maybe_get_template_decl_from_type_decl PARAMS ((tree));
 static int check_cv_quals_for_unify PARAMS ((int, tree, tree));
 static tree tsubst_template_arg_vector PARAMS ((tree, tree, tsubst_flags_t));
 static tree tsubst_template_parms PARAMS ((tree, tree, tsubst_flags_t));
@@ -167,30 +165,33 @@ static tree for_each_template_parm_r PARAMS ((tree *, int *, void *));
 static tree copy_default_args_to_explicit_spec_1 PARAMS ((tree, tree));
 static void copy_default_args_to_explicit_spec PARAMS ((tree));
 static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t));
+static int eq_local_specializations (const void *, const void *);
+static tree template_for_substitution (tree);
 
-/* Do any processing required when DECL (a member template declaration
-   using TEMPLATE_PARAMETERS as its innermost parameter list) is
-   finished.  Returns the TEMPLATE_DECL corresponding to DECL, unless
-   it is a specialization, in which case the DECL itself is returned.  */
+/* Do any processing required when DECL (a member template
+   declaration) is finished.  Returns the TEMPLATE_DECL corresponding
+   to DECL, unless it is a specialization, in which case the DECL
+   itself is returned.  */
 
 tree
 finish_member_template_decl (decl)
   tree decl;
 {
-  if (decl == NULL_TREE || decl == void_type_node)
-    return NULL_TREE;
-  else if (decl == error_mark_node)
-    /* By returning NULL_TREE, the parser will just ignore this
-       declaration.  We have already issued the error.  */
-    return NULL_TREE;
-  else if (TREE_CODE (decl) == TREE_LIST)
+  if (decl == error_mark_node)
+    return error_mark_node;
+
+  my_friendly_assert (DECL_P (decl), 20020812);
+
+  if (TREE_CODE (decl) == TYPE_DECL)
     {
-      /* Assume that the class is the only declspec.  */
-      decl = TREE_VALUE (decl);
-      if (IS_AGGR_TYPE (decl) && CLASSTYPE_TEMPLATE_INFO (decl)
-         && ! CLASSTYPE_TEMPLATE_SPECIALIZATION (decl))
+      tree type;
+
+      type = TREE_TYPE (decl);
+      if (IS_AGGR_TYPE (type) 
+         && CLASSTYPE_TEMPLATE_INFO (type)
+         && !CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
        {
-         tree tmpl = CLASSTYPE_TI_TEMPLATE (decl);
+         tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
          check_member_template (tmpl);
          return tmpl;
        }
@@ -665,15 +666,16 @@ note_template_header (specialization)
 void
 begin_explicit_instantiation ()
 {
-  ++processing_explicit_instantiation;
+  my_friendly_assert (!processing_explicit_instantiation, 20020913);
+  processing_explicit_instantiation = true;
 }
 
 
 void
 end_explicit_instantiation ()
 {
-  my_friendly_assert(processing_explicit_instantiation > 0, 0);
-  --processing_explicit_instantiation;
+  my_friendly_assert(processing_explicit_instantiation, 20020913);
+  processing_explicit_instantiation = false;
 }
 
 /* The TYPE is being declared.  If it is a template type, that means it
@@ -683,7 +685,7 @@ void
 maybe_process_partial_specialization (type)
      tree type;
 {
-  if (IS_AGGR_TYPE (type) && CLASSTYPE_USE_TEMPLATE (type))
+  if (CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type))
     {
       if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
          && !COMPLETE_TYPE_P (type))
@@ -743,7 +745,10 @@ static tree
 retrieve_local_specialization (tmpl)
      tree tmpl;
 {
-  return (tree) htab_find (local_specializations, tmpl);
+  tree spec = 
+    (tree) htab_find_with_hash (local_specializations, tmpl,
+                               htab_hash_pointer (tmpl));
+  return spec ? TREE_PURPOSE (spec) : NULL_TREE;
 }
 
 /* Returns nonzero iff DECL is a specialization of TMPL.  */
@@ -909,6 +914,16 @@ unregister_specialization (spec, tmpl)
   return 0;
 }
 
+/* Compare an entry in the local specializations hash table P1 (which
+   is really a pointer to a TREE_LIST) with P2 (which is really a
+   DECL).  */
+
+static int
+eq_local_specializations (const void *p1, const void *p2)
+{
+  return TREE_VALUE ((tree) p1) == (tree) p2;
+}
+
 /* Like register_specialization, but for local declarations.  We are
    registering SPEC, an instantiation of TMPL.  */
 
@@ -919,8 +934,9 @@ register_local_specialization (spec, tmpl)
 {
   void **slot;
 
-  slot = htab_find_slot (local_specializations, tmpl, INSERT);
-  *slot = spec;
+  slot = htab_find_slot_with_hash (local_specializations, tmpl, 
+                                  htab_hash_pointer (tmpl), INSERT);
+  *slot = build_tree_list (spec, tmpl);
 }
 
 /* Print the list of candidate FNS in an error message.  */
@@ -2600,9 +2616,7 @@ push_template_decl_real (decl, is_friend)
 
   if (!ctx 
       || TREE_CODE (ctx) == FUNCTION_DECL
-      || (TREE_CODE (ctx) != TEMPLATE_TYPE_PARM
-         && TREE_CODE (ctx) != BOUND_TEMPLATE_TEMPLATE_PARM
-         && TYPE_BEING_DEFINED (ctx))
+      || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
       || (is_friend && !DECL_TEMPLATE_INFO (decl)))
     {
       if (DECL_LANG_SPECIFIC (decl)
@@ -3875,7 +3889,7 @@ lookup_template_function (fns, arglist)
    return the associated TEMPLATE_DECL.  Otherwise, the original
    DECL is returned.  */
 
-static tree
+tree
 maybe_get_template_decl_from_type_decl (decl)
      tree decl;
 {
@@ -4427,6 +4441,12 @@ for_each_template_parm_r (tp, walk_subtrees, d)
       }
       break;
 
+    case TYPEOF_TYPE:
+      if (for_each_template_parm (TYPE_FIELDS (t), fn, data, 
+                                 pfd->visited))
+       return error_mark_node;
+      break;
+
     case FUNCTION_DECL:
     case VAR_DECL:
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
@@ -4435,8 +4455,12 @@ for_each_template_parm_r (tp, walk_subtrees, d)
        return error_mark_node;
       /* Fall through.  */
 
-    case CONST_DECL:
     case PARM_DECL:
+    case CONST_DECL:
+      if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)
+         && for_each_template_parm (DECL_INITIAL (t), fn, data,
+                                    pfd->visited))
+       return error_mark_node;
       if (DECL_CONTEXT (t) 
          && for_each_template_parm (DECL_CONTEXT (t), fn, data,
                                     pfd->visited))
@@ -5951,10 +5975,6 @@ tsubst_decl (t, args, type, complain)
               being called from tsubst_friend_function, and we want
               only to create a new decl (R) with appropriate types so
               that we can call determine_specialization.  */
-           my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t)) 
-                                == LOOKUP_EXPR)
-                               || (TREE_CODE (DECL_TI_TEMPLATE (t))
-                                   == IDENTIFIER_NODE), 0);
            gen_tmpl = NULL_TREE;
          }
 
@@ -7059,13 +7079,17 @@ tsubst_copy (t, args, complain, in_decl)
   switch (code)
     {
     case PARM_DECL:
-      return do_identifier (DECL_NAME (t), 0, NULL_TREE);
+      r = retrieve_local_specialization (t);
+      my_friendly_assert (r != NULL, 20020903);
+      return r;
 
     case CONST_DECL:
       {
        tree enum_type;
        tree v;
 
+       if (DECL_TEMPLATE_PARM_P (t))
+         return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
        if (!DECL_CONTEXT (t))
          /* This is a global enumeration constant.  */
          return t;
@@ -7111,13 +7135,53 @@ tsubst_copy (t, args, complain, in_decl)
 
     case VAR_DECL:
     case FUNCTION_DECL:
-      if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+      if ((DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+         || local_variable_p (t))
        t = tsubst (t, args, complain, in_decl);
       mark_used (t);
       return t;
 
+    case BASELINK:
+      {
+       tree name;
+       tree qualifying_scope;
+       tree fns;
+       tree template_args;
+       bool template_id_p = false;
+
+       /* A baselink indicates a function from a base class.  The
+          BASELINK_ACCESS_BINFO and BASELINK_BINFO are going to have
+          non-dependent types; otherwise, the lookup could not have
+          succeeded.  However, they may indicate bases of the template
+          class, rather than the instantiated class.  
+          
+          In addition, lookups that were not ambiguous before may be
+          ambiguous now.  Therefore, we perform the lookup again. */
+       qualifying_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (t));
+       fns = BASELINK_FUNCTIONS (t);
+       if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+         {
+           template_id_p = true;
+           template_args = TREE_OPERAND (fns, 1);
+           fns = TREE_OPERAND (fns, 0);
+         }
+       name = DECL_NAME (get_first_fn (fns));
+       t = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
+       if (BASELINK_P (t) && template_id_p)
+         BASELINK_FUNCTIONS (t) 
+           = build_nt (TEMPLATE_ID_EXPR,
+                       BASELINK_FUNCTIONS (t),
+                       template_args);
+       return adjust_result_of_qualified_name_lookup (t, 
+                                                      qualifying_scope,
+                                                      current_class_type);
+      }
+
     case TEMPLATE_DECL:
-      if (is_member_template (t))
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+       return tsubst (TREE_TYPE (DECL_TEMPLATE_RESULT (t)), 
+                      args, complain, in_decl);
+      else if (is_member_template (t))
        return tsubst (t, args, complain, in_decl);
       else
        return t;
@@ -7168,6 +7232,35 @@ tsubst_copy (t, args, complain, in_decl)
        (code, tsubst (TREE_TYPE (t), args, complain, in_decl),
         tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
 
+    case COMPONENT_REF:
+      {
+       tree object;
+       tree name;
+
+       object = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
+       name = TREE_OPERAND (t, 1);
+       if (TREE_CODE (name) == BIT_NOT_EXPR) 
+         {
+           name = tsubst_copy (TREE_OPERAND (name, 0), args,
+                               complain, in_decl);
+           name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
+         }
+       else if (TREE_CODE (name) == SCOPE_REF
+                && TREE_CODE (TREE_OPERAND (name, 1)) == BIT_NOT_EXPR)
+         {
+           tree base = tsubst_copy (TREE_OPERAND (name, 0), args,
+                                    complain, in_decl);
+           name = TREE_OPERAND (name, 1);
+           name = tsubst_copy (TREE_OPERAND (name, 0), args,
+                               complain, in_decl);
+           name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
+           name = build_nt (SCOPE_REF, base, name);
+         }
+       else
+         name = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
+       return build_nt (COMPONENT_REF, object, name);
+      }
+
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
@@ -7198,7 +7291,6 @@ tsubst_copy (t, args, complain, in_decl)
     case GE_EXPR:
     case LT_EXPR:
     case GT_EXPR:
-    case COMPONENT_REF:
     case ARRAY_REF:
     case COMPOUND_EXPR:
     case SCOPE_REF:
@@ -7213,48 +7305,20 @@ tsubst_copy (t, args, complain, in_decl)
         tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl));
 
     case CALL_EXPR:
-      {
-       tree fn = TREE_OPERAND (t, 0);
-       if (is_overloaded_fn (fn))
-         fn = tsubst_copy (get_first_fn (fn), args, complain, in_decl);
-       else
-         /* Sometimes FN is a LOOKUP_EXPR.  */
-         fn = tsubst_copy (fn, args, complain, in_decl);
-       return build_nt
-         (code, fn, tsubst_copy (TREE_OPERAND (t, 1), args, complain,
-                                 in_decl),
-          NULL_TREE);
-      }
+      return build_nt (code, 
+                      tsubst_copy (TREE_OPERAND (t, 0), args,
+                                   complain, in_decl),
+                      tsubst_copy (TREE_OPERAND (t, 1), args, complain,
+                                   in_decl),
+                      NULL_TREE);
 
     case METHOD_CALL_EXPR:
-      {
-       tree name = TREE_OPERAND (t, 0);
-       if (TREE_CODE (name) == BIT_NOT_EXPR)
-         {
-           name = tsubst_copy (TREE_OPERAND (name, 0), args,
-                               complain, in_decl);
-           name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
-         }
-       else if (TREE_CODE (name) == SCOPE_REF
-                && TREE_CODE (TREE_OPERAND (name, 1)) == BIT_NOT_EXPR)
-         {
-           tree base = tsubst_copy (TREE_OPERAND (name, 0), args,
-                                    complain, in_decl);
-           name = TREE_OPERAND (TREE_OPERAND (name, 1), 0);
-           if (TREE_CODE (name) == TYPE_DECL)
-             name = TREE_TYPE (name);
-           name = tsubst_copy (name, args, complain, in_decl);
-           name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
-           name = build_nt (SCOPE_REF, base, name);
-         }
-       else
-         name = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-       return build_nt
-         (code, name, tsubst_copy (TREE_OPERAND (t, 1), args,
-                                   complain, in_decl),
-          tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl),
-          NULL_TREE);
-      }
+      return build_nt
+       (code, 
+        tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
+        tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl),
+        tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl),
+        NULL_TREE);
 
     case STMT_EXPR:
       /* This processing should really occur in tsubst_expr, However,
@@ -7465,7 +7529,10 @@ tsubst_expr (t, args, complain, in_decl)
            tree name = DECL_NAME (decl);
            
            scope = tsubst_expr (scope, args, complain, in_decl);
-           do_local_using_decl (build_nt (SCOPE_REF, scope, name));
+           do_local_using_decl (lookup_qualified_name (scope,
+                                                       name, 
+                                                       /*is_type_p=*/0,
+                                                       /*flags=*/0));
          }
        else
          {
@@ -9123,6 +9190,8 @@ unify (tparms, targs, parm, arg, strict)
                    strict);
 
     case CONST_DECL:
+      if (DECL_TEMPLATE_PARM_P (parm))
+       return unify (tparms, targs, DECL_INITIAL (parm), arg, strict);
       if (arg != decl_constant_value (parm)) 
        return 1;
       return 0;
@@ -9915,7 +9984,7 @@ regenerate_decl_from_template (decl, tmpl)
     /* Make sure that we can see identifiers, and compute access
        correctly, for the class members used in the declaration of
        this static variable or function.  */
-    pushclass (DECL_CONTEXT (decl), 2);
+    push_nested_class (DECL_CONTEXT (decl), 2);
 
   /* Do the substitution to get the new declaration.  */
   new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE);
@@ -9939,7 +10008,7 @@ regenerate_decl_from_template (decl, tmpl)
 
   /* Pop the class context we pushed above.  */
   if (DECL_CLASS_SCOPE_P (decl))
-    popclass ();
+    pop_nested_class ();
 
   /* The immediate parent of the new template is still whatever it was
      before, even though tsubst sets DECL_TI_TEMPLATE up as the most
@@ -9960,6 +10029,65 @@ regenerate_decl_from_template (decl, tmpl)
   register_specialization (decl, gen_tmpl, args);
 }
 
+/* Return the TEMPLATE_DECL into which DECL_TI_ARGS(DECL) should be
+   substituted to get DECL.  */
+
+static tree
+template_for_substitution (tree decl)
+{
+  tree tmpl = DECL_TI_TEMPLATE (decl);
+
+  /* Set TMPL to the template whose DECL_TEMPLATE_RESULT is the pattern
+     for the instantiation.  This is not always the most general
+     template.  Consider, for example:
+
+        template <class T>
+       struct S { template <class U> void f();
+                  template <> void f<int>(); };
+
+     and an instantiation of S<double>::f<int>.  We want TD to be the
+     specialization S<T>::f<int>, not the more general S<T>::f<U>.  */
+  while (/* An instantiation cannot have a definition, so we need a
+           more general template.  */
+        DECL_TEMPLATE_INSTANTIATION (tmpl)
+          /* We must also deal with friend templates.  Given:
+
+               template <class T> struct S { 
+                 template <class U> friend void f() {};
+               };
+
+             S<int>::f<U> say, is not an instantiation of S<T>::f<U>,
+             so far as the language is concerned, but that's still
+             where we get the pattern for the instantiation from.  On
+             other hand, if the definition comes outside the class, say:
+
+               template <class T> struct S { 
+                 template <class U> friend void f();
+               };
+               template <class U> friend void f() {}
+
+             we don't need to look any further.  That's what the check for
+             DECL_INITIAL is for.  */
+         || (TREE_CODE (decl) == FUNCTION_DECL
+             && DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (tmpl)
+             && !DECL_INITIAL (DECL_TEMPLATE_RESULT (tmpl))))
+    {
+      /* The present template, TD, should not be a definition.  If it
+        were a definition, we should be using it!  Note that we
+        cannot restructure the loop to just keep going until we find
+        a template with a definition, since that might go too far if
+        a specialization was declared, but not defined.  */
+      my_friendly_assert (!(TREE_CODE (decl) == VAR_DECL
+                           && !DECL_IN_AGGR_P (DECL_TEMPLATE_RESULT (tmpl))), 
+                         0); 
+      
+      /* Fetch the more general template.  */
+      tmpl = DECL_TI_TEMPLATE (tmpl);
+    }
+
+  return tmpl;
+}
+
 /* Produce the definition of D, a _DECL generated from a template.  If
    DEFER_OK is nonzero, then we don't have to actually do the
    instantiation now; we just have to do it sometime.  */
@@ -10017,54 +10145,8 @@ instantiate_decl (d, defer_ok)
   timevar_push (TV_PARSE);
 
   /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
-     for the instantiation.  This is not always the most general
-     template.  Consider, for example:
-
-        template <class T>
-       struct S { template <class U> void f();
-                  template <> void f<int>(); };
-
-     and an instantiation of S<double>::f<int>.  We want TD to be the
-     specialization S<T>::f<int>, not the more general S<T>::f<U>.  */
-  td = tmpl;
-  while (/* An instantiation cannot have a definition, so we need a
-           more general template.  */
-        DECL_TEMPLATE_INSTANTIATION (td)
-          /* We must also deal with friend templates.  Given:
-
-               template <class T> struct S { 
-                 template <class U> friend void f() {};
-               };
-
-             S<int>::f<U> say, is not an instantiation of S<T>::f<U>,
-             so far as the language is concerned, but that's still
-             where we get the pattern for the instantiation from.  On
-             other hand, if the definition comes outside the class, say:
-
-               template <class T> struct S { 
-                 template <class U> friend void f();
-               };
-               template <class U> friend void f() {}
-
-             we don't need to look any further.  That's what the check for
-             DECL_INITIAL is for.  */
-         || (TREE_CODE (d) == FUNCTION_DECL
-             && DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (td)
-             && !DECL_INITIAL (DECL_TEMPLATE_RESULT (td))))
-    {
-      /* The present template, TD, should not be a definition.  If it
-        were a definition, we should be using it!  Note that we
-        cannot restructure the loop to just keep going until we find
-        a template with a definition, since that might go too far if
-        a specialization was declared, but not defined.  */
-      my_friendly_assert (!(TREE_CODE (d) == VAR_DECL
-                           && !DECL_IN_AGGR_P (DECL_TEMPLATE_RESULT (td))), 
-                         0); 
-      
-      /* Fetch the more general template.  */
-      td = DECL_TI_TEMPLATE (td);
-    }
-
+     for the instantiation.  */
+  td = template_for_substitution (d);
   code_pattern = DECL_TEMPLATE_RESULT (td);
 
   /* In the case of a friend template whose definition is provided
@@ -10223,6 +10305,9 @@ instantiate_decl (d, defer_ok)
   else if (TREE_CODE (d) == FUNCTION_DECL)
     {
       htab_t saved_local_specializations;
+      tree subst_decl;
+      tree tmpl_parm;
+      tree spec_parm;
 
       /* Save away the current list, in case we are instantiating one
         template from within the body of another.  */
@@ -10230,13 +10315,31 @@ instantiate_decl (d, defer_ok)
 
       /* Set up the list of local specializations.  */
       local_specializations = htab_create (37, 
-                                          htab_hash_pointer,
-                                          htab_eq_pointer,
+                                          NULL,
+                                          eq_local_specializations,
                                           NULL);
 
       /* Set up context.  */
       start_function (NULL_TREE, d, NULL_TREE, SF_PRE_PARSED);
 
+      /* Create substitution entries for the parameters.  */
+      subst_decl = DECL_TEMPLATE_RESULT (template_for_substitution (d));
+      tmpl_parm = DECL_ARGUMENTS (subst_decl);
+      spec_parm = DECL_ARGUMENTS (d);
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (d))
+       {
+         register_local_specialization (spec_parm, tmpl_parm);
+         spec_parm = skip_artificial_parms_for (d, spec_parm);
+         tmpl_parm = skip_artificial_parms_for (subst_decl, tmpl_parm);
+       }
+      while (tmpl_parm)
+       {
+         register_local_specialization (spec_parm, tmpl_parm);
+         tmpl_parm = TREE_CHAIN (tmpl_parm);
+         spec_parm = TREE_CHAIN (spec_parm);
+       }
+      my_friendly_assert (!spec_parm, 20020813);
+
       /* Substitute into the body of the function.  */
       tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
                   tf_error | tf_warning, tmpl);
index 495e0d4576a552adb479590f92dfa5a9035b0eb7..c1a4d824afe94071fb743d37554b581bba64748b 100644 (file)
@@ -110,14 +110,17 @@ static int doing_runtime = 0;
 void
 init_rtti_processing ()
 {
+  tree const_type_info_type;
+
   push_namespace (std_identifier);
   type_info_type_node 
     = xref_tag (class_type, get_identifier ("type_info"),
                /*attributes=*/NULL_TREE, 1);
   pop_namespace ();
-  type_info_ptr_type = 
-    build_pointer_type
-     (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST));
+  const_type_info_type = build_qualified_type (type_info_type_node, 
+                                              TYPE_QUAL_CONST);
+  type_info_ptr_type = build_pointer_type (const_type_info_type);
+  type_info_ref_type = build_reference_type (const_type_info_type);
 
   create_tinfo_types ();
 }
@@ -263,7 +266,7 @@ build_typeid (exp)
     return error_mark_node;
 
   if (processing_template_decl)
-    return build_min_nt (TYPEID_EXPR, exp);
+    return build_min (TYPEID_EXPR, type_info_ref_type, exp);
 
   if (TREE_CODE (exp) == INDIRECT_REF
       && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
@@ -394,7 +397,7 @@ get_typeid (type)
     return error_mark_node;
   
   if (processing_template_decl)
-    return build_min_nt (TYPEID_EXPR, type);
+    return build_min (TYPEID_EXPR, type_info_ref_type, type);
 
   /* If the type of the type-id is a reference type, the result of the
      typeid expression refers to a type_info object representing the
index 4c03f073afd053e9497eb4d203148ceb5434b352..263cda5bb433e17e622683001156b47b88a510f5 100644 (file)
@@ -1035,7 +1035,7 @@ accessible_p (type, decl)
   int protected_ok = 0;
 
   /* If we're not checking access, everything is accessible.  */
-  if (!flag_access_control)
+  if (!scope_chain->check_access)
     return 1;
 
   /* If this declaration is in a block or namespace scope, there's no
@@ -1674,11 +1674,11 @@ lookup_fnfields_1 (type, name)
   return -1;
 }
 
-/* DECL is the result of a qualified name lookup.  QUALIFYING_CLASS
-   was the class used to qualify the name.  CONTEXT_CLASS is the class
-   corresponding to the object in which DECL will be used.  Return a
-   possibly modified version of DECL that takes into account the
-   CONTEXT_CLASS.
+/* DECL is the result of a qualified name lookup.  QUALIFYING_SCOPE is
+   the class or namespace used to qualify the name.  CONTEXT_CLASS is
+   the class corresponding to the object in which DECL will be used.
+   Return a possibly modified version of DECL that takes into account
+   the CONTEXT_CLASS.
 
    In particular, consider an expression like `B::m' in the context of
    a derived class `D'.  If `B::m' has been resolved to a BASELINK,
@@ -1687,22 +1687,22 @@ lookup_fnfields_1 (type, name)
 
 tree
 adjust_result_of_qualified_name_lookup (tree decl, 
-                                       tree qualifying_class,
+                                       tree qualifying_scope,
                                        tree context_class)
 {
-  my_friendly_assert (CLASS_TYPE_P (qualifying_class), 20020808);
-  my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
-
-  if (BASELINK_P (decl) 
-      && DERIVED_FROM_P (qualifying_class, context_class))
+  if (context_class && CLASS_TYPE_P (qualifying_scope) 
+      && DERIVED_FROM_P (qualifying_scope, context_class)
+      && BASELINK_P (decl))
     {
       tree base;
 
-      /* Look for the QUALIFYING_CLASS as a base of the
-        CONTEXT_CLASS.  If QUALIFYING_CLASS is ambiguous, we cannot
+      my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
+
+      /* Look for the QUALIFYING_SCOPE as a base of the
+        CONTEXT_CLASS.  If QUALIFYING_SCOPE is ambiguous, we cannot
         be sure yet than an error has occurred; perhaps the function
         chosen by overload resolution will be static.  */
-      base = lookup_base (context_class, qualifying_class,
+      base = lookup_base (context_class, qualifying_scope,
                          ba_ignore | ba_quiet, NULL);
       if (base)
        {
index 42a740dd71f8f341b5ab14e818b252d83f365b03..6e06da54f38dd5758c7395436fa672ed2a2c4a7d 100644 (file)
@@ -947,9 +947,9 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
                                        &allows_reg,
                                        &is_inout))
            {
-             /* By marking the type as erroneous, we will not try to
-                process this operand again in expand_asm_operands.  */
-             TREE_TYPE (operand) = error_mark_node;
+             /* By marking this operand as erroneous, we will not try
+                to process this operand again in expand_asm_operands.  */
+             TREE_VALUE (t) = error_mark_node;
              continue;
            }
 
@@ -972,12 +972,12 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
 
 /* Finish a label with the indicated NAME.  */
 
-void
+tree
 finish_label_stmt (name)
      tree name;
 {
   tree decl = define_label (input_filename, lineno, name);
-  add_stmt (build_stmt (LABEL_STMT, decl));
+  return add_stmt (build_stmt (LABEL_STMT, decl));
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
@@ -1146,6 +1146,58 @@ finish_parenthesized_expr (expr)
   return expr;
 }
 
+/* Finish a reference to a non-static data member (DECL) that is not
+   preceded by `.' or `->'.  */
+
+tree
+finish_non_static_data_member (tree decl, tree qualifying_scope)
+{
+  my_friendly_assert (TREE_CODE (decl) == FIELD_DECL, 20020909);
+
+  if (current_class_ptr == NULL_TREE)
+    {
+      if (current_function_decl 
+         && DECL_STATIC_FUNCTION_P (current_function_decl))
+       cp_error_at ("invalid use of member `%D' in static member function",
+                    decl);
+      else
+       cp_error_at ("invalid use of non-static data member `%D'", decl);
+      error ("from this location");
+
+      return error_mark_node;
+    }
+  TREE_USED (current_class_ptr) = 1;
+  if (processing_template_decl)
+    return build_min_nt (COMPONENT_REF, current_class_ref, DECL_NAME (decl));
+  else
+    {
+      tree access_type = current_class_type;
+      tree object = current_class_ref;
+
+      while (!DERIVED_FROM_P (context_for_name_lookup (decl), access_type))
+       {
+         access_type = TYPE_CONTEXT (access_type);
+         while (DECL_P (access_type))
+           access_type = DECL_CONTEXT (access_type);
+       }
+
+      enforce_access (access_type, decl);
+
+      /* If the data member was named `C::M', convert `*this' to `C'
+        first.  */
+      if (qualifying_scope)
+       {
+         tree binfo = NULL_TREE;
+         object = build_scoped_ref (object, qualifying_scope,
+                                    &binfo);
+       }
+
+      return build_class_member_access_expr (object, decl,
+                                            /*access_path=*/NULL_TREE,
+                                            /*preserve_reference=*/false);
+    }
+}
+
 /* Begin a statement-expression.  The value returned must be passed to
    finish_stmt_expr.  */
 
@@ -1251,6 +1303,26 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
   my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
                      20020712);
 
+  /* A reference to a member function will appear as an overloaded
+     function (rather than a BASELINK) if an unqualified name was used
+     to refer to it.  */
+  if (!BASELINK_P (fn) && is_overloaded_fn (fn))
+    {
+      tree f;
+
+      if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+       f = get_first_fn (TREE_OPERAND (fn, 0));
+      else
+       f = get_first_fn (fn);
+      if (DECL_FUNCTION_MEMBER_P (f))
+       {
+         tree type = currently_open_derived_class (DECL_CONTEXT (f));
+         fn = build_baselink (TYPE_BINFO (type),
+                              TYPE_BINFO (type),
+                              fn, /*optype=*/NULL_TREE);
+       }
+    }
+
   if (BASELINK_P (fn))
     {
       tree object;
@@ -1296,6 +1368,20 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
   else if (is_overloaded_fn (fn))
     /* A call to a namespace-scope function.  */
     return build_new_function_call (fn, args);
+  else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
+    {
+      tree result;
+
+      if (args)
+       error ("arguments to destructor are not allowed");
+      /* Mark the pseudo-destructor call as having side-effects so
+        that we do not issue warnings about its use.  */
+      result = build1 (NOP_EXPR,
+                      void_type_node,
+                      TREE_OPERAND (fn, 0));
+      TREE_SIDE_EFFECTS (result) = 1;
+      return result;
+    }
   else if (CLASS_TYPE_P (TREE_TYPE (fn)))
     {
       /* If the "function" is really an object of class type, it might
@@ -1386,6 +1472,11 @@ finish_object_call_expr (fn, object, args)
        }
     }
   
+  if (processing_template_decl)
+    return build_nt (CALL_EXPR,
+                    build_nt (COMPONENT_REF, object, fn),
+                    args);
+
   if (name_p (fn))
     return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
   else
@@ -1405,29 +1496,38 @@ finish_qualified_object_call_expr (fn, object, args)
                                   TREE_OPERAND (fn, 1), args);
 }
 
-/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
-   being the scope, if any, of DESTRUCTOR.  Returns an expression for
-   the call.  */
+/* Finish a pseudo-destructor expression.  If SCOPE is NULL, the
+   expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is
+   the TYPE for the type given.  If SCOPE is non-NULL, the expression
+   was of the form `OBJECT.SCOPE::~DESTRUCTOR'.  */
 
 tree 
-finish_pseudo_destructor_call_expr (object, scope, destructor)
+finish_pseudo_destructor_expr (object, scope, destructor)
      tree object;
      tree scope;
      tree destructor;
 {
-  if (processing_template_decl)
-    return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor);
+  if (destructor == error_mark_node)
+    return error_mark_node;
 
-  if (scope && scope != destructor)
-    error ("destructor specifier `%T::~%T()' must have matching names", 
-             scope, destructor);
+  my_friendly_assert (TYPE_P (destructor), 20010905);
 
-  if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
-      && (TREE_CODE (TREE_TYPE (object)) !=
-         TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
-    error ("`%E' is not of type `%T'", object, destructor);
+  if (!processing_template_decl)
+    {
+      if (scope == error_mark_node)
+       {
+         error ("invalid qualifying scope in pseudo-destructor name");
+         return error_mark_node;
+       }
+      
+      if (!same_type_p (TREE_TYPE (object), destructor))
+       {
+         error ("`%E' is not of type `%T'", object, destructor);
+         return error_mark_node;
+       }
+    }
 
-  return cp_convert (void_type_node, object);
+  return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
 }
 
 /* Finish an expression of the form CODE EXPR.  */
@@ -1464,6 +1564,40 @@ finish_id_expr (expr)
   return expr;
 }
 
+/* Finish a compound-literal expression.  TYPE is the type to which
+   the INITIALIZER_LIST is being cast.  */
+
+tree
+finish_compound_literal (type, initializer_list)
+     tree type;
+     tree initializer_list;
+{
+  tree compound_literal;
+
+  /* Build a CONSTRUCTOR for the INITIALIZER_LIST.  */
+  compound_literal = build_nt (CONSTRUCTOR, NULL_TREE,
+                              initializer_list);
+  /* Mark it as a compound-literal.  */
+  TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+  if (processing_template_decl)
+    TREE_TYPE (compound_literal) = type;
+  else
+    {
+      /* Check the initialization.  */
+      compound_literal = digest_init (type, compound_literal, NULL);
+      /* If the TYPE was an array type with an unknown bound, then we can
+        figure out the dimension now.  For example, something like:
+
+          `(int []) { 2, 3 }'
+
+        implies that the array has two elements.  */
+      if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
+       complete_array_type (type, compound_literal, 1);
+    }
+
+  return compound_literal;
+}
+
 /* Return the declaration for the function-name variable indicated by
    ID.  */
 
@@ -1922,26 +2056,12 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
        note_got_semicolon (t);
     }
 
-  if (! semi)
-    check_for_missing_semicolon (t); 
   if (pop_scope_p)
     pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t)));
-  if (current_scope () == current_function_decl)
-    do_pending_defargs ();
 
   return t;
 }
 
-/* Finish processing the default argument expressions cached during
-   the processing of a class definition.  */
-
-void
-begin_inline_definitions ()
-{
-  if (current_scope () == current_function_decl)
-    do_pending_inlines ();
-}
-
 /* Finish processing the declaration of a member class template
    TYPES whose template parameters are given by PARMS.  */
 
@@ -2124,9 +2244,6 @@ tree
 finish_sizeof (t)
      tree t;
 {
-  if (processing_template_decl)
-    return build_min_nt (SIZEOF_EXPR, t);
-
   return TYPE_P (t) ? cxx_sizeof (t) : expr_sizeof (t);
 }
 
@@ -2138,7 +2255,7 @@ finish_alignof (t)
      tree t;
 {
   if (processing_template_decl)
-    return build_min_nt (ALIGNOF_EXPR, t);
+    return build_min (ALIGNOF_EXPR, size_type_node, t);
 
   return TYPE_P (t) ? cxx_alignof (t) : c_alignof_expr (t);
 }
index 947ca36c6d4cfc73ca50829fae0800f633517ae6..d50c926b0951424811b82c3eaa59ed9141085e9a 100644 (file)
@@ -33,7 +33,6 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "c-pragma.h"
 #include "lex.h"
-#include "parse.h"
 #include "flags.h"
 #include "obstack.h"
 #include "toplev.h"
index 4c328394114f03a4ed7ecdfd9c854b5ad21cd6fe..271fd0f2dbcc6d4866e5e029e7b08073ca557f0e 100644 (file)
@@ -1034,20 +1034,6 @@ really_overloaded_fn (x)
          || TREE_CODE (x) == TEMPLATE_ID_EXPR);
 }
 
-/* Return the OVERLOAD or FUNCTION_DECL inside FNS.  FNS can be an
-   OVERLOAD, FUNCTION_DECL, TEMPLATE_ID_EXPR, or baselink.  */
-
-tree
-get_overloaded_fn (fns)
-     tree fns;
-{
-  if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
-    fns = TREE_OPERAND (fns, 0);
-  if (BASELINK_P (fns))
-    fns = BASELINK_FUNCTIONS (fns);
-  return fns;
-}
-
 tree
 get_first_fn (from)
      tree from;
index 9285ec016867d7b594e6a05f99262064206c61ce..2e95f572705ad77258c14190b0dc35dd0d1f8109 100644 (file)
@@ -66,6 +66,7 @@ static void casts_away_constness_r PARAMS ((tree *, tree *));
 static int casts_away_constness PARAMS ((tree, tree));
 static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
 static tree strip_all_pointer_quals PARAMS ((tree));
+static tree lookup_destructor (tree, tree, tree);
 
 /* Return the target type of TYPE, which means return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
@@ -1858,6 +1859,9 @@ build_class_member_access_expr (tree object, tree member,
   if (object == error_mark_node || member == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
+    return member;
+
   my_friendly_assert (DECL_P (member) || BASELINK_P (member),
                      20020801);
 
@@ -1988,7 +1992,14 @@ build_class_member_access_expr (tree object, tree member,
         anonymous union.  Generate a reference to the anonymous union
         itself, and recur to find MEMBER.  */
       if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
-         && !same_type_p (object_type, DECL_CONTEXT (member)))
+         /* When this code is called from build_field_call, the
+            object already has the type of the anonymous union.
+            That is because the COMPONENT_REF was already
+            constructed, and was then disassembled before calling
+            build_field_call.  After the function-call code is
+            cleaned up, this waste can be eliminated.  */
+         && (!same_type_ignoring_top_level_qualifiers_p 
+             (TREE_TYPE (object), DECL_CONTEXT (member))))
        {
          tree anonymous_union;
 
@@ -2030,6 +2041,7 @@ build_class_member_access_expr (tree object, tree member,
     {
       /* The member is a (possibly overloaded) member function.  */
       tree functions;
+      tree type;
 
       /* If the MEMBER is exactly one static member function, then we
         know the type of the expression.  Otherwise, we must wait
@@ -2037,19 +2049,12 @@ build_class_member_access_expr (tree object, tree member,
       functions = BASELINK_FUNCTIONS (member);
       if (TREE_CODE (functions) == FUNCTION_DECL
          && DECL_STATIC_FUNCTION_P (functions))
-       {
-         /* A static member function.  */
-         result = functions;
-         mark_used (result);
-         /* If OBJECT has side-effects, they are supposed to occur.  */
-         if (TREE_SIDE_EFFECTS (object))
-           result = build (COMPOUND_EXPR, TREE_TYPE (result),
-                           object, result);
-       }
+       type = TREE_TYPE (functions);
       else
-       /* Note that we do not convert OBJECT to the BASELINK_BINFO
-          base.  That will happen when the function is called.  */
-       result = build (COMPONENT_REF, unknown_type_node, object, member);
+       type = unknown_type_node;
+      /* Note that we do not convert OBJECT to the BASELINK_BINFO
+        base.  That will happen when the function is called.  */
+      result = build (COMPONENT_REF, type, object, member);
     }
   else if (TREE_CODE (member) == CONST_DECL)
     {
@@ -2076,6 +2081,34 @@ build_class_member_access_expr (tree object, tree member,
   return result;
 }
 
+/* Return the destructor denoted by OBJECT.SCOPE::~DTOR_NAME, or, if
+   SCOPE is NULL, by OBJECT.~DTOR_NAME.  */
+
+static tree
+lookup_destructor (tree object, tree scope, tree dtor_name)
+{
+  tree object_type = TREE_TYPE (object);
+  tree dtor_type = TREE_OPERAND (dtor_name, 0);
+
+  if (scope && !check_dtor_name (scope, dtor_name))
+    {
+      error ("qualified type `%T' does not match destructor name `~%T'",
+            scope, dtor_type);
+      return error_mark_node;
+    }
+  if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
+    {
+      error ("destructor name `%T' does not match type `%T' of expression",
+            dtor_type, object_type);
+      return error_mark_node;
+    }
+  if (!TYPE_HAS_DESTRUCTOR (object_type))
+    return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
+                 dtor_type);
+  return lookup_member (object_type, complete_dtor_identifier,
+                       /*protect=*/1, /*want_type=*/0);
+}
+
 /* This function is called by the parser to process a class member
    access expression of the form OBJECT.NAME.  NAME is a node used by
    the parser to represent a name; it is not yet a DECL.  It may,
@@ -2171,33 +2204,24 @@ finish_class_member_access_expr (tree object, tree name)
          if (!access_path || access_path == error_mark_node)
            return error_mark_node;
 
-         /* Look up the member.  */
-         member = lookup_member (access_path, name, /*protect=*/1, 
-                                 /*want_type=*/0);
-         if (member == NULL_TREE)
+         if (TREE_CODE (name) == BIT_NOT_EXPR)
+           member = lookup_destructor (object, scope, name);
+         else
            {
-             error ("'%D' has no member named '%E'", object_type, name);
-             return error_mark_node;
+             /* Look up the member.  */
+             member = lookup_member (access_path, name, /*protect=*/1, 
+                                     /*want_type=*/0);
+             if (member == NULL_TREE)
+               {
+                 error ("'%D' has no member named '%E'", object_type, name);
+                 return error_mark_node;
+               }
+             if (member == error_mark_node)
+               return error_mark_node;
            }
-         else if (member == error_mark_node)
-           return error_mark_node;
        }
       else if (TREE_CODE (name) == BIT_NOT_EXPR)
-       {
-         /* A destructor.  */
-         if (TYPE_IDENTIFIER (object_type) != TREE_OPERAND (name, 0))
-           {
-             error ("destructor specifier `%T::~%T' must have matching names",
-                    object_type, TREE_OPERAND (name, 0));
-             return error_mark_node;
-           }
-         if (! TYPE_HAS_DESTRUCTOR (object_type))
-           {
-             error ("type `%T' has no destructor", object_type);
-             return error_mark_node;
-           }
-         member = CLASSTYPE_DESTRUCTORS (object_type);
-       }
+       member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
       else if (TREE_CODE (name) == IDENTIFIER_NODE)
        {
          /* An unqualified name.  */
@@ -2238,6 +2262,9 @@ finish_class_member_access_expr (tree object, tree name)
        }
     }
 
+  if (TREE_DEPRECATED (member))
+    warn_deprecated_use (member);
+
   return build_class_member_access_expr (object, member, access_path,
                                         /*preserve_reference=*/false);
 }
@@ -2907,7 +2934,8 @@ convert_arguments (typelist, values, fndecl, flags)
   if (typetail != 0 && typetail != void_list_node)
     {
       /* See if there are default arguments that can be used */
-      if (TREE_PURPOSE (typetail))
+      if (TREE_PURPOSE (typetail) 
+         && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
        {
          for (; typetail != void_list_node; ++i)
            {
@@ -4233,7 +4261,7 @@ build_unary_op (code, xarg, noconvert)
              if (current_class_type
                  && TREE_OPERAND (arg, 0) == current_class_ref)
                /* An expression like &memfn.  */
-               pedwarn ("ISO C++ forbids taking the address of an unqualified non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
+               pedwarn ("ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
              else
                pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&%T::%D'", base, name);
            }
@@ -4287,6 +4315,10 @@ build_unary_op (code, xarg, noconvert)
       {
        tree addr;
 
+       if (TREE_CODE (arg) == COMPONENT_REF
+           && TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
+         arg = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
+
        if (TREE_CODE (arg) == COMPONENT_REF
            && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
          {