diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 08177c091fa..077b97b1acb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,169 @@ +2002-12-27 Mark Mitchell + + * 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 PR c++/4803 diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 6c7a6753165..294ee52a3a0 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -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 # @@ -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 # # 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 # # 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 diff --git a/gcc/cp/NEWS b/gcc/cp/NEWS index 36720c60443..a94852cfac7 100644 --- a/gcc/cp/NEWS +++ b/gcc/cp/NEWS @@ -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 + class C { + friend void f<>(C&); + }; + + is rejected; you must first declare `f' as a template: + + template + void f(T); + +* You must use "template <>" to introduce template specializations, as + required by the standard. For example: + + template + struct S; + + struct S { }; + + is rejected; you must write: + + template <> struct S {}; + +* 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)". diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 919087059d8..805e5b27e3d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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)) + class_type = (conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE); + 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; + + /* We can end up here for copy-init of same or base class. */ + if ((flags & LOOKUP_ONLYCONVERTING) + && DECL_NONCONVERTING_P (t)) + continue; + + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) + this_arglist = mem_args; + else + this_arglist = args; + + if (TREE_CODE (t) == TEMPLATE_DECL) { - tree t = OVL_CURRENT (fn); - tree this_arglist; - - /* We can end up here for copy-init of same or base class. */ - if ((flags & LOOKUP_ONLYCONVERTING) - && DECL_NONCONVERTING_P (t)) - continue; - - 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); + /* 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); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index bf75d9de4bc..32f49a7bb11 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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 diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in index eeebb1aac57..73617f576ed 100644 --- a/gcc/cp/config-lang.in +++ b/gcc/cp/config-lang.in @@ -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" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b805f976419..5ffc6176b74 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 2443505bd8f..50d4a2ae953 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 95680dd60fa..fd3fc00a8ce 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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,111 +6073,57 @@ 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. */ + /* Conversion operators are handled specially because ordinary + unqualified name lookup will not find template conversion + operators. */ + if (IDENTIFIER_TYPENAME_P (name)) + { + struct cp_binding_level *level; + + for (level = current_binding_level; + level && !level->namespace_p; + level = level->level_chain) + { + 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; + } + + return NULL_TREE; + } + + /* Hack: copy flag set by parser, if set. */ if (only_namespace_names) namespaces_only = 1; - if (prefer_type == -2) - { - 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; - - if (type) - { - 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); - } - } - } - 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; - } + flags |= lookup_flags (prefer_type, namespaces_only); /* First, look in non-namespace scopes. */ @@ -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; } /* 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::type' in - 'B::type> B::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 + struct S { + typedef T X; + X f(); + }; + + template + typename S::X f() {} + + When parsing the decl-specifier-seq for the definition of `f', + we construct a TYPENAME_TYPE for `S::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; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 1607e379090..be91e713f3b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1220,51 +1220,34 @@ cplus_decl_attributes (decl, attributes, flags) SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); } -/* 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); } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 9ede84a7156..d7b293f7ba4 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -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. diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index ede1c473677..a550c675f44 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -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); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index bfce5564b4b..91dbf8a141c 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -913,18 +913,31 @@ 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); + return 0; + } + if (TREE_CODE (field) == VAR_DECL) + { + 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; } - if (TREE_STATIC (field)) - { - error ("field `%#D' is static; the only point of initialization is its definition", - field); - return 0; - } return 1; } @@ -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 { diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index e60ebe8761e..92d0aa63848 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -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 #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 = ""; init_reswords (); - init_spew (); init_tree (); init_cp_semantics (); init_operators (); @@ -655,75 +506,6 @@ cxx_init (filename) return filename; } -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; diff --git a/gcc/cp/lex.h b/gcc/cp/lex.h index 15de16866b7..ecd5861f686 100644 --- a/gcc/cp/lex.h +++ b/gcc/cp/lex.h @@ -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; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index e5a3bd974fb..707a4987e91 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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 index 00000000000..af5410e6428 --- /dev/null +++ b/gcc/cp/parser.c @@ -0,0 +1,14825 @@ +/* C++ Parser. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Written by Mark Mitchell . + + 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" + + +/* 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; +} + + +/* 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 void f() { + enum E { a = I }; + S 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 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 + int S::R::i = 3; + + we are supposed to assume that `S::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 struct S { ~S (); }; + template S::~S() {} + + is invalid, since `~' must be followed by a class-name, but + `S' 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 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 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 + + 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 ... + + or: + + template ... + + 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 struct S { S(); }; + template S::S(); + + correctly. We would treat `S' as a template -- if it were `S' + -- 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::i = 5, int S::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::B', `B' should be + considered a type-name, even if `A' 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 + int S::R::i = 3; + + the SCOPE will be a TYPENAME_TYPE for `S::R'. In this + context, we must resolve S::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::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 + int S::R::i = 3; + + will work; we must treat `S::R' as the name of a type. + Similarly, assume that qualified names are templates, where + required, so that: + + template + int S::R::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()', 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 struct A { + typename T::template X::I i; + }; + + are problematic. Is `T::template X' 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 struct S { struct T }; + template 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 struct A { + friend struct A::B; + }; + + A::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 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 struct B; + }; + + template struct A::B {}; + + Similarly, in a elaborated-type-specifier: + + namespace N { struct X{}; } + + struct A { + template 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 struct S{}; + template <> struct S { void f(); }; + void S::f () {} + + is correct; there shouldn't be a `template <>' for + the definition of `S::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' 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 void S::R::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 template void S::f(); */ + error ("too many template-parameter-lists"); + return false; +} + +/* Parse a binary-expression of the general form: + + binary-expression: + + binary-expression + + The TOKEN_TREE_MAP maps types to codes. FN is used + to parser the 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 struct S { S(); } + template S::S (); + + we must recognize that the nested `S' names a class. + Similarly, for: + + template S::S (); + + 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; +} + + + +/* 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" diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index eb574548e77..a7d1af13ff7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 + struct S { template void f(); + template <> void f(); }; + + and an instantiation of S::f. We want TD to be the + specialization S::f, not the more general S::f. */ + 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 struct S { + template friend void f() {}; + }; + + S::f say, is not an instantiation of S::f, + 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 struct S { + template friend void f(); + }; + template 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 - struct S { template void f(); - template <> void f(); }; - - and an instantiation of S::f. We want TD to be the - specialization S::f, not the more general S::f. */ - 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 struct S { - template friend void f() {}; - }; - - S::f say, is not an instantiation of S::f, - 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 struct S { - template friend void f(); - }; - template 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); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 495e0d4576a..c1a4d824afe 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -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 diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 4c03f073afd..263cda5bb43 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -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) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 42a740dd71f..6e06da54f38 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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); } diff --git a/gcc/cp/spew.c b/gcc/cp/spew.c index 947ca36c6d4..d50c926b095 100644 --- a/gcc/cp/spew.c +++ b/gcc/cp/spew.c @@ -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" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 4c328394114..271fd0f2dbc 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9285ec01686..2e95f572705 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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))) {